From f2bb8970a419245f9dd2fbb355ca98c11e10b2ed Mon Sep 17 00:00:00 2001 From: Daniil Sedov <42098239+Gusarich@users.noreply.github.com> Date: Fri, 19 Apr 2024 17:36:31 +0800 Subject: [PATCH] feat: `isEmpty` map method (#266) --- CHANGELOG.md | 1 + src/abi/map.ts | 29 +++++++++++++++++++++++++++++ src/test/feature-map.spec.ts | 23 +++++++++++++++++++++++ src/test/features/maps.tact | 4 ++++ 4 files changed, 57 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 03a3f71a2..c9c092867 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Display an error for integer overflow at compile-time: PR [#200](https://github.com/tact-lang/tact/pull/200) - Non-modifying `StringBuilder`'s `concat` method for chained string concatenations: PR [#217](https://github.com/tact-lang/tact/pull/217) - `toString` extension function for `Address` type: PR [#224](https://github.com/tact-lang/tact/pull/224) +- `isEmpty` method for `Map` type: PR [#266](https://github.com/tact-lang/tact/pull/266) ### Changed diff --git a/src/abi/map.ts b/src/abi/map.ts index 1605201f9..0c7d0f8fa 100644 --- a/src/abi/map.ts +++ b/src/abi/map.ts @@ -354,4 +354,33 @@ export const MapFunctions: Map = new Map([ }, }, ], + [ + "isEmpty", + { + name: "isEmpty", + resolve(ctx, args, ref) { + // Check arguments + if (args.length !== 1) { + throwError("isEmpty expects one argument", ref); // Ignore self argument + } + const self = args[0]; + if (!self || self.kind !== "map") { + throwError("isEmpty expects a map as self argument", ref); // Should not happen + } + + return { kind: "ref", name: "Bool", optional: false }; + }, + generate: (ctx, args, exprs, ref) => { + if (args.length !== 1) { + throwError("isEmpty expects one argument", ref); // Ignore self argument + } + const self = args[0]; + if (!self || self.kind !== "map") { + throwError("isEmpty expects a map as self argument", ref); // Should not happen + } + + return `null?(${writeExpression(exprs[0], ctx)})`; + }, + }, + ], ]); diff --git a/src/test/feature-map.spec.ts b/src/test/feature-map.spec.ts index 806683fa4..fc98a570e 100644 --- a/src/test/feature-map.spec.ts +++ b/src/test/feature-map.spec.ts @@ -41,6 +41,7 @@ describe("feature-map", () => { // Initial state expect((await contract.getIntMap1()).size).toBe(0); + expect(await contract.getIntMap1IsEmpty()).toBe(true); expect((await contract.getIntMap2()).size).toBe(0); expect((await contract.getIntMap3()).size).toBe(0); expect((await contract.getIntMap4()).size).toBe(0); @@ -518,6 +519,28 @@ describe("feature-map", () => { expect(await contract.getAddrMap7_5Value(addr)).toBe(null); expect(await contract.getAddrMap7_6Value(addr)).toBe(null); } + + // Test isEmpty + + expect(await contract.getIntMap1IsEmpty()).toBe(true); + + await contract.send( + treasure, + { value: toNano(1) }, + { $$type: "SetIntMap1", key: 1n, value: 1n }, + ); + await system.run(); + + expect(await contract.getIntMap1IsEmpty()).toBe(false); + + await contract.send( + treasure, + { value: toNano(1) }, + { $$type: "SetIntMap1", key: 1n, value: null }, + ); + await system.run(); + + expect(await contract.getIntMap1IsEmpty()).toBe(true); } catch (e) { if (e instanceof ComputeError) { if (e.logs) { diff --git a/src/test/features/maps.tact b/src/test/features/maps.tact index 522ac8aab..8d91e9644 100644 --- a/src/test/features/maps.tact +++ b/src/test/features/maps.tact @@ -775,4 +775,8 @@ contract MapTestContract { get fun mapAsCell(): Cell? { return self.addrMap7_6.asCell(); } + + get fun intMap1IsEmpty(): Bool { + return self.intMap1.isEmpty(); + } } \ No newline at end of file