Skip to content

Commit

Permalink
feat/fix: add VarInt16, VarInt32, VarUint16, VarUint32 intege…
Browse files Browse the repository at this point in the history
…r formats and fix `coins` in `foreach` (#1186)

* fix: implement `foreach` for coins and varints

* split map tests into two because we have exceeded the 255 usable stack items limit and started getting the following error `fatal: Too deep stack`
  • Loading branch information
Gusarich authored Dec 25, 2024
1 parent 402c86d commit 136665e
Show file tree
Hide file tree
Showing 27 changed files with 15,284 additions and 5,209 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- The `replace` and `replaceGet` methods for the `Map` type: PR [#941](https://github.com/tact-lang/tact/pull/941)
- Utility for logging errors in code that was supposed to be unreachable: PR [#991](https://github.com/tact-lang/tact/pull/991)
- Ability to specify a compile-time message opcode expression: PR [#1188](https://github.com/tact-lang/tact/pull/1188)
- The `VarInt16`, `VarInt32`, `VarUint16`, `VarUint32` integer serialization types: PR [#1186](https://github.com/tact-lang/tact/pull/1186)

### Changed

Expand All @@ -38,6 +39,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Type checking for `foreach` loops in trait methods: PR [#1017](https://github.com/tact-lang/tact/pull/1017)
- The `sha256()` function no longer throws on statically known strings of any length: PR [#907](https://github.com/tact-lang/tact/pull/907)
- TypeScript wrappers generation for messages with single quote: PR [#1106](https://github.com/tact-lang/tact/pull/1106)
- `foreach` loops now properly handle `as coins` map value serialization type: PR [#1186](https://github.com/tact-lang/tact/pull/1186)

### Docs

Expand Down
3 changes: 3 additions & 0 deletions cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,9 @@
"unixfs",
"untypable",
"varuint",
"varint",
"storer",
"Ints",
"workchain",
"xffff",
"привет"
Expand Down
16 changes: 16 additions & 0 deletions src/abi/map.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,10 @@ export const MapFunctions: Map<string, AbiFunction> = new Map([
vKind = "coins";
ctx.used(`__tact_dict_set_${kind}_${vKind}`);
return `${resolved[0]}~__tact_dict_set_${kind}_${vKind}(${bits}, ${resolved[1]}, ${resolved[2]})`;
} else if (self.valueAs?.startsWith("var")) {
vKind = self.valueAs;
ctx.used(`__tact_dict_set_${kind}_${vKind}`);
return `${resolved[0]}~__tact_dict_set_${kind}_${vKind}(${bits}, ${resolved[1]}, ${resolved[2]})`;
}
ctx.used(`__tact_dict_set_${kind}_${vKind}`);
return `${resolved[0]}~__tact_dict_set_${kind}_${vKind}(${bits}, ${resolved[1]}, ${resolved[2]}, ${vBits})`;
Expand Down Expand Up @@ -234,6 +238,10 @@ export const MapFunctions: Map<string, AbiFunction> = new Map([
vKind = "coins";
ctx.used(`__tact_dict_get_${kind}_${vKind}`);
return `__tact_dict_get_${kind}_${vKind}(${resolved[0]}, ${bits}, ${resolved[1]})`;
} else if (self.valueAs?.startsWith("var")) {
vKind = self.valueAs;
ctx.used(`__tact_dict_get_${kind}_${vKind}`);
return `__tact_dict_get_${kind}_${vKind}(${resolved[0]}, ${bits}, ${resolved[1]})`;
}
ctx.used(`__tact_dict_get_${kind}_${vKind}`);
return `__tact_dict_get_${kind}_${vKind}(${resolved[0]}, ${bits}, ${resolved[1]}, ${vBits})`;
Expand Down Expand Up @@ -583,6 +591,10 @@ export const MapFunctions: Map<string, AbiFunction> = new Map([
vKind = "coins";
ctx.used(`__tact_dict_replace_${kind}_${vKind}`);
return `${resolved[0]}~__tact_dict_replace_${kind}_${vKind}(${bits}, ${resolved[1]}, ${resolved[2]})`;
} else if (self.valueAs?.startsWith("var")) {
vKind = self.valueAs;
ctx.used(`__tact_dict_replace_${kind}_${vKind}`);
return `${resolved[0]}~__tact_dict_replace_${kind}_${vKind}(${bits}, ${resolved[1]}, ${resolved[2]})`;
}
ctx.used(`__tact_dict_replace_${kind}_${vKind}`);
return `${resolved[0]}~__tact_dict_replace_${kind}_${vKind}(${bits}, ${resolved[1]}, ${resolved[2]}, ${vBits})`;
Expand Down Expand Up @@ -665,6 +677,10 @@ export const MapFunctions: Map<string, AbiFunction> = new Map([
vKind = "coins";
ctx.used(`__tact_dict_replaceget_${kind}_${vKind}`);
return `${resolved[0]}~__tact_dict_replaceget_${kind}_${vKind}(${bits}, ${resolved[1]}, ${resolved[2]})`;
} else if (self.valueAs?.startsWith("var")) {
vKind = self.valueAs;
ctx.used(`__tact_dict_replaceget_${kind}_${vKind}`);
return `${resolved[0]}~__tact_dict_replaceget_${kind}_${vKind}(${bits}, ${resolved[1]}, ${resolved[2]})`;
}
ctx.used(`__tact_dict_replaceget_${kind}_${vKind}`);
return `${resolved[0]}~__tact_dict_replaceget_${kind}_${vKind}(${bits}, ${resolved[1]}, ${resolved[2]}, ${vBits})`;
Expand Down
87 changes: 86 additions & 1 deletion src/bindings/typescript/serializers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,77 @@ const coinsSerializer: Serializer<{ optional: boolean }> = {
},
};

const varIntSerializer: Serializer<{
format: "varint16" | "varint32" | "varuint16" | "varuint32";
optional: boolean;
}> = {
tsType(v) {
if (v.optional) {
return "bigint | null";
} else {
return "bigint";
}
},
tsLoad(v, slice, field, w) {
const loader =
v.format === "varint16" || v.format === "varint32"
? "loadVarIntBig"
: "loadVarUintBig";
const length =
v.format === "varint16" || v.format === "varuint16" ? 2 : 4;
if (v.optional) {
w.append(
`let ${field} = ${slice}.loadBit() ? ${slice}.${loader}(${length}) : null;`,
);
} else {
w.append(`let ${field} = ${slice}.${loader}(${length});`);
}
},
tsLoadTuple(v, reader, field, w) {
if (v.optional) {
w.append(`let ${field} = ${reader}.readBigNumberOpt();`);
} else {
w.append(`let ${field} = ${reader}.readBigNumber();`);
}
},
tsStore(v, builder, field, w) {
const storer =
v.format === "varint16" || v.format === "varint32"
? "storeVarInt"
: "storeVarUint";
const length =
v.format === "varint16" || v.format === "varuint16" ? 2 : 4;
if (v.optional) {
w.append(
`if (${field} !== null && ${field} !== undefined) { ${builder}.storeBit(true).${storer}(${field}, ${length}); } else { ${builder}.storeBit(false); }`,
);
} else {
w.append(`${builder}.${storer}(${field}, ${length});`);
}
},
tsStoreTuple(v, to, field, w) {
w.append(`${to}.writeNumber(${field});`);
},
abiMatcher(src) {
if (src.kind === "simple") {
if (src.type === "int" || src.type === "uint") {
if (
src.format === "varint16" ||
src.format === "varint32" ||
src.format === "varuint16" ||
src.format === "varuint32"
) {
return {
format: src.format,
optional: src.optional ? src.optional : false,
};
}
}
}
return null;
},
};

const boolSerializer: Serializer<{ optional: boolean }> = {
tsType(v) {
if (v.optional) {
Expand Down Expand Up @@ -621,6 +692,7 @@ type MapSerializerDescrKey =
type MapSerializerDescrValue =
| { kind: "int" | "uint"; bits: number }
| { kind: "varuint"; length: number }
| { kind: "varint"; length: number }
| { kind: "boolean" }
| { kind: "address" }
| { kind: "cell" }
Expand Down Expand Up @@ -669,6 +741,9 @@ function getValueParser(src: MapSerializerDescrValue) {
case "varuint": {
return `Dictionary.Values.BigVarUint(${src.length})`;
}
case "varint": {
return `Dictionary.Values.BigVarInt(${src.length})`;
}
case "address": {
return "Dictionary.Values.Address()";
}
Expand Down Expand Up @@ -732,6 +807,10 @@ const map: Serializer<MapSerializerDescr> = {
src.valueFormat === undefined
) {
value = { kind: "int", bits: 257 };
} else if (src.valueFormat === "varint16") {
value = { kind: "varint", length: 4 };
} else if (src.valueFormat === "varint32") {
value = { kind: "varint", length: 5 };
}
}
if (src.value === "uint") {
Expand All @@ -744,6 +823,10 @@ const map: Serializer<MapSerializerDescr> = {
value = { kind: "uint", bits: 256 };
} else if (src.valueFormat === "coins") {
value = { kind: "varuint", length: 4 };
} else if (src.valueFormat === "varuint16") {
value = { kind: "varuint", length: 4 };
} else if (src.valueFormat === "varuint32") {
value = { kind: "varuint", length: 5 };
}
}
if (src.value === "address") {
Expand Down Expand Up @@ -813,7 +896,8 @@ const map: Serializer<MapSerializerDescr> = {
}
}
break;
case "varuint": {
case "varuint":
case "varint": {
valueT = `bigint`;
break;
}
Expand Down Expand Up @@ -869,6 +953,7 @@ export const serializers: Serializer<any>[] = [
intSerializer,
uintSerializer,
coinsSerializer,
varIntSerializer,
boolSerializer,
addressSerializer,
cellSerializer,
Expand Down
Loading

0 comments on commit 136665e

Please sign in to comment.