@fleet-sdk/serializer 0.2.2 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,76 +0,0 @@
1
- import {
2
- Amount,
3
- BoxCandidate,
4
- ContextExtension,
5
- DataInput,
6
- isDefined,
7
- UnsignedInput
8
- } from "@fleet-sdk/common";
9
- import { SigmaWriter } from "../coders";
10
- import { serializeBox } from "./boxSerializer";
11
-
12
- export type MinimalUnsignedTransaction = {
13
- inputs: readonly UnsignedInput[];
14
- dataInputs: readonly DataInput[];
15
- outputs: readonly BoxCandidate<Amount>[];
16
- };
17
-
18
- export function serializeTransaction(transaction: MinimalUnsignedTransaction): SigmaWriter {
19
- const writer = new SigmaWriter(100_000);
20
-
21
- // write inputs
22
- writer.writeVLQ(transaction.inputs.length);
23
- transaction.inputs.map((input) => writeInput(writer, input));
24
-
25
- // write data inputs
26
- writer.writeVLQ(transaction.dataInputs.length);
27
- transaction.dataInputs.map((dataInput) => writer.writeHex(dataInput.boxId));
28
-
29
- // write distinct token IDs
30
- const distinctTokenIds = getDistinctTokenIds(transaction.outputs);
31
- writer.writeVLQ(distinctTokenIds.length);
32
- distinctTokenIds.map((tokenId) => writer.writeHex(tokenId));
33
-
34
- // write outputs
35
- writer.writeVLQ(transaction.outputs.length);
36
- transaction.outputs.map((output) => serializeBox(output, writer, distinctTokenIds));
37
-
38
- return writer;
39
- }
40
-
41
- function writeInput(writer: SigmaWriter, input: UnsignedInput): void {
42
- writer.writeHex(input.boxId);
43
- writer.write(0); // empty proof
44
- writeExtension(writer, input.extension);
45
- }
46
-
47
- function writeExtension(writer: SigmaWriter, extension: ContextExtension): void {
48
- const keys = Object.keys(extension);
49
- let length = 0;
50
-
51
- for (const key of keys) {
52
- const ext = extension[key as unknown as keyof ContextExtension];
53
- if (isDefined(ext)) {
54
- length++;
55
- }
56
- }
57
-
58
- writer.writeVLQ(length);
59
- if (length == 0) {
60
- return;
61
- }
62
-
63
- for (const key of keys) {
64
- const ext = extension[key as unknown as keyof ContextExtension];
65
- if (isDefined(ext)) {
66
- writer.writeVLQ(Number(key)).writeHex(ext);
67
- }
68
- }
69
- }
70
-
71
- function getDistinctTokenIds(outputs: readonly BoxCandidate<Amount>[]) {
72
- const tokenIds = new Set<string>();
73
- outputs.flatMap((output) => output.assets.map((asset) => tokenIds.add(asset.tokenId)));
74
-
75
- return Array.from(tokenIds);
76
- }
@@ -1,148 +0,0 @@
1
- import { assert, first, last } from "@fleet-sdk/common";
2
- import { SigmaReader, SigmaWriter } from "../coders";
3
- import { isColl, isTuple, SCollType, STupleType, SType } from "../types";
4
- import {
5
- constructorCode,
6
- descriptors,
7
- getPrimitiveType,
8
- PRIMITIVE_TYPE_RANGE
9
- } from "../types/descriptors";
10
-
11
- export class TypeSerializer {
12
- static serialize(type: SType, writer: SigmaWriter) {
13
- if (type.embeddable) {
14
- writer.write(type.code);
15
- } else if (type.code === descriptors.unit.code) {
16
- writer.write(type.code);
17
- } else if (isColl(type)) {
18
- if (type.elementsType.embeddable) {
19
- writer.write(descriptors.coll.simpleCollTypeCode + type.elementsType.code);
20
- } else if (isColl(type.elementsType)) {
21
- const nestedColl = type.elementsType;
22
- if (nestedColl.elementsType.embeddable) {
23
- writer.write(descriptors.coll.nestedCollTypeCode + nestedColl.elementsType.code);
24
- } else {
25
- writer.write(descriptors.coll.simpleCollTypeCode);
26
- this.serialize(nestedColl, writer);
27
- }
28
- } else {
29
- writer.write(descriptors.coll.simpleCollTypeCode);
30
- this.serialize(type.elementsType, writer);
31
- }
32
- } else if (isTuple(type)) {
33
- switch (type.elementsType.length) {
34
- case 2: {
35
- const left = first(type.elementsType);
36
- const right = last(type.elementsType);
37
-
38
- if (left.embeddable) {
39
- if (left.code === right.code) {
40
- // Symmetric pair of primitive types (`(Int, Int)`, `(Byte,Byte)`, etc.)
41
- writer.write(descriptors.tuple.symmetricPairTypeCode + left.code);
42
- } else {
43
- // Pair of types where first is primitive (`(_, Int)`)
44
- writer.write(descriptors.tuple.pairOneTypeCode + left.code);
45
- this.serialize(right, writer);
46
- }
47
- } else if (right.embeddable) {
48
- // Pair of types where second is primitive (`(Int, _)`)
49
- writer.write(descriptors.tuple.pairTwoTypeCode + right.code);
50
- this.serialize(left, writer);
51
- } else {
52
- // Pair of non-primitive types (`((Int, Byte), (Boolean,Box))`, etc.)
53
- writer.write(descriptors.tuple.pairOneTypeCode);
54
- this.serialize(left, writer);
55
- this.serialize(right, writer);
56
- }
57
-
58
- return;
59
- }
60
- case 3:
61
- writer.write(descriptors.tuple.tripleTypeCode);
62
- break;
63
- case 4:
64
- writer.write(descriptors.tuple.quadrupleTypeCode);
65
- break;
66
- default: {
67
- const len = type.elementsType.length;
68
- assert(len >= 2 && len <= 255, "Invalid type: tuples must have between 2 and 255 items.");
69
-
70
- // Generic tuple
71
- writer.write(descriptors.tuple.genericTupleTypeCode);
72
- writer.writeVLQ(len);
73
- }
74
- }
75
-
76
- for (let i = 0; i < type.elementsType.length; i++) {
77
- this.serialize(type.elementsType[i], writer);
78
- }
79
- } else {
80
- throw new Error("Serialization error: type not implemented.");
81
- }
82
- }
83
-
84
- static deserialize(r: SigmaReader): SType {
85
- const byte = r.readByte();
86
- assert(byte > 0, `Parsing Error: Unexpected type code '0x${byte.toString(16)}'`);
87
-
88
- if (byte < descriptors.tuple.genericTupleTypeCode) {
89
- const ctorCode = Math.floor(byte / PRIMITIVE_TYPE_RANGE);
90
- const embdCode = Math.floor(byte % PRIMITIVE_TYPE_RANGE);
91
-
92
- switch (ctorCode) {
93
- case constructorCode.embeddable: {
94
- return getPrimitiveType(embdCode);
95
- }
96
- case constructorCode.simpleColl: {
97
- const internal = embdCode === 0 ? this.deserialize(r) : getPrimitiveType(embdCode);
98
-
99
- return new SCollType(internal);
100
- }
101
- case constructorCode.nestedColl: {
102
- return new SCollType(new SCollType(getPrimitiveType(embdCode)));
103
- }
104
- case constructorCode.pairOne: {
105
- const internal =
106
- embdCode === 0
107
- ? [this.deserialize(r), this.deserialize(r)] // Pair of non-primitive types (`((Int, Byte), (Boolean,Box))`, etc.)
108
- : [getPrimitiveType(embdCode), this.deserialize(r)]; // Pair of types where first is primitive (`(_, Int)`)
109
-
110
- return new STupleType(internal);
111
- }
112
- case constructorCode.pairTwo: {
113
- const internal =
114
- embdCode === 0
115
- ? [this.deserialize(r), this.deserialize(r), this.deserialize(r)] // Triple of types
116
- : [this.deserialize(r), getPrimitiveType(embdCode)];
117
-
118
- return new STupleType(internal);
119
- }
120
- case constructorCode.symmetricPair: {
121
- const internal =
122
- embdCode === 0
123
- ? [this.deserialize(r), this.deserialize(r), this.deserialize(r), this.deserialize(r)] // Quadruple of types
124
- : [getPrimitiveType(embdCode), getPrimitiveType(embdCode)]; // Symmetric pair of primitive types (`(Int, Int)`, `(Byte,Byte)`, etc.)
125
-
126
- return new STupleType(internal);
127
- }
128
- }
129
- } else {
130
- switch (byte) {
131
- case descriptors.tuple.genericTupleTypeCode: {
132
- const len = r.readVlq();
133
- const wrapped = new Array<SType>(len);
134
- for (let i = 0; i < len; i++) {
135
- wrapped[i] = this.deserialize(r);
136
- }
137
-
138
- return new STupleType(wrapped);
139
- }
140
- case descriptors.unit.code: {
141
- return descriptors.unit;
142
- }
143
- }
144
- }
145
-
146
- throw new Error("Not implemented.");
147
- }
148
- }
@@ -1,59 +0,0 @@
1
- import { BytesInput, hex } from "@fleet-sdk/crypto";
2
- import { SigmaReader, SigmaWriter } from "./coders";
3
- import { DataSerializer } from "./serializers/dataSerializer";
4
- import { TypeSerializer } from "./serializers/typeSerializer";
5
- import { SType } from "./types";
6
-
7
- export const MAX_CONSTANT_LENGTH = 4096;
8
-
9
- export class SConstant<D = unknown, T extends SType = SType> {
10
- readonly #type: T;
11
- readonly #data: D;
12
-
13
- constructor(type: T, data: D) {
14
- this.#type = type;
15
- this.#data = type.coerce(data) as D;
16
- }
17
-
18
- static from<D, T extends SType = SType>(bytes: BytesInput): SConstant<D, T> {
19
- const reader = new SigmaReader(bytes);
20
- const type = TypeSerializer.deserialize(reader);
21
- const data = DataSerializer.deserialize(type, reader);
22
-
23
- return new SConstant(type as T, data as D);
24
- }
25
-
26
- get type(): T {
27
- return this.#type;
28
- }
29
-
30
- get data(): D {
31
- return this.#data;
32
- }
33
-
34
- toBytes(): Uint8Array {
35
- const writer = new SigmaWriter(MAX_CONSTANT_LENGTH);
36
- TypeSerializer.serialize(this.type, writer);
37
- DataSerializer.serialize(this.data, this.type, writer);
38
-
39
- return writer.toBytes();
40
- }
41
-
42
- toHex(): string {
43
- return hex.encode(this.toBytes());
44
- }
45
- }
46
-
47
- export function parse<T>(bytes: BytesInput): T;
48
- export function parse<T>(bytes: BytesInput, mode: "strict"): T;
49
- export function parse<T>(bytes: BytesInput, mode: "safe"): T | undefined;
50
- export function parse<T>(bytes: BytesInput, mode: "strict" | "safe" = "strict") {
51
- if (mode === "strict") return SConstant.from<T>(bytes).data;
52
- if (!bytes) return;
53
-
54
- try {
55
- return SConstant.from<T>(bytes).data;
56
- } catch {
57
- return;
58
- }
59
- }
package/src/types/base.ts DELETED
@@ -1,46 +0,0 @@
1
- export abstract class SType<I = unknown, O = I> {
2
- abstract get code(): number;
3
- abstract get embeddable(): boolean;
4
-
5
- coerce(data: I): O {
6
- // a bit hacky but most of types will not need a specific coercion function.
7
- return data as unknown as O;
8
- }
9
-
10
- abstract toString(): string;
11
- }
12
-
13
- export abstract class SMonomorphicType<I, O = I> extends SType<I, O> {
14
- abstract get code(): number;
15
-
16
- get embeddable(): boolean {
17
- return false;
18
- }
19
- }
20
-
21
- export abstract class SPrimitiveType<I, O = I> extends SMonomorphicType<I, O> {
22
- abstract get code(): number;
23
-
24
- override get embeddable(): boolean {
25
- return true;
26
- }
27
- }
28
-
29
- export abstract class SGenericType<T extends SType | SType[]> extends SType {
30
- readonly #internalType: T;
31
-
32
- constructor(type: T) {
33
- super();
34
- this.#internalType = type;
35
- }
36
-
37
- abstract get code(): number;
38
-
39
- get elementsType(): T {
40
- return this.#internalType;
41
- }
42
-
43
- get embeddable(): boolean {
44
- return false;
45
- }
46
- }
@@ -1,147 +0,0 @@
1
- import { describe, expectTypeOf, it } from "vitest";
2
- import { SConstant } from "../sigmaConstant";
3
- import {
4
- ByteInput,
5
- SBigInt,
6
- SBool,
7
- SByte,
8
- SColl,
9
- SConstructor,
10
- SGroupElement,
11
- SInt,
12
- SLong,
13
- SPair,
14
- SShort,
15
- SSigmaProp,
16
- SUnit
17
- } from "./constructors";
18
- import { SUnitType } from "./monomorphics";
19
- import {
20
- SBigIntType,
21
- SBoolType,
22
- SByteType,
23
- SGroupElementType,
24
- SIntType,
25
- SLongType,
26
- SShortType,
27
- SSigmaPropType
28
- } from "./primitives";
29
-
30
- describe("Constructor proxies types", () => {
31
- it("Should ensure correct types for monomorphics.", () => {
32
- expectTypeOf(SByte).parameter(0).toMatchTypeOf<number | undefined>();
33
- expectTypeOf(SByte()).toMatchTypeOf<SByteType>();
34
- expectTypeOf(SByte(1)).toMatchTypeOf<SConstant<number, SByteType>>();
35
-
36
- expectTypeOf(SBool).parameter(0).toMatchTypeOf<boolean | undefined>();
37
- expectTypeOf(SBool()).toMatchTypeOf<SBoolType>();
38
- expectTypeOf(SBool(true)).toMatchTypeOf<SConstant<boolean, SBoolType>>();
39
-
40
- expectTypeOf(SShort).parameter(0).toMatchTypeOf<number | undefined>();
41
- expectTypeOf(SShort()).toMatchTypeOf<SShortType>();
42
- expectTypeOf(SShort(1)).toMatchTypeOf<SConstant<number, SShortType>>();
43
-
44
- expectTypeOf(SInt).parameter(0).toMatchTypeOf<number | undefined>();
45
- expectTypeOf(SInt()).toMatchTypeOf<SIntType>();
46
- expectTypeOf(SInt(1)).toMatchTypeOf<SConstant<number, SIntType>>();
47
-
48
- expectTypeOf(SLong).parameter(0).toMatchTypeOf<string | bigint | undefined>();
49
- expectTypeOf(SLong()).toMatchTypeOf<SLongType>();
50
- expectTypeOf(SLong(1n)).toMatchTypeOf<SConstant<bigint, SLongType>>();
51
- expectTypeOf(SLong("1")).toMatchTypeOf<SConstant<bigint, SLongType>>();
52
-
53
- expectTypeOf(SBigInt).parameter(0).toMatchTypeOf<string | bigint | undefined>();
54
- expectTypeOf(SBigInt()).toMatchTypeOf<SBigIntType>();
55
- expectTypeOf(SBigInt(1n)).toMatchTypeOf<SConstant<bigint, SBigIntType>>();
56
- expectTypeOf(SBigInt("1")).toMatchTypeOf<SConstant<bigint, SBigIntType>>();
57
-
58
- expectTypeOf(SGroupElement).parameter(0).toMatchTypeOf<Uint8Array | string | undefined>();
59
- expectTypeOf(SGroupElement()).toMatchTypeOf<SGroupElementType>();
60
- expectTypeOf(SGroupElement(Uint8Array.from([1, 2, 3]))).toMatchTypeOf<
61
- SConstant<Uint8Array, SGroupElementType>
62
- >();
63
- expectTypeOf(SGroupElement("deadbeef")).toMatchTypeOf<
64
- SConstant<Uint8Array, SGroupElementType>
65
- >();
66
-
67
- expectTypeOf(SSigmaProp).parameter(0).toMatchTypeOf<SConstant<Uint8Array> | undefined>();
68
- expectTypeOf(SSigmaProp()).toMatchTypeOf<SSigmaPropType>();
69
- expectTypeOf(SSigmaProp(SGroupElement("deadbeef"))).toMatchTypeOf<
70
- SConstant<SConstant<Uint8Array>, SSigmaPropType>
71
- >();
72
-
73
- expectTypeOf(SUnit()).not.toMatchTypeOf<SUnitType>();
74
- expectTypeOf(SUnit()).toMatchTypeOf<SConstant<undefined, SUnitType>>();
75
- });
76
-
77
- it("Should ensure correct types for generics", () => {
78
- expectTypeOf(SColl(SByte)).toMatchTypeOf<SConstructor<number[], SByteType>>();
79
- expectTypeOf(SColl(SBool)).toMatchTypeOf<SConstructor<boolean[], SBoolType>>();
80
- expectTypeOf(SColl(SShort)).toMatchTypeOf<SConstructor<number[], SShortType>>();
81
- expectTypeOf(SColl(SInt)).toMatchTypeOf<SConstructor<number[], SIntType>>();
82
- expectTypeOf(SColl(SLong)).toMatchTypeOf<SConstructor<bigint[], SLongType>>();
83
- expectTypeOf(SColl(SBigInt)).toMatchTypeOf<SConstructor<bigint[], SBigIntType>>();
84
- expectTypeOf(SColl(SGroupElement)).toMatchTypeOf<
85
- SConstructor<Uint8Array[], SGroupElementType>
86
- >();
87
- expectTypeOf(SColl(SSigmaProp)).toMatchTypeOf<
88
- SConstructor<SConstant<Uint8Array>[], SSigmaPropType>
89
- >();
90
-
91
- expectTypeOf(
92
- SColl(SPair(SColl(SByte), SColl(SByte)), [
93
- [Uint8Array.from([1, 2, 3]), "deadbeef"],
94
- [
95
- [1, 2, 3],
96
- [4, 5, 6]
97
- ]
98
- ]).data
99
- ).toMatchTypeOf<[ByteInput | number[], ByteInput | number[]][]>();
100
-
101
- expectTypeOf(
102
- SColl(SPair(SColl(SBool), SColl(SByte)), [
103
- [[true, false], "deadbeef"],
104
- [
105
- [false, true],
106
- [4, 5, 6]
107
- ]
108
- ]).data
109
- ).toMatchTypeOf<[boolean[], ByteInput | number[]][]>();
110
-
111
- expectTypeOf(SColl(SBool, [true, false, true, true]).data).toMatchTypeOf<boolean[]>();
112
-
113
- expectTypeOf(SColl(SByte, "deadbeef").data).toMatchTypeOf<Uint8Array>();
114
- expectTypeOf(SColl(SByte, [1, 2]).data).toMatchTypeOf<Uint8Array>();
115
- expectTypeOf(SColl(SByte, Uint8Array.from([1])).data).toMatchTypeOf<Uint8Array>();
116
- expectTypeOf(SColl(SInt, [1, 2, 3]).data).toMatchTypeOf<number[]>();
117
- expectTypeOf(
118
- SColl(SColl(SBool), [
119
- [true, false],
120
- [false, false]
121
- ]).data
122
- ).toMatchTypeOf<boolean[][]>();
123
-
124
- expectTypeOf(SPair(SInt(1), SBool(false)).data).toMatchTypeOf<[number, boolean]>();
125
- expectTypeOf(SPair(SBool(true), SInt(1)).data).toMatchTypeOf<[boolean, number]>();
126
- expectTypeOf(SPair(SInt(1), SLong("1")).data).toMatchTypeOf<[number, bigint]>();
127
- expectTypeOf(SPair(SPair(SBool(true), SInt(1)), SLong("1")).data).toMatchTypeOf<
128
- [[boolean, number], bigint]
129
- >();
130
-
131
- // @ts-expect-error elements should be boolean[]
132
- SColl(SPair(SColl(SByte), SColl(SInt)), [[[1, 2, 3], 1]]);
133
- // @ts-expect-error elements should be boolean[]
134
- SColl(SBool, [true, false, true, 1]);
135
- // @ts-expect-error elements should be number[]
136
- SColl(SInt, Uint8Array.from([1]));
137
- // @ts-expect-error elements should be number[]
138
- SColl(SShort, "");
139
- // @ts-expect-error elements should be number[]
140
- SColl(SShort, {});
141
- // @ts-expect-error elements should be boolean[][]
142
- SColl(SColl(SBool), [
143
- [true, false],
144
- [false, "true"]
145
- ]);
146
- });
147
- });
@@ -1,144 +0,0 @@
1
- /* eslint-disable @typescript-eslint/no-explicit-any */
2
- /* eslint-disable @typescript-eslint/naming-convention */
3
- import { isEmpty } from "@fleet-sdk/common";
4
- import { SConstant } from "../sigmaConstant";
5
- import { SType } from "./base";
6
- import { descriptors } from "./descriptors";
7
- import { SCollType, STupleType } from "./generics";
8
- import { SUnitType } from "./monomorphics";
9
- import {
10
- SBigIntType,
11
- SBoolType,
12
- SByteType,
13
- SGroupElementType,
14
- SIntType,
15
- SLongType,
16
- SShortType,
17
- SSigmaPropType
18
- } from "./primitives";
19
-
20
- export type BigIntInput = string | bigint;
21
- export type ByteInput = Uint8Array | string;
22
-
23
- export type SConstructor<T = unknown, S extends SType = SType | SCollType<SType>> = (arg?: T) => S;
24
-
25
- type Constructable<T = any> = { new (...args: any): T };
26
- type GenericProxyArgs<R> = R extends (...args: any) => unknown ? Parameters<R> : [];
27
-
28
- type SProxy<T extends SType, I, O = I> = {
29
- (value: I): SConstant<O, T>;
30
- (value?: I): T;
31
- };
32
-
33
- /**
34
- * Creates a proxy for monomorphic types, this allows constructor
35
- * functions to be equivalent to their corresponding type.
36
- *
37
- * This function will return one instance of `ctor` if not params as set.
38
- * Otherwise it will return an `SigmaConstant` instance of `ctor` type.
39
- *
40
- * @example
41
- * // SInt is a proxy for SIntType
42
- * (intConstant instanceof SInt) === true
43
- * (intConstant instanceof SIntType) === true
44
- * @param ctor Class to be proxied.
45
- * @param cache If defined, proxy will return this instead of a new instance of `ctor`.
46
- * @param forceConstruction If true, bypasses the constant creation and returns a type.
47
- * @returns
48
- */
49
- function monoProxy<T extends SType, I, O = I>(
50
- ctor: Constructable<T>,
51
- cache?: T,
52
- forceConstruction?: boolean
53
- ): SProxy<T, I, O> {
54
- return new Proxy(ctor, {
55
- apply: (target, _, args) => {
56
- const instance = cache ?? new target();
57
- if (!forceConstruction && isEmpty(args)) return instance;
58
-
59
- return new (SConstant as Constructable)(instance, ...args);
60
- }
61
- }) as any;
62
- }
63
-
64
- /**
65
- * Creates a proxy for generic types.
66
- */
67
- function genericProxy<T extends SType, R>(
68
- ctor: Constructable<T>,
69
- handler: (target: Constructable<T>, thisArgs: unknown, args: GenericProxyArgs<R>) => unknown
70
- ) {
71
- return new Proxy(ctor, {
72
- apply: handler
73
- }) as R;
74
- }
75
-
76
- export const SByte = monoProxy<SByteType, number>(SByteType, descriptors.byte);
77
-
78
- export const SBool = monoProxy<SBoolType, boolean>(SBoolType, descriptors.bool);
79
-
80
- export const SShort = monoProxy<SShortType, number>(SShortType, descriptors.short);
81
-
82
- export const SInt = monoProxy<SIntType, number>(SIntType, descriptors.int);
83
-
84
- export const SLong = monoProxy<SLongType, BigIntInput, bigint>(SLongType, descriptors.long);
85
-
86
- export const SBigInt = monoProxy<SBigIntType, BigIntInput, bigint>(SBigIntType, descriptors.bigInt);
87
-
88
- export const SGroupElement = monoProxy<SGroupElementType, ByteInput, Uint8Array>(
89
- SGroupElementType,
90
- descriptors.groupElement
91
- );
92
-
93
- export const SSigmaProp = monoProxy<SSigmaPropType, SConstant<Uint8Array>>(
94
- SSigmaPropType,
95
- descriptors.sigmaProp
96
- );
97
-
98
- type SUnit = (value?: undefined) => SConstant<undefined, SUnitType>;
99
- export const SUnit: SUnit = monoProxy(SUnitType, undefined, true);
100
-
101
- type SColl = {
102
- <D, T extends SType>(type: SConstructor<D, T>): SConstructor<D[], T>;
103
- <D, T extends SByteType>(
104
- type: SConstructor<D, T>,
105
- elements: ByteInput | D[]
106
- ): SConstant<Uint8Array, T>;
107
- <D, T extends SType>(type: SConstructor<D, T>, elements: D[]): SConstant<D[], T>;
108
- };
109
-
110
- export const SColl = genericProxy<SCollType, SColl>(SCollType, (target, _, args) => {
111
- const [type, elements] = args;
112
- const elementsType = type();
113
- if (!elements) return () => new target(elementsType);
114
-
115
- return new SConstant(new target(elementsType), elements);
116
- });
117
-
118
- export function STuple(...items: SConstant[]) {
119
- return new SConstant(
120
- new STupleType(items.map((x) => x.type)),
121
- items.map((x) => x.data)
122
- );
123
- }
124
-
125
- type ByteInputOr<D, T extends SType> = T extends SByteType ? ByteInput | D : D;
126
- type SPair = {
127
- <L, R>(left: SConstant<L>, right: SConstant<R>): SConstant<[L, R], STupleType>;
128
- <LD, RD, LT extends SType, RT extends SType>(
129
- left: SConstructor<LD, LT>,
130
- right: SConstructor<RD, RT>
131
- ): SConstructor<[ByteInputOr<LD, LT>, ByteInputOr<RD, RT>]>;
132
- };
133
-
134
- export const SPair = genericProxy<STupleType, SPair>(STupleType, (target, _, args) => {
135
- const [left, right] = args;
136
-
137
- if (typeof left === "function" && typeof right === "function") {
138
- return () => new target([left(), right()]);
139
- } else if (left instanceof SConstant && right instanceof SConstant) {
140
- return new SConstant(new target([left.type, right.type]), [left.data, right.data]);
141
- }
142
-
143
- throw new Error("Invalid tuple declaration.");
144
- });