-
Notifications
You must be signed in to change notification settings - Fork 915
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor(experimental): add getConstantCodec to @solana/codecs-data-s…
…tructures (#2400) This PR adds two new helpers: `containsBytes` and `getConstantCodec`. The `containsBytes` helper checks if a `Uint8Array` contains another `Uint8Array` at a given offset. ```ts containsBytes(new Uint8Array([1, 2, 3, 4]), new Uint8Array([2, 3]), 1); // true containsBytes(new Uint8Array([1, 2, 3, 4]), new Uint8Array([2, 3]), 2); // false ``` The `getConstantCodec` function accepts any `Uint8Array` and returns a `Codec<void>`. When encoding, it will set the provided `Uint8Array` as-is. When decoding, it will assert that the next bytes contain the provided `Uint8Array` and move the offset forward. ```ts const codec = getConstantCodec(new Uint8Array([1, 2, 3])); codec.encode(undefined); // 0x010203 codec.decode(new Uint8Array([1, 2, 3])); // undefined codec.decode(new Uint8Array([1, 2, 4])); // Throws an error. ```
- Loading branch information
1 parent
e77a9b4
commit ebb03cd
Showing
12 changed files
with
214 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
--- | ||
'@solana/codecs-data-structures': patch | ||
'@solana/codecs-core': patch | ||
'@solana/errors': patch | ||
--- | ||
|
||
Added new `containsBytes` and `getConstantCodec` helpers | ||
|
||
The `containsBytes` helper checks if a `Uint8Array` contains another `Uint8Array` at a given offset. | ||
|
||
```ts | ||
containsBytes(new Uint8Array([1, 2, 3, 4]), new Uint8Array([2, 3]), 1); // true | ||
containsBytes(new Uint8Array([1, 2, 3, 4]), new Uint8Array([2, 3]), 2); // false | ||
``` | ||
|
||
The `getConstantCodec` function accepts any `Uint8Array` and returns a `Codec<void>`. When encoding, it will set the provided `Uint8Array` as-is. When decoding, it will assert that the next bytes contain the provided `Uint8Array` and move the offset forward. | ||
|
||
```ts | ||
const codec = getConstantCodec(new Uint8Array([1, 2, 3])); | ||
|
||
codec.encode(undefined); // 0x010203 | ||
codec.decode(new Uint8Array([1, 2, 3])); // undefined | ||
codec.decode(new Uint8Array([1, 2, 4])); // Throws an error. | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
46 changes: 46 additions & 0 deletions
46
packages/codecs-data-structures/src/__tests__/constant-test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
import { assertIsFixedSize } from '@solana/codecs-core'; | ||
import { SOLANA_ERROR__CODECS__INVALID_CONSTANT, SolanaError } from '@solana/errors'; | ||
|
||
import { getConstantCodec } from '../constant'; | ||
import { b } from './__setup__'; | ||
|
||
describe('getConstantCodec', () => { | ||
it('encodes the provided constant', () => { | ||
const codec = getConstantCodec(b('010203')); | ||
expect(codec.encode(undefined)).toStrictEqual(b('010203')); | ||
}); | ||
|
||
it('decodes undefined when the constant is present', () => { | ||
const codec = getConstantCodec(b('010203')); | ||
expect(codec.decode(b('010203'))).toBeUndefined(); | ||
}); | ||
|
||
it('pushes the offset forward when writing', () => { | ||
const codec = getConstantCodec(b('010203')); | ||
expect(codec.write(undefined, new Uint8Array(10), 3)).toBe(6); | ||
}); | ||
|
||
it('pushes the offset forward when reading', () => { | ||
const codec = getConstantCodec(b('010203')); | ||
expect(codec.read(b('ffff01020300'), 2)).toStrictEqual([undefined, 5]); | ||
}); | ||
|
||
it('throws when the decoded bytes do no contain the constant bytes', () => { | ||
const codec = getConstantCodec(b('010203')); | ||
expect(() => codec.decode(b('0102ff'))).toThrow( | ||
new SolanaError(SOLANA_ERROR__CODECS__INVALID_CONSTANT, { | ||
constant: b('010203'), | ||
data: b('0102ff'), | ||
hexConstant: '010203', | ||
hexData: '0102ff', | ||
offset: 0, | ||
}), | ||
); | ||
}); | ||
|
||
it('returns a fixed size codec of the size of the provided byte array', () => { | ||
const codec = getConstantCodec(b('010203')); | ||
assertIsFixedSize(codec); | ||
expect(codec.fixedSize).toBe(3); | ||
}); | ||
}); |
24 changes: 24 additions & 0 deletions
24
packages/codecs-data-structures/src/__typetests__/constant-typetest.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import { FixedSizeCodec, FixedSizeDecoder, FixedSizeEncoder } from '@solana/codecs-core'; | ||
|
||
import { getConstantCodec, getConstantDecoder, getConstantEncoder } from '../constant'; | ||
|
||
const constant = {} as Uint8Array; | ||
const constant3bytes = {} as Uint8Array & { length: 3 }; | ||
|
||
{ | ||
// [getConstantEncoder]: It returns a fixed size encoder. | ||
getConstantEncoder(constant) satisfies FixedSizeEncoder<void>; | ||
getConstantEncoder(constant3bytes) satisfies FixedSizeEncoder<void, 3>; | ||
} | ||
|
||
{ | ||
// [getConstantDecoder]: It returns a fixed size decoder. | ||
getConstantDecoder(constant) satisfies FixedSizeDecoder<void>; | ||
getConstantDecoder(constant3bytes) satisfies FixedSizeDecoder<void, 3>; | ||
} | ||
|
||
{ | ||
// [getConstantCodec]: It returns a fixed size codec. | ||
getConstantCodec(constant) satisfies FixedSizeCodec<void>; | ||
getConstantCodec(constant3bytes) satisfies FixedSizeCodec<void, void, 3>; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
import { | ||
combineCodec, | ||
containsBytes, | ||
createDecoder, | ||
createEncoder, | ||
FixedSizeCodec, | ||
FixedSizeDecoder, | ||
FixedSizeEncoder, | ||
ReadonlyUint8Array, | ||
} from '@solana/codecs-core'; | ||
import { getBase16Decoder } from '@solana/codecs-strings'; | ||
import { SOLANA_ERROR__CODECS__INVALID_CONSTANT, SolanaError } from '@solana/errors'; | ||
|
||
/** | ||
* Creates a void encoder that always sets the provided byte array when encoding. | ||
*/ | ||
export function getConstantEncoder<TConstant extends ReadonlyUint8Array>( | ||
constant: TConstant, | ||
): FixedSizeEncoder<void, TConstant['length']> { | ||
return createEncoder({ | ||
fixedSize: constant.length, | ||
write: (_, bytes, offset) => { | ||
bytes.set(constant, offset); | ||
return offset + constant.length; | ||
}, | ||
}); | ||
} | ||
|
||
/** | ||
* Creates a void decoder that reads the next bytes and fails if they do not match the provided constant. | ||
*/ | ||
export function getConstantDecoder<TConstant extends ReadonlyUint8Array>( | ||
constant: TConstant, | ||
): FixedSizeDecoder<void, TConstant['length']> { | ||
return createDecoder({ | ||
fixedSize: constant.length, | ||
read: (bytes, offset) => { | ||
const base16 = getBase16Decoder(); | ||
if (!containsBytes(bytes, constant, offset)) { | ||
throw new SolanaError(SOLANA_ERROR__CODECS__INVALID_CONSTANT, { | ||
constant, | ||
data: bytes, | ||
hexConstant: base16.decode(constant), | ||
hexData: base16.decode(bytes), | ||
offset, | ||
}); | ||
} | ||
return [undefined, offset + constant.length]; | ||
}, | ||
}); | ||
} | ||
|
||
/** | ||
* Creates a void codec that always sets the provided byte array | ||
* when encoding and, when decoding, asserts that the next | ||
* bytes match the provided byte array. | ||
*/ | ||
export function getConstantCodec<TConstant extends ReadonlyUint8Array>( | ||
constant: TConstant, | ||
): FixedSizeCodec<void, void, TConstant['length']> { | ||
return combineCodec(getConstantEncoder(constant), getConstantDecoder(constant)); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters