@helios-lang/effect 0.1.4 → 0.1.6

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.
Files changed (113) hide show
  1. package/bun.lock +60 -0
  2. package/dist/Ledger/NetworkParams.js +40 -0
  3. package/dist/Ledger/NetworkParams.js.map +1 -0
  4. package/dist/Ledger/index.js +1 -0
  5. package/dist/Ledger/index.js.map +1 -1
  6. package/package.json +1 -1
  7. package/tsconfig.build.tsbuildinfo +1 -0
  8. package/tsconfig.check.tsbuildinfo +1 -0
  9. package/tsconfig.tsbuildinfo +1 -0
  10. package/types/Address.d.ts +5 -0
  11. package/types/Address.d.ts.map +1 -0
  12. package/types/Bech32.d.ts +30 -0
  13. package/types/Bech32.d.ts.map +1 -0
  14. package/types/Cbor.d.ts +430 -0
  15. package/types/Cbor.d.ts.map +1 -0
  16. package/types/Ledger/Address.d.ts +109 -0
  17. package/types/Ledger/Address.d.ts.map +1 -0
  18. package/types/Ledger/AssetClass.d.ts +101 -0
  19. package/types/Ledger/AssetClass.d.ts.map +1 -0
  20. package/types/Ledger/Assets.d.ts +70 -0
  21. package/types/Ledger/Assets.d.ts.map +1 -0
  22. package/types/Ledger/Credential.d.ts +26 -0
  23. package/types/Ledger/Credential.d.ts.map +1 -0
  24. package/types/Ledger/DatumHash.d.ts +40 -0
  25. package/types/Ledger/DatumHash.d.ts.map +1 -0
  26. package/types/Ledger/IsMainnet.d.ts +6 -0
  27. package/types/Ledger/IsMainnet.d.ts.map +1 -0
  28. package/types/Ledger/MintingPolicy.d.ts +39 -0
  29. package/types/Ledger/MintingPolicy.d.ts.map +1 -0
  30. package/types/Ledger/NetworkParams.d.ts +40 -0
  31. package/types/Ledger/NetworkParams.d.ts.map +1 -0
  32. package/types/Ledger/PubKeyHash.d.ts +40 -0
  33. package/types/Ledger/PubKeyHash.d.ts.map +1 -0
  34. package/types/Ledger/TxId.d.ts +10 -0
  35. package/types/Ledger/TxId.d.ts.map +1 -0
  36. package/types/Ledger/TxInput.d.ts +55 -0
  37. package/types/Ledger/TxInput.d.ts.map +1 -0
  38. package/types/Ledger/TxOutput.d.ts +63 -0
  39. package/types/Ledger/TxOutput.d.ts.map +1 -0
  40. package/types/Ledger/TxOutputDatum.d.ts +41 -0
  41. package/types/Ledger/TxOutputDatum.d.ts.map +1 -0
  42. package/types/Ledger/TxOutputId.d.ts +14 -0
  43. package/types/Ledger/TxOutputId.d.ts.map +1 -0
  44. package/types/Ledger/ValidatorHash.d.ts +40 -0
  45. package/types/Ledger/ValidatorHash.d.ts.map +1 -0
  46. package/types/Ledger/index.d.ts +16 -0
  47. package/types/Ledger/index.d.ts.map +1 -0
  48. package/types/Uplc/Cek.d.ts +72 -0
  49. package/types/Uplc/Cek.d.ts.map +1 -0
  50. package/types/Uplc/Data.d.ts +530 -0
  51. package/types/Uplc/Data.d.ts.map +1 -0
  52. package/types/Uplc/DataSchema.d.ts +227 -0
  53. package/types/Uplc/DataSchema.d.ts.map +1 -0
  54. package/types/Uplc/Primitive.d.ts +26 -0
  55. package/types/Uplc/Primitive.d.ts.map +1 -0
  56. package/types/Uplc/index.d.ts +3 -0
  57. package/types/Uplc/index.d.ts.map +1 -0
  58. package/types/index.d.ts +5 -0
  59. package/types/index.d.ts.map +1 -0
  60. package/types/internal/Base32.d.ts +49 -0
  61. package/types/internal/Base32.d.ts.map +1 -0
  62. package/types/internal/BigEndian.d.ts +22 -0
  63. package/types/internal/BigEndian.d.ts.map +1 -0
  64. package/types/internal/Bits.d.ts +123 -0
  65. package/types/internal/Bits.d.ts.map +1 -0
  66. package/types/internal/Bytes.d.ts +88 -0
  67. package/types/internal/Bytes.d.ts.map +1 -0
  68. package/types/internal/Flat.d.ts +71 -0
  69. package/types/internal/Flat.d.ts.map +1 -0
  70. package/types/internal/Float.d.ts +38 -0
  71. package/types/internal/Float.d.ts.map +1 -0
  72. package/types/internal/Utf8.d.ts +24 -0
  73. package/types/internal/Utf8.d.ts.map +1 -0
  74. package/src/Bech32.test.ts +0 -117
  75. package/src/Bech32.ts +0 -198
  76. package/src/Cbor.test.ts +0 -1610
  77. package/src/Cbor.ts +0 -1704
  78. package/src/Ledger/Address.ts +0 -248
  79. package/src/Ledger/AssetClass.ts +0 -90
  80. package/src/Ledger/Assets.ts +0 -164
  81. package/src/Ledger/Credential.ts +0 -29
  82. package/src/Ledger/DatumHash.ts +0 -36
  83. package/src/Ledger/IsMainnet.ts +0 -6
  84. package/src/Ledger/MintingPolicy.ts +0 -57
  85. package/src/Ledger/PubKeyHash.ts +0 -36
  86. package/src/Ledger/TxId.ts +0 -31
  87. package/src/Ledger/TxInput.test.ts +0 -21
  88. package/src/Ledger/TxInput.ts +0 -66
  89. package/src/Ledger/TxOutput.ts +0 -166
  90. package/src/Ledger/TxOutputDatum.ts +0 -64
  91. package/src/Ledger/TxOutputId.ts +0 -63
  92. package/src/Ledger/ValidatorHash.ts +0 -36
  93. package/src/Ledger/index.ts +0 -14
  94. package/src/Uplc/Cek.ts +0 -92
  95. package/src/Uplc/Data.test.ts +0 -321
  96. package/src/Uplc/Data.ts +0 -657
  97. package/src/Uplc/Primitive.ts +0 -56
  98. package/src/Uplc/index.ts +0 -2
  99. package/src/index.ts +0 -4
  100. package/src/internal/Base32.test.ts +0 -219
  101. package/src/internal/Base32.ts +0 -341
  102. package/src/internal/BigEndian.test.ts +0 -79
  103. package/src/internal/BigEndian.ts +0 -67
  104. package/src/internal/Bits.test.ts +0 -300
  105. package/src/internal/Bits.ts +0 -398
  106. package/src/internal/Bytes.test.ts +0 -369
  107. package/src/internal/Bytes.ts +0 -343
  108. package/src/internal/Flat.test.ts +0 -29
  109. package/src/internal/Flat.ts +0 -387
  110. package/src/internal/Float.test.ts +0 -51
  111. package/src/internal/Float.ts +0 -190
  112. package/src/internal/Utf8.test.ts +0 -69
  113. package/src/internal/Utf8.ts +0 -58
package/src/Cbor.ts DELETED
@@ -1,1704 +0,0 @@
1
- import { Data, Effect, Either } from "effect"
2
- import * as BigEndian from "./internal/BigEndian.js"
3
- import * as Bytes from "./internal/Bytes.js"
4
- import * as Float from "./internal/Float.js"
5
- import * as Utf8 from "./internal/Utf8.js"
6
-
7
- export type Decoder<T> = (
8
- stream: Bytes.Stream
9
- ) => Effect.Effect<T, Bytes.EndOfStreamError | DecodeError>
10
-
11
- export type IndexedDecoder<T> = (
12
- stream: Bytes.Stream,
13
- index: number
14
- ) => Effect.Effect<T, Bytes.EndOfStreamError | DecodeError>
15
-
16
- export type DecodeEffect<T> = Effect.Effect<
17
- T,
18
- Bytes.EndOfStreamError | DecodeError
19
- >
20
- export type PeekEffect<T> = Effect.Effect<T, Bytes.EndOfStreamError>
21
-
22
- const FALSE_BYTE = 244 // m = 7, n = 20
23
- const TRUE_BYTE = 245 // m = 7, n = 21
24
-
25
- export class DecodeError extends Data.TaggedError("Cbor.DecodeError")<{
26
- message: string
27
- }> {
28
- constructor(_stream: Bytes.Stream, message: string) {
29
- super({ message: message })
30
- }
31
- }
32
-
33
- /**
34
- * Decodes a CBOR encoded `boolean`.
35
- * Throws an error if the next element in bytes isn't a `boolean`.
36
- * @param bytes
37
- * @returns
38
- */
39
- export const decodeBool = (bytes: Bytes.BytesLike): DecodeEffect<boolean> =>
40
- Effect.gen(function* () {
41
- const stream = Bytes.makeStream(bytes)
42
-
43
- const b = yield* stream.shiftOne()
44
-
45
- if (b == TRUE_BYTE) {
46
- return true
47
- } else if (b == FALSE_BYTE) {
48
- return false
49
- } else {
50
- return yield* new DecodeError(
51
- stream,
52
- "unexpected non-boolean cbor object"
53
- )
54
- }
55
- })
56
-
57
- /**
58
- * Encodes a `boolean` into its CBOR representation.
59
- * @param b
60
- * @returns
61
- */
62
- export function encodeBool(b: boolean): number[] {
63
- if (b) {
64
- return [TRUE_BYTE]
65
- } else {
66
- return [FALSE_BYTE]
67
- }
68
- }
69
-
70
- /**
71
- * @param bytes
72
- * @returns
73
- */
74
- export const isBool = (bytes: Bytes.BytesLike): PeekEffect<boolean> =>
75
- Bytes.makeStream(bytes)
76
- .peekOne()
77
- .pipe(Effect.map((head) => head == FALSE_BYTE || head == TRUE_BYTE))
78
-
79
- /**
80
- * Unwraps a CBOR encoded list of bytes
81
- * @param bytes
82
- * cborbytes, mutated to form remaining
83
- * @returns byteArray
84
- */
85
- export const decodeBytes = (bytes: Bytes.BytesLike): DecodeEffect<number[]> =>
86
- Effect.gen(function* () {
87
- const stream = Bytes.makeStream(bytes)
88
-
89
- if (yield* isIndefBytes(bytes)) {
90
- yield* stream.shiftOne()
91
-
92
- // multiple chunks
93
-
94
- let res: number[] = []
95
-
96
- while ((yield* stream.peekOne()) != 255) {
97
- const [, n] = yield* decodeDefHead(stream)
98
- if (n > 64n) {
99
- return yield* new DecodeError(stream, "Bytearray chunk too large")
100
- }
101
-
102
- res = res.concat(yield* stream.shiftMany(Number(n)))
103
- }
104
-
105
- if ((yield* stream.shiftOne()) != 255) {
106
- throw new Error("invalid indef bytes termination byte")
107
- }
108
-
109
- return res
110
- } else {
111
- const [m, n] = yield* decodeDefHead(stream)
112
-
113
- if (m != 2) {
114
- return yield* new DecodeError(stream, "Invalid def bytes")
115
- }
116
-
117
- return yield* stream.shiftMany(Number(n))
118
- }
119
- })
120
-
121
- /**
122
- * Wraps a list of bytes using CBOR. Optionally splits the bytes into chunks.
123
- * @example
124
- * bytesToHex(Cbor.encodeBytes("4d01000033222220051200120011")) == "4e4d01000033222220051200120011"
125
- * @param bytes
126
- * @param splitIntoChunks
127
- * @returns
128
- * cbor bytes
129
- */
130
- export function encodeBytes(
131
- bytes: string | number[] | Uint8Array,
132
- splitIntoChunks: boolean = false
133
- ): number[] {
134
- bytes = Bytes.toArray(bytes).slice()
135
-
136
- if (bytes.length <= 64 || !splitIntoChunks) {
137
- const head = encodeDefHead(2, BigInt(bytes.length))
138
- return head.concat(bytes)
139
- } else {
140
- let res = encodeIndefHead(2)
141
-
142
- while (bytes.length > 0) {
143
- const chunk = bytes.splice(0, 64)
144
-
145
- res = res.concat(encodeDefHead(2, BigInt(chunk.length))).concat(chunk)
146
- }
147
-
148
- res.push(255)
149
-
150
- return res
151
- }
152
- }
153
-
154
- /**
155
- * @param bytes
156
- * @returns
157
- */
158
- export const isBytes = (bytes: Bytes.BytesLike): PeekEffect<boolean> =>
159
- peekMajorType(bytes).pipe(Effect.map((m) => m == 2))
160
-
161
- /**
162
- * @param bytes
163
- * @returns
164
- */
165
- export const isDefBytes = (bytes: Bytes.BytesLike): PeekEffect<boolean> =>
166
- Effect.gen(function* () {
167
- const stream = Bytes.makeStream(bytes)
168
-
169
- const m = yield* peekMajorType(stream)
170
-
171
- return m == 2 && (yield* stream.peekOne()) != 2 * 32 + 31
172
- })
173
-
174
- /**
175
- * @param bytes
176
- * @returns
177
- */
178
- export const isIndefBytes = (bytes: Bytes.BytesLike): PeekEffect<boolean> =>
179
- Bytes.makeStream(bytes)
180
- .peekOne()
181
- .pipe(Effect.map((head) => head == 2 * 32 + 31))
182
-
183
- /**
184
- * The homogenous field type case is used by the uplc ConstrData (undetermined number of UplcData items)
185
- * @template Decoders
186
- * Note: the conditional tuple check loses the tupleness if we just check against array, hence first we check against a tuple, and then an array (needed for the empty case)
187
- * @param fieldDecoder
188
- * Array for heterogenous item types, single function for homogenous item types
189
- * @returns
190
- */
191
- export const decodeConstr =
192
- <
193
- Decoders extends
194
- | [Decoder<any>, ...Decoder<any>[]]
195
- | Array<Decoder<any>>
196
- | Decoder<any>
197
- >(
198
- fieldDecoder: Decoders extends [Decoder<any>, ...Decoder<any>[]]
199
- ? [...Decoders]
200
- : Decoders extends Array<any>
201
- ? [...Decoders]
202
- : Decoders
203
- ) =>
204
- (
205
- bytes: Bytes.BytesLike
206
- ): DecodeEffect<
207
- [
208
- number,
209
- Decoders extends Array<any>
210
- ? {
211
- [D in keyof Decoders]: Decoders[D] extends Decoder<infer T>
212
- ? T
213
- : never
214
- }
215
- : Decoders extends Decoder<infer T>
216
- ? T[]
217
- : never
218
- ]
219
- > =>
220
- Effect.gen(function* () {
221
- const stream = Bytes.makeStream(bytes)
222
-
223
- const tag = yield* decodeConstrTag(stream)
224
-
225
- const res: any[] = yield* decodeList(
226
- (itemStream: Bytes.Stream, i: number) =>
227
- Effect.gen(function* () {
228
- if (Array.isArray(fieldDecoder)) {
229
- const decoder: Decoder<any> | undefined = fieldDecoder[i]
230
-
231
- if (decoder === undefined) {
232
- return yield* new DecodeError(
233
- stream,
234
- `expected ${fieldDecoder.length} fields, got more than ${i}`
235
- )
236
- }
237
-
238
- // eslint-disable-next-line @typescript-eslint/no-unsafe-return
239
- return yield* decoder(itemStream)
240
- } else {
241
- // eslint-disable-next-line @typescript-eslint/no-unsafe-return
242
- return yield* fieldDecoder(itemStream)
243
- }
244
- })
245
- )(stream)
246
-
247
- if (Array.isArray(fieldDecoder)) {
248
- if (res.length < fieldDecoder.length) {
249
- return yield* new DecodeError(
250
- stream,
251
- `expected ${fieldDecoder.length} fields, only got ${res.length}`
252
- )
253
- }
254
- }
255
-
256
- return [tag, res] as [
257
- number,
258
- Decoders extends Array<any>
259
- ? {
260
- [D in keyof Decoders]: Decoders[D] extends Decoder<infer T>
261
- ? T
262
- : never
263
- }
264
- : Decoders extends Decoder<infer T>
265
- ? T[]
266
- : never
267
- ]
268
- })
269
-
270
- /**
271
- * @param bytes
272
- * @returns
273
- */
274
- export const decodeConstrLazy = (
275
- bytes: Bytes.BytesLike
276
- ): DecodeEffect<[number, <T>(itemDecoder: Decoder<T>) => DecodeEffect<T>]> =>
277
- Effect.gen(function* () {
278
- const stream = Bytes.makeStream(bytes)
279
- const tag = yield* decodeConstrTag(stream)
280
- const decodeField = yield* decodeListLazy(bytes)
281
-
282
- return [tag, decodeField] as [number, typeof decodeField]
283
- })
284
-
285
- /**
286
- * @param bytes
287
- * @returns
288
- */
289
- const decodeConstrTag = (bytes: Bytes.BytesLike): DecodeEffect<number> =>
290
- Effect.gen(function* () {
291
- const stream = Bytes.makeStream(bytes)
292
-
293
- // constr
294
- const [m, n] = yield* decodeDefHead(stream)
295
-
296
- if (m != 6) {
297
- return yield* new DecodeError(stream, "Unexpected constr tag head")
298
- }
299
-
300
- if (n < 102n) {
301
- return yield* new DecodeError(
302
- stream,
303
- `unexpected encoded constr tag ${n}`
304
- )
305
- } else if (n == 102n) {
306
- const [mCheck, nCheck] = yield* decodeDefHead(stream)
307
- if (mCheck != 4 || nCheck != 2n) {
308
- return yield* new DecodeError(
309
- stream,
310
- "Unexpected constr tag nested head"
311
- )
312
- }
313
-
314
- return Number(yield* decodeInt(stream))
315
- } else if (n < 121n) {
316
- return yield* new DecodeError(
317
- stream,
318
- `unexpected encoded constr tag ${n}`
319
- )
320
- } else if (n <= 127n) {
321
- return Number(n - 121n)
322
- } else if (n < 1280n) {
323
- return yield* new DecodeError(
324
- stream,
325
- `unexpected encoded constr tag ${n}`
326
- )
327
- } else if (n <= 1400n) {
328
- return Number(n - 1280n + 7n)
329
- } else {
330
- return yield* new DecodeError(
331
- stream,
332
- `unexpected encoded constr tag ${n}`
333
- )
334
- }
335
- })
336
-
337
- /**
338
- * Note: internally the indef list format is used if the number of fields is > 0, if the number of fields is 0 the def list format is used
339
- * see [well-typed/cborg/serialise/src/Codec/Serialise/Class.hs](https://github.com/well-typed/cborg/blob/4bdc818a1f0b35f38bc118a87944630043b58384/serialise/src/Codec/Serialise/Class.hs#L181).
340
- * @param tag
341
- * @param fields
342
- * @returns
343
- */
344
- export function encodeConstr(
345
- tag: number,
346
- fields: readonly number[][]
347
- ): number[] {
348
- return encodeConstrTag(tag).concat(encodeList(fields))
349
- }
350
-
351
- /**
352
- * Encode a constructor tag of a ConstrData type
353
- * @param tag
354
- * @returns
355
- * @throws
356
- * If the tag is negative or not a whole number
357
- */
358
- function encodeConstrTag(tag: number): number[] {
359
- if (tag < 0 || tag % 1.0 != 0.0) {
360
- throw new Error("invalid tag")
361
- } else if (tag >= 0 && tag <= 6) {
362
- return encodeDefHead(6, 121n + BigInt(tag))
363
- } else if (tag >= 7 && tag <= 127) {
364
- return encodeDefHead(6, 1280n + BigInt(tag - 7))
365
- } else {
366
- return encodeDefHead(6, 102n)
367
- .concat(encodeDefHead(4, 2n))
368
- .concat(encodeInt(BigInt(tag)))
369
- }
370
- }
371
-
372
- /**
373
- * @param bytes
374
- * @returns
375
- */
376
- export const isConstr = (bytes: Bytes.BytesLike): PeekEffect<boolean> =>
377
- decodeDefHead(Bytes.makeStream(bytes).copy()).pipe(
378
- Effect.map(([m, n]) => {
379
- if (m == 6) {
380
- return (
381
- n == 102n || (n >= 121n && n <= 127n) || (n >= 1280n && n <= 1400n)
382
- )
383
- } else {
384
- return false
385
- }
386
- }),
387
- Effect.catchTag("Cbor.DecodeError", () => {
388
- return Effect.succeed(false)
389
- })
390
- )
391
-
392
- const FLOAT16_HEAD = 249
393
- const FLOAT32_HEAD = 250
394
- const FLOAT64_HEAD = 251
395
-
396
- /**
397
- * @param bytes
398
- * @returns
399
- */
400
- export const decodeFloat = (bytes: Bytes.BytesLike): DecodeEffect<number> =>
401
- Effect.gen(function* () {
402
- const stream = Bytes.makeStream(bytes)
403
-
404
- const head = yield* stream.shiftOne()
405
-
406
- switch (head) {
407
- case FLOAT16_HEAD:
408
- return yield* Either.mapLeft(
409
- Float.decodeFloat16(yield* stream.shiftMany(2)),
410
- (e) =>
411
- new DecodeError(stream, `failed to decode float16 (${e.message})`)
412
- )
413
- case FLOAT32_HEAD:
414
- return yield* Either.mapLeft(
415
- Float.decodeFloat32(yield* stream.shiftMany(4)),
416
- (e) =>
417
- new DecodeError(stream, `failed to decode float32 (${e.message})`)
418
- )
419
- case FLOAT64_HEAD:
420
- return yield* Either.mapLeft(
421
- Float.decodeFloat64(yield* stream.shiftMany(8)),
422
- (e) =>
423
- new DecodeError(stream, `faild to decode float64 (${e.message})`)
424
- )
425
- default:
426
- return yield* new DecodeError(stream, "invalid float header")
427
- }
428
- })
429
-
430
- /**
431
- * @param bytes
432
- * @returns
433
- */
434
- export const decodeFloat16 = (bytes: Bytes.BytesLike): DecodeEffect<number> =>
435
- Effect.gen(function* () {
436
- const stream = Bytes.makeStream(bytes)
437
-
438
- const head = yield* stream.shiftOne()
439
-
440
- if (head != FLOAT16_HEAD) {
441
- return yield* new DecodeError(stream, "invalid Float16 header")
442
- }
443
-
444
- return yield* Either.mapLeft(
445
- Float.decodeFloat16(yield* stream.shiftMany(2)),
446
- (e) => new DecodeError(stream, `failed to decode float16 (${e.message})`)
447
- )
448
- })
449
-
450
- /**
451
- * @param bytes
452
- * @returns
453
- */
454
- export const decodeFloat32 = (bytes: Bytes.BytesLike): DecodeEffect<number> =>
455
- Effect.gen(function* () {
456
- const stream = Bytes.makeStream(bytes)
457
-
458
- const head = yield* stream.shiftOne()
459
-
460
- if (head != FLOAT32_HEAD) {
461
- return yield* new DecodeError(stream, "invalid Float32 header")
462
- }
463
-
464
- return yield* Either.mapLeft(
465
- Float.decodeFloat32(yield* stream.shiftMany(4)),
466
- (e) => new DecodeError(stream, `failed to decode float32 (${e.message})`)
467
- )
468
- })
469
-
470
- /**
471
- * @param bytes
472
- * @returns
473
- */
474
- export const decodeFloat64 = (bytes: Bytes.BytesLike): DecodeEffect<number> =>
475
- Effect.gen(function* () {
476
- const stream = Bytes.makeStream(bytes)
477
-
478
- const head = yield* stream.shiftOne()
479
-
480
- if (head != FLOAT64_HEAD) {
481
- return yield* new DecodeError(stream, "invalid Float64 header")
482
- }
483
-
484
- return yield* Either.mapLeft(
485
- Float.decodeFloat64(yield* stream.shiftMany(8)),
486
- (e) => new DecodeError(stream, `failed to decode float32 (${e.message})`)
487
- )
488
- })
489
-
490
- /**
491
- * @param f
492
- * @returns
493
- */
494
- export function encodeFloat16(f: number): number[] {
495
- return [FLOAT16_HEAD].concat(Float.encodeFloat16(f))
496
- }
497
-
498
- /**
499
- * @param f
500
- * @returns
501
- */
502
- export function encodeFloat32(f: number): number[] {
503
- return [FLOAT32_HEAD].concat(Float.encodeFloat32(f))
504
- }
505
-
506
- /**
507
- * @param f
508
- * @returns
509
- */
510
- export function encodeFloat64(f: number): number[] {
511
- return [FLOAT64_HEAD].concat(Float.encodeFloat64(f))
512
- }
513
-
514
- /**
515
- * @param bytes
516
- * @returns
517
- */
518
- export const isFloat = (bytes: Bytes.BytesLike): PeekEffect<boolean> =>
519
- Bytes.makeStream(bytes)
520
- .peekOne()
521
- .pipe(
522
- Effect.map(
523
- (head) =>
524
- head == FLOAT16_HEAD || head == FLOAT32_HEAD || head == FLOAT64_HEAD
525
- )
526
- )
527
-
528
- /**
529
- * @param bytes
530
- * @returns
531
- */
532
- export const isFloat16 = (bytes: Bytes.BytesLike): PeekEffect<boolean> =>
533
- Bytes.makeStream(bytes)
534
- .peekOne()
535
- .pipe(Effect.map((head) => head == FLOAT16_HEAD))
536
-
537
- /**
538
- * @param bytes
539
- * @returns
540
- */
541
- export const isFloat32 = (bytes: Bytes.BytesLike): PeekEffect<boolean> =>
542
- Bytes.makeStream(bytes)
543
- .peekOne()
544
- .pipe(Effect.map((head) => head == FLOAT32_HEAD))
545
-
546
- /**
547
- * @param bytes
548
- * @returns
549
- */
550
- export const isFloat64 = (bytes: Bytes.BytesLike): PeekEffect<boolean> =>
551
- Bytes.makeStream(bytes)
552
- .peekOne()
553
- .pipe(Effect.map((head) => head == FLOAT64_HEAD))
554
-
555
- /**
556
- * @param b0
557
- * @returns
558
- */
559
- function decodeFirstHeadByte(b0: number): [number, number] {
560
- const m = Math.trunc(b0 / 32)
561
- const n0 = b0 % 32
562
-
563
- return [m, n0]
564
- }
565
-
566
- /**
567
- * @param bytes
568
- * @returns
569
- * [majorType, n]
570
- */
571
- export const decodeDefHead = (
572
- bytes: Bytes.BytesLike
573
- ): DecodeEffect<[number, bigint]> =>
574
- Effect.gen(function* () {
575
- const stream = Bytes.makeStream(bytes)
576
-
577
- if (stream.isAtEnd()) {
578
- return yield* new DecodeError(stream, "Empty CBOR head")
579
- }
580
-
581
- const first = yield* stream.shiftOne()
582
-
583
- const [m, n0] = decodeFirstHeadByte(first)
584
-
585
- if (n0 <= 23) {
586
- return [m, BigInt(n0)]
587
- } else if (n0 == 24) {
588
- const l = yield* decodeIntInternal(stream, 1)
589
-
590
- return [m, l]
591
- } else if (n0 == 25) {
592
- if (m == 7) {
593
- return yield* new DecodeError(
594
- stream,
595
- "Unexpected float16 (hint: decode float16 by calling decodeFloat16 directly)"
596
- )
597
- }
598
-
599
- const n = yield* decodeIntInternal(stream, 2)
600
- return [m, n]
601
- } else if (n0 == 26) {
602
- if (m == 7) {
603
- return yield* new DecodeError(
604
- stream,
605
- "Unexpected float32 (hint: decode float32 by calling decodeFloat32 directly)"
606
- )
607
- }
608
-
609
- return [m, yield* decodeIntInternal(stream, 4)]
610
- } else if (n0 == 27) {
611
- if (m == 7) {
612
- return yield* new DecodeError(
613
- stream,
614
- "Unexpected float64 (hint: decode float64 by calling decodeFloat64 directly)"
615
- )
616
- }
617
-
618
- return [m, yield* decodeIntInternal(stream, 8)]
619
- } else if ((m == 2 || m == 3 || m == 4 || m == 5 || m == 7) && n0 == 31) {
620
- // head value 31 is used an indefinite length marker for 2,3,4,5,7 (never for 0,1,6)
621
- return yield* new DecodeError(
622
- stream,
623
- `Unexpected header m=${m} n0=${n0} (expected def instead of indef)`
624
- )
625
- } else {
626
- return yield* new DecodeError(stream, "Bad CBOR header")
627
- }
628
- })
629
-
630
- /**
631
- * @param m major type
632
- * @param n size parameter
633
- * @returns uint8 bytes
634
- * @throws
635
- * If n is out of range (i.e. very very large)
636
- */
637
- export function encodeDefHead(m: number, n: number | bigint): number[] {
638
- if (n <= 23n) {
639
- return [32 * m + Number(n)]
640
- } else if (n >= 24n && n <= 255n) {
641
- return [32 * m + 24, Number(n)]
642
- } else if (n >= 256n && n <= 256n * 256n - 1n) {
643
- return [
644
- 32 * m + 25,
645
- Number((BigInt(n) / 256n) % 256n),
646
- Number(BigInt(n) % 256n)
647
- ]
648
- } else if (n >= 256n * 256n && n <= 256n * 256n * 256n * 256n - 1n) {
649
- const e4 = BigEndian.encode(n)
650
-
651
- while (e4.length < 4) {
652
- e4.unshift(0)
653
- }
654
- return [32 * m + 26].concat(e4)
655
- } else if (
656
- n >= 256n * 256n * 256n * 256n &&
657
- n <= 256n * 256n * 256n * 256n * 256n * 256n * 256n * 256n - 1n
658
- ) {
659
- const e8 = BigEndian.encode(n)
660
-
661
- while (e8.length < 8) {
662
- e8.unshift(0)
663
- }
664
- return [32 * m + 27].concat(e8)
665
- } else {
666
- throw new Error("n out of range")
667
- }
668
- }
669
-
670
- /**
671
- * @param m
672
- * @returns
673
- */
674
- export function encodeIndefHead(m: number): number[] {
675
- return [32 * m + 31]
676
- }
677
-
678
- /**
679
- * @param bytes
680
- * @returns
681
- */
682
- export const peekMajorType = (bytes: Bytes.BytesLike): PeekEffect<number> =>
683
- Bytes.makeStream(bytes)
684
- .peekOne()
685
- .pipe(Effect.map((head) => Math.trunc(head / 32)))
686
-
687
- /**
688
- * @param bytes
689
- * @returns
690
- */
691
- export const peekMajorAndSimpleMinorType = (
692
- bytes: Bytes.BytesLike
693
- ): PeekEffect<[number, number]> =>
694
- Bytes.makeStream(bytes).peekOne().pipe(Effect.map(decodeFirstHeadByte))
695
-
696
- /**
697
- * Decodes a CBOR encoded bigint integer.
698
- * @param bytes
699
- * @returns
700
- */
701
- export const decodeInt = (bytes: Bytes.BytesLike): DecodeEffect<bigint> =>
702
- Effect.gen(function* () {
703
- const stream = Bytes.makeStream(bytes)
704
-
705
- const [m, n] = yield* decodeDefHead(stream)
706
-
707
- if (m == 0) {
708
- return n
709
- } else if (m == 1) {
710
- return -n - 1n
711
- } else if (m == 6) {
712
- if (n == 2n) {
713
- return yield* decodeIntInternal(stream)
714
- } else if (n == 3n) {
715
- return -(yield* decodeIntInternal(stream)) - 1n
716
- } else {
717
- return yield* new DecodeError(stream, `Unexpected tag m:${m}`)
718
- }
719
- } else {
720
- return yield* new DecodeError(stream, `Unexpected tag m:${m}`)
721
- }
722
- })
723
-
724
- const decodeIntInternal = (
725
- stream: Bytes.Stream,
726
- nBytes: number | undefined = undefined
727
- ): DecodeEffect<bigint> => {
728
- return (
729
- nBytes === undefined ? decodeBytes(stream) : stream.shiftMany(nBytes)
730
- ).pipe(
731
- Effect.map(BigEndian.decode),
732
- Effect.flatMap((result) => {
733
- if (result._tag == "Left") {
734
- return Effect.fail(
735
- new DecodeError(
736
- stream,
737
- `failed to decode BigEndian int (${result.left.message})`
738
- )
739
- )
740
- } else {
741
- return Effect.succeed(result.right)
742
- }
743
- })
744
- )
745
- }
746
-
747
- /**
748
- * Encodes a bigint integer using CBOR.
749
- * @param n
750
- * @returns
751
- */
752
- export function encodeInt(n: number | bigint): number[] {
753
- if (typeof n == "number") {
754
- return encodeInt(BigInt(n))
755
- } else if (n >= 0n && n <= (2n << 63n) - 1n) {
756
- return encodeDefHead(0, n)
757
- } else if (n >= 2n << 63n) {
758
- return encodeDefHead(6, 2).concat(encodeBytes(BigEndian.encode(n)))
759
- } else if (n <= -1n && n >= -(2n << 63n)) {
760
- return encodeDefHead(1, -n - 1n)
761
- } else {
762
- return encodeDefHead(6, 3).concat(encodeBytes(BigEndian.encode(-n - 1n)))
763
- }
764
- }
765
-
766
- /**
767
- * @param bytes
768
- * @returns
769
- */
770
- export const isInt = (bytes: Bytes.BytesLike): PeekEffect<boolean> =>
771
- peekMajorAndSimpleMinorType(bytes).pipe(
772
- Effect.map(([m, n0]) => {
773
- if (m == 0 || m == 1) {
774
- return true
775
- } else if (m == 6) {
776
- return n0 == 2 || n0 == 3
777
- } else {
778
- return false
779
- }
780
- })
781
- )
782
-
783
- /**
784
- * Decodes a CBOR encoded list.
785
- * A decoder function is called with the bytes of every contained item (nothing is returning directly).
786
- * @template T
787
- * @param itemDecoder
788
- * @returns
789
- */
790
- export const decodeList =
791
- <T>(
792
- itemDecoder: IndexedDecoder<T>
793
- ): ((bytes: Bytes.BytesLike) => DecodeEffect<T[]>) =>
794
- (bytes: Bytes.BytesLike) =>
795
- Effect.gen(function* () {
796
- const stream = Bytes.makeStream(bytes)
797
-
798
- const res: T[] = []
799
-
800
- if (yield* isIndefList(stream)) {
801
- yield* stream.shiftOne()
802
-
803
- let i = 0
804
- while ((yield* stream.peekOne()) != 255) {
805
- res.push(yield* itemDecoder(stream, i))
806
- i++
807
- }
808
-
809
- const last = yield* stream.shiftOne()
810
- if (last != 255) {
811
- return yield* new DecodeError(stream, "Invalid def list head byte")
812
- }
813
- } else {
814
- const [m, n] = yield* decodeDefHead(stream)
815
-
816
- if (m != 4) {
817
- return yield* new DecodeError(stream, "invalid def list head byte")
818
- }
819
-
820
- for (let i = 0; i < Number(n); i++) {
821
- res.push(yield* itemDecoder(stream, i))
822
- }
823
- }
824
-
825
- return res
826
- })
827
-
828
- /**
829
- * @param bytes
830
- * @returns
831
- *
832
- *
833
- */
834
- export const decodeListLazy = (
835
- bytes: Bytes.BytesLike
836
- ): DecodeEffect<<T>(itemDecoder: IndexedDecoder<T>) => DecodeEffect<T>> =>
837
- Effect.gen(function* () {
838
- const stream = Bytes.makeStream(bytes)
839
-
840
- let i = 0
841
- let done = false
842
- let checkDone: () => Effect.Effect<void, Bytes.EndOfStreamError>
843
-
844
- if (yield* isIndefList(stream)) {
845
- yield* stream.shiftOne()
846
-
847
- checkDone = () =>
848
- Effect.gen(function* () {
849
- if ((yield* stream.peekOne()) == 255) {
850
- yield* stream.shiftOne()
851
- done = true
852
- }
853
- })
854
- } else {
855
- const [m, n] = yield* decodeDefHead(stream)
856
-
857
- if (m != 4) {
858
- return yield* new DecodeError(stream, "Unexpected header major type")
859
- }
860
-
861
- checkDone = () => {
862
- if (i >= n) {
863
- done = true
864
- }
865
-
866
- return Effect.void
867
- }
868
- }
869
-
870
- yield* checkDone()
871
-
872
- const decodeItem = <T>(itemDecoder: IndexedDecoder<T>): DecodeEffect<T> =>
873
- Effect.gen(function* () {
874
- if (done) {
875
- return yield* new DecodeError(stream, "end-of-list")
876
- }
877
-
878
- const res = yield* itemDecoder(stream, i)
879
-
880
- i++
881
-
882
- yield* checkDone()
883
-
884
- return res
885
- })
886
-
887
- return decodeItem
888
- })
889
-
890
- /**
891
- * @param bytes
892
- * @returns
893
- */
894
- export const decodeListLazyOption = (
895
- bytes: Bytes.BytesLike
896
- ): DecodeEffect<
897
- <T>(itemDecoder: IndexedDecoder<T>) => DecodeEffect<T | undefined>
898
- > =>
899
- Effect.gen(function* () {
900
- const stream = Bytes.makeStream(bytes)
901
-
902
- let i = 0
903
- let done = false
904
- let checkDone: () => Effect.Effect<void, Bytes.EndOfStreamError>
905
-
906
- if (yield* isIndefList(stream)) {
907
- yield* stream.shiftOne()
908
-
909
- checkDone = () =>
910
- Effect.gen(function* () {
911
- if ((yield* stream.peekOne()) == 255) {
912
- yield* stream.shiftOne()
913
- done = true
914
- }
915
- })
916
- } else {
917
- const [m, n] = yield* decodeDefHead(stream)
918
-
919
- if (m != 4) {
920
- return yield* new DecodeError(stream, "Unexpected major type for list")
921
- }
922
-
923
- checkDone = () => {
924
- if (i >= n) {
925
- done = true
926
- }
927
-
928
- return Effect.void
929
- }
930
- }
931
-
932
- yield* checkDone()
933
-
934
- const decodeItem = <T>(
935
- itemDecoder: IndexedDecoder<T>
936
- ): DecodeEffect<T | undefined> =>
937
- Effect.gen(function* () {
938
- if (done) {
939
- return undefined
940
- }
941
-
942
- const res = yield* itemDecoder(stream, i)
943
-
944
- i++
945
-
946
- yield* checkDone()
947
-
948
- return res
949
- })
950
-
951
- return decodeItem
952
- })
953
-
954
- /**
955
- * This follows the serialization format that the Haskell input-output-hk/plutus UPLC evaluator (i.e. empty lists use `encodeDefList`, non-empty lists use `encodeIndefList`).
956
- * See [well-typed/cborg/serialise/src/Codec/Serialise/Class.hs](https://github.com/well-typed/cborg/blob/4bdc818a1f0b35f38bc118a87944630043b58384/serialise/src/Codec/Serialise/Class.hs#L181).
957
- * @param items already encoded
958
- * @returns
959
- */
960
- export function encodeList(items: readonly number[][]): number[] {
961
- return items.length > 0 ? encodeIndefList(items) : encodeDefList(items)
962
- }
963
-
964
- /**
965
- * @returns
966
- */
967
- function encodeIndefListStart(): number[] {
968
- return encodeIndefHead(4)
969
- }
970
-
971
- /**
972
- * @param list
973
- * @returns
974
- */
975
- function encodeListInternal(list: readonly number[][]): number[] {
976
- /**
977
- * @type {number[]}
978
- */
979
- let res: number[] = []
980
- for (const item of list) {
981
- res = res.concat(item)
982
- }
983
-
984
- return res
985
- }
986
-
987
- const INDEF_LIST_END = [255]
988
-
989
- /**
990
- * Encodes a list of CBOR encodeable items using CBOR indefinite length encoding.
991
- * @param list Each item is either already serialized.
992
- * @returns
993
- */
994
- export function encodeIndefList(list: readonly number[][]): number[] {
995
- return encodeIndefListStart()
996
- .concat(encodeListInternal(list))
997
- .concat(INDEF_LIST_END)
998
- }
999
-
1000
- /**
1001
- * @param n
1002
- * @returns
1003
- */
1004
- function encodeDefListStart(n: bigint): number[] {
1005
- return encodeDefHead(4, n)
1006
- }
1007
-
1008
- /**
1009
- * Encodes a list of CBOR encodeable items using CBOR definite length encoding
1010
- * (i.e. header bytes of the element represent the length of the list).
1011
- * @param items Each item is already serialized
1012
- * @returns
1013
- */
1014
- export function encodeDefList(items: readonly number[][]): number[] {
1015
- return encodeDefListStart(BigInt(items.length)).concat(
1016
- encodeListInternal(items)
1017
- )
1018
- }
1019
-
1020
- /**
1021
- * @param bytes
1022
- * @returns
1023
- */
1024
- export const isList = (bytes: Bytes.BytesLike): PeekEffect<boolean> =>
1025
- peekMajorType(bytes).pipe(Effect.map((m) => m == 4))
1026
-
1027
- /**
1028
- * @param bytes
1029
- * @returns
1030
- */
1031
- export const isDefList = (bytes: Bytes.BytesLike): PeekEffect<boolean> =>
1032
- Effect.gen(function* () {
1033
- const stream = Bytes.makeStream(bytes)
1034
-
1035
- return (
1036
- (yield* peekMajorType(stream)) == 4 &&
1037
- (yield* stream.peekOne()) != 4 * 32 + 31
1038
- )
1039
- })
1040
-
1041
- /**
1042
- * @param bytes
1043
- * @returns
1044
- */
1045
- export const isIndefList = (bytes: Bytes.BytesLike): PeekEffect<boolean> =>
1046
- Bytes.makeStream(bytes)
1047
- .peekOne()
1048
- .pipe(Effect.map((head) => head == 4 * 32 + 31))
1049
-
1050
- /**
1051
- * Decodes a CBOR encoded map.
1052
- * Calls a decoder function for each key-value pair (nothing is returned directly).
1053
- *
1054
- * The decoder function is responsible for separating the key from the value,
1055
- * which are simply stored as consecutive CBOR elements.
1056
- * @param keyDecoder
1057
- * @param valueDecoder
1058
- * @returns
1059
- */
1060
- export const decodeMap =
1061
- <TKey, TValue>(keyDecoder: Decoder<TKey>, valueDecoder: Decoder<TValue>) =>
1062
- (bytes: Bytes.BytesLike): DecodeEffect<[TKey, TValue][]> =>
1063
- Effect.gen(function* () {
1064
- const stream = Bytes.makeStream(bytes)
1065
-
1066
- if (yield* isIndefMap(stream)) {
1067
- yield* stream.shiftOne()
1068
-
1069
- return yield* decodeIndefMap<TKey, TValue>(
1070
- stream,
1071
- keyDecoder,
1072
- valueDecoder
1073
- )
1074
- } else {
1075
- const [m, n] = yield* decodeDefHead(stream)
1076
-
1077
- if (m != 5) {
1078
- return yield* new DecodeError(stream, "invalid def map")
1079
- }
1080
-
1081
- return yield* decodeDefMap<TKey, TValue>(
1082
- stream,
1083
- Number(n),
1084
- keyDecoder,
1085
- valueDecoder
1086
- )
1087
- }
1088
- })
1089
-
1090
- /**
1091
- * Internal use only, header already decoded
1092
- * @param stream
1093
- * @param n
1094
- * @param keyDecoder
1095
- * @param valueDecoder
1096
- * @returns
1097
- */
1098
- const decodeDefMap = <TKey, TValue>(
1099
- stream: Bytes.Stream,
1100
- n: number,
1101
- keyDecoder: Decoder<TKey>,
1102
- valueDecoder: Decoder<TValue>
1103
- ): DecodeEffect<[TKey, TValue][]> =>
1104
- Effect.gen(function* () {
1105
- const res: [TKey, TValue][] = []
1106
-
1107
- for (let i = 0; i < n; i++) {
1108
- res.push([yield* keyDecoder(stream), yield* valueDecoder(stream)])
1109
- }
1110
-
1111
- return res
1112
- })
1113
-
1114
- /**
1115
- * Used internally, head already decoded
1116
- * @template TKey
1117
- * @template TValue
1118
- * @param stream
1119
- * @param keyDecoder
1120
- * @param valueDecoder
1121
- * @returns
1122
- */
1123
- const decodeIndefMap = <TKey, TValue>(
1124
- stream: Bytes.Stream,
1125
- keyDecoder: Decoder<TKey>,
1126
- valueDecoder: Decoder<TValue>
1127
- ): DecodeEffect<[TKey, TValue][]> =>
1128
- Effect.gen(function* () {
1129
- const res: [TKey, TValue][] = []
1130
-
1131
- while ((yield* stream.peekOne()) != 255) {
1132
- res.push([yield* keyDecoder(stream), yield* valueDecoder(stream)])
1133
- }
1134
-
1135
- yield* stream.shiftOne()
1136
-
1137
- return res
1138
- })
1139
-
1140
- /**
1141
- * Unlike lists, the default serialization format for maps seems to always be the defined format
1142
- * @param pairs already encoded
1143
- * @returns
1144
- */
1145
- export function encodeMap(pairs: [number[], number[]][]): number[] {
1146
- return encodeDefMap(pairs)
1147
- }
1148
-
1149
- /**
1150
- * Encodes a list of key-value pairs.
1151
- * @param pairs
1152
- * Each key and each value is an already encoded list of CBOR bytes.
1153
- * @returns
1154
- */
1155
- export function encodeDefMap(pairs: [number[], number[]][]): number[] {
1156
- return encodeDefHead(5, BigInt(pairs.length)).concat(encodeMapInternal(pairs))
1157
- }
1158
-
1159
- /**
1160
- * Encodes a list of key-value pairs using the length undefined format.
1161
- * @param pairs
1162
- * Each key and each value is an already encoded list of CBOR bytes.
1163
- * @returns
1164
- */
1165
- export function encodeIndefMap(pairs: [number[], number[]][]): number[] {
1166
- return encodeIndefHead(5).concat(encodeMapInternal(pairs)).concat([255])
1167
- }
1168
-
1169
- /**
1170
- * @param pairs already encoded
1171
- * @returns
1172
- */
1173
- function encodeMapInternal(pairs: [number[], number[]][]): number[] {
1174
- let res: number[] = []
1175
-
1176
- for (const pair of pairs) {
1177
- const key = pair[0]
1178
- const value = pair[1]
1179
-
1180
- res = res.concat(key)
1181
- res = res.concat(value)
1182
- }
1183
-
1184
- return res
1185
- }
1186
-
1187
- /**
1188
- * @param bytes
1189
- * @returns
1190
- */
1191
- export const isMap = (bytes: Bytes.BytesLike): PeekEffect<boolean> =>
1192
- peekMajorType(bytes).pipe(Effect.map((m) => m == 5))
1193
-
1194
- /**
1195
- * @param bytes
1196
- * @returns
1197
- */
1198
- const isIndefMap = (bytes: Bytes.BytesLike): PeekEffect<boolean> =>
1199
- Bytes.makeStream(bytes)
1200
- .peekOne()
1201
- .pipe(Effect.map((head) => head == 5 * 32 + 31))
1202
-
1203
- const NULL_BYTE = 246 // m = 7, n = 22
1204
-
1205
- /**
1206
- * Checks if next element in `bytes` is a `null`.
1207
- * Throws an error if it isn't.
1208
- * @param bytes
1209
- * @returns
1210
- */
1211
- export const decodeNull = (bytes: Bytes.BytesLike): DecodeEffect<null> =>
1212
- Effect.gen(function* () {
1213
- const stream = Bytes.makeStream(bytes)
1214
-
1215
- const b = yield* stream.shiftOne()
1216
-
1217
- if (b != NULL_BYTE) {
1218
- return yield* new DecodeError(stream, "not null")
1219
- }
1220
-
1221
- return null
1222
- })
1223
-
1224
- /**
1225
- * Encode `null` into its CBOR representation.
1226
- * @param _null ignored
1227
- * @returns
1228
- */
1229
- export function encodeNull(_null: null = null): number[] {
1230
- return [NULL_BYTE]
1231
- }
1232
-
1233
- /**
1234
- * @param bytes
1235
- * @returns
1236
- */
1237
- export const isNull = (bytes: Bytes.BytesLike): PeekEffect<boolean> =>
1238
- Bytes.makeStream(bytes)
1239
- .peekOne()
1240
- .pipe(Effect.map((head) => head == NULL_BYTE))
1241
-
1242
- /**
1243
- * Decodes a CBOR encoded object with integer keys.
1244
- * For each field a decoder is called which takes the field index and the field bytes as arguments.
1245
- * @template Decoders
1246
- * @param fieldDecoders
1247
- * @returns
1248
- */
1249
- export const decodeObjectIKey =
1250
- <Decoders extends { [key: number]: Decoder<any> }>(fieldDecoders: Decoders) =>
1251
- (
1252
- bytes: Bytes.BytesLike
1253
- ): DecodeEffect<{
1254
- [D in keyof Decoders]+?: Decoders[D] extends Decoder<infer T> ? T : never
1255
- }> => {
1256
- const stream = Bytes.makeStream(bytes)
1257
-
1258
- const res: Record<number, any> = {}
1259
-
1260
- return decodeMap(
1261
- () => Effect.succeed(null),
1262
- (pairStream) =>
1263
- Effect.gen(function* () {
1264
- const key = Number(yield* decodeInt(pairStream))
1265
-
1266
- const decoder: Decoder<any> | undefined = fieldDecoders[key]
1267
-
1268
- if (decoder === undefined) {
1269
- return yield* new DecodeError(
1270
- pairStream,
1271
- `unhandled object field ${key}`
1272
- )
1273
- }
1274
-
1275
- /* eslint-disable-next-line @typescript-eslint/no-unsafe-assignment */
1276
- res[key] = yield* decoder(pairStream)
1277
-
1278
- return Effect.void
1279
- })
1280
- )(stream).pipe(
1281
- Effect.map(() => {
1282
- return res as {
1283
- [D in keyof Decoders]+?: Decoders[D] extends Decoder<infer T>
1284
- ? T
1285
- : never
1286
- }
1287
- })
1288
- )
1289
- }
1290
-
1291
- /**
1292
- * Decodes a CBOR encoded object with string keys.
1293
- * For each field a decoder is called which takes the field index and the field bytes as arguments.
1294
- * @template Decoders
1295
- * @param fieldDecoders
1296
- * @returns
1297
- */
1298
- export const decodeObjectSKey =
1299
- <Decoders extends { [key: string]: Decoder<any> }>(fieldDecoders: Decoders) =>
1300
- (
1301
- bytes: Bytes.BytesLike
1302
- ): DecodeEffect<{
1303
- [D in keyof Decoders]+?: Decoders[D] extends Decoder<infer T> ? T : never
1304
- }> => {
1305
- const stream = Bytes.makeStream(bytes)
1306
-
1307
- const res: Record<string, any> = {}
1308
-
1309
- return decodeMap(
1310
- () => Effect.succeed(null),
1311
- (pairStream) =>
1312
- Effect.gen(function* () {
1313
- const key = yield* decodeString(pairStream)
1314
-
1315
- const decoder: Decoder<any> | undefined = fieldDecoders[key]
1316
-
1317
- if (decoder === undefined) {
1318
- return yield* new DecodeError(
1319
- pairStream,
1320
- `unhandled object field ${key}`
1321
- )
1322
- }
1323
-
1324
- /* eslint-disable-next-line @typescript-eslint/no-unsafe-assignment */
1325
- res[key] = yield* decoder(pairStream)
1326
-
1327
- return Effect.void
1328
- })
1329
- )(stream).pipe(
1330
- Effect.map(() => {
1331
- return res as {
1332
- [D in keyof Decoders]+?: Decoders[D] extends Decoder<infer T>
1333
- ? T
1334
- : never
1335
- }
1336
- })
1337
- )
1338
- }
1339
-
1340
- /**
1341
- * Encodes an object with optional fields using integer keys.
1342
- * @param object
1343
- * A `Map` with integer keys representing the field indices.
1344
- * @returns
1345
- */
1346
- export function encodeObjectIKey(
1347
- object: Map<number, number[]> | Record<number, number[]>
1348
- ): number[] {
1349
- const entries: [number[], number[]][] =
1350
- object instanceof Map
1351
- ? Array.from(object.entries()).map((pair) => [
1352
- encodeInt(pair[0]),
1353
- pair[1]
1354
- ])
1355
- : Object.entries(object).map((pair) => [
1356
- encodeInt(parseInt(pair[0])),
1357
- pair[1]
1358
- ])
1359
-
1360
- return encodeDefMap(entries)
1361
- }
1362
-
1363
- /**
1364
- * Encodes an object with optional fields using string keys.
1365
- * @param object
1366
- * A `Map` with string keys representing the field indices.
1367
- * @returns
1368
- */
1369
- export function encodeObjectSKey(
1370
- object: Map<string, number[]> | Record<string, number[]>
1371
- ): number[] {
1372
- const entries: [number[], number[]][] =
1373
- object instanceof Map
1374
- ? Array.from(object.entries()).map((pair) => [
1375
- encodeString(pair[0]),
1376
- pair[1]
1377
- ])
1378
- : Object.entries(object).map((pair) => [encodeString(pair[0]), pair[1]])
1379
-
1380
- return encodeDefMap(entries)
1381
- }
1382
-
1383
- /**
1384
- * @param bytes
1385
- * @returns
1386
- */
1387
- export const isObject = (bytes: Bytes.BytesLike): PeekEffect<boolean> =>
1388
- isMap(bytes)
1389
-
1390
- const SET_TAG = 258n
1391
-
1392
- /**
1393
- * Like a list, but with an optional 258 tag
1394
- * See: https://github.com/Emurgo/cardano-serialization-lib/releases/tag/13.0.0
1395
- * @template T
1396
- * @param itemDecoder
1397
- * @returns
1398
- */
1399
- export const decodeSet =
1400
- <T>(itemDecoder: Decoder<T>) =>
1401
- (bytes: Bytes.BytesLike): DecodeEffect<T[]> =>
1402
- Effect.gen(function* () {
1403
- const stream = Bytes.makeStream(bytes)
1404
-
1405
- if (yield* isTag(stream)) {
1406
- const tag = yield* decodeTag(stream)
1407
- if (tag != SET_TAG) {
1408
- return yield* new DecodeError(
1409
- stream,
1410
- `expected tag ${SET_TAG} for set, got tag ${tag}`
1411
- )
1412
- }
1413
- }
1414
-
1415
- return yield* decodeList(itemDecoder)(stream)
1416
- })
1417
-
1418
- /**
1419
- * A tagged def list (tag 258n)
1420
- * @param items
1421
- * @returns
1422
- */
1423
- export function encodeSet(items: number[][]): number[] {
1424
- return encodeTag(SET_TAG).concat(encodeDefList(items))
1425
- }
1426
-
1427
- /**
1428
- * @param bytes
1429
- * @returns
1430
- */
1431
- export const isSet = (bytes: Bytes.BytesLike): PeekEffect<boolean> =>
1432
- peekTag(bytes).pipe(Effect.map((t) => t == SET_TAG))
1433
-
1434
- /**
1435
- * @param bytes
1436
- * @returns
1437
- */
1438
- export const decodeString = (bytes: Bytes.BytesLike): DecodeEffect<string> =>
1439
- Effect.gen(function* () {
1440
- const stream = Bytes.makeStream(bytes)
1441
-
1442
- if (yield* isDefList(stream)) {
1443
- let result = ""
1444
-
1445
- yield* decodeList((itemBytes) =>
1446
- decodeStringInternal(itemBytes).pipe(
1447
- Effect.tap((s) => {
1448
- result += s
1449
- })
1450
- )
1451
- )(stream)
1452
-
1453
- return result
1454
- } else {
1455
- return yield* decodeStringInternal(stream)
1456
- }
1457
- })
1458
-
1459
- /**
1460
- * @param bytes
1461
- * @returns
1462
- */
1463
- const decodeStringInternal = (bytes: Bytes.BytesLike): DecodeEffect<string> =>
1464
- Effect.gen(function* () {
1465
- const stream = Bytes.makeStream(bytes)
1466
-
1467
- const [m, n] = yield* decodeDefHead(stream)
1468
-
1469
- if (m !== 3) {
1470
- return yield* new DecodeError(stream, "unexpected")
1471
- }
1472
-
1473
- return yield* Utf8.decode(yield* stream.shiftMany(Number(n))).pipe(
1474
- Effect.mapError(
1475
- (e) => new DecodeError(stream, `invalid utf8 (${e.message})`)
1476
- )
1477
- )
1478
- })
1479
-
1480
- /**
1481
- * Encodes a Utf8 string into Cbor bytes.
1482
- * Strings can be split into lists with chunks of up to 64 bytes
1483
- * to play nice with Cardano tx metadata constraints.
1484
- * @param str
1485
- * @param split
1486
- * @returns
1487
- */
1488
- export function encodeString(str: string, split: boolean = false): number[] {
1489
- const bytes = Bytes.toArray(Utf8.encode(str))
1490
-
1491
- if (split && bytes.length > 64) {
1492
- const chunks: number[][] = []
1493
-
1494
- let i = 0
1495
- while (i < bytes.length) {
1496
- // We encode the largest chunk up to 64 bytes
1497
- // that is valid UTF-8
1498
- let maxChunkLength = 64
1499
- let chunk: number[]
1500
- while (true) {
1501
- chunk = bytes.slice(i, i + maxChunkLength)
1502
- if (Utf8.isValid(chunk)) {
1503
- break
1504
- }
1505
- maxChunkLength--
1506
- }
1507
-
1508
- chunks.push(encodeDefHead(3, BigInt(chunk.length)).concat(chunk))
1509
- i += chunk.length
1510
- }
1511
-
1512
- return encodeDefList(chunks)
1513
- } else {
1514
- return encodeDefHead(3, BigInt(bytes.length)).concat(bytes)
1515
- }
1516
- }
1517
-
1518
- /**
1519
- * @param bytes
1520
- * @returns
1521
- */
1522
- export const isString = (bytes: Bytes.BytesLike): PeekEffect<boolean> =>
1523
- peekMajorType(bytes).pipe(Effect.map((m) => m == 3))
1524
-
1525
- /**
1526
- * @param bytes
1527
- * @returns
1528
- */
1529
- export const decodeTag = (bytes: Bytes.BytesLike): DecodeEffect<bigint> =>
1530
- Effect.gen(function* () {
1531
- const stream = Bytes.makeStream(bytes)
1532
-
1533
- const [m, n] = yield* decodeDefHead(stream)
1534
-
1535
- if (m != 6) {
1536
- return yield* new DecodeError(stream, "unexpected major type for tag")
1537
- }
1538
-
1539
- return n
1540
- })
1541
-
1542
- /**
1543
- * Unrelated to constructor
1544
- * @param tag
1545
- * @returns
1546
- */
1547
- export function encodeTag(tag: number | bigint): number[] {
1548
- if (typeof tag == "number") {
1549
- return encodeTag(BigInt(tag))
1550
- } else if (tag < 0) {
1551
- throw new Error("can't encode negative tag")
1552
- }
1553
-
1554
- return encodeDefHead(6, tag)
1555
- }
1556
-
1557
- /**
1558
- * @param bytes
1559
- * @returns
1560
- */
1561
- export const isTag = (bytes: Bytes.BytesLike): PeekEffect<boolean> =>
1562
- peekMajorType(bytes).pipe(Effect.map((m) => m == 6))
1563
-
1564
- /**
1565
- * @param bytes
1566
- * @returns
1567
- */
1568
- export const peekTag = (
1569
- bytes: Bytes.BytesLike
1570
- ): PeekEffect<bigint | undefined> =>
1571
- decodeTag(Bytes.makeStream(bytes).copy()).pipe(
1572
- Effect.catchTag("Cbor.DecodeError", () => Effect.succeed(undefined))
1573
- )
1574
-
1575
- /**
1576
- * @param bytes
1577
- * @returns
1578
- */
1579
- export const decodeTagged = (
1580
- bytes: Bytes.BytesLike
1581
- ): DecodeEffect<[number, <T>(itemDecoder: Decoder<T>) => DecodeEffect<T>]> =>
1582
- Effect.gen(function* () {
1583
- const stream = Bytes.makeStream(bytes)
1584
-
1585
- if (yield* isList(stream)) {
1586
- const decodeItem = yield* decodeListLazy(stream)
1587
-
1588
- const tag = Number(yield* decodeItem(decodeInt))
1589
-
1590
- return [tag, decodeItem]
1591
- } else {
1592
- return yield* decodeConstrLazy(stream)
1593
- }
1594
- })
1595
-
1596
- /**
1597
- * @template Decoders
1598
- * @template OptionalDecoders
1599
- * @param itemDecoders
1600
- * @param optionalDecoders
1601
- * Defaults to empty tuple
1602
- * @returns
1603
- */
1604
- export const decodeTuple =
1605
- <
1606
- Decoders extends Array<Decoder<any>>,
1607
- OptionalDecoders extends Array<Decoder<any>>
1608
- >(
1609
- itemDecoders: [...Decoders],
1610
- optionalDecoders: [...OptionalDecoders] | [] = []
1611
- ) =>
1612
- (
1613
- bytes: Bytes.BytesLike
1614
- ): DecodeEffect<
1615
- [
1616
- ...{
1617
- [D in keyof Decoders]: Decoders[D] extends Decoder<infer T> ? T : never
1618
- },
1619
- ...{
1620
- [D in keyof OptionalDecoders]: OptionalDecoders[D] extends Decoder<
1621
- infer T
1622
- >
1623
- ? T | undefined
1624
- : never
1625
- }
1626
- ]
1627
- > =>
1628
- Effect.gen(function* () {
1629
- const stream = Bytes.makeStream(bytes)
1630
-
1631
- /**
1632
- * decodeList is the right decoder, but has the wrong type interface
1633
- * Cast the result to `any` to avoid type errors
1634
- */
1635
- const res: any[] = yield* decodeList((itemStream, i) =>
1636
- Effect.gen(function* () {
1637
- let decoder: Decoder<any> | undefined = itemDecoders[i]
1638
-
1639
- if (decoder === undefined) {
1640
- decoder = optionalDecoders[i - itemDecoders.length]
1641
-
1642
- if (decoder === undefined) {
1643
- return yield* new DecodeError(
1644
- itemStream,
1645
- `expected at most ${
1646
- itemDecoders.length + optionalDecoders.length
1647
- } items, got more than ${i}`
1648
- )
1649
- }
1650
- }
1651
-
1652
- // eslint-disable-next-line @typescript-eslint/no-unsafe-return
1653
- return yield* decoder(itemStream)
1654
- })
1655
- )(stream)
1656
-
1657
- if (res.length < itemDecoders.length) {
1658
- return yield* new DecodeError(
1659
- stream,
1660
- `expected at least ${itemDecoders.length} items, only got ${res.length}`
1661
- )
1662
- }
1663
-
1664
- return res as [
1665
- ...{
1666
- [D in keyof Decoders]: Decoders[D] extends Decoder<infer T>
1667
- ? T
1668
- : never
1669
- },
1670
- ...{
1671
- [D in keyof OptionalDecoders]: OptionalDecoders[D] extends Decoder<
1672
- infer T
1673
- >
1674
- ? T | undefined
1675
- : never
1676
- }
1677
- ]
1678
- })
1679
-
1680
- /**
1681
- * @param bytes
1682
- * @returns
1683
- */
1684
- export function decodeTupleLazy(
1685
- bytes: Bytes.BytesLike
1686
- ): DecodeEffect<<T>(itemDecoder: Decoder<T>) => DecodeEffect<T>> {
1687
- return decodeListLazy(bytes)
1688
- }
1689
-
1690
- /**
1691
- * @param tuple
1692
- * @returns
1693
- */
1694
- export function encodeTuple(tuple: number[][]): number[] {
1695
- return encodeDefList(tuple)
1696
- }
1697
-
1698
- /**
1699
- * @param bytes
1700
- * @returns
1701
- */
1702
- export function isTuple(bytes: Bytes.BytesLike): PeekEffect<boolean> {
1703
- return isList(bytes)
1704
- }