Skip to content

Commit

Permalink
Allow to decode t as opt t
Browse files Browse the repository at this point in the history
This is a strawman PR to implement coercion of
`t` to `opt t` when decoding values.
  • Loading branch information
frederikrothenberger committed Apr 25, 2023
1 parent d8665b3 commit a58d018
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 2 deletions.
17 changes: 16 additions & 1 deletion packages/candid/src/idl.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,9 @@ test('IDL encoding (arraybuffer)', () => {
IDL.encode([IDL.Vec(IDL.Nat8)], [new Uint8Array()]);
IDL.encode([IDL.Vec(IDL.Nat8)], [new Uint8Array(100).fill(42)]);
IDL.encode([IDL.Vec(IDL.Nat16)], [new Uint16Array(200).fill(42)]);
expect(() => IDL.encode([IDL.Vec(IDL.Int8)], [new Uint16Array(10).fill(420)])).toThrow(/Invalid vec int8 argument/);
expect(() => IDL.encode([IDL.Vec(IDL.Int8)], [new Uint16Array(10).fill(420)])).toThrow(
/Invalid vec int8 argument/,
);
});

test('IDL encoding (array)', () => {
Expand Down Expand Up @@ -677,3 +679,16 @@ test('should decode matching optional fields if wire type contains additional fi
b: ['123'],
});
});

test('should coerce value to opt value', () => {
const encoded = IDL.encode([IDL.Text], ['hello']);
const value = IDL.decode([IDL.Opt(IDL.Text)], encoded)[0] as [string];
expect(value).toEqual(['hello']);
});

test('should not coerce nested opt opt', () => {
const encoded = IDL.encode([IDL.Text], ['hello']);
expect(() => IDL.decode([IDL.Opt(IDL.Opt(IDL.Text))], encoded)).toThrow(
'type mismatch: type on the wire text, expect type opt opt text',
);
});
17 changes: 16 additions & 1 deletion packages/candid/src/idl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -914,10 +914,25 @@ export class OptClass<T> extends ConstructType<[T] | []> {
typeTable.add(this, concat(opCode, buffer));
}

public checkType(t: Type): Type {
try {
return super.checkType(t);
} catch (e) {
// try to coerce t to opt t
if (!(t instanceof OptClass) && !(this._type instanceof OptClass)) {
if (this._type.checkType(t)) {
return t;
}
}
// rethrow if opt coercion is not applicable
throw e;
}
}

public decodeValue(b: Pipe, t: Type): [T] | [] {
const opt = this.checkType(t);
if (!(opt instanceof OptClass)) {
throw new Error('Not an option type');
return [this._type.decodeValue(b, opt)];
}
switch (safeReadUint8(b)) {
case 0:
Expand Down

0 comments on commit a58d018

Please sign in to comment.