Skip to content

Commit 4043eca

Browse files
committed
Accept bytes, enum shorthands and struct defaults when encoding dynamic codecs
1 parent f5179fa commit 4043eca

16 files changed

Lines changed: 479 additions & 111 deletions

‎packages/dynamic-codecs/README.md‎

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ const codec = getNodeValueCodec([root, program, definedType], { bytesEncoding: '
6767

6868
## Value format
6969

70-
Values are raw JavaScript values that stay close to the bytes. For instance, a fixed point decodes to its raw integer, not to a decimal number. Types such as `Uint8Array`, `Set` or `Map` are avoided to keep values JSON compatible, with the exception of `bigint`.
70+
Values are raw JavaScript values that stay close to the bytes. For instance, a fixed point decodes to its raw integer, not to a decimal number. Types such as `Uint8Array`, `Set` or `Map` are avoided in decoded values to keep them JSON compatible, with the exception of `bigint`. When encoding, a few more inputs are accepted for convenience, as described in the notes below.
7171

7272
| Node | Example | Notes |
7373
| ------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------ | --------------------------------------------------------------------------------------- |
@@ -78,19 +78,19 @@ Values are raw JavaScript values that stay close to the bytes. For instance, a f
7878
| [`DurationTypeNode`](https://github.com/codama-idl/spec/blob/main/docs/typeNodes/DurationTypeNode.md) | `1500n` | The raw integer, in ticks. |
7979
| [`BooleanTypeNode`](https://github.com/codama-idl/spec/blob/main/docs/typeNodes/BooleanTypeNode.md) | `true` | |
8080
| [`StringTypeNode`](https://github.com/codama-idl/spec/blob/main/docs/typeNodes/StringTypeNode.md) | `"Hello World"` | Uses the encoding of the node. |
81-
| [`BytesTypeNode`](https://github.com/codama-idl/spec/blob/main/docs/typeNodes/BytesTypeNode.md) | `["base64", "SGVsbG8="]` | Encodes using the given encoding and decodes using the `bytesEncoding` option. |
81+
| [`BytesTypeNode`](https://github.com/codama-idl/spec/blob/main/docs/typeNodes/BytesTypeNode.md) | `["base64", "SGVsbG8="]` | Also encodes from a `Uint8Array`. Decodes using the `bytesEncoding` option. |
8282
| [`PublicKeyTypeNode`](https://github.com/codama-idl/spec/blob/main/docs/typeNodes/PublicKeyTypeNode.md) | `"9BbWp6tcX9MEGSUEpNXfspYxYsWCxE9FgRkAc3RpftkT"` | A base58 string. |
83-
| [`StructTypeNode`](https://github.com/codama-idl/spec/blob/main/docs/typeNodes/StructTypeNode.md) | `{ first_name: "John", age: 42n }` | Keys are the raw field identifiers. |
83+
| [`StructTypeNode`](https://github.com/codama-idl/spec/blob/main/docs/typeNodes/StructTypeNode.md) | `{ first_name: "John", age: 42n }` | Keys are the raw field identifiers. See [Default values](#default-values). |
8484
| [`TupleTypeNode`](https://github.com/codama-idl/spec/blob/main/docs/typeNodes/TupleTypeNode.md) | `["John", 42n]` | |
85-
| [`EnumTypeNode`](https://github.com/codama-idl/spec/blob/main/docs/typeNodes/EnumTypeNode.md) | `{ __kind: "move", __discriminator: 2, data: { x: 1n } }` | See [Enums](#enums). |
85+
| [`EnumTypeNode`](https://github.com/codama-idl/spec/blob/main/docs/typeNodes/EnumTypeNode.md) | `{ __kind: "move", __discriminator: 2, data: { x: 1n } }` | See [Enums](#enums). Variants without data also encode from their identifier. |
8686
| [`ArrayTypeNode`](https://github.com/codama-idl/spec/blob/main/docs/typeNodes/ArrayTypeNode.md) | `[1n, 2n, 3n]` | |
8787
| [`SetTypeNode`](https://github.com/codama-idl/spec/blob/main/docs/typeNodes/SetTypeNode.md) | `[1n, 2n, 3n]` | Same as arrays. |
8888
| [`MapTypeNode`](https://github.com/codama-idl/spec/blob/main/docs/typeNodes/MapTypeNode.md) | `{ key1: "value1", key2: "value2" }` | An object. |
8989
| [`OptionTypeNode`](https://github.com/codama-idl/spec/blob/main/docs/typeNodes/OptionTypeNode.md) | `{ __option: "Some", value: 42n }` or `{ __option: "None" }` | Option objects, rather than `T \| null`, keep nested options distinct. |
9090
| [`RemainderOptionTypeNode`](https://github.com/codama-idl/spec/blob/main/docs/typeNodes/RemainderOptionTypeNode.md) | `{ __option: "Some", value: 42n }` or `{ __option: "None" }` | Same as options. |
9191
| [`ZeroableOptionTypeNode`](https://github.com/codama-idl/spec/blob/main/docs/typeNodes/ZeroableOptionTypeNode.md) | `{ __option: "Some", value: 42n }` or `{ __option: "None" }` | Same as options. |
9292
| [`StructFieldTypeNode`](https://github.com/codama-idl/spec/blob/main/docs/typeNodes/StructFieldTypeNode.md) | - | Same as `node.type`. |
93-
| [`EnumVariantTypeNode`](https://github.com/codama-idl/spec/blob/main/docs/typeNodes/EnumVariantTypeNode.md) | - | Same as `node.data`, without the enum discriminator. |
93+
| [`EnumVariantTypeNode`](https://github.com/codama-idl/spec/blob/main/docs/typeNodes/EnumVariantTypeNode.md) | - | `{ __kind, data }`, prefixed by the enum discriminator when the path includes the enum. |
9494
| [`DefinedTypeNode`](https://github.com/codama-idl/spec/blob/main/docs/DefinedTypeNode.md) | - | Same as `node.type`. |
9595
| [`AccountNode`](https://github.com/codama-idl/spec/blob/main/docs/AccountNode.md) | - | Same as `node.data`. |
9696
| [`EventNode`](https://github.com/codama-idl/spec/blob/main/docs/EventNode.md) | - | Same as `node.data`. |
@@ -101,7 +101,7 @@ Values are raw JavaScript values that stay close to the bytes. For instance, a f
101101

102102
### Enums
103103

104-
Every enum decodes to an object with the raw variant identifier as `__kind` and the variant discriminator as `__discriminator`. Variants with data carry it under `data`, whatever its type. When encoding, only `__kind` and `data` are read.
104+
Every enum decodes to an object with the raw variant identifier as `__kind` and the variant discriminator as `__discriminator`. Variants with data carry it under `data`, whatever its type. When encoding, only `__kind` and `data` are read, and variants without data may also be encoded from their identifier alone. Identifiers must match exactly, and variants with data must provide it.
105105

106106
```ts
107107
const codec = getNodeValueCodec([
@@ -117,8 +117,34 @@ const codec = getNodeValueCodec([
117117
codec.decode(hex('00')); // { __kind: 'quit', __discriminator: 0 }
118118
codec.decode(hex('012a000000')); // { __kind: 'amount', __discriminator: 1, data: 42n }
119119
codec.decode(hex('020a')); // { __kind: 'move', __discriminator: 2, data: { x: 10n } }
120+
121+
codec.encode('quit'); // 0x00, same as { __kind: 'quit' }
122+
```
123+
124+
### Default values
125+
126+
Struct fields with a `defaultValue` do not need to be provided when encoding. Fields whose `defaultValueStrategy` is `omitted`, such as discriminators, always encode their default value, even if a value is provided. Other fields encode their default value when missing from the input.
127+
128+
```ts
129+
const codec = getNodeValueCodec([
130+
structTypeNode([
131+
structFieldTypeNode({
132+
defaultValue: integerValueNode('3'),
133+
defaultValueStrategy: 'omitted',
134+
identifier: 'discriminator',
135+
type: integerTypeNode('u8'),
136+
}),
137+
structFieldTypeNode({ identifier: 'amount', type: integerTypeNode('u16') }),
138+
structFieldTypeNode({ defaultValue: integerValueNode('5'), identifier: 'fee', type: integerTypeNode('u8') }),
139+
]),
140+
]);
141+
142+
codec.encode({ amount: 42 }); // 0x032a0005
143+
codec.encode({ amount: 42, fee: 9 }); // 0x032a0009
120144
```
121145

146+
Default values are only evaluated when needed. For instance, an `injectedValueNode` default only throws when it is not provided and the field is missing from the input.
147+
122148
### Transforms
123149

124150
The `transforms` of a type node are applied in order, from the innermost to the outermost. Here, the size prefix wraps the fixed-size string.

0 commit comments

Comments
 (0)