dependabot-hex 0.119.0.beta1 → 0.119.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,634 +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
- case Map.to_list(value) do
101
- [] -> "{}"
102
- keyword -> encode_map.(keyword, escape, encode_map)
103
- end
104
- end
105
-
106
- def value(value, escape, encode_map) do
107
- Encoder.encode(value, {escape, encode_map})
108
- end
109
-
110
- @compile {:inline, integer: 1, float: 1}
111
-
112
- @spec atom(atom, opts) :: iodata
113
- def atom(atom, {escape, _encode_map}) do
114
- encode_atom(atom, escape)
115
- end
116
-
117
- defp encode_atom(nil, _escape), do: "null"
118
- defp encode_atom(true, _escape), do: "true"
119
- defp encode_atom(false, _escape), do: "false"
120
- defp encode_atom(atom, escape),
121
- do: encode_string(Atom.to_string(atom), escape)
122
-
123
- @spec integer(integer) :: iodata
124
- def integer(integer) do
125
- Integer.to_string(integer)
126
- end
127
-
128
- @spec float(float) :: iodata
129
- def float(float) do
130
- :io_lib_format.fwrite_g(float)
131
- end
132
-
133
- @spec list(list, opts) :: iodata
134
- def list(list, {escape, encode_map}) do
135
- list(list, escape, encode_map)
136
- end
137
-
138
- defp list([], _escape, _encode_map) do
139
- "[]"
140
- end
141
-
142
- defp list([head | tail], escape, encode_map) do
143
- [?[, value(head, escape, encode_map)
144
- | list_loop(tail, escape, encode_map)]
145
- end
146
-
147
- defp list_loop([], _escape, _encode_map) do
148
- ']'
149
- end
150
-
151
- defp list_loop([head | tail], escape, encode_map) do
152
- [?,, value(head, escape, encode_map)
153
- | list_loop(tail, escape, encode_map)]
154
- end
155
-
156
- @spec keyword(keyword, opts) :: iodata
157
- def keyword(list, _) when list == [], do: "{}"
158
- def keyword(list, {escape, encode_map}) when is_list(list) do
159
- encode_map.(list, escape, encode_map)
160
- end
161
-
162
- @spec map(map, opts) :: iodata
163
- def map(value, {escape, encode_map}) do
164
- case Map.to_list(value) do
165
- [] -> "{}"
166
- keyword -> encode_map.(keyword, escape, encode_map)
167
- end
168
- end
169
-
170
- defp map_naive([{key, value} | tail], escape, encode_map) do
171
- ["{\"", key(key, escape), "\":",
172
- value(value, escape, encode_map)
173
- | map_naive_loop(tail, escape, encode_map)]
174
- end
175
-
176
- defp map_naive_loop([], _escape, _encode_map) do
177
- '}'
178
- end
179
-
180
- defp map_naive_loop([{key, value} | tail], escape, encode_map) do
181
- [",\"", key(key, escape), "\":",
182
- value(value, escape, encode_map)
183
- | map_naive_loop(tail, escape, encode_map)]
184
- end
185
-
186
- defp map_strict([{key, value} | tail], escape, encode_map) do
187
- key = IO.iodata_to_binary(key(key, escape))
188
- visited = %{key => []}
189
- ["{\"", key, "\":",
190
- value(value, escape, encode_map)
191
- | map_strict_loop(tail, escape, encode_map, visited)]
192
- end
193
-
194
- defp map_strict_loop([], _encode_map, _escape, _visited) do
195
- '}'
196
- end
197
-
198
- defp map_strict_loop([{key, value} | tail], escape, encode_map, visited) do
199
- key = IO.iodata_to_binary(key(key, escape))
200
- case visited do
201
- %{^key => _} ->
202
- error({:duplicate_key, key})
203
- _ ->
204
- visited = Map.put(visited, key, [])
205
- [",\"", key, "\":",
206
- value(value, escape, encode_map)
207
- | map_strict_loop(tail, escape, encode_map, visited)]
208
- end
209
- end
210
-
211
- @spec struct(struct, opts) :: iodata
212
- def struct(%module{} = value, {escape, encode_map}) do
213
- struct(value, escape, encode_map, module)
214
- end
215
-
216
- # TODO: benchmark the effect of inlining the to_iso8601 functions
217
- for module <- [Date, Time, NaiveDateTime, DateTime] do
218
- defp struct(value, _escape, _encode_map, unquote(module)) do
219
- [?\", unquote(module).to_iso8601(value), ?\"]
220
- end
221
- end
222
-
223
- defp struct(value, _escape, _encode_map, Decimal) do
224
- # silence the xref warning
225
- decimal = Decimal
226
- [?\", decimal.to_string(value, :normal), ?\"]
227
- end
228
-
229
- defp struct(value, escape, encode_map, Fragment) do
230
- %{encode: encode} = value
231
- encode.({escape, encode_map})
232
- end
233
-
234
- defp struct(value, escape, encode_map, _module) do
235
- Encoder.encode(value, {escape, encode_map})
236
- end
237
-
238
- @doc false
239
- # This is used in the helpers and deriving implementation
240
- def key(string, escape) when is_binary(string) do
241
- escape.(string, string, 0)
242
- end
243
- def key(atom, escape) when is_atom(atom) do
244
- string = Atom.to_string(atom)
245
- escape.(string, string, 0)
246
- end
247
- def key(other, escape) do
248
- string = String.Chars.to_string(other)
249
- escape.(string, string, 0)
250
- end
251
-
252
- @spec string(String.t, opts) :: iodata
253
- def string(string, {escape, _encode_map}) do
254
- encode_string(string, escape)
255
- end
256
-
257
- defp encode_string(string, escape) do
258
- [?\", escape.(string, string, 0), ?\"]
259
- end
260
-
261
- slash_escapes = Enum.zip('\b\t\n\f\r\"\\', 'btnfr"\\')
262
- surogate_escapes = Enum.zip([0x2028, 0x2029], ["\\u2028", "\\u2029"])
263
- ranges = [{0x00..0x1F, :unicode} | slash_escapes]
264
- html_ranges = [{0x00..0x1F, :unicode}, {?<, :unicode}, {?/, ?/} | slash_escapes]
265
- escape_jt = Codegen.jump_table(html_ranges, :error)
266
-
267
- Enum.each(escape_jt, fn
268
- {byte, :unicode} ->
269
- sequence = List.to_string(:io_lib.format("\\u~4.16.0B", [byte]))
270
- defp escape(unquote(byte)), do: unquote(sequence)
271
- {byte, char} when is_integer(char) ->
272
- defp escape(unquote(byte)), do: unquote(<<?\\, char>>)
273
- {byte, :error} ->
274
- defp escape(unquote(byte)), do: throw(:error)
275
- end)
276
-
277
- ## regular JSON escape
278
-
279
- json_jt = Codegen.jump_table(ranges, :chunk, 0x7F + 1)
280
-
281
- defp escape_json(data, original, skip) do
282
- escape_json(data, [], original, skip)
283
- end
284
-
285
- Enum.map(json_jt, fn
286
- {byte, :chunk} ->
287
- defp escape_json(<<byte, rest::bits>>, acc, original, skip)
288
- when byte === unquote(byte) do
289
- escape_json_chunk(rest, acc, original, skip, 1)
290
- end
291
- {byte, _escape} ->
292
- defp escape_json(<<byte, rest::bits>>, acc, original, skip)
293
- when byte === unquote(byte) do
294
- acc = [acc | escape(byte)]
295
- escape_json(rest, acc, original, skip + 1)
296
- end
297
- end)
298
- defp escape_json(<<char::utf8, rest::bits>>, acc, original, skip)
299
- when char <= 0x7FF do
300
- escape_json_chunk(rest, acc, original, skip, 2)
301
- end
302
- defp escape_json(<<char::utf8, rest::bits>>, acc, original, skip)
303
- when char <= 0xFFFF do
304
- escape_json_chunk(rest, acc, original, skip, 3)
305
- end
306
- defp escape_json(<<_char::utf8, rest::bits>>, acc, original, skip) do
307
- escape_json_chunk(rest, acc, original, skip, 4)
308
- end
309
- defp escape_json(<<>>, acc, _original, _skip) do
310
- acc
311
- end
312
- defp escape_json(<<byte, _rest::bits>>, _acc, original, _skip) do
313
- error({:invalid_byte, byte, original})
314
- end
315
-
316
- Enum.map(json_jt, fn
317
- {byte, :chunk} ->
318
- defp escape_json_chunk(<<byte, rest::bits>>, acc, original, skip, len)
319
- when byte === unquote(byte) do
320
- escape_json_chunk(rest, acc, original, skip, len + 1)
321
- end
322
- {byte, _escape} ->
323
- defp escape_json_chunk(<<byte, rest::bits>>, acc, original, skip, len)
324
- when byte === unquote(byte) do
325
- part = binary_part(original, skip, len)
326
- acc = [acc, part | escape(byte)]
327
- escape_json(rest, acc, original, skip + len + 1)
328
- end
329
- end)
330
- defp escape_json_chunk(<<char::utf8, rest::bits>>, acc, original, skip, len)
331
- when char <= 0x7FF do
332
- escape_json_chunk(rest, acc, original, skip, len + 2)
333
- end
334
- defp escape_json_chunk(<<char::utf8, rest::bits>>, acc, original, skip, len)
335
- when char <= 0xFFFF do
336
- escape_json_chunk(rest, acc, original, skip, len + 3)
337
- end
338
- defp escape_json_chunk(<<_char::utf8, rest::bits>>, acc, original, skip, len) do
339
- escape_json_chunk(rest, acc, original, skip, len + 4)
340
- end
341
- defp escape_json_chunk(<<>>, acc, original, skip, len) do
342
- part = binary_part(original, skip, len)
343
- [acc | part]
344
- end
345
- defp escape_json_chunk(<<byte, _rest::bits>>, _acc, original, _skip, _len) do
346
- error({:invalid_byte, byte, original})
347
- end
348
-
349
- ## javascript safe JSON escape
350
-
351
- defp escape_javascript(data, original, skip) do
352
- escape_javascript(data, [], original, skip)
353
- end
354
-
355
- Enum.map(json_jt, fn
356
- {byte, :chunk} ->
357
- defp escape_javascript(<<byte, rest::bits>>, acc, original, skip)
358
- when byte === unquote(byte) do
359
- escape_javascript_chunk(rest, acc, original, skip, 1)
360
- end
361
- {byte, _escape} ->
362
- defp escape_javascript(<<byte, rest::bits>>, acc, original, skip)
363
- when byte === unquote(byte) do
364
- acc = [acc | escape(byte)]
365
- escape_javascript(rest, acc, original, skip + 1)
366
- end
367
- end)
368
- defp escape_javascript(<<char::utf8, rest::bits>>, acc, original, skip)
369
- when char <= 0x7FF do
370
- escape_javascript_chunk(rest, acc, original, skip, 2)
371
- end
372
- Enum.map(surogate_escapes, fn {byte, escape} ->
373
- defp escape_javascript(<<unquote(byte)::utf8, rest::bits>>, acc, original, skip) do
374
- acc = [acc | unquote(escape)]
375
- escape_javascript(rest, acc, original, skip + 3)
376
- end
377
- end)
378
- defp escape_javascript(<<char::utf8, rest::bits>>, acc, original, skip)
379
- when char <= 0xFFFF do
380
- escape_javascript_chunk(rest, acc, original, skip, 3)
381
- end
382
- defp escape_javascript(<<_char::utf8, rest::bits>>, acc, original, skip) do
383
- escape_javascript_chunk(rest, acc, original, skip, 4)
384
- end
385
- defp escape_javascript(<<>>, acc, _original, _skip) do
386
- acc
387
- end
388
- defp escape_javascript(<<byte, _rest::bits>>, _acc, original, _skip) do
389
- error({:invalid_byte, byte, original})
390
- end
391
-
392
- Enum.map(json_jt, fn
393
- {byte, :chunk} ->
394
- defp escape_javascript_chunk(<<byte, rest::bits>>, acc, original, skip, len)
395
- when byte === unquote(byte) do
396
- escape_javascript_chunk(rest, acc, original, skip, len + 1)
397
- end
398
- {byte, _escape} ->
399
- defp escape_javascript_chunk(<<byte, rest::bits>>, acc, original, skip, len)
400
- when byte === unquote(byte) do
401
- part = binary_part(original, skip, len)
402
- acc = [acc, part | escape(byte)]
403
- escape_javascript(rest, acc, original, skip + len + 1)
404
- end
405
- end)
406
- defp escape_javascript_chunk(<<char::utf8, rest::bits>>, acc, original, skip, len)
407
- when char <= 0x7FF do
408
- escape_javascript_chunk(rest, acc, original, skip, len + 2)
409
- end
410
- Enum.map(surogate_escapes, fn {byte, escape} ->
411
- defp escape_javascript_chunk(<<unquote(byte)::utf8, rest::bits>>, acc, original, skip, len) do
412
- part = binary_part(original, skip, len)
413
- acc = [acc, part | unquote(escape)]
414
- escape_javascript(rest, acc, original, skip + len + 3)
415
- end
416
- end)
417
- defp escape_javascript_chunk(<<char::utf8, rest::bits>>, acc, original, skip, len)
418
- when char <= 0xFFFF do
419
- escape_javascript_chunk(rest, acc, original, skip, len + 3)
420
- end
421
- defp escape_javascript_chunk(<<_char::utf8, rest::bits>>, acc, original, skip, len) do
422
- escape_javascript_chunk(rest, acc, original, skip, len + 4)
423
- end
424
- defp escape_javascript_chunk(<<>>, acc, original, skip, len) do
425
- part = binary_part(original, skip, len)
426
- [acc | part]
427
- end
428
- defp escape_javascript_chunk(<<byte, _rest::bits>>, _acc, original, _skip, _len) do
429
- error({:invalid_byte, byte, original})
430
- end
431
-
432
- ## HTML safe JSON escape
433
-
434
- html_jt = Codegen.jump_table(html_ranges, :chunk, 0x7F + 1)
435
-
436
- defp escape_html(data, original, skip) do
437
- escape_html(data, [], original, skip)
438
- end
439
-
440
- Enum.map(html_jt, fn
441
- {byte, :chunk} ->
442
- defp escape_html(<<byte, rest::bits>>, acc, original, skip)
443
- when byte === unquote(byte) do
444
- escape_html_chunk(rest, acc, original, skip, 1)
445
- end
446
- {byte, _escape} ->
447
- defp escape_html(<<byte, rest::bits>>, acc, original, skip)
448
- when byte === unquote(byte) do
449
- acc = [acc | escape(byte)]
450
- escape_html(rest, acc, original, skip + 1)
451
- end
452
- end)
453
- defp escape_html(<<char::utf8, rest::bits>>, acc, original, skip)
454
- when char <= 0x7FF do
455
- escape_html_chunk(rest, acc, original, skip, 2)
456
- end
457
- Enum.map(surogate_escapes, fn {byte, escape} ->
458
- defp escape_html(<<unquote(byte)::utf8, rest::bits>>, acc, original, skip) do
459
- acc = [acc | unquote(escape)]
460
- escape_html(rest, acc, original, skip + 3)
461
- end
462
- end)
463
- defp escape_html(<<char::utf8, rest::bits>>, acc, original, skip)
464
- when char <= 0xFFFF do
465
- escape_html_chunk(rest, acc, original, skip, 3)
466
- end
467
- defp escape_html(<<_char::utf8, rest::bits>>, acc, original, skip) do
468
- escape_html_chunk(rest, acc, original, skip, 4)
469
- end
470
- defp escape_html(<<>>, acc, _original, _skip) do
471
- acc
472
- end
473
- defp escape_html(<<byte, _rest::bits>>, _acc, original, _skip) do
474
- error({:invalid_byte, byte, original})
475
- end
476
-
477
- Enum.map(html_jt, fn
478
- {byte, :chunk} ->
479
- defp escape_html_chunk(<<byte, rest::bits>>, acc, original, skip, len)
480
- when byte === unquote(byte) do
481
- escape_html_chunk(rest, acc, original, skip, len + 1)
482
- end
483
- {byte, _escape} ->
484
- defp escape_html_chunk(<<byte, rest::bits>>, acc, original, skip, len)
485
- when byte === unquote(byte) do
486
- part = binary_part(original, skip, len)
487
- acc = [acc, part | escape(byte)]
488
- escape_html(rest, acc, original, skip + len + 1)
489
- end
490
- end)
491
- defp escape_html_chunk(<<char::utf8, rest::bits>>, acc, original, skip, len)
492
- when char <= 0x7FF do
493
- escape_html_chunk(rest, acc, original, skip, len + 2)
494
- end
495
- Enum.map(surogate_escapes, fn {byte, escape} ->
496
- defp escape_html_chunk(<<unquote(byte)::utf8, rest::bits>>, acc, original, skip, len) do
497
- part = binary_part(original, skip, len)
498
- acc = [acc, part | unquote(escape)]
499
- escape_html(rest, acc, original, skip + len + 3)
500
- end
501
- end)
502
- defp escape_html_chunk(<<char::utf8, rest::bits>>, acc, original, skip, len)
503
- when char <= 0xFFFF do
504
- escape_html_chunk(rest, acc, original, skip, len + 3)
505
- end
506
- defp escape_html_chunk(<<_char::utf8, rest::bits>>, acc, original, skip, len) do
507
- escape_html_chunk(rest, acc, original, skip, len + 4)
508
- end
509
- defp escape_html_chunk(<<>>, acc, original, skip, len) do
510
- part = binary_part(original, skip, len)
511
- [acc | part]
512
- end
513
- defp escape_html_chunk(<<byte, _rest::bits>>, _acc, original, _skip, _len) do
514
- error({:invalid_byte, byte, original})
515
- end
516
-
517
- ## unicode escape
518
-
519
- defp escape_unicode(data, original, skip) do
520
- escape_unicode(data, [], original, skip)
521
- end
522
-
523
- Enum.map(json_jt, fn
524
- {byte, :chunk} ->
525
- defp escape_unicode(<<byte, rest::bits>>, acc, original, skip)
526
- when byte === unquote(byte) do
527
- escape_unicode_chunk(rest, acc, original, skip, 1)
528
- end
529
- {byte, _escape} ->
530
- defp escape_unicode(<<byte, rest::bits>>, acc, original, skip)
531
- when byte === unquote(byte) do
532
- acc = [acc | escape(byte)]
533
- escape_unicode(rest, acc, original, skip + 1)
534
- end
535
- end)
536
- defp escape_unicode(<<char::utf8, rest::bits>>, acc, original, skip)
537
- when char <= 0xFF do
538
- acc = [acc, "\\u00" | Integer.to_string(char, 16)]
539
- escape_unicode(rest, acc, original, skip + 2)
540
- end
541
- defp escape_unicode(<<char::utf8, rest::bits>>, acc, original, skip)
542
- when char <= 0x7FF do
543
- acc = [acc, "\\u0" | Integer.to_string(char, 16)]
544
- escape_unicode(rest, acc, original, skip + 2)
545
- end
546
- defp escape_unicode(<<char::utf8, rest::bits>>, acc, original, skip)
547
- when char <= 0xFFF do
548
- acc = [acc, "\\u0" | Integer.to_string(char, 16)]
549
- escape_unicode(rest, acc, original, skip + 3)
550
- end
551
- defp escape_unicode(<<char::utf8, rest::bits>>, acc, original, skip)
552
- when char <= 0xFFFF do
553
- acc = [acc, "\\u" | Integer.to_string(char, 16)]
554
- escape_unicode(rest, acc, original, skip + 3)
555
- end
556
- defp escape_unicode(<<char::utf8, rest::bits>>, acc, original, skip) do
557
- char = char - 0x10000
558
- acc =
559
- [
560
- acc,
561
- "\\uD", Integer.to_string(0x800 ||| (char >>> 10), 16),
562
- "\\uD" | Integer.to_string(0xC00 ||| (char &&& 0x3FF), 16)
563
- ]
564
- escape_unicode(rest, acc, original, skip + 4)
565
- end
566
- defp escape_unicode(<<>>, acc, _original, _skip) do
567
- acc
568
- end
569
- defp escape_unicode(<<byte, _rest::bits>>, _acc, original, _skip) do
570
- error({:invalid_byte, byte, original})
571
- end
572
-
573
- Enum.map(json_jt, fn
574
- {byte, :chunk} ->
575
- defp escape_unicode_chunk(<<byte, rest::bits>>, acc, original, skip, len)
576
- when byte === unquote(byte) do
577
- escape_unicode_chunk(rest, acc, original, skip, len + 1)
578
- end
579
- {byte, _escape} ->
580
- defp escape_unicode_chunk(<<byte, rest::bits>>, acc, original, skip, len)
581
- when byte === unquote(byte) do
582
- part = binary_part(original, skip, len)
583
- acc = [acc, part | escape(byte)]
584
- escape_unicode(rest, acc, original, skip + len + 1)
585
- end
586
- end)
587
- defp escape_unicode_chunk(<<char::utf8, rest::bits>>, acc, original, skip, len)
588
- when char <= 0xFF do
589
- part = binary_part(original, skip, len)
590
- acc = [acc, part, "\\u00" | Integer.to_string(char, 16)]
591
- escape_unicode(rest, acc, original, skip + len + 2)
592
- end
593
- defp escape_unicode_chunk(<<char::utf8, rest::bits>>, acc, original, skip, len)
594
- when char <= 0x7FF do
595
- part = binary_part(original, skip, len)
596
- acc = [acc, part, "\\u0" | Integer.to_string(char, 16)]
597
- escape_unicode(rest, acc, original, skip + len + 2)
598
- end
599
- defp escape_unicode_chunk(<<char::utf8, rest::bits>>, acc, original, skip, len)
600
- when char <= 0xFFF do
601
- part = binary_part(original, skip, len)
602
- acc = [acc, part, "\\u0" | Integer.to_string(char, 16)]
603
- escape_unicode(rest, acc, original, skip + len + 3)
604
- end
605
- defp escape_unicode_chunk(<<char::utf8, rest::bits>>, acc, original, skip, len)
606
- when char <= 0xFFFF do
607
- part = binary_part(original, skip, len)
608
- acc = [acc, part, "\\u" | Integer.to_string(char, 16)]
609
- escape_unicode(rest, acc, original, skip + len + 3)
610
- end
611
- defp escape_unicode_chunk(<<char::utf8, rest::bits>>, acc, original, skip, len) do
612
- char = char - 0x10000
613
- part = binary_part(original, skip, len)
614
- acc =
615
- [
616
- acc, part,
617
- "\\uD", Integer.to_string(0x800 ||| (char >>> 10), 16),
618
- "\\uD" | Integer.to_string(0xC00 ||| (char &&& 0x3FF), 16)
619
- ]
620
- escape_unicode(rest, acc, original, skip + len + 4)
621
- end
622
- defp escape_unicode_chunk(<<>>, acc, original, skip, len) do
623
- part = binary_part(original, skip, len)
624
- [acc | part]
625
- end
626
- defp escape_unicode_chunk(<<byte, _rest::bits>>, _acc, original, _skip, _len) do
627
- error({:invalid_byte, byte, original})
628
- end
629
-
630
- @compile {:inline, error: 1}
631
- defp error(error) do
632
- throw EncodeError.new(error)
633
- end
634
- end