simdjson bindings with streaming support
at main 12 kB view raw
1type error = { path : string list; message : string } 2 3exception Decode_error of error 4 5let error_to_string e = 6 let path = 7 match e.path with [] -> "" | p -> String.concat "." (List.rev p) ^ ": " 8 in 9 path ^ e.message 10 11let decode_error path msg = raise (Decode_error { path; message = msg }) 12 13type 'a decoder = string list -> Simdjsont_raw.element -> 'a 14type encoder = Buffer.t -> unit 15 16type 'a t = { 17 decode : 'a decoder; 18 encode : 'a -> encoder; 19 to_json : 'a -> Simdjsont_json.t; 20} 21 22let decode_element codec elt = 23 try Ok (codec.decode [] elt) 24 with Decode_error e -> Error (error_to_string e) 25 26let decode_string codec s = 27 let parser = Simdjsont_raw.create_parser () in 28 match Simdjsont_raw.parse_string parser s with 29 | Ok elt -> 30 let result = decode_element codec elt in 31 let _ = Sys.opaque_identity parser in 32 result 33 | Error e -> Error e.Simdjsont_raw.message 34 35let decode_string_exn codec s = 36 match decode_string codec s with Ok v -> v | Error msg -> failwith msg 37 38let encode_to_buffer codec v = 39 let buf = Buffer.create 256 in 40 codec.encode v buf; 41 buf 42 43let encode_string codec v = Buffer.contents (encode_to_buffer codec v) 44let to_json codec v = codec.to_json v 45 46let write_escaped_string buf s = 47 Buffer.add_char buf '"'; 48 for i = 0 to String.length s - 1 do 49 match String.unsafe_get s i with 50 | '"' -> Buffer.add_string buf "\\\"" 51 | '\\' -> Buffer.add_string buf "\\\\" 52 | '\b' -> Buffer.add_string buf "\\b" 53 | '\012' -> Buffer.add_string buf "\\f" 54 | '\n' -> Buffer.add_string buf "\\n" 55 | '\r' -> Buffer.add_string buf "\\r" 56 | '\t' -> Buffer.add_string buf "\\t" 57 | c when Char.code c < 0x20 -> 58 Buffer.add_string buf (Printf.sprintf "\\u%04x" (Char.code c)) 59 | c -> Buffer.add_char buf c 60 done; 61 Buffer.add_char buf '"' 62 63let null : unit t = 64 { 65 decode = 66 (fun path elt -> 67 match Simdjsont_raw.element_type elt with 68 | Simdjsont_raw.Null -> () 69 | _ -> decode_error path "expected null"); 70 encode = (fun () buf -> Buffer.add_string buf "null"); 71 to_json = (fun () -> Simdjsont_json.Null); 72 } 73 74let bool : bool t = 75 { 76 decode = 77 (fun path elt -> 78 match Simdjsont_raw.get_bool elt with 79 | Ok b -> b 80 | Error _ -> decode_error path "expected bool"); 81 encode = 82 (fun b buf -> Buffer.add_string buf (if b then "true" else "false")); 83 to_json = (fun b -> Simdjsont_json.Bool b); 84 } 85 86let int : int t = 87 { 88 decode = 89 (fun path elt -> 90 match Simdjsont_raw.get_int64 elt with 91 | Ok i -> Int64.to_int i 92 | Error _ -> decode_error path "expected int"); 93 encode = (fun i buf -> Buffer.add_string buf (string_of_int i)); 94 to_json = (fun i -> Simdjsont_json.Int (Int64.of_int i)); 95 } 96 97let int64 : int64 t = 98 { 99 decode = 100 (fun path elt -> 101 match Simdjsont_raw.get_int64 elt with 102 | Ok i -> i 103 | Error _ -> decode_error path "expected int64"); 104 encode = (fun i buf -> Buffer.add_string buf (Int64.to_string i)); 105 to_json = (fun i -> Simdjsont_json.Int i); 106 } 107 108let float : float t = 109 { 110 decode = 111 (fun path elt -> 112 match Simdjsont_raw.element_type elt with 113 | Simdjsont_raw.Double -> ( 114 match Simdjsont_raw.get_double elt with 115 | Ok f -> f 116 | Error _ -> Float.nan) 117 | Simdjsont_raw.Int64 -> ( 118 match Simdjsont_raw.get_int64 elt with 119 | Ok i -> Int64.to_float i 120 | Error _ -> Float.nan) 121 | Simdjsont_raw.Uint64 -> ( 122 match Simdjsont_raw.get_uint64 elt with 123 | Ok u -> Int64.to_float (Unsigned.UInt64.to_int64 u) 124 | Error _ -> Float.nan) 125 | Simdjsont_raw.Null -> Float.nan 126 | _ -> decode_error path "expected number"); 127 encode = 128 (fun f buf -> 129 if Float.is_finite f then 130 Buffer.add_string buf (Printf.sprintf "%.17g" f) 131 else Buffer.add_string buf "null"); 132 to_json = (fun f -> Simdjsont_json.Float f); 133 } 134 135let string : string t = 136 { 137 decode = 138 (fun path elt -> 139 match Simdjsont_raw.get_string elt with 140 | Ok s -> s 141 | Error _ -> decode_error path "expected string"); 142 encode = (fun s buf -> write_escaped_string buf s); 143 to_json = (fun s -> Simdjsont_json.String s); 144 } 145 146let list (item : 'a t) : 'a list t = 147 { 148 decode = 149 (fun path elt -> 150 match Simdjsont_raw.get_array elt with 151 | Ok arr -> 152 let result = ref [] in 153 let idx = ref 0 in 154 Simdjsont_raw.array_iter 155 (fun e -> 156 let item_path = string_of_int !idx :: path in 157 result := item.decode item_path e :: !result; 158 incr idx) 159 arr; 160 List.rev !result 161 | Error _ -> decode_error path "expected array"); 162 encode = 163 (fun items buf -> 164 Buffer.add_char buf '['; 165 (match items with 166 | [] -> () 167 | x :: xs -> 168 item.encode x buf; 169 List.iter 170 (fun v -> 171 Buffer.add_char buf ','; 172 item.encode v buf) 173 xs); 174 Buffer.add_char buf ']'); 175 to_json = (fun items -> Simdjsont_json.Array (List.map item.to_json items)); 176 } 177 178let array (item : 'a t) : 'a array t = 179 { 180 decode = 181 (fun path elt -> 182 match Simdjsont_raw.get_array elt with 183 | Ok arr -> 184 let len = Simdjsont_raw.array_length arr in 185 if len = 0 then [||] 186 else begin 187 let result = ref [||] in 188 let idx = ref 0 in 189 Simdjsont_raw.array_iter 190 (fun e -> 191 let item_path = string_of_int !idx :: path in 192 let v = item.decode item_path e in 193 if !idx = 0 then result := Array.make len v 194 else Array.unsafe_set !result !idx v; 195 incr idx) 196 arr; 197 !result 198 end 199 | Error _ -> decode_error path "expected array"); 200 encode = 201 (fun items buf -> 202 Buffer.add_char buf '['; 203 let len = Array.length items in 204 if len > 0 then begin 205 item.encode (Array.unsafe_get items 0) buf; 206 for i = 1 to len - 1 do 207 Buffer.add_char buf ','; 208 item.encode (Array.unsafe_get items i) buf 209 done 210 end; 211 Buffer.add_char buf ']'); 212 to_json = 213 (fun items -> 214 Simdjsont_json.Array (List.map item.to_json (Array.to_list items))); 215 } 216 217let optional (inner : 'a t) : 'a option t = 218 { 219 decode = 220 (fun path elt -> 221 match Simdjsont_raw.element_type elt with 222 | Simdjsont_raw.Null -> None 223 | _ -> Some (inner.decode path elt)); 224 encode = 225 (fun opt buf -> 226 match opt with 227 | None -> Buffer.add_string buf "null" 228 | Some v -> inner.encode v buf); 229 to_json = 230 (function None -> Simdjsont_json.Null | Some v -> inner.to_json v); 231 } 232 233let map (f : 'a -> 'b) (g : 'b -> 'a) (codec : 'a t) : 'b t = 234 { 235 decode = (fun path elt -> f (codec.decode path elt)); 236 encode = (fun v buf -> codec.encode (g v) buf); 237 to_json = (fun v -> codec.to_json (g v)); 238 } 239 240let decode_obj_field path (obj : Simdjsont_raw.object_) name (dec : 'a decoder) 241 : 'a = 242 let field_path = name :: path in 243 match Simdjsont_raw.object_find obj name with 244 | Ok elt -> dec field_path elt 245 | Error _ -> decode_error path ("missing field: " ^ name) 246 247let decode_obj_opt_field path (obj : Simdjsont_raw.object_) name 248 (dec : 'a decoder) : 'a option = 249 let field_path = name :: path in 250 match Simdjsont_raw.object_find obj name with 251 | Ok elt -> ( 252 match Simdjsont_raw.element_type elt with 253 | Simdjsont_raw.Null -> None 254 | _ -> Some (dec field_path elt)) 255 | Error _ -> None 256 257module Obj = struct 258 type ('o, 'dec) builder = { 259 dec : string list -> Simdjsont_raw.object_ -> 'dec; 260 enc : 'o -> Buffer.t -> bool -> bool; 261 ast : 'o -> (string * Simdjsont_json.t) list; 262 } 263 264 let field constructor = 265 { 266 dec = (fun _path _obj -> constructor); 267 enc = (fun _v _buf first -> first); 268 ast = (fun _v -> []); 269 } 270 271 let mem name (codec : 'a t) ~enc:(get : 'o -> 'a) 272 (builder : ('o, 'a -> 'b) builder) : ('o, 'b) builder = 273 { 274 dec = 275 (fun path obj -> 276 let value = decode_obj_field path obj name codec.decode in 277 builder.dec path obj value); 278 enc = 279 (fun v buf first -> 280 let first = builder.enc v buf first in 281 if not first then Buffer.add_char buf ','; 282 write_escaped_string buf name; 283 Buffer.add_char buf ':'; 284 codec.encode (get v) buf; 285 false); 286 ast = (fun v -> (name, codec.to_json (get v)) :: builder.ast v); 287 } 288 289 let opt_mem name (codec : 'a t) ~enc:(get : 'o -> 'a option) 290 (builder : ('o, 'a option -> 'b) builder) : ('o, 'b) builder = 291 { 292 dec = 293 (fun path obj -> 294 let value = decode_obj_opt_field path obj name codec.decode in 295 builder.dec path obj value); 296 enc = 297 (fun v buf first -> 298 let first = builder.enc v buf first in 299 match get v with 300 | None -> first 301 | Some inner_v -> 302 if not first then Buffer.add_char buf ','; 303 write_escaped_string buf name; 304 Buffer.add_char buf ':'; 305 codec.encode inner_v buf; 306 false); 307 ast = 308 (fun v -> 309 match get v with 310 | None -> builder.ast v 311 | Some inner_v -> (name, codec.to_json inner_v) :: builder.ast v); 312 } 313 314 let finish (builder : ('o, 'o) builder) : 'o t = 315 { 316 decode = 317 (fun path elt -> 318 match Simdjsont_raw.get_object elt with 319 | Ok obj -> builder.dec path obj 320 | Error _ -> decode_error path "expected object"); 321 encode = 322 (fun v buf -> 323 Buffer.add_char buf '{'; 324 let _ = builder.enc v buf true in 325 Buffer.add_char buf '}'); 326 to_json = (fun v -> Simdjsont_json.Object (builder.ast v)); 327 } 328end 329 330let value : Simdjsont_json.t t = 331 let rec decode_value path elt = 332 match Simdjsont_raw.element_type elt with 333 | Simdjsont_raw.Null -> Simdjsont_json.Null 334 | Simdjsont_raw.Bool -> 335 Simdjsont_json.Bool 336 (match Simdjsont_raw.get_bool elt with Ok b -> b | _ -> false) 337 | Simdjsont_raw.Int64 -> 338 Simdjsont_json.Int 339 (match Simdjsont_raw.get_int64 elt with Ok i -> i | _ -> 0L) 340 | Simdjsont_raw.Uint64 -> 341 let i = 342 match Simdjsont_raw.get_uint64 elt with 343 | Ok u -> Unsigned.UInt64.to_int64 u 344 | _ -> 0L 345 in 346 Simdjsont_json.Int i 347 | Simdjsont_raw.Double -> 348 Simdjsont_json.Float 349 (match Simdjsont_raw.get_double elt with Ok f -> f | _ -> 0.0) 350 | Simdjsont_raw.String -> 351 Simdjsont_json.String 352 (match Simdjsont_raw.get_string elt with Ok s -> s | _ -> "") 353 | Simdjsont_raw.Array -> ( 354 match Simdjsont_raw.get_array elt with 355 | Ok arr -> 356 let items = ref [] in 357 let idx = ref 0 in 358 Simdjsont_raw.array_iter 359 (fun e -> 360 items := decode_value (string_of_int !idx :: path) e :: !items; 361 incr idx) 362 arr; 363 Simdjsont_json.Array (List.rev !items) 364 | Error _ -> Simdjsont_json.Array []) 365 | Simdjsont_raw.Object -> ( 366 match Simdjsont_raw.get_object elt with 367 | Ok obj -> 368 let members = ref [] in 369 Simdjsont_raw.object_iter 370 (fun k v -> 371 members := (k, decode_value (k :: path) v) :: !members) 372 obj; 373 Simdjsont_json.Object (List.rev !members) 374 | Error _ -> Simdjsont_json.Object []) 375 in 376 { 377 decode = decode_value; 378 encode = (fun v buf -> Simdjsont_json.write buf v); 379 to_json = (fun v -> v); 380 }