20
20
open Js
21
21
open ! Import
22
22
23
+ (* ***)
24
+
25
+ (* The writing logic for basic types is copied from [lib/deriving_json]. *)
26
+
27
+ let write_string buffer s =
28
+ Buffer. add_char buffer '"' ;
29
+ for i = 0 to String. length s - 1 do
30
+ match s.[i] with
31
+ | '"' -> Buffer. add_string buffer {| \" |}
32
+ | '\\ ' -> Buffer.add_string buffer {|\\ |}
33
+ | '\b ' -> Buffer.add_string buffer {|\b |}
34
+ | '\x0C ' -> Buffer.add_string buffer {|\f |}
35
+ | '\n ' -> Buffer.add_string buffer {|\n |}
36
+ | '\r ' -> Buffer.add_string buffer {|\r |}
37
+ | '\t ' -> Buffer.add_string buffer {|\t |}
38
+ | c when Poly.(c <= '\x1F ') ->
39
+ (* Other control characters are escaped. *)
40
+ Printf.bprintf buffer {|\u %04X|} (int_of_char c)
41
+ | c when Poly.(c < '\x80 ') -> Buffer.add_char buffer s.[i]
42
+ | _c (* >= '\x80 ' *) ->
43
+ (* Bytes greater than 127 are embedded in a UTF-8 sequence. *)
44
+ Buffer.add_char buffer (Char.chr (0xC2 lor (Char.code s.[i] lsr 6)));
45
+ Buffer.add_char buffer (Char.chr (0x80 lor (Char.code s.[i] land 0x3F)))
46
+ done;
47
+ Buffer.add_char buffer '" '
48
+
49
+ let write_float buffer f =
50
+ (* "%.15g" can be (much) shorter; "%.17g" is round-trippable *)
51
+ let s = Printf. sprintf " %.15g" f in
52
+ if Poly. (float_of_string s = f)
53
+ then Buffer. add_string buffer s
54
+ else Printf. bprintf buffer " %.17g" f
55
+
56
+ let write_int64 buffer i =
57
+ let mask16 = Int64. of_int 0xffff in
58
+ let mask24 = Int64. of_int 0xffffff in
59
+ Printf. bprintf
60
+ buffer
61
+ " [255,%Ld,%Ld,%Ld]"
62
+ (Int64. logand i mask24)
63
+ (Int64. logand (Int64. shift_right i 24 ) mask24)
64
+ (Int64. logand (Int64. shift_right i 48 ) mask16)
65
+
66
+ external custom_identifier : Obj .t -> string = " caml_custom_identifier"
67
+
68
+ let rec write b v =
69
+ if Obj. is_int v
70
+ then Printf. bprintf b " %d" (Obj. obj v : int )
71
+ else
72
+ let t = Obj. tag v in
73
+ if t < = Obj. last_non_constant_constructor_tag
74
+ then (
75
+ Printf. bprintf b " [%d" t;
76
+ for i = 0 to Obj. size v - 1 do
77
+ Buffer. add_char b ',' ;
78
+ write b (Obj. field v i)
79
+ done ;
80
+ Buffer. add_char b ']' )
81
+ else if t = Obj. string_tag
82
+ then write_string b (Obj. obj v : string )
83
+ else if t = Obj. double_tag
84
+ then write_float b (Obj. obj v : float )
85
+ else if t = Obj. double_array_tag
86
+ then (
87
+ Printf. bprintf b " [%d" t;
88
+ for i = 0 to Obj. size v - 1 do
89
+ Buffer. add_char b ',' ;
90
+ write_float b (Obj. double_field v i)
91
+ done ;
92
+ Buffer. add_char b ']' )
93
+ else if t = Obj. custom_tag
94
+ then
95
+ match custom_identifier v with
96
+ | "_i" -> Printf. bprintf b " %ld" (Obj. obj v : int32 )
97
+ | "_j" ->
98
+ let i : int64 = Obj. obj v in
99
+ write_int64 b i
100
+ | id -> failwith (Printf. sprintf " Json.output: unsupported custom value %s " id)
101
+ else failwith (Printf. sprintf " Json.output: unsupported tag %d " t)
102
+
103
+ let to_json v =
104
+ let buf = Buffer. create 50 in
105
+ write buf v;
106
+ Buffer. contents buf
107
+
108
+ (* ***)
109
+
23
110
class type json = object
24
111
method parse : 'a. js_string t -> 'a meth
25
112
@@ -51,13 +138,22 @@ let input_reviver =
51
138
in
52
139
wrap_meth_callback reviver
53
140
54
- let unsafe_input s = json##parse_ s input_reviver
141
+ let unsafe_input s =
142
+ match Sys. backend_type with
143
+ | Other "wasm_of_ocaml" ->
144
+ (* https://github.com/ocsigen/js_of_ocaml/pull/1660#discussion_r1731099372
145
+ The encoding of OCaml values is ambiguous since both integers and floats
146
+ are mapped to numbers *)
147
+ failwith " Json.unsafe_input: not implemented in the Wasm backend"
148
+ | _ -> json##parse_ s input_reviver
55
149
56
150
class type obj = object
57
151
method constructor : 'a. 'a constr Js. readonly_prop
58
152
end
59
153
60
154
let mlInt64_constr =
155
+ Js.Unsafe. pure_expr
156
+ @@ fun () ->
61
157
let dummy_int64 = 1L in
62
158
let dummy_obj : obj t = Obj. magic dummy_int64 in
63
159
dummy_obj##.constructor
@@ -71,4 +167,20 @@ let output_reviver _key (value : Unsafe.any) : Obj.t =
71
167
Obj. repr (array [| 255 ; value##.lo; value##.mi; value##.hi |])
72
168
else Obj. repr value
73
169
74
- let output obj = json##stringify_ obj (Js. wrap_callback output_reviver)
170
+ let use_native_stringify_ =
171
+ ref
172
+ (match Sys. backend_type with
173
+ | Other "js_of_ocaml" -> true
174
+ | Native | Bytecode | Other _ -> false )
175
+
176
+ let use_native_stringify () = ! use_native_stringify_
177
+
178
+ let set_use_native_stringify b = use_native_stringify_ := b
179
+
180
+ let output_ x = to_json (Obj. repr x)
181
+
182
+ let output obj =
183
+ match Sys. backend_type with
184
+ | Other "js_of_ocaml" when use_native_stringify () ->
185
+ json##stringify_ obj (Js. wrap_callback output_reviver)
186
+ | _ -> Js. string (output_ obj)
0 commit comments