src/base64.bend
bend-kube-runtime@0.2.0.0 · 125 lines · 13 definitions
1import Base
2
3
4
5
6
7
8
9
10type B64 is Data:
11 B64{acc: U32, bits: U32, ok: Bool}
12
13def B64.val.go(+x: U32, up: Bool, low: Bool, dig: Bool) -> U32:
14 match up low dig:
15 case True{} _ _:
16 (x - 65 : U32)
17 case False{} True{} _:
18 (x - 71 : U32)
19 case False{} False{} True{}:
20 (x + 4 : U32)
21 case _ _ _:
22 65
23
24
25def B64.val(+c: Char) -> U32:
26 match c:
27 case '+':
28 62
29 case '/':
30 63
31 case '=':
32 64
33 case ' ':
34 64
35 case '\n':
36 64
37 case '\r':
38 64
39 case '\t':
40 64
41 case Chr{+x}:
42 B64.val.go(x, Char.is_upper(Chr{x}), Char.is_lower(Chr{x}), Char.is_digit(Chr{x}))
43
44def B64.next.go(+acc: U32, +bits: U32, ok: Bool, +v: U32, skip: Bool, bad: Bool, full: Bool) ->
45 B64:
46 match skip bad full:
47 case True{} _ _:
48 B64{acc, bits, ok}
49 case False{} True{} _:
50 B64{acc, bits, False{}}
51 case False{} False{} True{}:
52
53 B64{(((acc << 6n) .|. v) .&. ((1 << U32.to_nat((bits - 2 : U32))) - 1) : U32),
54 (bits - 2 : U32), ok}
55 case False{} False{} False{}:
56 B64{((acc << 6n) .|. v : U32), (bits + 6 : U32), ok}
57
58
59def B64.next(st: B64, +v: U32) -> B64:
60 match st:
61 case B64{+acc, +bits, ok}:
62 B64.next.go(acc, bits, ok, v, U32.is_eq(v, 64), U32.is_eq(v, 65), U32.is_ge(bits, 2))
63
64def B64.emit.go(+acc: U32, +bits: U32, +v: U32, out: List<&2, U32>, skip: Bool, full: Bool) ->
65 List<&2, U32>:
66 match skip full:
67 case False{} True{}:
68 ((((acc << 6n) .|. v) >> U32.to_nat((bits - 2 : U32))) .&. 255 : U32) <> out
69 case _ _:
70 out
71
72
73def B64.emit(st: B64, +v: U32, out: List<&2, U32>) -> List<&2, U32>:
74 match st:
75 case B64{+acc, +bits, ok}:
76 B64.emit.go(acc, bits, v, out, U32.is_ge(v, 64), U32.is_ge(bits, 2))
77
78def B64.go(s: String, +st: B64, out: List<&2, U32>) -> B64 & List<&2, U32>:
79 match s:
80 case SNil{}:
81 (st, out)
82 case SCon{+c, t}:
83 B64.go(t, B64.next(st, B64.val(c)), B64.emit(st, B64.val(c), out))
84
85def B64.decode.fin(r: B64 & List<&2, U32>) -> Maybe<&2, List<&2, U32>>:
86 match r:
87 case (B64{acc, bits, True{}}, out):
88 Some{List.reverse(&2, U32, out)}
89 case _:
90 None{}
91
92
93def B64.decode(s: String) -> Maybe<&2, List<&2, U32>>:
94 B64.decode.fin(B64.go(s, B64{0, 0, True{}}, Nil{}))
95
96def B64.chr.go(+v: U32, up: Bool, low: Bool, dig: Bool, plus: Bool) -> Char:
97 match up low dig plus:
98 case True{} _ _ _:
99 Chr{(v + 65 : U32)}
100 case False{} True{} _ _:
101 Chr{(v + 71 : U32)}
102 case False{} False{} True{} _:
103 Chr{(v - 4 : U32)}
104 case False{} False{} False{} True{}:
105 '+'
106 case _ _ _ _:
107 '/'
108
109def B64.chr(+v: U32) -> Char:
110 B64.chr.go(v, U32.is_lt(v, 26), U32.is_lt(v, 52), U32.is_lt(v, 62), U32.is_eq(v, 62))
111
112
113def B64.encode(bs: List<&2, U32>) -> String:
114 match bs:
115 case Nil{}:
116 ""
117 case Con{+a, Nil{}}:
118 SCon{B64.chr((a >> 2n : U32)), SCon{B64.chr(((a .&. 3) << 4n : U32)), "=="}}
119 case Con{+a, Con{+b, Nil{}}}:
120 SCon{B64.chr((a >> 2n : U32)), SCon{B64.chr((((a .&. 3) << 4n) .|. (b >> 4n) : U32)),
121 SCon{B64.chr(((b .&. 15) << 2n : U32)), "="}}}
122 case Con{+a, Con{+b, Con{+c, t}}}:
123 SCon{B64.chr((a >> 2n : U32)), SCon{B64.chr((((a .&. 3) << 4n) .|. (b >> 4n) : U32)),
124 SCon{B64.chr((((b .&. 15) << 2n) .|. (c >> 6n) : U32)), SCon{B64.chr((c .&. 63 : U32)),
125 B64.encode(t)}}}}