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))