@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
@@ -1,219 +0,0 @@
1
- import { Effect, Either } from "effect"
2
- import { describe, it, expect } from "bun:test"
3
- import * as Base32 from "./Base32.js"
4
- import * as Utf8 from "./Utf8.js"
5
-
6
- /**
7
- * Some test vectors taken from https://chromium.googlesource.com/chromium/src/+/lkgr/components/base32/base32_unittest.cc
8
- */
9
-
10
- describe(`Base32.make()`, () => {
11
- it("fails for non-32 char alphabet", () => {
12
- expect(() => Base32.make({ alphabet: "abcdefg" })).toThrow()
13
- })
14
-
15
- it("fails for non-unique 32 char alphabet", () => {
16
- expect(() =>
17
- Base32.make({ alphabet: "aacdefghijklmnopqrstuvwxyz234567" })
18
- ).toThrow()
19
- })
20
-
21
- it("fails for non-single char padding (0 chars)", () => {
22
- expect(() =>
23
- Base32.make({
24
- alphabet: Base32.DEFAULT_ALPHABET,
25
- padChar: ""
26
- })
27
- ).toThrow()
28
- })
29
-
30
- it("fails for non-single char padding (more than 1 chars)", () => {
31
- expect(() =>
32
- Base32.make({
33
- alphabet: Base32.DEFAULT_ALPHABET,
34
- padChar: "=="
35
- })
36
- ).toThrow()
37
- })
38
-
39
- it("fails if padding char is part of alphabet", () => {
40
- expect(() =>
41
- Base32.make({
42
- alphabet: "abcdefghijklmnopqrstuvwxyz23456=",
43
- padChar: "="
44
- })
45
- ).toThrow()
46
- })
47
- })
48
-
49
- describe("Base32.DEFAULT.isValid()", () => {
50
- it("returns true for an empty string", () => {
51
- expect(Base32.DEFAULT.isValid("")).toBe(true)
52
- })
53
-
54
- it('returns true for "my"', () => {
55
- expect(Base32.DEFAULT.isValid("my")).toBe(true)
56
- })
57
-
58
- it('returns false for "f0" (invalid char)', () => {
59
- expect(Base32.DEFAULT.isValid("f0")).toBe(false)
60
- })
61
-
62
- it('returns false for "fo=" (bad alignment with padding)', () => {
63
- expect(Base32.DEFAULT.isValid("fo=")).toBe(false)
64
- })
65
-
66
- it('returns false for "fo=o====" (interrupted padding)', () => {
67
- expect(Base32.DEFAULT.isValid("fo=o====")).toBe(false)
68
- })
69
-
70
- it('returns false for "foo=====" (invalid padding length)', () => {
71
- expect(Base32.DEFAULT.isValid("foo=====")).toBe(false)
72
- })
73
-
74
- it('returns false for "fooo====" (bad terminating char)', () => {
75
- expect(Base32.DEFAULT.isValid("fooo====")).toBe(false)
76
- })
77
-
78
- it('returns true for "fooa===="', () => {
79
- expect(Base32.DEFAULT.isValid("fooa====")).toBe(true)
80
- })
81
- })
82
-
83
- describe("Base32.encode() without padding", () => {
84
- const codec = Base32.make({})
85
-
86
- it("returns an empty string for []", () => {
87
- expect(codec.encode([])).toBe("")
88
- })
89
-
90
- it('returns "my" for the utf-8 bytes of "f"', () => {
91
- expect(codec.encode(Utf8.encode("f"))).toBe("my")
92
- })
93
-
94
- it('returns "mzxq" for the utf-8 bytes of "fo"', () => {
95
- expect(codec.encode(Utf8.encode("fo"))).toBe("mzxq")
96
- })
97
-
98
- it('returns "mzxw6" for the utf-8 bytes of "foo"', () => {
99
- expect(codec.encode(Utf8.encode("foo"))).toBe("mzxw6")
100
- })
101
-
102
- it('returns "mzxw6yq" for the utf-8 bytes of "foob"', () => {
103
- expect(codec.encode(Utf8.encode("foob"))).toBe("mzxw6yq")
104
- })
105
-
106
- it('returns "mzxw6ytb" for the utf-8 bytes of "fooba"', () => {
107
- expect(codec.encode(Utf8.encode("fooba"))).toBe("mzxw6ytb")
108
- })
109
-
110
- it('returns "mzxw6ytboi" for the utf-8 bytes of "foobar"', () => {
111
- expect(codec.encode(Utf8.encode("foobar"))).toBe("mzxw6ytboi")
112
- })
113
- })
114
-
115
- describe("Base32.decode()", () => {
116
- const paddingLessCodec = Base32.make({ alphabet: Base32.DEFAULT_ALPHABET })
117
- const paddingCodec = Base32.make({
118
- ...Base32.DEFAULT_PROPS,
119
- strict: true
120
- })
121
-
122
- it("returns [] for an empty string", () => {
123
- expect(Base32.DEFAULT.decode("")).toEqual(Either.right(new Uint8Array([])))
124
- })
125
-
126
- it('returns the utf-8 bytes of "f" for "my"', () => {
127
- expect(paddingLessCodec.decode("my")).toEqual(
128
- Either.right(Utf8.encode("f"))
129
- )
130
- })
131
-
132
- it('returns the utf-8 bytes of "fo" for "mzxq"', () => {
133
- expect(Base32.DEFAULT.decode("mzxq")).toEqual(
134
- Either.right(Utf8.encode("fo"))
135
- )
136
- })
137
-
138
- it('fails for "mzxq" if strict', () => {
139
- expect(paddingCodec.decode("mzxq")._tag).toBe("Left")
140
- })
141
-
142
- it('returns the utf-8 btyes of "foo" for "mzxw6"', () => {
143
- expect(Base32.DEFAULT.decode("mzxw6")).toEqual(
144
- Either.right(Utf8.encode("foo"))
145
- )
146
- })
147
-
148
- it('returns the utf-8 bytes of "foob" for "mzxw6yq"', () => {
149
- expect(Base32.DEFAULT.decode("mzxw6yq")).toEqual(
150
- Either.right(Utf8.encode("foob"))
151
- )
152
- })
153
-
154
- it('returns the utf-8 bytes of "fooba" for "mzxw6ytb"', () => {
155
- expect(Base32.DEFAULT.decode("mzxw6ytb")).toEqual(
156
- Either.right(Utf8.encode("fooba"))
157
- )
158
- })
159
-
160
- it('returns the utf-8 bytes of "foobar" for "mzxw6ytboi"', () => {
161
- expect(Base32.DEFAULT.decode("mzxw6ytboi")).toEqual(
162
- Either.right(Utf8.encode("foobar"))
163
- )
164
- })
165
-
166
- it('fails for "0" (invalid char)', () => {
167
- expect(Base32.DEFAULT.decode("0")._tag).toBe("Left")
168
- })
169
-
170
- it('fails for "1" (invalid char)', () => {
171
- expect(Base32.DEFAULT.decode("1")._tag).toBe("Left")
172
- })
173
-
174
- it('fails for "8" (invalid char)', () => {
175
- expect(Base32.DEFAULT.decode("8")._tag).toBe("Left")
176
- })
177
-
178
- it('fails for "9" (invalid char)', () => {
179
- expect(Base32.DEFAULT.decode("9")._tag).toBe("Left")
180
- })
181
-
182
- it('fails for "$" (invalid char)', () => {
183
- expect(Base32.DEFAULT.decode("$")._tag).toBe("Left")
184
- })
185
-
186
- it('returns the same for "mzxw6ytboi" as for "MZXW6YTBOI" (case insensitive)', () => {
187
- const s = "mzxw6ytboi"
188
-
189
- expect(Base32.DEFAULT.decode(s)).toEqual(
190
- Base32.DEFAULT.decode(s.toUpperCase())
191
- )
192
- })
193
- })
194
-
195
- describe("Base32.decode()/Base32.encode() roundtrip", () => {
196
- function roundtrip(encoded: string): string {
197
- return Base32.DEFAULT.encode(Effect.runSync(Base32.DEFAULT.decode(encoded)))
198
- }
199
-
200
- it("fails for foo=====", () => {
201
- expect(() => roundtrip("foo=====")).toThrow()
202
- })
203
-
204
- it("fails for foo====", () => {
205
- expect(() => roundtrip("foo====")).toThrow()
206
- })
207
-
208
- it("fails for foo=b", () => {
209
- expect(() => roundtrip("foo=b")).toThrow()
210
- })
211
-
212
- it("ok for fooa====", () => {
213
- expect(roundtrip("fooa====")).toBe("fooa====")
214
- })
215
-
216
- it("fails for for fooo====", () => {
217
- expect(() => roundtrip("fooo====")).toThrow()
218
- })
219
- })
@@ -1,341 +0,0 @@
1
- import { Encoding, Either } from "effect"
2
- import * as Bits from "./Bits.js"
3
-
4
- export interface Base32 {
5
- readonly alphabet: string
6
- readonly padChar: string
7
- readonly strict: boolean
8
-
9
- /**
10
- * @param encoded
11
- * @returns array of bytes
12
- */
13
- decode(encoded: string): Either.Either<Uint8Array, Encoding.DecodeException>
14
-
15
- /**
16
- * @param encoded
17
- * @returns array of numbers in range [0,32)
18
- */
19
- decodeRaw(encoded: string): Either.Either<number[], Encoding.DecodeException>
20
-
21
- /**
22
- * @param bytes
23
- * @returns base32 encoded string
24
- */
25
- encode(bytes: string | Uint8Array | number[]): string
26
-
27
- /**
28
- *
29
- * @param bytes
30
- * @returns array of numbers in range [0,32)
31
- */
32
- encodeRaw(bytes: string | Uint8Array | number[]): number[]
33
-
34
- /**
35
- * Checks if encoded bytes are valid base32
36
- * @param encoded
37
- */
38
- isValid(encoded: string): boolean
39
- }
40
-
41
- export type Props =
42
- | {
43
- alphabet?: string
44
- }
45
- | {
46
- alphabet?: string
47
- padChar: string
48
- strict?: boolean
49
- }
50
-
51
- export const DEFAULT_ALPHABET = "abcdefghijklmnopqrstuvwxyz234567" as const
52
-
53
- export const DEFAULT_PAD_CHAR = "=" as const
54
-
55
- export const DEFAULT_PROPS: Props = {
56
- alphabet: DEFAULT_ALPHABET,
57
- padChar: DEFAULT_PAD_CHAR,
58
- strict: false
59
- }
60
-
61
- export const DEFAULT: Base32 = /* @__PURE__ */ make()
62
-
63
- /**
64
- * @param props
65
- * @returns
66
- */
67
- export function make(props: Props = DEFAULT_PROPS): Base32 {
68
- const alphabet = props.alphabet ?? DEFAULT_ALPHABET
69
- const padChar = "padChar" in props ? props.padChar : ""
70
- const strict = "strict" in props ? (props.strict ?? false) : false
71
-
72
- if (alphabet.length != 32) {
73
- throw new Error(
74
- `Expected base32 alphabet with 32 characters, got ${alphabet.length} characters`
75
- )
76
- }
77
-
78
- if (new Set(alphabet.split("")).size != 32) {
79
- throw new Error(
80
- "Invalid base32 alphabet, doesn't consist 32 unique characters"
81
- )
82
- }
83
-
84
- if ("padChar" in props && padChar.length != 1) {
85
- throw new Error("Expected single base32 padChar")
86
- }
87
-
88
- if ("padChar" in props && alphabet.indexOf(padChar) != -1) {
89
- throw new Error("Base32 padChar can't be part of alphabet")
90
- }
91
-
92
- return new Base32Impl(alphabet, padChar, strict)
93
- }
94
-
95
- class Base32Impl implements Base32 {
96
- readonly alphabet: string
97
- readonly padChar: string
98
- readonly strict: boolean
99
-
100
- constructor(alphabet: string, padChar: string, strict: boolean) {
101
- this.alphabet = alphabet
102
- this.padChar = padChar
103
- this.strict = strict
104
- }
105
-
106
- /**
107
- * Decodes a Base32 string into bytes.
108
- * @param encoded
109
- * @returns
110
- */
111
- decode(encoded: string): Either.Either<Uint8Array, Encoding.DecodeException> {
112
- const writer = Bits.makeWriter()
113
-
114
- const rawResult = this.decodeRaw(encoded)
115
-
116
- if (rawResult._tag == "Left") {
117
- return Either.left(rawResult.left)
118
- }
119
-
120
- const raw = rawResult.right
121
-
122
- const n = raw.length
123
-
124
- raw.forEach((code, i) => {
125
- if (i == n - 1) {
126
- // last, make sure we align to byte
127
-
128
- const nCut = n * 5 - 8 * Math.floor((n * 5) / 8)
129
-
130
- const bits = Bits.pad(code.toString(2), 5)
131
-
132
- writer.writeBits(bits.slice(0, 5 - nCut))
133
- } else {
134
- const bits = Bits.pad(code.toString(2), 5)
135
-
136
- writer.writeBits(bits)
137
- }
138
- })
139
-
140
- const result = writer.finalize(false)
141
-
142
- return Either.right(new Uint8Array(result))
143
- }
144
-
145
- /**
146
- * @param encoded
147
- * @returns array with numbers in range [0,32)
148
- */
149
- decodeRaw(
150
- encoded: string
151
- ): Either.Either<number[], Encoding.DecodeException> {
152
- const trimResult = trim(encoded, this.padChar, this.strict)
153
-
154
- if (trimResult._tag == "Left") {
155
- return Either.left(trimResult.left)
156
- }
157
-
158
- encoded = trimResult.right
159
-
160
- const n = encoded.length
161
-
162
- const res: number[] = []
163
-
164
- for (let i = 0; i < n; i++) {
165
- const c = encoded[i]
166
-
167
- if (c == this.padChar) {
168
- // TODO: yield with Effect
169
- return Either.left(
170
- Encoding.DecodeException(
171
- encoded,
172
- `Unexpected padding character '${c}' at position ${i}`
173
- )
174
- )
175
- }
176
-
177
- const code = this.alphabet.indexOf(c.toLowerCase())
178
-
179
- if (code < 0) {
180
- return Either.left(
181
- Encoding.DecodeException(
182
- encoded,
183
- `Invalid base32 character '${c}' at position ${i}`
184
- )
185
- )
186
- } else if (i == n - 1) {
187
- const nBitsExtra = n * 5 - Math.floor((n * 5) / 8) * 8
188
-
189
- if ((((1 << nBitsExtra) - 1) & code) != 0) {
190
- return Either.left(
191
- Encoding.DecodeException(
192
- encoded,
193
- `Invalid base32 final character '${c}'`
194
- )
195
- )
196
- }
197
- }
198
-
199
- res.push(code)
200
- }
201
-
202
- return Either.right(res)
203
- }
204
-
205
- /**
206
- * Encodes bytes in using Base32.
207
- * @param bytes hex encoded or list of uint8 numbers
208
- * @returns
209
- */
210
- encode(bytes: string | number[] | Uint8Array): string {
211
- const s = this.encodeRaw(bytes)
212
- .map((c) => this.alphabet[c])
213
- .join("")
214
-
215
- const n = s.length
216
-
217
- if (n % 8 != 0 && this.padChar.length != 0) {
218
- return s + new Array(8 - (n % 8)).fill(this.padChar).join("")
219
- } else {
220
- return s
221
- }
222
- }
223
-
224
- /**
225
- * @param bytes
226
- * @returns {number[]} list of numbers between 0 and 32
227
- */
228
- encodeRaw(bytes: string | number[] | Uint8Array): number[] {
229
- const result: number[] = []
230
-
231
- const reader = Bits.makeReader(bytes, false)
232
-
233
- while (!reader.isAtEnd()) {
234
- result.push(reader.readBits(5))
235
- }
236
-
237
- return result
238
- }
239
-
240
- /**
241
- * Checks if all the characters in `encoded` are in the given base32 alphabet.
242
- * Checks lengths if their pad characters at the end
243
- * @param encoded
244
- * @returns
245
- */
246
- isValid(encoded: string): boolean {
247
- let n = encoded.length
248
-
249
- if (
250
- this.padChar.length == 1 &&
251
- (this.strict || encoded.endsWith(this.padChar))
252
- ) {
253
- if (encoded.length % 8 != 0) {
254
- return false
255
- }
256
-
257
- const iPad = encoded.indexOf(this.padChar)
258
-
259
- for (let i = iPad + 1; i < n; i++) {
260
- if (encoded.at(i) != this.padChar) {
261
- return false
262
- }
263
- }
264
-
265
- const nPad = n - iPad
266
-
267
- if (nPad != 6 && nPad != 4 && nPad != 3 && nPad != 1) {
268
- return false
269
- }
270
-
271
- encoded = encoded.slice(0, iPad)
272
-
273
- n = iPad
274
- }
275
-
276
- // the last char can't be any possible number
277
-
278
- return encoded.split("").every((c, i) => {
279
- const code = this.alphabet.indexOf(c.toLowerCase())
280
-
281
- if (code < 0) {
282
- return false
283
- }
284
-
285
- if (i == n - 1) {
286
- const nBitsExtra = n * 5 - Math.floor((n * 5) / 8) * 8
287
-
288
- return (((1 << nBitsExtra) - 1) & code) == 0
289
- } else {
290
- return true
291
- }
292
- })
293
- }
294
- }
295
-
296
- /**
297
- * Trims the padding, asserting it is correctly formed
298
- * @param encoded
299
- * @param padChar
300
- * @returns
301
- */
302
- function trim(
303
- encoded: string,
304
- padChar: string,
305
- strict: boolean
306
- ): Either.Either<string, Encoding.DecodeException> {
307
- if (padChar.length == 1) {
308
- let n = encoded.length
309
-
310
- while (n >= 0 && encoded.at(n - 1) == padChar) {
311
- n -= 1
312
- }
313
-
314
- // length alignment is only checked if there are some padding characters at the end
315
- if ((strict || n < encoded.length) && encoded.length % 8 != 0) {
316
- return Either.left(
317
- Encoding.DecodeException(
318
- encoded,
319
- "Invalid length (expected multiple of 8)"
320
- )
321
- )
322
- }
323
-
324
- const nPad = encoded.length - n
325
-
326
- if (nPad != 0) {
327
- if (nPad != 6 && nPad != 4 && nPad != 3 && nPad != 1) {
328
- return Either.left(
329
- Encoding.DecodeException(
330
- encoded,
331
- "Invalid number of base32 padding characters"
332
- )
333
- )
334
- }
335
- }
336
-
337
- return Either.right(encoded.slice(0, n))
338
- } else {
339
- return Either.right(encoded)
340
- }
341
- }
@@ -1,79 +0,0 @@
1
- import { describe, expect, it } from "bun:test"
2
- import { Either } from "effect"
3
- import * as BigEndian from "./BigEndian.js"
4
- import { toHex } from "./Bytes.js"
5
-
6
- describe("BigEndian.decode", () => {
7
- it("returns 255n for [255]", () => {
8
- expect(BigEndian.decode([255])).toEqual(Either.right(255n))
9
- })
10
-
11
- it("returns 255n for [0, 0, 0, 255]", () => {
12
- expect(BigEndian.decode([0, 0, 0, 255])).toEqual(Either.right(255n))
13
- })
14
-
15
- it("fails for [256] (invalid byte)", () => {
16
- expect(BigEndian.decode([256])._tag).toBe("Left")
17
- })
18
-
19
- it("fails for [3.14] (invalid byte)", () => {
20
- expect(BigEndian.decode([3.14])._tag).toBe("Left")
21
- })
22
-
23
- it("fails for [-1] (invalid byte)", () => {
24
- expect(BigEndian.decode([-1])._tag).toBe("Left")
25
- })
26
-
27
- it("fails for empty bytes", () => {
28
- expect(BigEndian.decode([])._tag).toBe("Left")
29
- })
30
-
31
- describe("BigEndian.decode compared to alt formula", () => {
32
- const alt = (bytes: number[]): bigint => {
33
- let sum = 0n
34
- bytes = bytes.slice().reverse()
35
- bytes.forEach((b, i) => {
36
- sum += BigInt(b) * (1n << BigInt(i * 8))
37
- })
38
- return sum
39
- }
40
-
41
- const testVector: number[][] = [
42
- [0x00],
43
- [0x80],
44
- [0xff],
45
- [0xff, 0xff],
46
- [0xfe, 0xfe],
47
- [0x80, 0x80],
48
- [0xab, 0xcd, 0xef, 0x01, 0x23, 0x45, 0x67, 0x89]
49
- ]
50
-
51
- testVector.forEach((t) => {
52
- it(`ok for #${toHex(t)}`, () => {
53
- expect(BigEndian.decode(t)).toEqual(Either.right(alt(t)))
54
- })
55
- })
56
- })
57
- })
58
-
59
- describe("BigEndian.encode", () => {
60
- it("returns [1, 0] for 256", () => {
61
- expect(BigEndian.encode(256)).toEqual([1, 0])
62
- })
63
-
64
- it("returns [0] for 0", () => {
65
- expect(BigEndian.encode(0)).toEqual([0])
66
- })
67
-
68
- it("returns [0] for 0n", () => {
69
- expect(BigEndian.encode(0n)).toEqual([0])
70
- })
71
-
72
- it("fails for a non-whole number", () => {
73
- expect(() => BigEndian.encode(0.5)).toThrow()
74
- })
75
-
76
- it("fails for a negative number", () => {
77
- expect(() => BigEndian.encode(-1n)).toThrow()
78
- })
79
- })
@@ -1,67 +0,0 @@
1
- import { Either, Encoding } from "effect"
2
- import { DecodeException } from "./Bytes.js"
3
-
4
- /**
5
- * Converts a list of big endian uint8 numbers into an unbounded int
6
- * @param bytes
7
- * @returns
8
- * @throws
9
- * If `bytes` is empty
10
- * @throws
11
- * If any input number is out of range [0,256) or not a whole number
12
- */
13
- export function decode(
14
- bytes: number[] | Uint8Array
15
- ): Either.Either<bigint, Encoding.DecodeException> {
16
- if (bytes.length == 0) {
17
- return Either.left(DecodeException(bytes, "Empty bytes"))
18
- }
19
-
20
- let p = 1n
21
- let total = 0n
22
-
23
- for (let i = bytes.length - 1; i >= 0; i--) {
24
- const b = bytes[i]
25
-
26
- if (b < 0 || b > 255 || b % 1.0 != 0.0) {
27
- return Either.left(
28
- DecodeException(bytes, `Invalide bytes '${b}' at position ${i}`)
29
- )
30
- }
31
-
32
- total += BigInt(b) * p
33
-
34
- p *= 256n
35
- }
36
-
37
- return Either.right(total)
38
- }
39
-
40
- /**
41
- * Converts an unbounded integer into a list of big endian uint8 numbers.
42
- * @param x
43
- * @returns
44
- * @throws
45
- * If `x` isn't a whole number
46
- * @throws
47
- * If `x` is negative.
48
- */
49
- export function encode(x: number | bigint): number[] {
50
- if (typeof x == "number") {
51
- return encode(BigInt(x))
52
- } else if (x < 0n) {
53
- throw new RangeError(`Unexpected negative number: ${x}`)
54
- } else if (x == 0n) {
55
- return [0]
56
- } else {
57
- const res: number[] = []
58
-
59
- while (x > 0n) {
60
- res.unshift(Number(x % 256n))
61
-
62
- x = x / 256n
63
- }
64
-
65
- return res
66
- }
67
- }