Source file Bare_encoding.ml
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
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
module String_map = Map.Make(String)
let spf = Printf.sprintf
module Decode = struct
exception Error of string
type t = {
bs: bytes;
mutable off: int;
}
type 'a dec = t -> 'a
let fail_ e = raise (Error e)
let fail_eof_ what =
fail_ (spf "unexpected end of input, expected %s" what)
let uint (self:t) : int64 =
let rec loop () =
if self.off >= Bytes.length self.bs then fail_eof_ "uint";
let c = Char.code (Bytes.get self.bs self.off) in
self.off <- 1 + self.off;
if c land 0b1000_0000 <> 0 then (
let rest = loop() in
let c = Int64.of_int (c land 0b0111_1111) in
Int64.(logor (shift_left rest 7) c)
) else (
Int64.of_int c
)
in
loop()
let int (self:t) : int64 =
let open Int64 in
let i = uint self in
let sign_bit = logand 0b1L i in
let sign = equal sign_bit 0L in
let res =
if sign then (
shift_right_logical i 1
) else (
logor (shift_left 1L 63) (shift_right_logical (lognot i) 1)
)
in
res
let u8 self : char =
let x = Bytes.get self.bs self.off in
self.off <- self.off + 1;
x
let i8 = u8
let u16 self =
let x = Bytes.get_int16_le self.bs self.off in
self.off <- self.off + 2;
x
let i16 = u16
let u32 self =
let x = Bytes.get_int32_le self.bs self.off in
self.off <- self.off + 4;
x
let i32 = u32
let u64 self =
let i = Bytes.get_int64_le self.bs self.off in
self.off <- 8 + self.off;
i
let i64 = u64
let bool self : bool =
let c = Bytes.get self.bs self.off in
self.off <- 1 + self.off;
Char.code c <> 0
let f32 (self:t) : float =
let i = i32 self in
Int32.float_of_bits i
let f64 (self:t) : float =
let i = i64 self in
Int64.float_of_bits i
let data_of ~size self : bytes =
let s = Bytes.sub self.bs self.off size in
self.off <- self.off + size;
s
let data self : bytes =
let size = uint self in
if Int64.compare size (Int64.of_int Sys.max_string_length) > 0 then
fail_ "string too large";
let size = Int64.to_int size in
data_of ~size self
let string self : string =
Bytes.unsafe_to_string (data self)
let[@inline] optional dec self : _ option =
let c = u8 self in
if Char.code c = 0 then None else Some (dec self)
end
module Encode = struct
type t = Buffer.t
let of_buffer buf : t = buf
type 'a enc = t -> 'a -> unit
external unsafe_chr : int -> char = "%identity"
let uint (self:t) (i:int64) : unit =
let module I = Int64 in
let i = ref i in
let continue = ref true in
while !continue do
let j = I.logand 0b0111_1111L !i in
if !i = j then (
continue := false;
let j = I.to_int j in
Buffer.add_char self (unsafe_chr j)
) else (
let lsb = I.to_int (I.logor 0b1000_0000L j) in
let lsb = (unsafe_chr lsb) in
Buffer.add_char self lsb;
i := I.shift_right_logical !i 7;
)
done
let[@inline] int (self:t) i =
let open Int64 in
let ui = logxor (shift_left i 1) (shift_right i 63) in
uint self ui
let u8 self x = Buffer.add_char self x
let i8 = u8
let u16 self x = Buffer.add_int16_le self x
let i16 = u16
let u32 self x = Buffer.add_int32_le self x
let i32 = u32
let u64 self x = Buffer.add_int64_le self x
let i64 = u64
let bool self x = Buffer.add_char self (if x then Char.chr 1 else Char.chr 0)
let f64 (self:t) x = Buffer.add_int64_le self (Int64.bits_of_float x)
let data_of ~size self x =
if size <> Bytes.length x then failwith "invalid length for Encode.data_of";
Buffer.add_bytes self x
let data self x =
uint self (Int64.of_int (Bytes.length x));
Buffer.add_bytes self x
let string self x = data self (Bytes.unsafe_of_string x)
let[@inline] optional enc self x : unit =
match x with
| None -> u8 self (Char.chr 0)
| Some x ->
u8 self (Char.chr 1);
enc self x
end
module Pp = struct
type 'a t = Format.formatter -> 'a -> unit
type 'a iter = ('a -> unit) -> unit
let unit out () = Format.pp_print_string out "()"
let int8 out c = Format.fprintf out "%d" (Char.code c)
let int out x = Format.fprintf out "%d" x
let int32 out x = Format.fprintf out "%ld" x
let int64 out x = Format.fprintf out "%Ld" x
let float out x = Format.fprintf out "%h" x
let bool = Format.pp_print_bool
let string out x = Format.fprintf out "%S" x
let data out x = string out (Bytes.unsafe_to_string x)
let option ppelt out x = match x with
| None -> Format.fprintf out "None"
| Some x -> Format.fprintf out "(Some %a)" ppelt x
let array ppelt out x =
Format.fprintf out "[@[";
Array.iteri (fun i x ->
if i>0 then Format.fprintf out ";@ ";
ppelt out x)
x;
Format.fprintf out "@]]"
let iter ppelt out xs =
Format.fprintf out "[@[";
let i = ref 0 in
xs (fun x ->
if !i>0 then Format.fprintf out ",@ ";
incr i;
ppelt out x);
Format.fprintf out "@]]"
let list ppelt out l = iter ppelt out (fun f->List.iter f l)
end
let to_string (e:'a Encode.enc) (x:'a) =
let buf = Buffer.create 32 in
e buf x;
Buffer.contents buf
let of_bytes_exn ?(off=0) dec bs =
let i = {Decode.bs; off} in
dec i
let of_bytes ?off dec bs =
try Ok (of_bytes_exn ?off dec bs)
with Decode.Error e -> Error e
let of_string_exn dec s = of_bytes_exn dec (Bytes.unsafe_of_string s)
let of_string dec s = of_bytes dec (Bytes.unsafe_of_string s)