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
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
type value =
[ `Null
| `Bool of bool
| `Float of float
| `String of string
| `A of value list
| `O of (string * value) list ]
type t =
[ `A of value list
| `O of (string * value) list ]
let value: t -> value = fun t -> (t :> value)
exception Escape of ((int * int) * (int * int)) * Jsonm.error
module List = struct
include List
let map f l = rev (rev_map f l)
end
let json_of_src src =
let d = Jsonm.decoder src in
let dec () = match Jsonm.decode d with
| `Lexeme l -> l
| `Error e -> raise (Escape (Jsonm.decoded_range d, e))
| `End
| `Await -> assert false
in
let rec value v k = match v with
| `Os -> obj [] k
| `As -> arr [] k
| `Null
| `Bool _
| `String _
| `Float _ as v -> k v
| _ -> assert false
and arr vs k = match dec () with
| `Ae -> k (`A (List.rev vs))
| v -> value v (fun v -> arr (v :: vs) k)
and obj ms k = match dec () with
| `Oe -> k (`O (List.rev ms))
| `Name n -> value (dec ()) (fun v -> obj ((n, v) :: ms) k)
| _ -> assert false
in
try `JSON (value (dec ()) (fun x -> x))
with Escape (r, e) -> `Error (r, e)
let value_to_dst ?(minify=true) dst json =
let enc e l = ignore (Jsonm.encode e (`Lexeme l)) in
let rec t v k e = match v with
| `A vs -> arr vs k e
| `O ms -> obj ms k e
and value v k e = match v with
| `Null | `Bool _ | `Float _ | `String _ as v -> enc e v; k e
| #t as x -> t (x :> t) k e
and arr vs k e = enc e `As; arr_vs vs k e
and arr_vs vs k e = match vs with
| v :: vs' -> value v (arr_vs vs' k) e
| [] -> enc e `Ae; k e
and obj ms k e = enc e `Os; obj_ms ms k e
and obj_ms ms k e = match ms with
| (n, v) :: ms -> enc e (`Name n); value v (obj_ms ms k) e
| [] -> enc e `Oe; k e
in
let e = Jsonm.encoder ~minify dst in
let finish e = ignore (Jsonm.encode e `End) in
value json finish e
let value_to_buffer ?minify buf json =
value_to_dst ?minify (`Buffer buf) json
let to_buffer ?minify buf json = value_to_buffer ?minify buf (json :> value)
let value_to_string ?minify json =
let buf = Buffer.create 1024 in
value_to_buffer ?minify buf json;
Buffer.contents buf
let to_string ?minify json = value_to_string ?minify (json :> value)
let value_to_channel ?minify oc json =
value_to_dst ?minify (`Channel oc) json
let to_channel ?minify oc json = value_to_channel ?minify oc (json :> value)
exception Parse_error of value * string
let parse_error t fmt =
Printf.kprintf (fun msg ->
raise (Parse_error (t, msg))
) fmt
let wrap t = `A [t]
let unwrap = function
| `A [t] -> t
| v -> parse_error (v :> value) "Not unwrappable"
let string_of_error error =
Jsonm.pp_error Format.str_formatter error;
Format.flush_str_formatter ()
let value_from_src src =
match json_of_src src with
| `JSON t -> t
| `Error (_,e) -> parse_error `Null "JSON.of_buffer %s" (string_of_error e)
let value_from_string str = value_from_src (`String str)
let value_from_channel chan = value_from_src (`Channel chan)
let ensure_document: [> value] -> [> t] = function
| #t as t -> t
| _ -> assert false
let from_string str = value_from_string str |> ensure_document
let from_channel chan = value_from_channel chan |> ensure_document
let unit () = `Null
let get_unit = function
| `Null -> ()
| j -> parse_error j "Ezjsonm.get_unit"
let bool b = `Bool b
let get_bool = function
| `Bool b -> b
| j -> parse_error j "Ezjsonm.get_bool"
let string s = `String s
let get_string = function
| `String s -> s
| j -> parse_error j "Ezjsonm.get_string"
let int i = `Float (float_of_int i)
let int32 i = `Float (Int32.to_float i)
let int64 i = `Float (Int64.to_float i)
let get_int = function
| `Float f -> int_of_float f
| j -> parse_error j "Ezjsonm.get_int"
let get_int32 = function
| `Float f -> Int32.of_float f
| j -> parse_error j "Ezjsonm.get_int32"
let get_int64 = function
| `Float f -> Int64.of_float f
| j -> parse_error j "Ezjsonm.get_int64"
let float f = `Float f
let get_float = function
| `Float f -> f
| j -> parse_error j "Ezjsonm.get_float"
let list fn l =
`A (List.map fn l)
let get_list fn = function
| `A ks -> List.map fn ks
| j -> parse_error j "Ezjsonm.get_list"
let strings strings = list string strings
let get_strings = get_list get_string
let option fn = function
| None -> `Null
| Some x -> `A [fn x]
let get_option fn = function
| `Null -> None
| `A [j] -> Some (fn j)
| j -> parse_error j "Ezjsonm.get_option"
let dict d = `O d
let get_dict = function
| `O d -> d
| j -> parse_error j "Ezjsonm.get_dict"
let pair fk fv (k, v) =
`A [fk k; fv v]
let get_pair fk fv = function
| `A [k; v] -> (fk k, fv v)
| j -> parse_error j "Ezjsonm.get_pair"
let triple fa fb fc (a, b, c) =
`A [fa a; fb b; fc c]
let get_triple fa fb fc = function
| `A [a; b; c] -> (fa a, fb b, fc c)
| j -> parse_error j "Ezjsonm.get_triple"
let mem t path =
let rec aux j p = match p, j with
| [] , _ -> true
| h::tl, `O o -> List.mem_assoc h o && aux (List.assoc h o) tl
| _ -> false in
aux t path
let find t path =
let rec aux j p = match p, j with
| [] , j -> j
| h::tl, `O o -> aux (List.assoc h o) tl
| _ -> raise Not_found in
aux t path
let map_dict f dict label =
let rec aux acc = function
| [] ->
begin match f `Null with
| None -> List.rev acc
| Some j -> List.rev_append acc [label, j]
end
| (l,j) as e :: dict ->
if l = label then
match f j with
| None -> List.rev_append acc dict
| Some j -> List.rev_append acc ((l,j)::dict)
else
aux (e::acc) dict in
aux [] dict
let map f t path =
let rec aux t = function
| [] -> f t
| h::tl ->
match t with
| `O d -> Some (`O (map_dict (fun t -> aux t tl) d h))
| _ -> None in
match aux t path with
| None -> raise Not_found
| Some j -> j
let update t path v =
map (fun _ -> v) t path
exception Not_utf8
let is_valid_utf8 str =
try
Uutf.String.fold_utf_8 (fun _ _ -> function
| `Malformed _ -> raise Not_utf8
| _ -> ()
) () str;
true
with Not_utf8 -> false
let encode_string str =
if is_valid_utf8 str
then string str
else
let `Hex h = Hex.of_string str in
`O [ "hex", string h ]
let decode_string = function
| `String str -> Some str
| `O [ "hex", `String str ] -> Some (Hex.to_string (`Hex str))
| _ -> None
let decode_string_exn j =
match decode_string j with
| Some s -> s
| None -> parse_error j "Ezjsonm.decode_string_exn"
let rec of_sexp = function
| Sexplib.Type.Atom x -> encode_string x
| Sexplib.Type.List l -> list of_sexp l
let value_of_sexp = of_sexp
let t_of_sexp s = match value_of_sexp s with
| `A x -> `A x
| `O x -> `O x
| _ -> failwith "Ezjsonm: t_of_sexp encountered a value (fragment) rather than a t"
let rec to_sexp json =
match decode_string json with
| Some s -> Sexplib.Type.Atom s
| None ->
match json with
| `A l -> Sexplib.Type.List (List.map to_sexp l)
| _ -> parse_error json "Ezjsonm.to_sexp"
let sexp_of_value = to_sexp
let sexp_of_t t = sexp_of_value @@ value t