@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.
- package/bun.lock +60 -0
- package/dist/Ledger/NetworkParams.js +40 -0
- package/dist/Ledger/NetworkParams.js.map +1 -0
- package/dist/Ledger/index.js +1 -0
- package/dist/Ledger/index.js.map +1 -1
- package/package.json +1 -1
- package/tsconfig.build.tsbuildinfo +1 -0
- package/tsconfig.check.tsbuildinfo +1 -0
- package/tsconfig.tsbuildinfo +1 -0
- package/types/Address.d.ts +5 -0
- package/types/Address.d.ts.map +1 -0
- package/types/Bech32.d.ts +30 -0
- package/types/Bech32.d.ts.map +1 -0
- package/types/Cbor.d.ts +430 -0
- package/types/Cbor.d.ts.map +1 -0
- package/types/Ledger/Address.d.ts +109 -0
- package/types/Ledger/Address.d.ts.map +1 -0
- package/types/Ledger/AssetClass.d.ts +101 -0
- package/types/Ledger/AssetClass.d.ts.map +1 -0
- package/types/Ledger/Assets.d.ts +70 -0
- package/types/Ledger/Assets.d.ts.map +1 -0
- package/types/Ledger/Credential.d.ts +26 -0
- package/types/Ledger/Credential.d.ts.map +1 -0
- package/types/Ledger/DatumHash.d.ts +40 -0
- package/types/Ledger/DatumHash.d.ts.map +1 -0
- package/types/Ledger/IsMainnet.d.ts +6 -0
- package/types/Ledger/IsMainnet.d.ts.map +1 -0
- package/types/Ledger/MintingPolicy.d.ts +39 -0
- package/types/Ledger/MintingPolicy.d.ts.map +1 -0
- package/types/Ledger/NetworkParams.d.ts +40 -0
- package/types/Ledger/NetworkParams.d.ts.map +1 -0
- package/types/Ledger/PubKeyHash.d.ts +40 -0
- package/types/Ledger/PubKeyHash.d.ts.map +1 -0
- package/types/Ledger/TxId.d.ts +10 -0
- package/types/Ledger/TxId.d.ts.map +1 -0
- package/types/Ledger/TxInput.d.ts +55 -0
- package/types/Ledger/TxInput.d.ts.map +1 -0
- package/types/Ledger/TxOutput.d.ts +63 -0
- package/types/Ledger/TxOutput.d.ts.map +1 -0
- package/types/Ledger/TxOutputDatum.d.ts +41 -0
- package/types/Ledger/TxOutputDatum.d.ts.map +1 -0
- package/types/Ledger/TxOutputId.d.ts +14 -0
- package/types/Ledger/TxOutputId.d.ts.map +1 -0
- package/types/Ledger/ValidatorHash.d.ts +40 -0
- package/types/Ledger/ValidatorHash.d.ts.map +1 -0
- package/types/Ledger/index.d.ts +16 -0
- package/types/Ledger/index.d.ts.map +1 -0
- package/types/Uplc/Cek.d.ts +72 -0
- package/types/Uplc/Cek.d.ts.map +1 -0
- package/types/Uplc/Data.d.ts +530 -0
- package/types/Uplc/Data.d.ts.map +1 -0
- package/types/Uplc/DataSchema.d.ts +227 -0
- package/types/Uplc/DataSchema.d.ts.map +1 -0
- package/types/Uplc/Primitive.d.ts +26 -0
- package/types/Uplc/Primitive.d.ts.map +1 -0
- package/types/Uplc/index.d.ts +3 -0
- package/types/Uplc/index.d.ts.map +1 -0
- package/types/index.d.ts +5 -0
- package/types/index.d.ts.map +1 -0
- package/types/internal/Base32.d.ts +49 -0
- package/types/internal/Base32.d.ts.map +1 -0
- package/types/internal/BigEndian.d.ts +22 -0
- package/types/internal/BigEndian.d.ts.map +1 -0
- package/types/internal/Bits.d.ts +123 -0
- package/types/internal/Bits.d.ts.map +1 -0
- package/types/internal/Bytes.d.ts +88 -0
- package/types/internal/Bytes.d.ts.map +1 -0
- package/types/internal/Flat.d.ts +71 -0
- package/types/internal/Flat.d.ts.map +1 -0
- package/types/internal/Float.d.ts +38 -0
- package/types/internal/Float.d.ts.map +1 -0
- package/types/internal/Utf8.d.ts +24 -0
- package/types/internal/Utf8.d.ts.map +1 -0
- package/src/Bech32.test.ts +0 -117
- package/src/Bech32.ts +0 -198
- package/src/Cbor.test.ts +0 -1610
- package/src/Cbor.ts +0 -1704
- package/src/Ledger/Address.ts +0 -248
- package/src/Ledger/AssetClass.ts +0 -90
- package/src/Ledger/Assets.ts +0 -164
- package/src/Ledger/Credential.ts +0 -29
- package/src/Ledger/DatumHash.ts +0 -36
- package/src/Ledger/IsMainnet.ts +0 -6
- package/src/Ledger/MintingPolicy.ts +0 -57
- package/src/Ledger/PubKeyHash.ts +0 -36
- package/src/Ledger/TxId.ts +0 -31
- package/src/Ledger/TxInput.test.ts +0 -21
- package/src/Ledger/TxInput.ts +0 -66
- package/src/Ledger/TxOutput.ts +0 -166
- package/src/Ledger/TxOutputDatum.ts +0 -64
- package/src/Ledger/TxOutputId.ts +0 -63
- package/src/Ledger/ValidatorHash.ts +0 -36
- package/src/Ledger/index.ts +0 -14
- package/src/Uplc/Cek.ts +0 -92
- package/src/Uplc/Data.test.ts +0 -321
- package/src/Uplc/Data.ts +0 -657
- package/src/Uplc/Primitive.ts +0 -56
- package/src/Uplc/index.ts +0 -2
- package/src/index.ts +0 -4
- package/src/internal/Base32.test.ts +0 -219
- package/src/internal/Base32.ts +0 -341
- package/src/internal/BigEndian.test.ts +0 -79
- package/src/internal/BigEndian.ts +0 -67
- package/src/internal/Bits.test.ts +0 -300
- package/src/internal/Bits.ts +0 -398
- package/src/internal/Bytes.test.ts +0 -369
- package/src/internal/Bytes.ts +0 -343
- package/src/internal/Flat.test.ts +0 -29
- package/src/internal/Flat.ts +0 -387
- package/src/internal/Float.test.ts +0 -51
- package/src/internal/Float.ts +0 -190
- package/src/internal/Utf8.test.ts +0 -69
- package/src/internal/Utf8.ts +0 -58
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from "bun:test"
|
|
2
|
-
import { makeWriter as makeBitWriter } from "./Bits.js"
|
|
3
|
-
import * as Flat from "./Flat.js"
|
|
4
|
-
|
|
5
|
-
describe("Flat.encodeInt()", () => {
|
|
6
|
-
it("writes 8 bits for 0", () => {
|
|
7
|
-
const bw = makeBitWriter()
|
|
8
|
-
|
|
9
|
-
Flat.encodeInt(bw, 0n)
|
|
10
|
-
|
|
11
|
-
expect(bw.length).toBe(8)
|
|
12
|
-
})
|
|
13
|
-
|
|
14
|
-
it("writes 8 bits for 127", () => {
|
|
15
|
-
const bw = makeBitWriter()
|
|
16
|
-
|
|
17
|
-
Flat.encodeInt(bw, 127n)
|
|
18
|
-
|
|
19
|
-
expect(bw.length).toBe(8)
|
|
20
|
-
})
|
|
21
|
-
|
|
22
|
-
it("writes 16 bits for 128", () => {
|
|
23
|
-
const bw = makeBitWriter()
|
|
24
|
-
|
|
25
|
-
Flat.encodeInt(bw, 128n)
|
|
26
|
-
|
|
27
|
-
expect(bw.length).toBe(16)
|
|
28
|
-
})
|
|
29
|
-
})
|
package/src/internal/Flat.ts
DELETED
|
@@ -1,387 +0,0 @@
|
|
|
1
|
-
import * as Bits from "./Bits.js"
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Instantiate a `Flat.Reader` with {@link makeReader}.
|
|
5
|
-
*/
|
|
6
|
-
export interface Reader {
|
|
7
|
-
isAtEnd(): boolean
|
|
8
|
-
readBits(n: number): number
|
|
9
|
-
readBool(): boolean
|
|
10
|
-
readBuiltinId(): number
|
|
11
|
-
readBytes(): number[]
|
|
12
|
-
readInt(): bigint
|
|
13
|
-
readTag(): number
|
|
14
|
-
readList<T>(readItem: (r: Reader) => T): T[]
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* @param bytes
|
|
19
|
-
* @returns
|
|
20
|
-
*/
|
|
21
|
-
export function makeReader(bytes: string | number[] | Uint8Array): Reader {
|
|
22
|
-
return new ReaderImpl(bytes)
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
class ReaderImpl implements Reader {
|
|
26
|
-
private readonly bitReader: Bits.Reader
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* @param bytes
|
|
30
|
-
*/
|
|
31
|
-
constructor(bytes: string | number[] | Uint8Array) {
|
|
32
|
-
this.bitReader = Bits.makeReader(bytes)
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
isAtEnd(): boolean {
|
|
36
|
-
return this.bitReader.isAtEnd()
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* @param n
|
|
41
|
-
* @returns
|
|
42
|
-
*/
|
|
43
|
-
readBits(n: number): number {
|
|
44
|
-
return this.bitReader.readBits(n)
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
readBool(): boolean {
|
|
48
|
-
return this.readBits(1) == 1
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
readBuiltinId(): number {
|
|
52
|
-
return this.readBits(7)
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
readBytes(): number[] {
|
|
56
|
-
return decodeBytes(this.bitReader)
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* @returns {bigint}
|
|
61
|
-
*/
|
|
62
|
-
readInt(): bigint {
|
|
63
|
-
return decodeInt(this.bitReader)
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Reads a Plutus-core list with a specified size per element
|
|
68
|
-
* Calls itself recursively until the end of the list is reached
|
|
69
|
-
* @template T
|
|
70
|
-
* @param readItem
|
|
71
|
-
* @returns
|
|
72
|
-
*/
|
|
73
|
-
readList<T>(readItem: (r: Reader) => T): T[] {
|
|
74
|
-
// Cons and Nil constructors come from Lisp/Haskell
|
|
75
|
-
// cons 'a' creates a linked list node,
|
|
76
|
-
// nil creates an empty linked list
|
|
77
|
-
const nilOrCons = this.readBits(1)
|
|
78
|
-
|
|
79
|
-
if (nilOrCons == 0) {
|
|
80
|
-
return []
|
|
81
|
-
} else {
|
|
82
|
-
return [readItem(this)].concat(this.readList(readItem))
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
readTag(): number {
|
|
87
|
-
return this.readBits(4)
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* Instantiate a `FlatWriter` with {@link makeWriter}.
|
|
93
|
-
*/
|
|
94
|
-
export interface Writer {
|
|
95
|
-
writeBool(b: boolean): Writer
|
|
96
|
-
writeBytes(bytes: number[]): Writer
|
|
97
|
-
writeInt(x: bigint | number): Writer
|
|
98
|
-
writeListCons(): Writer
|
|
99
|
-
writeListNil(): Writer
|
|
100
|
-
writeTermTag(tag: number): Writer
|
|
101
|
-
writeTypeBits(typeBits: string): Writer
|
|
102
|
-
writeBuiltinId(id: number): Writer
|
|
103
|
-
finalize(): number[]
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* @returns
|
|
108
|
-
*/
|
|
109
|
-
export function makeWriter(): Writer {
|
|
110
|
-
return new WriterImpl()
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
class WriterImpl implements Writer {
|
|
114
|
-
private readonly bitWriter: Bits.Writer
|
|
115
|
-
|
|
116
|
-
constructor() {
|
|
117
|
-
this.bitWriter = Bits.makeWriter()
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
* @param b
|
|
122
|
-
* @returns
|
|
123
|
-
* Self for chaining
|
|
124
|
-
*/
|
|
125
|
-
writeBool(b: boolean): Writer {
|
|
126
|
-
if (b) {
|
|
127
|
-
this.bitWriter.writeBits("1")
|
|
128
|
-
} else {
|
|
129
|
-
this.bitWriter.writeBits("0")
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
return this
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
/**
|
|
136
|
-
* @param bytes
|
|
137
|
-
* @returns
|
|
138
|
-
* Self for chaining
|
|
139
|
-
*/
|
|
140
|
-
writeBytes(bytes: number[]): Writer {
|
|
141
|
-
encodeBytes(this.bitWriter, bytes)
|
|
142
|
-
|
|
143
|
-
return this
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
/**
|
|
147
|
-
* @param x
|
|
148
|
-
* @returns
|
|
149
|
-
* Self for chaining
|
|
150
|
-
* @throws
|
|
151
|
-
* If x is negative
|
|
152
|
-
*/
|
|
153
|
-
writeInt(x: bigint): Writer {
|
|
154
|
-
if (x < 0) {
|
|
155
|
-
throw new Error("x in writeInt isn't positive")
|
|
156
|
-
}
|
|
157
|
-
encodeInt(this.bitWriter, x)
|
|
158
|
-
|
|
159
|
-
return this
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
/**
|
|
163
|
-
* @returns
|
|
164
|
-
* Self for chaining
|
|
165
|
-
*/
|
|
166
|
-
writeListCons(): Writer {
|
|
167
|
-
this.bitWriter.writeBits("1")
|
|
168
|
-
return this
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
/**
|
|
172
|
-
* @returns
|
|
173
|
-
* Self for chaining
|
|
174
|
-
*/
|
|
175
|
-
writeListNil(): Writer {
|
|
176
|
-
this.bitWriter.writeBits("0")
|
|
177
|
-
return this
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
/**
|
|
181
|
-
* @param tag
|
|
182
|
-
* @returns
|
|
183
|
-
* Self for chaining
|
|
184
|
-
*/
|
|
185
|
-
writeTermTag(tag: number): Writer {
|
|
186
|
-
this.bitWriter.writeBits(Bits.pad(tag.toString(2), 4))
|
|
187
|
-
return this
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
/**
|
|
191
|
-
* @param typeBits
|
|
192
|
-
* @returns
|
|
193
|
-
* Self for chaining
|
|
194
|
-
*/
|
|
195
|
-
writeTypeBits(typeBits: string): Writer {
|
|
196
|
-
this.bitWriter.writeBits("1" + typeBits + "0")
|
|
197
|
-
return this
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
/**
|
|
201
|
-
* @param id
|
|
202
|
-
*/
|
|
203
|
-
writeBuiltinId(id: number): Writer {
|
|
204
|
-
this.bitWriter.writeBits(Bits.pad(id.toString(2), 7))
|
|
205
|
-
|
|
206
|
-
return this
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
/**
|
|
210
|
-
* @returns
|
|
211
|
-
*/
|
|
212
|
-
finalize(): number[] {
|
|
213
|
-
return this.bitWriter.finalize()
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
/**
|
|
218
|
-
* @param reader
|
|
219
|
-
* @returns
|
|
220
|
-
*/
|
|
221
|
-
export function decodeBytes(reader: Bits.Reader): number[] {
|
|
222
|
-
reader.moveToByteBoundary(true)
|
|
223
|
-
|
|
224
|
-
const bytes = []
|
|
225
|
-
|
|
226
|
-
let nChunk = reader.readByte()
|
|
227
|
-
|
|
228
|
-
while (nChunk > 0) {
|
|
229
|
-
for (let i = 0; i < nChunk; i++) {
|
|
230
|
-
bytes.push(reader.readByte())
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
nChunk = reader.readByte()
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
return bytes
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
/**
|
|
240
|
-
* Write a list of bytes to the bitWriter using flat encoding.
|
|
241
|
-
* Used by UplcString, UplcByteArray and UplcDataValue
|
|
242
|
-
* Equivalent to E_B* function in Plutus-core docs
|
|
243
|
-
* @param writer
|
|
244
|
-
* @param bytes
|
|
245
|
-
* @param pad
|
|
246
|
-
* Optional, defaults to false
|
|
247
|
-
*/
|
|
248
|
-
export function encodeBytes(
|
|
249
|
-
writer: Bits.Writer,
|
|
250
|
-
bytes: number[],
|
|
251
|
-
pad: boolean = true
|
|
252
|
-
): void {
|
|
253
|
-
if (pad) {
|
|
254
|
-
writer.padToByteBoundary(true)
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
// the rest of this function is equivalent to E_C* function in Plutus-core docs
|
|
258
|
-
const n = bytes.length
|
|
259
|
-
let pos = 0
|
|
260
|
-
|
|
261
|
-
// write chunks of 255
|
|
262
|
-
while (pos < n) {
|
|
263
|
-
// each iteration is equivalent to E_C function in Plutus-core docs
|
|
264
|
-
|
|
265
|
-
const nChunk = Math.min(n - pos, 255)
|
|
266
|
-
|
|
267
|
-
// equivalent to E_8 function in Plutus-core docs
|
|
268
|
-
writer.writeBits(Bits.pad(nChunk.toString(2), 8))
|
|
269
|
-
|
|
270
|
-
for (let i = pos; i < pos + nChunk; i++) {
|
|
271
|
-
const b = bytes[i]
|
|
272
|
-
|
|
273
|
-
// equivalent to E_8 function in Plutus-core docs
|
|
274
|
-
writer.writeBits(Bits.pad(b.toString(2), 8))
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
pos += nChunk
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
if (pad) {
|
|
281
|
-
writer.writeBits("00000000")
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
/**
|
|
286
|
-
* Includes type bits
|
|
287
|
-
* @param n
|
|
288
|
-
* @returns
|
|
289
|
-
*/
|
|
290
|
-
export function bytesSize(n: number): number {
|
|
291
|
-
return 4 + n * 8 + Math.ceil(n / 256) * 8 + 8
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
/**
|
|
295
|
-
* Returns an unsigned (zigzag encoded) bigint
|
|
296
|
-
* @param reader
|
|
297
|
-
* @returns
|
|
298
|
-
*/
|
|
299
|
-
export function decodeInt(reader: Bits.Reader): bigint {
|
|
300
|
-
const bytes = []
|
|
301
|
-
|
|
302
|
-
let b = reader.readByte()
|
|
303
|
-
bytes.push(b)
|
|
304
|
-
|
|
305
|
-
while (!rawByteIsLast(b)) {
|
|
306
|
-
b = reader.readByte()
|
|
307
|
-
bytes.push(b)
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
// strip the leading bit
|
|
311
|
-
return decodeIntLE7(bytes.map((b) => parseRawByte(b))) // raw int is unsigned
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
/**
|
|
315
|
-
* Combines a list of Plutus-core bytes into a bigint (leading bit of each byte is ignored).
|
|
316
|
-
* Differs from bytesToBigInt in utils.js because only 7 bits are used from each byte.
|
|
317
|
-
* @param bytes
|
|
318
|
-
* @returns
|
|
319
|
-
*/
|
|
320
|
-
function decodeIntLE7(bytes: number[]): bigint {
|
|
321
|
-
let value = BigInt(0)
|
|
322
|
-
|
|
323
|
-
const n = bytes.length
|
|
324
|
-
|
|
325
|
-
for (let i = 0; i < n; i++) {
|
|
326
|
-
const b = bytes[i]
|
|
327
|
-
|
|
328
|
-
// 7 (not 8), because leading bit isn't used here
|
|
329
|
-
value = value + BigInt(b) * pow2(BigInt(i) * 7n)
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
return value
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
/**
|
|
336
|
-
* 2 to the power 'p' for bigint.
|
|
337
|
-
* @param p
|
|
338
|
-
* @returns
|
|
339
|
-
*/
|
|
340
|
-
function pow2(p: bigint): bigint {
|
|
341
|
-
return p <= 0n ? 1n : 2n << (p - 1n)
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
/**
|
|
345
|
-
* Parses a single byte in the Plutus-core byte-list representation of an int
|
|
346
|
-
* @param b
|
|
347
|
-
* @returns
|
|
348
|
-
*/
|
|
349
|
-
function parseRawByte(b: number): number {
|
|
350
|
-
return b & 0b01111111
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
/**
|
|
354
|
-
* Returns true if 'b' is the last byte in the Plutus-core byte-list representation of an int.
|
|
355
|
-
* @param b
|
|
356
|
-
* @returns
|
|
357
|
-
*/
|
|
358
|
-
function rawByteIsLast(b: number): boolean {
|
|
359
|
-
return (b & 0b10000000) == 0
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
/**
|
|
363
|
-
* @param bitWriter
|
|
364
|
-
* @param x
|
|
365
|
-
* positive number
|
|
366
|
-
*/
|
|
367
|
-
export function encodeInt(bitWriter: Bits.Writer, x: bigint) {
|
|
368
|
-
const bitString = Bits.pad(x.toString(2), 7)
|
|
369
|
-
|
|
370
|
-
// split every 7th
|
|
371
|
-
const parts = []
|
|
372
|
-
for (let i = 0; i < bitString.length; i += 7) {
|
|
373
|
-
parts.push(bitString.slice(i, i + 7))
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
// reverse the parts
|
|
377
|
-
parts.reverse()
|
|
378
|
-
|
|
379
|
-
for (let i = 0; i < parts.length; i++) {
|
|
380
|
-
if (i == parts.length - 1) {
|
|
381
|
-
// last
|
|
382
|
-
bitWriter.writeBits("0" + parts[i])
|
|
383
|
-
} else {
|
|
384
|
-
bitWriter.writeBits("1" + parts[i])
|
|
385
|
-
}
|
|
386
|
-
}
|
|
387
|
-
}
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from "bun:test"
|
|
2
|
-
import { Either } from "effect"
|
|
3
|
-
import { toHex } from "./Bytes.js"
|
|
4
|
-
import * as Float from "./Float.js"
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Taken from https://en.wikipedia.org/wiki/Half-precision_floating-point_format
|
|
8
|
-
* [encoded, original number]
|
|
9
|
-
*/
|
|
10
|
-
const testVector: [number[], number][] = [
|
|
11
|
-
[[0, 0], 0],
|
|
12
|
-
[[0, 1], 0.000000059604645],
|
|
13
|
-
[[0x03, 0xff], 0.000060975552],
|
|
14
|
-
[[4, 0], 0.00006103515625],
|
|
15
|
-
[[0x35, 0x55], 0.33325195],
|
|
16
|
-
[[0x3b, 0xff], 0.99951172],
|
|
17
|
-
[[0x3c, 0x00], 1],
|
|
18
|
-
[[0x3c, 0x01], 1.00097656],
|
|
19
|
-
[[0x7b, 0xff], 65504],
|
|
20
|
-
[[0x7c, 0x00], Number.POSITIVE_INFINITY],
|
|
21
|
-
[[0x7c, 0x01], Number.NaN],
|
|
22
|
-
[[0x80, 0x00], -0],
|
|
23
|
-
[[0xc0, 0x00], -2],
|
|
24
|
-
[[0xfc, 0x00], Number.NEGATIVE_INFINITY]
|
|
25
|
-
]
|
|
26
|
-
|
|
27
|
-
describe("Float.decodeFloat16()", () => {
|
|
28
|
-
testVector.forEach(([bytes, f]) => {
|
|
29
|
-
it(`decodes #${toHex(bytes)} as ${f}`, () => {
|
|
30
|
-
expect(
|
|
31
|
-
Either.map(Float.decodeFloat16(bytes), (x) => x.toExponential(7))
|
|
32
|
-
).toEqual(Either.right(f.toExponential(7)))
|
|
33
|
-
})
|
|
34
|
-
})
|
|
35
|
-
|
|
36
|
-
it("fails for more than 2 input bytes", () => {
|
|
37
|
-
expect(Float.decodeFloat16([0, 0, 0])._tag).toBe("Left")
|
|
38
|
-
})
|
|
39
|
-
|
|
40
|
-
it("fails for less than 2 input bytes", () => {
|
|
41
|
-
expect(Float.decodeFloat16([0])._tag).toBe("Left")
|
|
42
|
-
})
|
|
43
|
-
})
|
|
44
|
-
|
|
45
|
-
describe("Float.encodeFloat16()", () => {
|
|
46
|
-
testVector.forEach(([bytes, f]) => {
|
|
47
|
-
it(`encodes ${f} as #${toHex(bytes)}`, () => {
|
|
48
|
-
expect(Float.encodeFloat16(f)).toEqual(bytes)
|
|
49
|
-
})
|
|
50
|
-
})
|
|
51
|
-
})
|
package/src/internal/Float.ts
DELETED
|
@@ -1,190 +0,0 @@
|
|
|
1
|
-
import { Encoding, Either } from "effect"
|
|
2
|
-
import { toHex } from "./Bytes.js"
|
|
3
|
-
|
|
4
|
-
const SPECIAL_EXPONENT = 31
|
|
5
|
-
const LARGEST_SIGNIFICAND = 1024
|
|
6
|
-
const POW2 = [
|
|
7
|
-
0.00006103515625, // 2^-14
|
|
8
|
-
0.0001220703125, // 2^-13
|
|
9
|
-
0.000244140625, // 2^-12
|
|
10
|
-
0.00048828125, // 2^-11
|
|
11
|
-
0.0009765625, // 2^-10
|
|
12
|
-
0.001953125, // 2^-9
|
|
13
|
-
0.00390625, // 2^-8
|
|
14
|
-
0.0078125, // 2^-7
|
|
15
|
-
0.015625, // 2^-6
|
|
16
|
-
0.03125, // 2^-5
|
|
17
|
-
0.0625, // 2^-4
|
|
18
|
-
0.125, // 2^-3
|
|
19
|
-
0.25, // 2^-2
|
|
20
|
-
0.5, // 2^-1
|
|
21
|
-
1, // 2^0
|
|
22
|
-
2, // 2^1
|
|
23
|
-
4, // 2^2
|
|
24
|
-
8, // 2^3
|
|
25
|
-
16, // 2^4
|
|
26
|
-
32, // 2^5
|
|
27
|
-
64, // 2^6
|
|
28
|
-
128, // 2^7
|
|
29
|
-
256, // 2^8
|
|
30
|
-
512, // 2^9
|
|
31
|
-
1024, // 2^10
|
|
32
|
-
2048, // 2^11
|
|
33
|
-
4096, // 2^12
|
|
34
|
-
8192, // 2^13
|
|
35
|
-
16384, // 2^14
|
|
36
|
-
32768, // 2^15
|
|
37
|
-
65536 // 2^16
|
|
38
|
-
]
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Custom IEEE 754 Float16 implementation, not fast, but easy to audit
|
|
42
|
-
* @param {number[]} bytes
|
|
43
|
-
* @returns {number}
|
|
44
|
-
*/
|
|
45
|
-
export function decodeFloat16(
|
|
46
|
-
bytes: number[]
|
|
47
|
-
): Either.Either<number, Encoding.DecodeException> {
|
|
48
|
-
if (bytes.length != 2) {
|
|
49
|
-
return Either.left(
|
|
50
|
-
Encoding.DecodeException(
|
|
51
|
-
toHex(bytes),
|
|
52
|
-
`expected 2 bytes for IEEE 754 encoded Float16 number, got ${bytes.length}`
|
|
53
|
-
)
|
|
54
|
-
)
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
const sign = bytes[0] >> 7 ? -1 : 1
|
|
58
|
-
const exponent = (bytes[0] & 0b01111100) >> 2
|
|
59
|
-
const significand = (bytes[0] & 0b00000011) * 256 + bytes[1]
|
|
60
|
-
|
|
61
|
-
if (exponent === 0) {
|
|
62
|
-
if (significand == 0) {
|
|
63
|
-
return Either.right(sign < 0 ? -0 : 0)
|
|
64
|
-
} else {
|
|
65
|
-
return Either.right((sign * POW2[0] * significand) / LARGEST_SIGNIFICAND)
|
|
66
|
-
}
|
|
67
|
-
} else if (exponent === SPECIAL_EXPONENT) {
|
|
68
|
-
if (significand == 0) {
|
|
69
|
-
return Either.right(
|
|
70
|
-
sign < 0 ? Number.NEGATIVE_INFINITY : Number.POSITIVE_INFINITY
|
|
71
|
-
)
|
|
72
|
-
} else {
|
|
73
|
-
return Either.right(Number.NaN)
|
|
74
|
-
}
|
|
75
|
-
} else {
|
|
76
|
-
return Either.right(
|
|
77
|
-
sign * POW2[exponent - 1] * (1.0 + significand / LARGEST_SIGNIFICAND)
|
|
78
|
-
)
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* Custom IEEE 754 Float16 implementation, not fast, but easy to audit
|
|
84
|
-
* @param f
|
|
85
|
-
* @returns
|
|
86
|
-
*/
|
|
87
|
-
export function encodeFloat16(f: number): number[] {
|
|
88
|
-
if (Object.is(f, 0)) {
|
|
89
|
-
return [0, 0]
|
|
90
|
-
} else if (Object.is(f, -0)) {
|
|
91
|
-
return [0x80, 0]
|
|
92
|
-
} else if (f === Number.NEGATIVE_INFINITY) {
|
|
93
|
-
return [0xfc, 0]
|
|
94
|
-
} else if (f === Number.POSITIVE_INFINITY) {
|
|
95
|
-
return [0x7c, 0]
|
|
96
|
-
} else if (Number.isNaN(f)) {
|
|
97
|
-
return [0x7c, 1]
|
|
98
|
-
} else {
|
|
99
|
-
const sign = Math.sign(f)
|
|
100
|
-
const signBit = sign > 0 ? 0 : 0b10000000
|
|
101
|
-
f = Math.abs(f)
|
|
102
|
-
|
|
103
|
-
if (f < POW2[0]) {
|
|
104
|
-
const significand = Math.floor((f / POW2[0]) * LARGEST_SIGNIFICAND)
|
|
105
|
-
|
|
106
|
-
return [signBit | (significand >> 8), significand & 0xff]
|
|
107
|
-
} else {
|
|
108
|
-
const unbiasedExponent = Math.floor(Math.log2(f))
|
|
109
|
-
const exponent = (unbiasedExponent + 15) & 0b00011111
|
|
110
|
-
|
|
111
|
-
const significand = Math.round(
|
|
112
|
-
(f / POW2[exponent - 1] - 1) * LARGEST_SIGNIFICAND
|
|
113
|
-
)
|
|
114
|
-
|
|
115
|
-
return [
|
|
116
|
-
signBit | (exponent << 2) | (significand >> 8),
|
|
117
|
-
significand & 0xff
|
|
118
|
-
]
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* Leverages the builtin DataView class to decode a IEEE 754 float32 number
|
|
125
|
-
* @param {number[]} bytes
|
|
126
|
-
* @returns
|
|
127
|
-
*/
|
|
128
|
-
export function decodeFloat32(
|
|
129
|
-
bytes: number[]
|
|
130
|
-
): Either.Either<number, Encoding.DecodeException> {
|
|
131
|
-
if (bytes.length != 4) {
|
|
132
|
-
return Either.left(
|
|
133
|
-
Encoding.DecodeException(
|
|
134
|
-
toHex(bytes),
|
|
135
|
-
`expected 4 bytes for IEEE 754 encoded Float32, got ${bytes.length} bytes`
|
|
136
|
-
)
|
|
137
|
-
)
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
const view = new DataView(Uint8Array.from(bytes).buffer)
|
|
141
|
-
|
|
142
|
-
return Either.right(view.getFloat32(0))
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
/**
|
|
146
|
-
* Leverages the builtin DataView class to encode a floating point number using IEEE 754 float32 encoding
|
|
147
|
-
* @param f
|
|
148
|
-
* @returns
|
|
149
|
-
*/
|
|
150
|
-
export function encodeFloat32(f: number): number[] {
|
|
151
|
-
const view = new DataView(new ArrayBuffer(4))
|
|
152
|
-
|
|
153
|
-
view.setFloat32(0, f)
|
|
154
|
-
|
|
155
|
-
return Array.from(new Uint8Array(view.buffer))
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
/**
|
|
159
|
-
* Leverages the builtin DataView class to decode a IEEE 754 float64 number
|
|
160
|
-
* @param bytes
|
|
161
|
-
* @returns
|
|
162
|
-
*/
|
|
163
|
-
export function decodeFloat64(
|
|
164
|
-
bytes: number[]
|
|
165
|
-
): Either.Either<number, Encoding.DecodeException> {
|
|
166
|
-
if (bytes.length != 8) {
|
|
167
|
-
return Either.left(
|
|
168
|
-
Encoding.DecodeException(
|
|
169
|
-
`expected 8 bytes for IEEE 754 encoded Float64, got ${bytes.length} bytes`
|
|
170
|
-
)
|
|
171
|
-
)
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
const view = new DataView(Uint8Array.from(bytes).buffer)
|
|
175
|
-
|
|
176
|
-
return Either.right(view.getFloat64(0))
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
/**
|
|
180
|
-
* Leverages the builtin DataView class to encode a floating point number using IEEE 754 float64 encoding
|
|
181
|
-
* @param f
|
|
182
|
-
* @returns
|
|
183
|
-
*/
|
|
184
|
-
export function encodeFloat64(f: number): number[] {
|
|
185
|
-
const view = new DataView(new ArrayBuffer(8))
|
|
186
|
-
|
|
187
|
-
view.setFloat64(0, f)
|
|
188
|
-
|
|
189
|
-
return Array.from(new Uint8Array(view.buffer))
|
|
190
|
-
}
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from "bun:test"
|
|
2
|
-
import { Effect } from "effect"
|
|
3
|
-
import * as Utf8 from "./Utf8.js"
|
|
4
|
-
|
|
5
|
-
describe("Utf8.isValid", () => {
|
|
6
|
-
it("returns true for []", () => {
|
|
7
|
-
expect(Utf8.isValid([])).toBe(true)
|
|
8
|
-
})
|
|
9
|
-
|
|
10
|
-
it("returns true for [104, 101, 108, ...]", () => {
|
|
11
|
-
expect(
|
|
12
|
-
Utf8.isValid([104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100])
|
|
13
|
-
).toBe(true)
|
|
14
|
-
})
|
|
15
|
-
|
|
16
|
-
it("returns false for [256] (invalid byte)", () => {
|
|
17
|
-
expect(Utf8.isValid([256])).toBe(false)
|
|
18
|
-
})
|
|
19
|
-
|
|
20
|
-
it("returns false for [255, 255, 255, 255] (invalid utf-8 sequence)", () => {
|
|
21
|
-
expect(Utf8.isValid([255, 255, 255, 255])).toBe(false)
|
|
22
|
-
})
|
|
23
|
-
|
|
24
|
-
it("returns true for [0xf0, 0xb1, 0x8d, 0x90]", () => {
|
|
25
|
-
expect(Utf8.isValid([0xf0, 0xb1, 0x8d, 0x90])).toBe(true)
|
|
26
|
-
})
|
|
27
|
-
})
|
|
28
|
-
|
|
29
|
-
describe("Utf8.encode", () => {
|
|
30
|
-
it("returns [] for an empty string", () => {
|
|
31
|
-
expect(Array.from(Utf8.encode(""))).toEqual([])
|
|
32
|
-
})
|
|
33
|
-
|
|
34
|
-
it('returns [104, 101, 108, ...] for "hello world"', () => {
|
|
35
|
-
expect(Array.from(Utf8.encode("hello world"))).toEqual([
|
|
36
|
-
104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100
|
|
37
|
-
])
|
|
38
|
-
})
|
|
39
|
-
|
|
40
|
-
it('returns [0xf0, 0xb1, 0x8d, 0x90] for "\ud884\udf50"', () => {
|
|
41
|
-
expect(Array.from(Utf8.encode("\ud884\udf50"))).toEqual([
|
|
42
|
-
0xf0, 0xb1, 0x8d, 0x90
|
|
43
|
-
])
|
|
44
|
-
})
|
|
45
|
-
})
|
|
46
|
-
|
|
47
|
-
describe("Utf8.decode", () => {
|
|
48
|
-
it("returns an empty string for []", () => {
|
|
49
|
-
expect(Effect.runSync(Utf8.decode([]))).toBe("")
|
|
50
|
-
})
|
|
51
|
-
|
|
52
|
-
it('returns "hello world" for [104, 101, 108, ...]', () => {
|
|
53
|
-
expect(
|
|
54
|
-
Effect.runSync(
|
|
55
|
-
Utf8.decode([104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100])
|
|
56
|
-
)
|
|
57
|
-
).toBe("hello world")
|
|
58
|
-
})
|
|
59
|
-
|
|
60
|
-
it('returns "\ud884\udf50" for [0xf0, 0xb1, 0x8d, 0x90]', () => {
|
|
61
|
-
expect(Effect.runSync(Utf8.decode([0xf0, 0xb1, 0x8d, 0x90]))).toBe(
|
|
62
|
-
"\ud884\udf50"
|
|
63
|
-
)
|
|
64
|
-
})
|
|
65
|
-
|
|
66
|
-
it("fails for [255, 255, 255, 255] (invalid utf-8 sequence)", () => {
|
|
67
|
-
expect(() => Effect.runSync(Utf8.decode([255, 255, 255, 255]))).toThrow()
|
|
68
|
-
})
|
|
69
|
-
})
|