hex.bend
bend-encoding@0.2.0.0 · 175 lines · 0 definitions
1import Base
2import bend-encoding@0.2.0.0/bytes.bend as B
3
4type HexCase is Data:
5 HexLower{}
6 HexUpper{}
7
8type Hex.Error is Data:
9 InvalidChar{offset: Nat, char: Char}
10 OddLength{offset: Nat}
11 InvalidByte{index: Nat, value: U32}
12
13type Hex.Pend is Data:
14 PendNone{}
15 PendHi{hi: U32}
16
17def Hex.from_bytes_err(e: B.Bytes.Error) -> Hex.Error:
18 match e:
19 case B.InvalidByte{index, value}:
20 InvalidByte{index, value}
21
22def Hex.lo_digit_if(+n: U32, is_num: Bool) -> Char:
23 match is_num:
24 case True{}:
25 Char.from_u32((Char.to_u32('0') + n : U32))
26 case False{}:
27 Char.from_u32((Char.to_u32('a') + (n - 10 : U32) : U32))
28
29def Hex.lo_digit(+n: U32) -> Char:
30 Hex.lo_digit_if(n, U32.is_lt(n, 10))
31
32def Hex.up_digit_if(+n: U32, is_num: Bool) -> Char:
33 match is_num:
34 case True{}:
35 Char.from_u32((Char.to_u32('0') + n : U32))
36 case False{}:
37 Char.from_u32((Char.to_u32('A') + (n - 10 : U32) : U32))
38
39def Hex.up_digit(+n: U32) -> Char:
40 Hex.up_digit_if(n, U32.is_lt(n, 10))
41
42def Hex.digit(+n: U32, c: HexCase) -> Char:
43 match c:
44 case HexLower{}:
45 Hex.lo_digit(n)
46 case HexUpper{}:
47 Hex.up_digit(n)
48
49def Hex.encode.byte(+b: U32, acc: String, +casing: HexCase) -> String:
50 hi = U32.shrn(b, 4n)
51 lo = U32.and(b, 15)
52 SCon{Hex.digit(lo, casing), SCon{Hex.digit(hi, casing), acc}}
53
54def Hex.encode.go(xs: List<&2, U32>, acc: String, +casing: HexCase) -> String:
55 match xs:
56 case Nil{}:
57 String.reverse(acc)
58 case Con{+h, t}:
59 Hex.encode.go(t, Hex.encode.byte(h, acc, casing), casing)
60
61def Hex.encode(bytes: B.Bytes, casing: HexCase) -> String:
62 match bytes:
63 case B.Bytes{data}:
64 Hex.encode.go(data, SNil{}, casing)
65
66def Hex.nibble.af2(+x: U32, le: Bool) -> Maybe<&2, U32>:
67 match le:
68 case True{}:
69 Some{(x - Char.to_u32('7') : U32)}
70 case False{}:
71 None{}
72
73def Hex.nibble.af(+x: U32, ge: Bool) -> Maybe<&2, U32>:
74 match ge:
75 case False{}:
76 None{}
77 case True{}:
78 Hex.nibble.af2(x, U32.is_le(x, Char.to_u32('F')))
79
80def Hex.nibble.az2(+x: U32, le: Bool) -> Maybe<&2, U32>:
81 match le:
82 case True{}:
83 Some{(x - Char.to_u32('W') : U32)}
84 case False{}:
85 Hex.nibble.af(x, U32.is_ge(x, Char.to_u32('A')))
86
87def Hex.nibble.az(+x: U32, ge: Bool) -> Maybe<&2, U32>:
88 match ge:
89 case False{}:
90 Hex.nibble.af(x, U32.is_ge(x, Char.to_u32('A')))
91 case True{}:
92 Hex.nibble.az2(x, U32.is_le(x, Char.to_u32('f')))
93
94def Hex.nibble.d092(+x: U32, le: Bool) -> Maybe<&2, U32>:
95 match le:
96 case True{}:
97 Some{(x - Char.to_u32('0') : U32)}
98 case False{}:
99 Hex.nibble.az(x, U32.is_ge(x, Char.to_u32('a')))
100
101def Hex.nibble.d09(+x: U32, ge: Bool) -> Maybe<&2, U32>:
102 match ge:
103 case False{}:
104 Hex.nibble.az(x, U32.is_ge(x, Char.to_u32('a')))
105 case True{}:
106 Hex.nibble.d092(x, U32.is_le(x, Char.to_u32('9')))
107
108def Hex.nibble.u(+x: U32) -> Maybe<&2, U32>:
109 Hex.nibble.d09(x, U32.is_ge(x, Char.to_u32('0')))
110
111def Hex.nibble(c: Char) -> Maybe<&2, U32>:
112 Hex.nibble.u(Char.to_u32(c))
113
114def Hex.decode.go(
115 s: String, n: Maybe<&2, U32>, +h: Char, pend: Hex.Pend, acc: List<&2, U32>,
116 off: Nat
117) -> Result<&2, &2, Hex.Error, B.Bytes>:
118 match s n pend:
119 case _ None{} _:
120 Fail{InvalidChar{off, h}}
121 case SNil{} Some{_} PendNone{}:
122 Fail{OddLength{1n+off}}
123 case SNil{} Some{v} PendHi{hi}:
124 Done{
125 B.Bytes{
126 List.reverse(&2, U32, Con{U32.or(U32.shln(hi, 4n), v), acc})
127 }
128 }
129 case SCon{+h2, t} Some{v} PendNone{}:
130 Hex.decode.go(t, Hex.nibble(h2), h2, PendHi{v}, acc, 1n+off)
131 case SCon{+h2, t} Some{v} PendHi{hi}:
132 Hex.decode.go(
133 t, Hex.nibble(h2), h2, PendNone{},
134 Con{U32.or(U32.shln(hi, 4n), v), acc}, 1n+off
135 )
136
137def Hex.decode.start(
138 s: String
139) -> Result<&2, &2, Hex.Error, B.Bytes>:
140 match s:
141 case SNil{}:
142 Done{B.Bytes{Nil{}}}
143 case SCon{+h, t}:
144 Hex.decode.go(t, Hex.nibble(h), h, PendNone{}, Nil{}, 0n)
145
146def Hex.decode(text: String) -> Result<&2, &2, Hex.Error, B.Bytes>:
147 Hex.decode.start(text)
148
149def Hex.encode_u32_list.from(
150 r: Result<&2, &2, B.Bytes.Error, B.Bytes>, +casing: HexCase
151) -> Result<&2, &2, Hex.Error, String>:
152 match r:
153 case Fail{e}:
154 Fail{Hex.from_bytes_err(e)}
155 case Done{b}:
156 Done{Hex.encode(b, casing)}
157
158def Hex.encode_u32_list(
159 values: List<&2, U32>, casing: HexCase
160) -> Result<&2, &2, Hex.Error, String>:
161 Hex.encode_u32_list.from(B.Bytes.from_u32_list(values), casing)
162
163def Hex.decode_u32_list.from(
164 r: Result<&2, &2, Hex.Error, B.Bytes>
165) -> Result<&2, &2, Hex.Error, List<&2, U32>>:
166 match r:
167 case Fail{e}:
168 Fail{e}
169 case Done{b}:
170 Done{B.Bytes.to_u32_list(b)}
171
172def Hex.decode_u32_list(
173 text: String
174) -> Result<&2, &2, Hex.Error, List<&2, U32>>:
175 Hex.decode_u32_list.from(Hex.decode(text))