dependabot-hex 0.95.47 → 0.95.48

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,630 +0,0 @@
1
- defmodule Jason.EncodeError do
2
- defexception [:message]
3
-
4
- @type t :: %__MODULE__{message: String.t}
5
-
6
- def new({:duplicate_key, key}) do
7
- %__MODULE__{message: "duplicate key: #{key}"}
8
- end
9
- def new({:invalid_byte, byte, original}) do
10
- %__MODULE__{message: "invalid byte #{inspect byte, base: :hex} in #{inspect original}"}
11
- end
12
- end
13
-
14
- defmodule Jason.Encode do
15
- @moduledoc """
16
- Utilities for encoding elixir values to JSON.
17
- """
18
-
19
- import Bitwise
20
-
21
- alias Jason.{Codegen, EncodeError, Encoder, Fragment}
22
-
23
- @typep escape :: (String.t, String.t, integer -> iodata)
24
- @typep encode_map :: (map, escape, encode_map -> iodata)
25
- @opaque opts :: {escape, encode_map}
26
-
27
- # @compile :native
28
-
29
- @doc false
30
- @spec encode(any, map) :: {:ok, iodata} | {:error, EncodeError.t | Exception.t}
31
- def encode(value, opts) do
32
- escape = escape_function(opts)
33
- encode_map = encode_map_function(opts)
34
- try do
35
- {:ok, value(value, escape, encode_map)}
36
- catch
37
- :throw, %EncodeError{} = e ->
38
- {:error, e}
39
- :error, %Protocol.UndefinedError{protocol: Jason.Encoder} = e ->
40
- {:error, e}
41
- end
42
- end
43
-
44
- defp encode_map_function(%{maps: maps}) do
45
- case maps do
46
- :naive -> &map_naive/3
47
- :strict -> &map_strict/3
48
- end
49
- end
50
-
51
- defp escape_function(%{escape: escape}) do
52
- case escape do
53
- :json -> &escape_json/3
54
- :html_safe -> &escape_html/3
55
- :unicode_safe -> &escape_unicode/3
56
- :javascript_safe -> &escape_javascript/3
57
- # Keep for compatibility with Poison
58
- :javascript -> &escape_javascript/3
59
- :unicode -> &escape_unicode/3
60
- end
61
- end
62
-
63
- @doc """
64
- Equivalent to calling the `Jason.Encoder.encode/2` protocol function.
65
-
66
- Slightly more efficient for built-in types because of the internal dispatching.
67
- """
68
- @spec value(term, opts) :: iodata
69
- def value(value, {escape, encode_map}) do
70
- value(value, escape, encode_map)
71
- end
72
-
73
- @doc false
74
- # We use this directly in the helpers and deriving for extra speed
75
- def value(value, escape, _encode_map) when is_atom(value) do
76
- encode_atom(value, escape)
77
- end
78
-
79
- def value(value, escape, _encode_map) when is_binary(value) do
80
- encode_string(value, escape)
81
- end
82
-
83
- def value(value, _escape, _encode_map) when is_integer(value) do
84
- integer(value)
85
- end
86
-
87
- def value(value, _escape, _encode_map) when is_float(value) do
88
- float(value)
89
- end
90
-
91
- def value(value, escape, encode_map) when is_list(value) do
92
- list(value, escape, encode_map)
93
- end
94
-
95
- def value(%{__struct__: module} = value, escape, encode_map) do
96
- struct(value, escape, encode_map, module)
97
- end
98
-
99
- def value(value, escape, encode_map) when is_map(value) do
100
- encode_map.(value, escape, encode_map)
101
- end
102
-
103
- def value(value, escape, encode_map) do
104
- Encoder.encode(value, {escape, encode_map})
105
- end
106
-
107
- @compile {:inline, integer: 1, float: 1}
108
-
109
- @spec atom(atom, opts) :: iodata
110
- def atom(atom, {escape, _encode_map}) do
111
- encode_atom(atom, escape)
112
- end
113
-
114
- defp encode_atom(nil, _escape), do: "null"
115
- defp encode_atom(true, _escape), do: "true"
116
- defp encode_atom(false, _escape), do: "false"
117
- defp encode_atom(atom, escape),
118
- do: encode_string(Atom.to_string(atom), escape)
119
-
120
- @spec integer(integer) :: iodata
121
- def integer(integer) do
122
- Integer.to_string(integer)
123
- end
124
-
125
- @spec float(float) :: iodata
126
- def float(float) do
127
- :io_lib_format.fwrite_g(float)
128
- end
129
-
130
- @spec list(list, opts) :: iodata
131
- def list(list, {escape, encode_map}) do
132
- list(list, escape, encode_map)
133
- end
134
-
135
- defp list([], _escape, _encode_map) do
136
- "[]"
137
- end
138
-
139
- defp list([head | tail], escape, encode_map) do
140
- [?[, value(head, escape, encode_map)
141
- | list_loop(tail, escape, encode_map)]
142
- end
143
-
144
- defp list_loop([], _escape, _encode_map) do
145
- ']'
146
- end
147
-
148
- defp list_loop([head | tail], escape, encode_map) do
149
- [?,, value(head, escape, encode_map)
150
- | list_loop(tail, escape, encode_map)]
151
- end
152
-
153
- @spec map(map, opts) :: iodata
154
- def map(value, {escape, encode_map}) do
155
- encode_map.(value, escape, encode_map)
156
- end
157
-
158
- defp map_naive(value, escape, encode_map) do
159
- case Map.to_list(value) do
160
- [] -> "{}"
161
- [{key, value} | tail] ->
162
- ["{\"", key(key, escape), "\":",
163
- value(value, escape, encode_map)
164
- | map_naive_loop(tail, escape, encode_map)]
165
- end
166
- end
167
-
168
- defp map_naive_loop([], _escape, _encode_map) do
169
- '}'
170
- end
171
-
172
- defp map_naive_loop([{key, value} | tail], escape, encode_map) do
173
- [",\"", key(key, escape), "\":",
174
- value(value, escape, encode_map)
175
- | map_naive_loop(tail, escape, encode_map)]
176
- end
177
-
178
- defp map_strict(value, escape, encode_map) do
179
- case Map.to_list(value) do
180
- [] -> "{}"
181
- [{key, value} | tail] ->
182
- key = IO.iodata_to_binary(key(key, escape))
183
- visited = %{key => []}
184
- ["{\"", key, "\":",
185
- value(value, escape, encode_map)
186
- | map_strict_loop(tail, escape, encode_map, visited)]
187
- end
188
- end
189
-
190
- defp map_strict_loop([], _encode_map, _escape, _visited) do
191
- '}'
192
- end
193
-
194
- defp map_strict_loop([{key, value} | tail], escape, encode_map, visited) do
195
- key = IO.iodata_to_binary(key(key, escape))
196
- case visited do
197
- %{^key => _} ->
198
- error({:duplicate_key, key})
199
- _ ->
200
- visited = Map.put(visited, key, [])
201
- [",\"", key, "\":",
202
- value(value, escape, encode_map)
203
- | map_strict_loop(tail, escape, encode_map, visited)]
204
- end
205
- end
206
-
207
- @spec struct(struct, opts) :: iodata
208
- def struct(%module{} = value, {escape, encode_map}) do
209
- struct(value, escape, encode_map, module)
210
- end
211
-
212
- # TODO: benchmark the effect of inlining the to_iso8601 functions
213
- for module <- [Date, Time, NaiveDateTime, DateTime] do
214
- defp struct(value, _escape, _encode_map, unquote(module)) do
215
- [?\", unquote(module).to_iso8601(value), ?\"]
216
- end
217
- end
218
-
219
- defp struct(value, _escape, _encode_map, Decimal) do
220
- # silence the xref warning
221
- decimal = Decimal
222
- [?\", decimal.to_string(value, :normal), ?\"]
223
- end
224
-
225
- defp struct(value, escape, encode_map, Fragment) do
226
- %{encode: encode} = value
227
- encode.({escape, encode_map})
228
- end
229
-
230
- defp struct(value, escape, encode_map, _module) do
231
- Encoder.encode(value, {escape, encode_map})
232
- end
233
-
234
- @doc false
235
- # This is used in the helpers and deriving implementation
236
- def key(string, escape) when is_binary(string) do
237
- escape.(string, string, 0)
238
- end
239
- def key(atom, escape) when is_atom(atom) do
240
- string = Atom.to_string(atom)
241
- escape.(string, string, 0)
242
- end
243
- def key(other, escape) do
244
- string = String.Chars.to_string(other)
245
- escape.(string, string, 0)
246
- end
247
-
248
- @spec string(String.t, opts) :: iodata
249
- def string(string, {escape, _encode_map}) do
250
- encode_string(string, escape)
251
- end
252
-
253
- defp encode_string(string, escape) do
254
- [?\", escape.(string, string, 0), ?\"]
255
- end
256
-
257
- slash_escapes = Enum.zip('\b\t\n\f\r\"\\', 'btnfr"\\')
258
- surogate_escapes = Enum.zip([0x2028, 0x2029], ["\\u2028", "\\u2029"])
259
- ranges = [{0x00..0x1F, :unicode} | slash_escapes]
260
- html_ranges = [{0x00..0x1F, :unicode}, {?/, ?/} | slash_escapes]
261
- escape_jt = Codegen.jump_table(html_ranges, :error)
262
-
263
- Enum.each(escape_jt, fn
264
- {byte, :unicode} ->
265
- sequence = List.to_string(:io_lib.format("\\u~4.16.0B", [byte]))
266
- defp escape(unquote(byte)), do: unquote(sequence)
267
- {byte, char} when is_integer(char) ->
268
- defp escape(unquote(byte)), do: unquote(<<?\\, char>>)
269
- {byte, :error} ->
270
- defp escape(unquote(byte)), do: throw(:error)
271
- end)
272
-
273
- ## regular JSON escape
274
-
275
- json_jt = Codegen.jump_table(ranges, :chunk, 0x7F + 1)
276
-
277
- defp escape_json(data, original, skip) do
278
- escape_json(data, [], original, skip)
279
- end
280
-
281
- Enum.map(json_jt, fn
282
- {byte, :chunk} ->
283
- defp escape_json(<<byte, rest::bits>>, acc, original, skip)
284
- when byte === unquote(byte) do
285
- escape_json_chunk(rest, acc, original, skip, 1)
286
- end
287
- {byte, _escape} ->
288
- defp escape_json(<<byte, rest::bits>>, acc, original, skip)
289
- when byte === unquote(byte) do
290
- acc = [acc | escape(byte)]
291
- escape_json(rest, acc, original, skip + 1)
292
- end
293
- end)
294
- defp escape_json(<<char::utf8, rest::bits>>, acc, original, skip)
295
- when char <= 0x7FF do
296
- escape_json_chunk(rest, acc, original, skip, 2)
297
- end
298
- defp escape_json(<<char::utf8, rest::bits>>, acc, original, skip)
299
- when char <= 0xFFFF do
300
- escape_json_chunk(rest, acc, original, skip, 3)
301
- end
302
- defp escape_json(<<_char::utf8, rest::bits>>, acc, original, skip) do
303
- escape_json_chunk(rest, acc, original, skip, 4)
304
- end
305
- defp escape_json(<<>>, acc, _original, _skip) do
306
- acc
307
- end
308
- defp escape_json(<<byte, _rest::bits>>, _acc, original, _skip) do
309
- error({:invalid_byte, byte, original})
310
- end
311
-
312
- Enum.map(json_jt, fn
313
- {byte, :chunk} ->
314
- defp escape_json_chunk(<<byte, rest::bits>>, acc, original, skip, len)
315
- when byte === unquote(byte) do
316
- escape_json_chunk(rest, acc, original, skip, len + 1)
317
- end
318
- {byte, _escape} ->
319
- defp escape_json_chunk(<<byte, rest::bits>>, acc, original, skip, len)
320
- when byte === unquote(byte) do
321
- part = binary_part(original, skip, len)
322
- acc = [acc, part | escape(byte)]
323
- escape_json(rest, acc, original, skip + len + 1)
324
- end
325
- end)
326
- defp escape_json_chunk(<<char::utf8, rest::bits>>, acc, original, skip, len)
327
- when char <= 0x7FF do
328
- escape_json_chunk(rest, acc, original, skip, len + 2)
329
- end
330
- defp escape_json_chunk(<<char::utf8, rest::bits>>, acc, original, skip, len)
331
- when char <= 0xFFFF do
332
- escape_json_chunk(rest, acc, original, skip, len + 3)
333
- end
334
- defp escape_json_chunk(<<_char::utf8, rest::bits>>, acc, original, skip, len) do
335
- escape_json_chunk(rest, acc, original, skip, len + 4)
336
- end
337
- defp escape_json_chunk(<<>>, acc, original, skip, len) do
338
- part = binary_part(original, skip, len)
339
- [acc | part]
340
- end
341
- defp escape_json_chunk(<<byte, _rest::bits>>, _acc, original, _skip, _len) do
342
- error({:invalid_byte, byte, original})
343
- end
344
-
345
- ## javascript safe JSON escape
346
-
347
- defp escape_javascript(data, original, skip) do
348
- escape_javascript(data, [], original, skip)
349
- end
350
-
351
- Enum.map(json_jt, fn
352
- {byte, :chunk} ->
353
- defp escape_javascript(<<byte, rest::bits>>, acc, original, skip)
354
- when byte === unquote(byte) do
355
- escape_javascript_chunk(rest, acc, original, skip, 1)
356
- end
357
- {byte, _escape} ->
358
- defp escape_javascript(<<byte, rest::bits>>, acc, original, skip)
359
- when byte === unquote(byte) do
360
- acc = [acc | escape(byte)]
361
- escape_javascript(rest, acc, original, skip + 1)
362
- end
363
- end)
364
- defp escape_javascript(<<char::utf8, rest::bits>>, acc, original, skip)
365
- when char <= 0x7FF do
366
- escape_javascript_chunk(rest, acc, original, skip, 2)
367
- end
368
- Enum.map(surogate_escapes, fn {byte, escape} ->
369
- defp escape_javascript(<<unquote(byte)::utf8, rest::bits>>, acc, original, skip) do
370
- acc = [acc | unquote(escape)]
371
- escape_javascript(rest, acc, original, skip + 3)
372
- end
373
- end)
374
- defp escape_javascript(<<char::utf8, rest::bits>>, acc, original, skip)
375
- when char <= 0xFFFF do
376
- escape_javascript_chunk(rest, acc, original, skip, 3)
377
- end
378
- defp escape_javascript(<<_char::utf8, rest::bits>>, acc, original, skip) do
379
- escape_javascript_chunk(rest, acc, original, skip, 4)
380
- end
381
- defp escape_javascript(<<>>, acc, _original, _skip) do
382
- acc
383
- end
384
- defp escape_javascript(<<byte, _rest::bits>>, _acc, original, _skip) do
385
- error({:invalid_byte, byte, original})
386
- end
387
-
388
- Enum.map(json_jt, fn
389
- {byte, :chunk} ->
390
- defp escape_javascript_chunk(<<byte, rest::bits>>, acc, original, skip, len)
391
- when byte === unquote(byte) do
392
- escape_javascript_chunk(rest, acc, original, skip, len + 1)
393
- end
394
- {byte, _escape} ->
395
- defp escape_javascript_chunk(<<byte, rest::bits>>, acc, original, skip, len)
396
- when byte === unquote(byte) do
397
- part = binary_part(original, skip, len)
398
- acc = [acc, part | escape(byte)]
399
- escape_javascript(rest, acc, original, skip + len + 1)
400
- end
401
- end)
402
- defp escape_javascript_chunk(<<char::utf8, rest::bits>>, acc, original, skip, len)
403
- when char <= 0x7FF do
404
- escape_javascript_chunk(rest, acc, original, skip, len + 2)
405
- end
406
- Enum.map(surogate_escapes, fn {byte, escape} ->
407
- defp escape_javascript_chunk(<<unquote(byte)::utf8, rest::bits>>, acc, original, skip, len) do
408
- part = binary_part(original, skip, len)
409
- acc = [acc, part | unquote(escape)]
410
- escape_javascript(rest, acc, original, skip + len + 3)
411
- end
412
- end)
413
- defp escape_javascript_chunk(<<char::utf8, rest::bits>>, acc, original, skip, len)
414
- when char <= 0xFFFF do
415
- escape_javascript_chunk(rest, acc, original, skip, len + 3)
416
- end
417
- defp escape_javascript_chunk(<<_char::utf8, rest::bits>>, acc, original, skip, len) do
418
- escape_javascript_chunk(rest, acc, original, skip, len + 4)
419
- end
420
- defp escape_javascript_chunk(<<>>, acc, original, skip, len) do
421
- part = binary_part(original, skip, len)
422
- [acc | part]
423
- end
424
- defp escape_javascript_chunk(<<byte, _rest::bits>>, _acc, original, _skip, _len) do
425
- error({:invalid_byte, byte, original})
426
- end
427
-
428
- ## HTML safe JSON escape
429
-
430
- html_jt = Codegen.jump_table(html_ranges, :chunk, 0x7F + 1)
431
-
432
- defp escape_html(data, original, skip) do
433
- escape_html(data, [], original, skip)
434
- end
435
-
436
- Enum.map(html_jt, fn
437
- {byte, :chunk} ->
438
- defp escape_html(<<byte, rest::bits>>, acc, original, skip)
439
- when byte === unquote(byte) do
440
- escape_html_chunk(rest, acc, original, skip, 1)
441
- end
442
- {byte, _escape} ->
443
- defp escape_html(<<byte, rest::bits>>, acc, original, skip)
444
- when byte === unquote(byte) do
445
- acc = [acc | escape(byte)]
446
- escape_html(rest, acc, original, skip + 1)
447
- end
448
- end)
449
- defp escape_html(<<char::utf8, rest::bits>>, acc, original, skip)
450
- when char <= 0x7FF do
451
- escape_html_chunk(rest, acc, original, skip, 2)
452
- end
453
- Enum.map(surogate_escapes, fn {byte, escape} ->
454
- defp escape_html(<<unquote(byte)::utf8, rest::bits>>, acc, original, skip) do
455
- acc = [acc | unquote(escape)]
456
- escape_html(rest, acc, original, skip + 3)
457
- end
458
- end)
459
- defp escape_html(<<char::utf8, rest::bits>>, acc, original, skip)
460
- when char <= 0xFFFF do
461
- escape_html_chunk(rest, acc, original, skip, 3)
462
- end
463
- defp escape_html(<<_char::utf8, rest::bits>>, acc, original, skip) do
464
- escape_html_chunk(rest, acc, original, skip, 4)
465
- end
466
- defp escape_html(<<>>, acc, _original, _skip) do
467
- acc
468
- end
469
- defp escape_html(<<byte, _rest::bits>>, _acc, original, _skip) do
470
- error({:invalid_byte, byte, original})
471
- end
472
-
473
- Enum.map(html_jt, fn
474
- {byte, :chunk} ->
475
- defp escape_html_chunk(<<byte, rest::bits>>, acc, original, skip, len)
476
- when byte === unquote(byte) do
477
- escape_html_chunk(rest, acc, original, skip, len + 1)
478
- end
479
- {byte, _escape} ->
480
- defp escape_html_chunk(<<byte, rest::bits>>, acc, original, skip, len)
481
- when byte === unquote(byte) do
482
- part = binary_part(original, skip, len)
483
- acc = [acc, part | escape(byte)]
484
- escape_html(rest, acc, original, skip + len + 1)
485
- end
486
- end)
487
- defp escape_html_chunk(<<char::utf8, rest::bits>>, acc, original, skip, len)
488
- when char <= 0x7FF do
489
- escape_html_chunk(rest, acc, original, skip, len + 2)
490
- end
491
- Enum.map(surogate_escapes, fn {byte, escape} ->
492
- defp escape_html_chunk(<<unquote(byte)::utf8, rest::bits>>, acc, original, skip, len) do
493
- part = binary_part(original, skip, len)
494
- acc = [acc, part | unquote(escape)]
495
- escape_html(rest, acc, original, skip + len + 3)
496
- end
497
- end)
498
- defp escape_html_chunk(<<char::utf8, rest::bits>>, acc, original, skip, len)
499
- when char <= 0xFFFF do
500
- escape_html_chunk(rest, acc, original, skip, len + 3)
501
- end
502
- defp escape_html_chunk(<<_char::utf8, rest::bits>>, acc, original, skip, len) do
503
- escape_html_chunk(rest, acc, original, skip, len + 4)
504
- end
505
- defp escape_html_chunk(<<>>, acc, original, skip, len) do
506
- part = binary_part(original, skip, len)
507
- [acc | part]
508
- end
509
- defp escape_html_chunk(<<byte, _rest::bits>>, _acc, original, _skip, _len) do
510
- error({:invalid_byte, byte, original})
511
- end
512
-
513
- ## unicode escape
514
-
515
- defp escape_unicode(data, original, skip) do
516
- escape_unicode(data, [], original, skip)
517
- end
518
-
519
- Enum.map(json_jt, fn
520
- {byte, :chunk} ->
521
- defp escape_unicode(<<byte, rest::bits>>, acc, original, skip)
522
- when byte === unquote(byte) do
523
- escape_unicode_chunk(rest, acc, original, skip, 1)
524
- end
525
- {byte, _escape} ->
526
- defp escape_unicode(<<byte, rest::bits>>, acc, original, skip)
527
- when byte === unquote(byte) do
528
- acc = [acc | escape(byte)]
529
- escape_unicode(rest, acc, original, skip + 1)
530
- end
531
- end)
532
- defp escape_unicode(<<char::utf8, rest::bits>>, acc, original, skip)
533
- when char <= 0xFF do
534
- acc = [acc, "\\u00" | Integer.to_string(char, 16)]
535
- escape_unicode(rest, acc, original, skip + 2)
536
- end
537
- defp escape_unicode(<<char::utf8, rest::bits>>, acc, original, skip)
538
- when char <= 0x7FF do
539
- acc = [acc, "\\u0" | Integer.to_string(char, 16)]
540
- escape_unicode(rest, acc, original, skip + 2)
541
- end
542
- defp escape_unicode(<<char::utf8, rest::bits>>, acc, original, skip)
543
- when char <= 0xFFF do
544
- acc = [acc, "\\u0" | Integer.to_string(char, 16)]
545
- escape_unicode(rest, acc, original, skip + 3)
546
- end
547
- defp escape_unicode(<<char::utf8, rest::bits>>, acc, original, skip)
548
- when char <= 0xFFFF do
549
- acc = [acc, "\\u" | Integer.to_string(char, 16)]
550
- escape_unicode(rest, acc, original, skip + 3)
551
- end
552
- defp escape_unicode(<<char::utf8, rest::bits>>, acc, original, skip) do
553
- char = char - 0x10000
554
- acc =
555
- [
556
- acc,
557
- "\\uD", Integer.to_string(0x800 ||| (char >>> 10), 16),
558
- "\\uD" | Integer.to_string(0xC00 ||| (char &&& 0x3FF), 16)
559
- ]
560
- escape_unicode(rest, acc, original, skip + 4)
561
- end
562
- defp escape_unicode(<<>>, acc, _original, _skip) do
563
- acc
564
- end
565
- defp escape_unicode(<<byte, _rest::bits>>, _acc, original, _skip) do
566
- error({:invalid_byte, byte, original})
567
- end
568
-
569
- Enum.map(json_jt, fn
570
- {byte, :chunk} ->
571
- defp escape_unicode_chunk(<<byte, rest::bits>>, acc, original, skip, len)
572
- when byte === unquote(byte) do
573
- escape_unicode_chunk(rest, acc, original, skip, len + 1)
574
- end
575
- {byte, _escape} ->
576
- defp escape_unicode_chunk(<<byte, rest::bits>>, acc, original, skip, len)
577
- when byte === unquote(byte) do
578
- part = binary_part(original, skip, len)
579
- acc = [acc, part | escape(byte)]
580
- escape_unicode(rest, acc, original, skip + len + 1)
581
- end
582
- end)
583
- defp escape_unicode_chunk(<<char::utf8, rest::bits>>, acc, original, skip, len)
584
- when char <= 0xFF do
585
- part = binary_part(original, skip, len)
586
- acc = [acc, part, "\\u00" | Integer.to_string(char, 16)]
587
- escape_unicode(rest, acc, original, skip + len + 2)
588
- end
589
- defp escape_unicode_chunk(<<char::utf8, rest::bits>>, acc, original, skip, len)
590
- when char <= 0x7FF do
591
- part = binary_part(original, skip, len)
592
- acc = [acc, part, "\\u0" | Integer.to_string(char, 16)]
593
- escape_unicode(rest, acc, original, skip + len + 2)
594
- end
595
- defp escape_unicode_chunk(<<char::utf8, rest::bits>>, acc, original, skip, len)
596
- when char <= 0xFFF do
597
- part = binary_part(original, skip, len)
598
- acc = [acc, part, "\\u0" | Integer.to_string(char, 16)]
599
- escape_unicode(rest, acc, original, skip + len + 3)
600
- end
601
- defp escape_unicode_chunk(<<char::utf8, rest::bits>>, acc, original, skip, len)
602
- when char <= 0xFFFF do
603
- part = binary_part(original, skip, len)
604
- acc = [acc, part, "\\u" | Integer.to_string(char, 16)]
605
- escape_unicode(rest, acc, original, skip + len + 3)
606
- end
607
- defp escape_unicode_chunk(<<char::utf8, rest::bits>>, acc, original, skip, len) do
608
- char = char - 0x10000
609
- part = binary_part(original, skip, len)
610
- acc =
611
- [
612
- acc, part,
613
- "\\uD", Integer.to_string(0x800 ||| (char >>> 10), 16),
614
- "\\uD" | Integer.to_string(0xC00 ||| (char &&& 0x3FF), 16)
615
- ]
616
- escape_unicode(rest, acc, original, skip + len + 4)
617
- end
618
- defp escape_unicode_chunk(<<>>, acc, original, skip, len) do
619
- part = binary_part(original, skip, len)
620
- [acc | part]
621
- end
622
- defp escape_unicode_chunk(<<byte, _rest::bits>>, _acc, original, _skip, _len) do
623
- error({:invalid_byte, byte, original})
624
- end
625
-
626
- @compile {:inline, error: 1}
627
- defp error(error) do
628
- throw EncodeError.new(error)
629
- end
630
- end