• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

ahamez / protox / e15af0256f3f71593a1665002110d365d8c4b084

20 Jan 2025 08:42AM UTC coverage: 94.55%. Remained the same
e15af0256f3f71593a1665002110d365d8c4b084

push

github

ahamez
refactor: reify scalar kind

26 of 26 new or added lines in 5 files covered. (100.0%)

9 existing lines in 3 files now uncovered.

746 of 789 relevant lines covered (94.55%)

19117.59 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

95.38
/lib/protox/define_decoder.ex
1
defmodule Protox.DefineDecoder do
2
  @moduledoc false
3
  # Internal. Generates the decoder of a message.
4

5
  alias Protox.{Field, Scalar}
6
  use Protox.{Float, WireTypes}
7

8
  def define(msg_name, fields, required_fields, opts \\ []) do
9
    vars = %{
90✔
10
      bytes: Macro.var(:bytes, __MODULE__),
11
      delimited: Macro.var(:delimited, __MODULE__),
12
      field: Macro.var(:field, __MODULE__),
13
      msg: Macro.var(:msg, __MODULE__),
14
      rest: Macro.var(:rest, __MODULE__),
15
      set_fields: Macro.var(:set_fields, __MODULE__),
16
      value: Macro.var(:value, __MODULE__)
17
    }
18

19
    # The public function to decode the binary protobuf.
20
    decode_fun = make_decode_fun(required_fields, msg_name, vars)
90✔
21

22
    # The function that decodes the binary protobuf and possibly dispatches to other decoding
23
    # functions.
24
    parse_key_value_fun = make_parse_key_value_fun(required_fields, fields, vars, opts)
90✔
25

26
    # The functions that decodes maps.
27
    parse_map_entries = make_parse_map_entries_funs(vars, fields)
90✔
28

29
    quote do
30
      unquote(decode_fun)
31
      unquote(parse_key_value_fun)
32
      unquote(parse_map_entries)
33
    end
34
  end
35

36
  defp make_decode_fun(required_fields, msg_name, vars) do
37
    decode_bang_fun = make_decode_bang_fun(required_fields, msg_name, vars)
90✔
38

39
    quote do
40
      @spec decode(binary()) :: {:ok, struct()} | {:error, any()}
41
      def decode(bytes) do
42
        try do
43
          {:ok, decode!(bytes)}
44
        rescue
45
          e in [Protox.DecodingError, Protox.IllegalTagError, Protox.RequiredFieldsError] ->
46
            {:error, e}
47
        end
48
      end
49

50
      unquote(decode_bang_fun)
51
    end
52
  end
53

54
  defp make_decode_bang_fun([], msg_name, _vars) do
55
    quote do
56
      @spec decode!(binary()) :: struct() | no_return()
57
      def decode!(bytes) do
58
        parse_key_value(bytes, struct(unquote(msg_name)))
59
      end
60
    end
61
  end
62

63
  defp make_decode_bang_fun(required_fields, msg_name, vars) do
64
    quote do
65
      @spec decode!(binary()) :: struct() | no_return()
66
      def decode!(bytes) do
67
        {msg, unquote(vars.set_fields)} = parse_key_value([], bytes, struct(unquote(msg_name)))
5✔
68

69
        case unquote(required_fields) -- unquote(vars.set_fields) do
5✔
70
          [] -> msg
71
          missing_fields -> raise Protox.RequiredFieldsError.new(missing_fields)
72
        end
73
      end
74
    end
75
  end
76

77
  defp make_parse_key_value_fun(required_fields, fields, vars, opts) do
78
    keep_set_fields = required_fields != []
90✔
79

80
    parse_key_value_body =
90✔
81
      make_parse_key_value_body(keep_set_fields, fields, vars, opts)
82

83
    if keep_set_fields do
90✔
84
      quote do
85
        @spec parse_key_value([atom()], binary(), struct()) :: {struct(), [atom()]}
86
        defp parse_key_value(unquote(vars.set_fields), <<>>, msg) do
5✔
87
          {msg, unquote(vars.set_fields)}
5✔
88
        end
89

90
        defp parse_key_value(unquote(vars.set_fields), bytes, msg) do
5✔
91
          unquote(parse_key_value_body)
92
        end
93
      end
94
    else
95
      quote do
96
        @spec parse_key_value(binary(), struct()) :: struct()
97
        defp parse_key_value(<<>>, msg), do: msg
98

99
        defp parse_key_value(bytes, msg), do: unquote(parse_key_value_body)
100
      end
101
    end
102
  end
103

104
  defp make_parse_key_value_body(keep_set_fields, fields, vars, opts) do
105
    # Fragment to handle the (invalid) field with tag 0.
106
    tag_0_case = make_parse_key_value_tag_0()
90✔
107

108
    # Fragment to parse unknown fields. Those are identified with an unknown tag.
109
    unknown_fields_name = Keyword.fetch!(opts, :unknown_fields_name)
90✔
110

111
    unknown_tag_case =
90✔
112
      make_parse_key_value_unknown(
113
        vars,
114
        keep_set_fields,
115
        unknown_fields_name
116
      )
117

118
    # Fragment to parse known fields.
119
    known_tags_case = make_parse_key_value_known(vars, fields, keep_set_fields)
90✔
120

121
    all_cases = tag_0_case ++ known_tags_case ++ unknown_tag_case
90✔
122

123
    if keep_set_fields do
90✔
124
      quote do
125
        {new_set_fields, unquote(vars.field), rest} =
5✔
126
          case Protox.Decode.parse_key(bytes) do
127
            unquote(all_cases)
128
          end
129

130
        msg_updated = struct(unquote(vars.msg), unquote(vars.field))
5✔
131
        parse_key_value(new_set_fields, rest, msg_updated)
132
      end
133
    else
134
      quote do
135
        {unquote(vars.field), rest} =
85✔
136
          case Protox.Decode.parse_key(bytes) do
137
            unquote(all_cases)
138
          end
139

140
        msg_updated = struct(unquote(vars.msg), unquote(vars.field))
85✔
141
        parse_key_value(rest, msg_updated)
142
      end
143
    end
144
  end
145

146
  defp make_parse_key_value_tag_0() do
90✔
147
    quote do
148
      {0, _, _} -> raise %Protox.IllegalTagError{}
149
    end
150
  end
151

152
  defp make_parse_key_value_known(vars, fields, keep_set_fields) do
153
    Enum.flat_map(fields, fn %Field{} = field ->
90✔
154
      single = make_single_case(vars, keep_set_fields, field)
975✔
155

156
      single_generated = single != []
975✔
157
      delimited = make_delimited_case(vars, keep_set_fields, single_generated, field)
975✔
158

159
      delimited ++ single
975✔
160
    end)
161
  end
162

163
  defp make_parse_key_value_unknown(vars, keep_set_fields, unknown_fields_name) do
164
    body =
90✔
165
      quote do
166
        {
167
          unquote(unknown_fields_name),
168
          # Order is important here, we want to keep the order of the unknown fields.
169
          unquote(vars.msg).unquote(unknown_fields_name) ++ [unquote(vars.value)]
90✔
170
        }
171
      end
172

173
    case_return =
90✔
174
      case keep_set_fields do
175
        true -> quote(do: {unquote(vars.set_fields), [unquote(body)], rest})
5✔
176
        # No need to maintain a list of set fields when the list of required fields is empty
177
        false -> quote(do: {[unquote(body)], rest})
85✔
178
      end
179

180
    quote do
181
      {tag, wire_type, rest} ->
182
        {unquote(vars.value), rest} = Protox.Decode.parse_unknown(tag, wire_type, rest)
90✔
183

184
        unquote(case_return)
185
    end
186
  end
187

188
  defp make_single_case(_vars, _keep_set_fields, %Field{type: {:message, _}}) do
225✔
189
    quote(do: [])
190
  end
191

192
  defp make_single_case(_vars, _keep_set_fields, %Field{type: :string}), do: quote(do: [])
105✔
193
  defp make_single_case(_vars, _keep_set_fields, %Field{type: :bytes}), do: quote(do: [])
20✔
194

195
  defp make_single_case(_vars, _keep_set_fields, %Field{type: {x, _}}) when x != :enum do
95✔
196
    quote(do: [])
197
  end
198

199
  defp make_single_case(vars, keep_set_fields, %Field{} = field) do
200
    parse_single = make_parse_single(vars.bytes, field.type)
530✔
201
    update_field = make_update_field(vars.value, field, vars, _wrap_value = true)
530✔
202

203
    # No need to maintain a list of set fields for proto3
204
    case_return =
530✔
205
      case keep_set_fields do
206
        true ->
207
          quote do: {[unquote(field.name) | set_fields], [unquote(update_field)], rest}
5✔
208

209
        false ->
525✔
210
          quote do: {[unquote(update_field)], rest}
211
      end
212

213
    quote do
214
      {unquote(field.tag), _, unquote(vars.bytes)} ->
530✔
215
        {value, rest} = unquote(parse_single)
216
        unquote(case_return)
217
    end
218
  end
219

220
  defp make_delimited_case(
221
         vars,
222
         keep_set_fields,
223
         single_generated,
224
         %Field{type: {:message, _}} = field
225
       ) do
226
    make_delimited_case_impl(vars, keep_set_fields, single_generated, field)
225✔
227
  end
228

229
  defp make_delimited_case(vars, keep_set_fields, single_generated, %Field{type: :bytes} = field) do
230
    make_delimited_case_impl(vars, keep_set_fields, single_generated, field)
20✔
231
  end
232

233
  defp make_delimited_case(vars, keep_set_fields, single_generated, %Field{type: :string} = field) do
234
    make_delimited_case_impl(vars, keep_set_fields, single_generated, field)
105✔
235
  end
236

237
  defp make_delimited_case(_vars, _keep_set_fields, _single_generated, %Field{kind: %Scalar{}}) do
280✔
238
    []
239
  end
240

241
  defp make_delimited_case(_vars, _keep_set_fields, _single_generated, %Field{kind: {:oneof, _}}) do
35✔
242
    []
243
  end
244

245
  defp make_delimited_case(vars, keep_set_fields, single_generated, %Field{} = field) do
246
    make_delimited_case_impl(vars, keep_set_fields, single_generated, field)
310✔
247
  end
248

249
  defp make_delimited_case_impl(vars, keep_set_fields, single_generated, %Field{} = field) do
250
    # If the case to decode single occurrences of repeated elements has been generated,
251
    # it means that it's a repeated field of scalar elements (as non-scalar cannot be packed,
252
    # see https://developers.google.com/protocol-buffers/docs/encoding#optional).
253
    # Thus, it's useless to wrap in a list the result of the decoding as it means
254
    # we're using a parse_repeated_* function that always returns a list.
255
    update_field =
660✔
256
      if field.type == :bytes do
660✔
257
        make_update_field(vars.delimited, field, vars, _wrap_value = !single_generated)
20✔
258
      else
259
        parse_delimited = make_parse_delimited(vars.delimited, field.type)
640✔
260
        make_update_field(parse_delimited, field, vars, _wrap_value = !single_generated)
640✔
261
      end
262

263
    case_return =
660✔
264
      case keep_set_fields do
265
        true -> quote do: {[unquote(field.name) | set_fields], [unquote(update_field)], rest}
5✔
266
        false -> quote do: {[unquote(update_field)], rest}
655✔
267
      end
268

269
    # If `single` was not generated, then we don't need the `@wire_delimited discrimant
270
    # as there is only one clause for this `tag`.
271
    wire_type =
660✔
272
      case single_generated do
273
        true -> quote do: unquote(@wire_delimited)
215✔
274
        false -> quote do: _
275
      end
276

277
    quote do
278
      {unquote(field.tag), unquote(wire_type), unquote(vars.bytes)} ->
660✔
279
        {len, unquote(vars.bytes)} = Protox.Varint.decode(unquote(vars.bytes))
660✔
280
        {unquote(vars.delimited), rest} = Protox.Decode.parse_delimited(unquote(vars.bytes), len)
660✔
281
        unquote(case_return)
282
    end
283
  end
284

285
  defp make_update_field(value, %Field{kind: :map} = field, vars, _wrap_value) do
286
    quote do
287
      {entry_key, entry_value} = unquote(value)
288

289
      {unquote(field.name),
95✔
290
       Map.put(unquote(vars.msg).unquote(field.name), entry_key, entry_value)}
95✔
291
    end
292
  end
293

294
  defp make_update_field(
295
         value,
296
         %Field{label: :proto3_optional, kind: {:oneof, _}, type: {:message, _}} = field,
297
         vars,
298
         _wrap_value
299
       ) do
300
    quote do
UNCOV
301
      case unquote(vars.msg).unquote(field.name) do
×
302
        {unquote(field.name), previous_value} ->
×
UNCOV
303
          {unquote(field.name), Protox.MergeMessage.merge(previous_value, unquote(value))}
×
304

305
        _ ->
UNCOV
306
          {unquote(field.name), unquote(value)}
×
307
      end
308
    end
309
  end
310

311
  defp make_update_field(
312
         value,
313
         %Field{kind: {:oneof, parent_field}, type: {:message, _}} = field,
314
         vars,
315
         _wrap_value
316
       ) do
317
    quote do
318
      case unquote(vars.msg).unquote(parent_field) do
5✔
319
        {unquote(field.name), previous_value} ->
5✔
320
          {unquote(parent_field),
321
           {unquote(field.name), Protox.MergeMessage.merge(previous_value, unquote(value))}}
5✔
322

323
        _ ->
324
          {unquote(parent_field), {unquote(field.name), unquote(value)}}
5✔
325
      end
326
    end
327
  end
328

329
  defp make_update_field(value, %Field{kind: {:oneof, parent_field}} = field, _vars, _wrap_value) do
330
    case field.label do
45✔
UNCOV
331
      :proto3_optional ->
×
UNCOV
332
        quote(do: {unquote(field.name), unquote(value)})
×
333

334
      _ ->
45✔
335
        quote(do: {unquote(parent_field), {unquote(field.name), unquote(value)}})
45✔
336
    end
337
  end
338

339
  defp make_update_field(
120✔
340
         value,
341
         %Field{kind: %Scalar{}, type: {:message, _}} = field,
342
         vars,
343
         _wrap_value
344
       ) do
345
    quote do
346
      {
347
        unquote(field.name),
120✔
348
        Protox.MergeMessage.merge(unquote(vars.msg).unquote(field.name), unquote(value))
120✔
349
      }
350
    end
351
  end
352

353
  defp make_update_field(value, %Field{kind: %Scalar{}} = field, _vars, _wrap_value) do
375✔
354
    quote(do: {unquote(field.name), unquote(value)})
375✔
355
  end
356

357
  defp make_update_field(value, %Field{} = field, vars, true = _wrap_value) do
335✔
358
    quote do
359
      {unquote(field.name), unquote(vars.msg).unquote(field.name) ++ [unquote(value)]}
335✔
360
    end
361
  end
362

363
  defp make_update_field(value, %Field{} = field, vars, false = _wrap_value) do
215✔
364
    quote do
365
      {unquote(field.name), unquote(vars.msg).unquote(field.name) ++ unquote(value)}
215✔
366
    end
367
  end
368

369
  defp make_parse_delimited(bytes_var, :bytes) do
370
    quote(do: unquote(bytes_var))
5✔
371
  end
372

373
  defp make_parse_delimited(bytes_var, :string) do
374
    quote(do: Protox.Decode.validate_string!(unquote(bytes_var)))
375
  end
376

377
  defp make_parse_delimited(bytes_var, {:enum, mod}) do
378
    quote(do: Protox.Decode.parse_repeated_enum([], unquote(bytes_var), unquote(mod)))
379
  end
380

381
  defp make_parse_delimited(bytes_var, {:message, mod}) do
382
    quote(do: unquote(mod).decode!(unquote(bytes_var)))
383
  end
384

385
  defp make_parse_delimited(bytes_var, :bool) do
386
    quote(do: Protox.Decode.parse_repeated_bool([], unquote(bytes_var)))
387
  end
388

389
  defp make_parse_delimited(bytes_var, :int32) do
390
    quote(do: Protox.Decode.parse_repeated_int32([], unquote(bytes_var)))
391
  end
392

393
  defp make_parse_delimited(bytes_var, :uint32) do
394
    quote(do: Protox.Decode.parse_repeated_uint32([], unquote(bytes_var)))
395
  end
396

397
  defp make_parse_delimited(bytes_var, :sint32) do
398
    quote(do: Protox.Decode.parse_repeated_sint32([], unquote(bytes_var)))
399
  end
400

401
  defp make_parse_delimited(bytes_var, :int64) do
402
    quote(do: Protox.Decode.parse_repeated_int64([], unquote(bytes_var)))
403
  end
404

405
  defp make_parse_delimited(bytes_var, :uint64) do
406
    quote(do: Protox.Decode.parse_repeated_uint64([], unquote(bytes_var)))
407
  end
408

409
  defp make_parse_delimited(bytes_var, :sint64) do
410
    quote(do: Protox.Decode.parse_repeated_sint64([], unquote(bytes_var)))
411
  end
412

413
  defp make_parse_delimited(bytes_var, :fixed32) do
414
    quote(do: Protox.Decode.parse_repeated_fixed32([], unquote(bytes_var)))
415
  end
416

417
  defp make_parse_delimited(bytes_var, :fixed64) do
418
    quote(do: Protox.Decode.parse_repeated_fixed64([], unquote(bytes_var)))
419
  end
420

421
  defp make_parse_delimited(bytes_var, :sfixed32) do
422
    quote(do: Protox.Decode.parse_repeated_sfixed32([], unquote(bytes_var)))
423
  end
424

425
  defp make_parse_delimited(bytes_var, :sfixed64) do
426
    quote(do: Protox.Decode.parse_repeated_sfixed64([], unquote(bytes_var)))
427
  end
428

429
  defp make_parse_delimited(bytes_var, :float) do
430
    quote(do: Protox.Decode.parse_repeated_float([], unquote(bytes_var)))
431
  end
432

433
  defp make_parse_delimited(bytes_var, :double) do
434
    quote(do: Protox.Decode.parse_repeated_double([], unquote(bytes_var)))
435
  end
436

437
  defp make_parse_delimited(bytes_var, {key_type, value_type}) do
438
    unset_map_value =
95✔
439
      case value_type do
440
        {:message, msg_type} -> quote(do: struct(unquote(msg_type)))
441
        _ -> quote(do: Protox.Default.default(unquote(value_type)))
442
      end
443

444
    parser_fun_name = make_map_decode_fun_name(key_type, value_type)
95✔
445

446
    quote do
447
      {map_key, map_value} = unquote(parser_fun_name)({:unset, :unset}, unquote(bytes_var))
448

449
      map_key =
450
        case map_key do
451
          :unset -> Protox.Default.default(unquote(key_type))
452
          _ -> map_key
453
        end
454

455
      map_value =
456
        case map_value do
457
          :unset -> unquote(unset_map_value)
458
          _ -> map_value
459
        end
460

461
      {map_key, map_value}
462
    end
463
  end
464

465
  defp make_parse_single(bytes_var, :double) do
466
    quote(do: Protox.Decode.parse_double(unquote(bytes_var)))
467
  end
468

469
  defp make_parse_single(bytes_var, :float) do
470
    quote(do: Protox.Decode.parse_float(unquote(bytes_var)))
471
  end
472

473
  defp make_parse_single(bytes_var, :sfixed64) do
474
    quote(do: Protox.Decode.parse_sfixed64(unquote(bytes_var)))
475
  end
476

477
  defp make_parse_single(bytes_var, :fixed64) do
478
    quote(do: Protox.Decode.parse_fixed64(unquote(bytes_var)))
479
  end
480

481
  defp make_parse_single(bytes_var, :sfixed32) do
482
    quote(do: Protox.Decode.parse_sfixed32(unquote(bytes_var)))
483
  end
484

485
  defp make_parse_single(bytes_var, :fixed32) do
486
    quote(do: Protox.Decode.parse_fixed32(unquote(bytes_var)))
487
  end
488

489
  defp make_parse_single(bytes_var, :bool) do
490
    quote(do: Protox.Decode.parse_bool(unquote(bytes_var)))
491
  end
492

493
  defp make_parse_single(bytes_var, :sint32) do
494
    quote(do: Protox.Decode.parse_sint32(unquote(bytes_var)))
495
  end
496

497
  defp make_parse_single(bytes_var, :sint64) do
498
    quote(do: Protox.Decode.parse_sint64(unquote(bytes_var)))
499
  end
500

501
  defp make_parse_single(bytes_var, :uint32) do
502
    quote(do: Protox.Decode.parse_uint32(unquote(bytes_var)))
503
  end
504

505
  defp make_parse_single(bytes_var, :uint64) do
506
    quote(do: Protox.Decode.parse_uint64(unquote(bytes_var)))
507
  end
508

509
  defp make_parse_single(bytes_var, :int32) do
510
    quote(do: Protox.Decode.parse_int32(unquote(bytes_var)))
511
  end
512

513
  defp make_parse_single(bytes_var, :int64) do
514
    quote(do: Protox.Decode.parse_int64(unquote(bytes_var)))
515
  end
516

517
  defp make_parse_single(bytes_var, {:enum, mod}) do
518
    quote(do: Protox.Decode.parse_enum(unquote(bytes_var), unquote(mod)))
519
  end
520

521
  defp make_parse_map_entries_funs(vars, fields) do
522
    {maps, _other_fields} = Protox.Defs.split_maps(fields)
90✔
523

524
    maps
525
    |> Enum.map(fn %Field{kind: :map} = field ->
526
      key_type = elem(field.type, 0)
95✔
527
      value_type = elem(field.type, 1)
95✔
528

529
      fun_name = make_map_decode_fun_name(key_type, value_type)
95✔
530

531
      key_parser = make_parse_map_entry(vars, key_type)
95✔
532
      value_parser = make_parse_map_entry(vars, value_type)
95✔
533

534
      code =
95✔
535
        quote do
536
          defp unquote(fun_name)(map_entry, <<>>) do
537
            map_entry
538
          end
539

540
          # https://developers.google.com/protocol-buffers/docs/proto3#backwards-compatibility
541
          # Maps are equivalent to:
542
          #   message MapFieldEntry {
543
          #     key_type key = 1;
544
          #     value_type value = 2;
545
          #   }
546
          # repeated MapFieldEntry map_field = N;
547
          #
548
          defp unquote(fun_name)({entry_key, entry_value}, unquote(vars.bytes)) do
95✔
549
            {map_entry, unquote(vars.rest)} =
95✔
550
              case Protox.Decode.parse_key(unquote(vars.bytes)) do
95✔
551
                # key
552
                {1, _, unquote(vars.rest)} ->
95✔
553
                  {res, unquote(vars.rest)} = unquote(key_parser)
95✔
554
                  {{res, entry_value}, unquote(vars.rest)}
95✔
555

556
                # value
557
                {2, _, unquote(vars.rest)} ->
95✔
558
                  {res, unquote(vars.rest)} = unquote(value_parser)
95✔
559
                  {{entry_key, res}, unquote(vars.rest)}
95✔
560

561
                {tag, wire_type, unquote(vars.rest)} ->
95✔
562
                  {_, unquote(vars.rest)} =
95✔
563
                    Protox.Decode.parse_unknown(tag, wire_type, unquote(vars.rest))
95✔
564

565
                  {{entry_key, entry_value}, unquote(vars.rest)}
95✔
566
              end
567

568
            unquote(fun_name)(map_entry, unquote(vars.rest))
95✔
569
          end
570
        end
571

572
      {fun_name, code}
573
    end)
574
    |> Enum.sort(fn {lhs_fun_name, _}, {rhs_fun_name, _} -> lhs_fun_name < rhs_fun_name end)
355✔
575
    |> Enum.dedup_by(fn {fun_name, _} -> fun_name end)
95✔
576
    |> Enum.map(fn {_, code} -> code end)
90✔
577
  end
578

579
  defp make_map_decode_fun_name(key_type, value_type) do
580
    value_name =
190✔
581
      case value_type do
582
        {:message, sub_msg} -> "msg_#{Atom.to_string(sub_msg)}"
20✔
583
        {:enum, enum} -> "enum_#{Atom.to_string(enum)}"
20✔
584
        ty -> "#{Atom.to_string(ty)}"
150✔
585
      end
586

587
    value_name =
190✔
588
      value_name
589
      |> Macro.underscore()
590
      |> String.replace("/", "_")
591

592
    String.to_atom("parse_#{Atom.to_string(key_type)}_#{value_name}")
190✔
593
  end
594

595
  defp make_parse_map_entry(vars, type) do
596
    parse_delimited =
190✔
597
      quote do
598
        {len, new_rest} = Protox.Varint.decode(unquote(vars.rest))
190✔
599
        {unquote(vars.delimited), new_rest} = Protox.Decode.parse_delimited(new_rest, len)
190✔
600

601
        {unquote(make_parse_delimited(vars.delimited, type)), new_rest}
190✔
602
      end
603

604
    case type do
190✔
605
      :string -> parse_delimited
35✔
606
      :bytes -> parse_delimited
5✔
607
      {:message, _} -> parse_delimited
10✔
608
      _ -> make_parse_single(vars.rest, type)
140✔
609
    end
610
  end
611
end
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc