-
Notifications
You must be signed in to change notification settings - Fork 0
/
binary_primitive_steps.ts
149 lines (128 loc) · 5.72 KB
/
binary_primitive_steps.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
import { NumericArrayType, NumericType, decode_bytes, decode_cstr, decode_number, decode_number_array, decode_str, encode_bytes, encode_cstr, encode_number, encode_number_array, encode_str } from "./deps.ts"
import { BinaryInput, BinaryLengthedDataPureStep, BinaryOutput, BinaryPureStep, LengthedArgs, PureStep, SubtractSubset } from "./typedefs.ts"
export class BinaryCStringStep extends BinaryPureStep<string, never> {
forward(input: BinaryInput<never>): BinaryOutput<string> {
const
{ bin, pos } = input,
[str, bytelength] = decode_cstr(bin, pos)
return { val: str, len: bytelength }
}
backward(input: Omit<BinaryOutput<string>, "len">): BinaryInput<never> {
const bin = encode_cstr(input.val)
return { bin, pos: 0 } as any
}
}
export class BinaryNumberStep<ENCODING extends NumericType> extends BinaryPureStep<number, never> {
// TODO: later on, add support for the variable sized numeric types `"iv"` and `"uv"`
protected readonly kind: ENCODING
constructor(kind: ENCODING) {
super()
this.kind = kind
}
forward(input: BinaryInput<never>): BinaryOutput<number> {
const
{ bin, pos } = input,
[num, bytelength] = decode_number(bin, pos, this.kind)
return { val: num, len: bytelength }
}
backward(input: Omit<BinaryOutput<number>, "len">): BinaryInput<never> {
const bin = encode_number(input.val, this.kind)
return { bin, pos: 0 } as any
}
}
export class BinaryStringStep extends BinaryPureStep<string, LengthedArgs> implements BinaryLengthedDataPureStep {
forward(input: BinaryInput<LengthedArgs>): BinaryOutput<string> {
const
{ bin, pos, args: { length: str_length } } = input,
[str, bytelength] = decode_str(bin, pos, str_length >= 0 ? str_length : undefined)
return { val: str, len: bytelength }
}
backward(input: Omit<BinaryOutput<string>, "len">): BinaryInput<LengthedArgs> {
const
bin = encode_str(input.val),
str_length = bin.length
return { bin, pos: 0, args: { length: str_length } }
}
}
export class BinaryNumberArrayStep<ENCODING extends NumericType> extends BinaryPureStep<number[], LengthedArgs> implements BinaryLengthedDataPureStep {
// TODO: later on, add support for the variable sized numeric types `"iv"` and `"uv"`
protected readonly kind: ENCODING
constructor(kind: ENCODING) {
super()
this.kind = kind
}
forward(input: BinaryInput<LengthedArgs>): BinaryOutput<number[]> {
const
{ bin, pos, args: { length } } = input,
[arr, bytelength] = decode_number_array(bin, pos, this.kind + "[]" as NumericArrayType, length >= 0 ? length : undefined)
return { val: arr, len: bytelength }
}
backward(input: Omit<BinaryOutput<number[]>, "len">): BinaryInput<LengthedArgs> {
const
val = input.val,
arr_len = val.length,
bin = encode_number_array(val, this.kind + "[]" as NumericArrayType)
return { bin, pos: 0, args: { length: arr_len } }
}
}
export class BinaryBytesStep extends BinaryPureStep<Uint8Array, LengthedArgs> implements BinaryLengthedDataPureStep {
forward(input: BinaryInput<LengthedArgs>): BinaryOutput<Uint8Array> {
const
{ bin, pos, args: { length: bytes_length } } = input,
[bytes, bytelength] = decode_bytes(bin, pos, bytes_length >= 0 ? bytes_length : undefined)
return { val: bytes, len: bytelength }
}
backward(input: Omit<BinaryOutput<Uint8Array>, "len">): BinaryInput<LengthedArgs> {
const
bin = encode_bytes(input.val),
length = bin.length
return { bin, pos: 0, args: { length } }
}
}
export class BinaryDefaultArgs<
STEP extends BinaryPureStep<any>,
OUT extends (STEP extends BinaryPureStep<infer T> ? T : unknown) = (STEP extends BinaryPureStep<infer T> ? T : unknown),
ARGS extends (STEP extends BinaryPureStep<OUT, infer T> ? T : unknown) = (STEP extends BinaryPureStep<OUT, infer T> ? T : unknown),
DEFAULT_ARGS extends Partial<ARGS> = Partial<ARGS>,
REQUIRED_ARGS extends SubtractSubset<DEFAULT_ARGS, ARGS> = SubtractSubset<DEFAULT_ARGS, ARGS>
> extends BinaryPureStep<OUT, ARGS> {
protected readonly step: STEP
protected readonly args: DEFAULT_ARGS
protected readonly priority: -1 | 1
constructor(step: STEP, default_args: DEFAULT_ARGS, priority: -1 | 1 = 1) {
super()
this.step = step
this.args = default_args
this.priority = priority
}
forward(input: BinaryInput<REQUIRED_ARGS & Partial<DEFAULT_ARGS>>): BinaryOutput<OUT> {
const
{ bin, pos, args = {} as REQUIRED_ARGS } = input,
step = this.step,
default_args = this.args,
priority = this.priority,
overridden_args = priority > 0 ? { ...args, ...default_args } : { ...default_args, ...args }
return step.forward({ bin, pos, args: overridden_args })
}
backward(input: Omit<BinaryOutput<OUT>, "len">): BinaryInput<ARGS> {
return this.step.backward(input)
}
}
export class BinaryOutputUnwrapStep<T> extends PureStep<Omit<BinaryOutput<T>, "len">, T> {
forward(input: BinaryOutput<T>): T { return input.val }
backward(input: T): Omit<BinaryOutput<T>, "len"> { return { val: input } }
}
// TODO: add a warning about forward method's `output.len === undefined`, as it might ruin accumulated
// size computation, and will be hard to debug and come across this as being the culprit
export class BinaryOutputWrapStep<T> extends PureStep<T, BinaryOutput<T>> {
forward(input: T): BinaryOutput<T> { return { val: input, len: undefined as any } }
backward(input: BinaryOutput<T>): T { return input.val }
}
export class BinaryInputUnwrapStep extends PureStep<BinaryInput, Uint8Array> {
forward(input: BinaryInput): Uint8Array { return input.bin }
backward(input: Uint8Array): BinaryInput { return { bin: input, pos: 0, args: undefined } }
}
export class BinaryInputWrapStep extends PureStep<Uint8Array, BinaryInput> {
forward(input: Uint8Array): BinaryInput { return { bin: input, pos: 0, args: undefined } }
backward(input: BinaryInput): Uint8Array { return input.bin }
}