diff --git a/borsh-ts/index.ts b/borsh-ts/index.ts index b61f4574..d69bb5f4 100644 --- a/borsh-ts/index.ts +++ b/borsh-ts/index.ts @@ -246,6 +246,13 @@ function serializeField(schema: Schema, fieldName: string, value: any, fieldType throw new BorshError(`Expecting byte array of length ${fieldType[0]}, but got ${value.length} bytes`); } writer.writeFixedArray(value); + } else if(fieldType.length === 2 && typeof fieldType[1] === 'number' ) { + if (value.length !== fieldType[1]) { + throw new BorshError(`Expecting byte array of length ${fieldType[1]}, but got ${value.length} bytes`); + } + for(let i = 0; i < fieldType[1]; i++) { + serializeField(schema, null, value[i], fieldType[0], writer); + } } else { writer.writeArray(value, (item: any) => { serializeField(schema, fieldName, item, fieldType[0], writer); }); } @@ -275,8 +282,8 @@ function serializeField(schema: Schema, fieldName: string, value: any, fieldType function serializeStruct(schema: Schema, obj: any, writer: BinaryWriter) { if (typeof obj.borshSerialize === 'function') { - obj.borshSerialize(writer); - return; + obj.borshSerialize(writer); + return; } const structSchema = schema.get(obj.constructor); if (!structSchema) { @@ -318,9 +325,15 @@ function deserializeField(schema: Schema, fieldName: string, fieldType: any, rea if (fieldType instanceof Array) { if (typeof fieldType[0] === 'number') { return reader.readFixedArray(fieldType[0]); + } else if(typeof fieldType[1] === 'number') { + const arr = []; + for(let i = 0; i < fieldType[1]; i++) { + arr.push(deserializeField(schema, null, fieldType[0], reader)); + } + return arr; + } else { + return reader.readArray(() => deserializeField(schema, fieldName, fieldType[0], reader)); } - - return reader.readArray(() => deserializeField(schema, fieldName, fieldType[0], reader)); } if (fieldType.kind === 'option') { diff --git a/borsh-ts/test/serialize.test.js b/borsh-ts/test/serialize.test.js index 460b95ae..fd8d39cf 100644 --- a/borsh-ts/test/serialize.test.js +++ b/borsh-ts/test/serialize.test.js @@ -91,9 +91,55 @@ test('serialize/deserialize with class methods', () => { expect(newValue).toEqual(item); }); +test('serialize/deserialize fixed array', () => { + const value = new Test({ + a: ['hello', 'world'] + }); + const schema = new Map([[Test, { + kind: 'struct', + fields: [ + ['a', ['string', 2]] + ] + }]]); + + const buf = borsh.serialize(schema, value); + const deserializedValue = borsh.deserialize(schema, Test, buf); + + expect(buf).toEqual(Buffer.from([5, 0, 0, 0, 104, 101, 108, 108, 111, 5, 0, 0, 0, 119, 111, 114, 108, 100])); + expect(deserializedValue.a).toEqual(['hello', 'world']); +}); + +test('errors serializing fixed array of wrong size', () => { + const value = new Test({ + a: ['hello', 'world', 'you'] + }); + const schema = new Map([[Test, { + kind: 'struct', + fields: [ + ['a', ['string', 2]] + ] + }]]); + + expect(() => borsh.serialize(schema, value)).toThrow('Expecting byte array of length 2, but got 3 bytes'); +}); + +test('errors serializing fixed array of wrong type', () => { + const value = new Test({ + a: [244, 34] + }); + const schema = new Map([[Test, { + kind: 'struct', + fields: [ + ['a', ['string', 2]] + ] + }]]); + + expect(() => borsh.serialize(schema, value)).toThrow('The first argument must be of type string'); +}); + test('baseEncode string test', async () => { - const encodedValue = borsh.baseEncode("244ZQ9cgj3CQ6bWBdytfrJMuMQ1jdXLFGnr4HhvtCTnM"); - const expectedValue = "HKk9gqNj4xb4rLdJuzT5zzJbLa4vHBdYCxQT9H99csQh6nz3Hfpqn4jtWA92"; + const encodedValue = borsh.baseEncode('244ZQ9cgj3CQ6bWBdytfrJMuMQ1jdXLFGnr4HhvtCTnM'); + const expectedValue = 'HKk9gqNj4xb4rLdJuzT5zzJbLa4vHBdYCxQT9H99csQh6nz3Hfpqn4jtWA92'; expect(encodedValue).toEqual(expectedValue); }); @@ -102,7 +148,7 @@ test('baseEncode array test', async () => { }); test('baseDecode test', async () => { - const value = "HKk9gqNj4xb4rLdJu"; + const value = 'HKk9gqNj4xb4rLdJu'; const expectedDecodedArray = [3, 96, 254, 84, 10, 240, 93, 199, 52, 244, 164, 240, 6]; const expectedBuffer = Buffer.from(expectedDecodedArray); expect(borsh.baseDecode(value)).toEqual(expectedBuffer); diff --git a/lib/index.js b/lib/index.js index b6682a14..50b19aa6 100644 --- a/lib/index.js +++ b/lib/index.js @@ -260,6 +260,14 @@ function serializeField(schema, fieldName, value, fieldType, writer) { } writer.writeFixedArray(value); } + else if (fieldType.length === 2 && typeof fieldType[1] === 'number') { + if (value.length !== fieldType[1]) { + throw new BorshError(`Expecting byte array of length ${fieldType[1]}, but got ${value.length} bytes`); + } + for (let i = 0; i < fieldType[1]; i++) { + serializeField(schema, null, value[i], fieldType[0], writer); + } + } else { writer.writeArray(value, (item) => { serializeField(schema, fieldName, item, fieldType[0], writer); }); } @@ -336,7 +344,16 @@ function deserializeField(schema, fieldName, fieldType, reader) { if (typeof fieldType[0] === 'number') { return reader.readFixedArray(fieldType[0]); } - return reader.readArray(() => deserializeField(schema, fieldName, fieldType[0], reader)); + else if (typeof fieldType[1] === 'number') { + const arr = []; + for (let i = 0; i < fieldType[1]; i++) { + arr.push(deserializeField(schema, null, fieldType[0], reader)); + } + return arr; + } + else { + return reader.readArray(() => deserializeField(schema, fieldName, fieldType[0], reader)); + } } if (fieldType.kind === 'option') { const option = reader.readU8();