Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Candid UI cannot encode nat8 #575

Merged
merged 4 commits into from Jun 17, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
32 changes: 28 additions & 4 deletions packages/candid/src/candid-ui.ts
Expand Up @@ -117,6 +117,20 @@ class Parse extends IDL.Visitor<string, any> {
public visitFloat(t: IDL.FloatClass, v: string): number {
return parseFloat(v);
}
public visitFixedInt(t: IDL.FixedIntClass, v: string): number | bigint {
if (t._bits <= 32) {
return parseInt(v, 10);
} else {
return BigInt(v);
}
}
public visitFixedNat(t: IDL.FixedNatClass, v: string): number | bigint {
if (t._bits <= 32) {
return parseInt(v, 10);
} else {
return BigInt(v);
}
}
public visitNumber(t: IDL.PrimitiveType, v: string): bigint {
return BigInt(v);
}
Expand Down Expand Up @@ -151,11 +165,21 @@ class Random extends IDL.Visitor<string, any> {
public visitNat(t: IDL.NatClass, v: string): bigint {
return BigInt(this.generateNumber(false));
}
public visitFixedInt(t: IDL.FixedIntClass, v: string): bigint {
return BigInt(this.generateNumber(true));
public visitFixedInt(t: IDL.FixedIntClass, v: string): number | bigint {
const x = this.generateNumber(true);
if (t._bits <= 32) {
return x;
} else {
return BigInt(v);
}
}
public visitFixedNat(t: IDL.FixedNatClass, v: string): bigint {
return BigInt(this.generateNumber(false));
public visitFixedNat(t: IDL.FixedNatClass, v: string): number | bigint {
const x = this.generateNumber(false);
if (t._bits <= 32) {
return x;
} else {
return BigInt(v);
}
}
private generateNumber(signed: boolean): number {
const num = Math.floor(Math.random() * 100);
Expand Down
39 changes: 23 additions & 16 deletions packages/candid/src/idl.ts
Expand Up @@ -621,7 +621,7 @@ export class FloatClass extends PrimitiveType<number> {
* Represents an IDL fixed-width Int(n)
*/
export class FixedIntClass extends PrimitiveType<bigint | number> {
constructor(public _bits: number) {
constructor(public readonly _bits: number) {
super();
}

Expand Down Expand Up @@ -674,7 +674,7 @@ export class FixedIntClass extends PrimitiveType<bigint | number> {
* Represents an IDL fixed-width Nat(n)
*/
export class FixedNatClass extends PrimitiveType<bigint | number> {
constructor(public readonly bits: number) {
constructor(public readonly _bits: number) {
super();
}

Expand All @@ -683,7 +683,7 @@ export class FixedNatClass extends PrimitiveType<bigint | number> {
}

public covariant(x: any): x is bigint {
const max = BigInt(2) ** BigInt(this.bits);
const max = BigInt(2) ** BigInt(this._bits);
if (typeof x === 'bigint' && x >= BigInt(0)) {
return x < max;
} else if (Number.isInteger(x) && x >= 0) {
Expand All @@ -695,26 +695,26 @@ export class FixedNatClass extends PrimitiveType<bigint | number> {
}

public encodeValue(x: bigint | number) {
return writeUIntLE(x, this.bits / 8);
return writeUIntLE(x, this._bits / 8);
}

public encodeType() {
const offset = Math.log2(this.bits) - 3;
const offset = Math.log2(this._bits) - 3;
return slebEncode(-5 - offset);
}

public decodeValue(b: Pipe, t: Type) {
this.checkType(t);
const num = readUIntLE(b, this.bits / 8);
if (this.bits <= 32) {
const num = readUIntLE(b, this._bits / 8);
if (this._bits <= 32) {
return Number(num);
} else {
return num;
}
}

get name() {
return `nat${this.bits}`;
return `nat${this._bits}`;
}

public valueToString(x: bigint | number) {
Expand All @@ -741,7 +741,7 @@ export class VecClass<T> extends ConstructType<T[]> {

constructor(protected _type: Type<T>) {
super();
if (_type instanceof FixedNatClass && _type.bits === 8) {
if (_type instanceof FixedNatClass && _type._bits === 8) {
this._blobOptimization = true;
}
}
Expand All @@ -752,9 +752,16 @@ export class VecClass<T> extends ConstructType<T[]> {

public covariant(x: any): x is T[] {
// Special case for ArrayBuffer
const bits = this._type instanceof FixedNatClass ? this._type.bits : (this._type instanceof FixedIntClass ? this._type._bits : 0);
return (ArrayBuffer.isView(x) && bits == (x as any).BYTES_PER_ELEMENT * 8)
|| (Array.isArray(x) && x.every(v => this._type.covariant(v)));
const bits =
this._type instanceof FixedNatClass
? this._type._bits
: this._type instanceof FixedIntClass
? this._type._bits
: 0;
return (
(ArrayBuffer.isView(x) && bits == (x as any).BYTES_PER_ELEMENT * 8) ||
(Array.isArray(x) && x.every(v => this._type.covariant(v)))
);
}

public encodeValue(x: T[]) {
Expand Down Expand Up @@ -790,16 +797,16 @@ export class VecClass<T> extends ConstructType<T[]> {
const len = Number(lebDecode(b));

if (this._type instanceof FixedNatClass) {
if (this._type.bits == 8) {
if (this._type._bits == 8) {
return new Uint8Array(b.read(len)) as unknown as T[];
}
if (this._type.bits == 16) {
if (this._type._bits == 16) {
return new Uint16Array(b.read(len * 2)) as unknown as T[];
}
if (this._type.bits == 32) {
if (this._type._bits == 32) {
return new Uint32Array(b.read(len * 4)) as unknown as T[];
}
if (this._type.bits == 64) {
if (this._type._bits == 64) {
return new BigUint64Array(b.read(len * 8)) as unknown as T[];
}
}
Expand Down