1 import Base 2 import ./bytes.bend as B 3 4 type HexCase is Data: 5 HexLower{} 6 HexUpper{} 7 8 type Hex.Error is Data: 9 InvalidChar{offset: Nat, char: Char} 10 OddLength{offset: Nat} 11 InvalidByte{index: Nat, value: U32} 12 13 type Hex.Pend is Data: 14 PendNone{} 15 PendHi{hi: U32} 16 17 def Hex.from_bytes_err(e: B.Bytes.Error) -> Hex.Error: 18 match e: 19 case B.InvalidByte{index, value}: 20 InvalidByte{index, value} 21 22 def 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 29 def Hex.lo_digit(+n: U32) -> Char: 30 Hex.lo_digit_if(n, U32.is_lt(n, 10)) 31 32 def 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 39 def Hex.up_digit(+n: U32) -> Char: 40 Hex.up_digit_if(n, U32.is_lt(n, 10)) 41 42 def 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 49 def 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 54 def 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 61 def Hex.encode(bytes: B.Bytes, casing: HexCase) -> String: 62 match bytes: 63 case B.Bytes{data}: 64 Hex.encode.go(data, SNil{}, casing) 65 66 def 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 73 def 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 80 def 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 87 def 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 94 def 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 101 def 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 108 def Hex.nibble.u(+x: U32) -> Maybe<&2, U32>: 109 Hex.nibble.d09(x, U32.is_ge(x, Char.to_u32('0'))) 110 111 def Hex.nibble(c: Char) -> Maybe<&2, U32>: 112 Hex.nibble.u(Char.to_u32(c)) 113 114 def 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 137 def 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 146 def Hex.decode(text: String) -> Result<&2, &2, Hex.Error, B.Bytes>: 147 Hex.decode.start(text) 148 149 def 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 158 def 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 163 def 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 172 def 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))