dependabot-hex 0.119.0.beta1 → 0.119.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -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