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

ahamez / protox / 4aa0551b8521800478ca0097bfe866a750fd1124

11 Feb 2025 12:51PM UTC coverage: 95.188% (+0.2%) from 94.965%
4aa0551b8521800478ca0097bfe866a750fd1124

push

github

ahamez
test: test more cases for optional fields in proto3

811 of 852 relevant lines covered (95.19%)

12516.37 hits per line

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

96.03
/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, OneOf, Scalar}
6
  use Protox.{Float, WireTypes}
7

8
  def define(msg_name, 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(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(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_splicing(parse_map_entries)
33
    end
34
  end
35

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

39
    quote do
40
      @spec decode(binary()) :: {:ok, t()} | {: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()) :: t() | 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_parse_key_value_fun(fields, vars, opts) do
64
    parse_key_value_body =
90✔
65
      make_parse_key_value_body(fields, vars, opts)
66

67
    quote do
68
      @spec parse_key_value(binary(), struct()) :: struct()
69
      defp parse_key_value(<<>>, msg), do: msg
70

71
      defp parse_key_value(bytes, msg), do: unquote(parse_key_value_body)
72
    end
73
  end
74

75
  defp make_parse_key_value_body(fields, vars, opts) do
76
    # Fragment to parse unknown fields. Those are identified with an unknown tag.
77
    unknown_tag_clause =
90✔
78
      make_parse_key_value_unknown(vars, Keyword.fetch!(opts, :unknown_fields_name))
79

80
    # Fragment to parse all regular fields.
81
    all_fields_clause = make_parse_key_value_known(vars, fields)
90✔
82

83
    all_clauses =
90✔
84
      make_parse_key_value_invalid_varint() ++
85
        make_parse_key_value_tag_0() ++
86
        all_fields_clause ++
87
        unknown_tag_clause
88

89
    # Note we directly pattern-match against the bytes: we don't decode the tag
90
    # and the wire type using Varint.decode. Indeed, as we know the varint encoding
91
    # at compile time, we can generate the appropriate clauses.
92
    # This has the benefit of a small speedup (~1%-10%) and a decrease in memory usage (~10%) from
93
    # the Varint.decode version.
94
    quote do
95
      {unquote(vars.field), rest} =
90✔
96
        case bytes, do: unquote(all_clauses)
97

98
      msg_updated = struct(unquote(vars.msg), unquote(vars.field))
90✔
99
      parse_key_value(rest, msg_updated)
100
    end
101
  end
102

103
  defp make_parse_key_value_tag_0() do
90✔
104
    quote do
105
      <<0::5, _::3, _rest::binary>> -> raise %Protox.IllegalTagError{}
106
    end
107
  end
108

109
  defp make_parse_key_value_invalid_varint() do
90✔
110
    quote do
111
      <<_::5, 3::3, _rest::binary>> ->
112
        raise Protox.DecodingError.new(bytes, "invalid wire type 3")
113

114
      <<_::5, 4::3, _rest::binary>> ->
115
        raise Protox.DecodingError.new(bytes, "invalid wire type 4")
116

117
      <<_::5, 6::3, _rest::binary>> ->
118
        raise Protox.DecodingError.new(bytes, "invalid wire type 6")
119

120
      <<_::5, 7::3, _rest::binary>> ->
121
        raise Protox.DecodingError.new(bytes, "invalid wire type 7")
122
    end
123
  end
124

125
  defp make_parse_key_value_known(vars, fields) do
126
    Enum.flat_map(fields, fn %Field{} = field ->
90✔
127
      single = make_single_case(vars, field)
975✔
128

129
      single_generated = single != []
975✔
130
      delimited = make_delimited_case(vars, single_generated, field)
975✔
131

132
      delimited ++ single
975✔
133
    end)
134
  end
135

136
  defp make_parse_key_value_unknown(vars, unknown_fields_name) do
137
    body =
90✔
138
      quote do
139
        {
140
          unquote(unknown_fields_name),
141
          # Order is important here, we want to keep the order of the unknown fields.
142
          unquote(vars.msg).unquote(unknown_fields_name) ++ [unquote(vars.value)]
90✔
143
        }
144
      end
145

146
    quote do
147
      <<unquote(vars.bytes)::binary>> ->
90✔
148
        {tag, wire_type, rest} = Protox.Decode.parse_key(unquote(vars.bytes))
90✔
149
        {unquote(vars.value), rest} = Protox.Decode.parse_unknown(tag, wire_type, rest)
90✔
150

151
        {[unquote(body)], rest}
152
    end
153
  end
154

155
  defp make_single_case(_vars, %Field{type: {:message, _}}) do
225✔
156
    quote(do: [])
157
  end
158

159
  defp make_single_case(_vars, %Field{type: :string}), do: quote(do: [])
105✔
160
  defp make_single_case(_vars, %Field{type: :bytes}), do: quote(do: [])
20✔
161

162
  defp make_single_case(_vars, %Field{type: {x, _}}) when x != :enum do
95✔
163
    quote(do: [])
164
  end
165

166
  defp make_single_case(vars, %Field{} = field) do
167
    parse_single = make_parse_single(vars.bytes, field.type)
530✔
168
    update_field = make_update_field(vars.value, field, vars, _wrap_value = true)
530✔
169

170
    key_bytes = make_key_bytes(field)
530✔
171

172
    # The last 3 bits of the first byte are the wire type, which we can to ignore here as we know beforehand
173
    # how the field is encoded.
174
    <<first_byte::5, _wire_type::3, tail::binary>> = key_bytes
530✔
175

176
    clause =
530✔
177
      case tail do
178
        "" ->
179
          quote do
180
            <<unquote(first_byte)::5, _wire_type::3, unquote(vars.bytes)::binary>>
135✔
181
          end
182

183
        _ ->
184
          quote do
185
            <<unquote(first_byte)::5, _wire_type::3, unquote(tail), unquote(vars.bytes)::binary>>
395✔
186
          end
187
      end
188

189
    quote do
190
      unquote(clause) ->
191
        {value, rest} = unquote(parse_single)
192
        {[unquote(update_field)], rest}
193
    end
194
  end
195

196
  defp make_delimited_case(vars, single_generated, %Field{type: {:message, _}} = field) do
197
    make_delimited_case_impl(vars, single_generated, field)
225✔
198
  end
199

200
  defp make_delimited_case(vars, single_generated, %Field{type: :bytes} = field) do
201
    make_delimited_case_impl(vars, single_generated, field)
20✔
202
  end
203

204
  defp make_delimited_case(vars, single_generated, %Field{type: :string} = field) do
205
    make_delimited_case_impl(vars, single_generated, field)
105✔
206
  end
207

208
  defp make_delimited_case(_vars, _single_generated, %Field{kind: %Scalar{}}) do
280✔
209
    []
210
  end
211

212
  defp make_delimited_case(_vars, _single_generated, %Field{kind: %OneOf{}}) do
35✔
213
    []
214
  end
215

216
  defp make_delimited_case(vars, single_generated, %Field{} = field) do
217
    make_delimited_case_impl(vars, single_generated, field)
310✔
218
  end
219

220
  defp make_delimited_case_impl(vars, single_generated, %Field{} = field) do
221
    # If the case to decode single occurrences of repeated elements has been generated,
222
    # it means that it's a repeated field of scalar elements (as non-scalar cannot be packed,
223
    # see https://developers.google.com/protocol-buffers/docs/encoding#optional).
224
    # Thus, it's useless to wrap in a list the result of the decoding as it means
225
    # we're using a parse_repeated_* function that always returns a list.
226
    update_field =
660✔
227
      if field.type == :bytes do
660✔
228
        make_update_field(vars.delimited, field, vars, _wrap_value = !single_generated)
20✔
229
      else
230
        parse_delimited = make_parse_delimited(vars.delimited, field.type)
640✔
231
        make_update_field(parse_delimited, field, vars, _wrap_value = !single_generated)
640✔
232
      end
233

234
    key_bytes = make_key_bytes(%Field{field | kind: :packed})
660✔
235

236
    clause =
660✔
237
      if single_generated do
238
        # If the single clause was not generated for this field, we don't need the wire type
239
        # discrimant as there is only one clause matching for this field.
240
        quote do
241
          <<unquote(key_bytes), unquote(vars.bytes)::binary>>
215✔
242
        end
243
      else
244
        <<first_byte::5, _wire_type::3, tail::binary>> = key_bytes
445✔
245

246
        case tail do
445✔
247
          "" ->
248
            quote do
249
              <<unquote(first_byte)::5, _wire_type::3, unquote(vars.bytes)::binary>>
75✔
250
            end
251

252
          _ ->
253
            quote do
254
              <<unquote(first_byte)::5, _wire_type::3, unquote(tail),
255
                unquote(vars.bytes)::binary>>
370✔
256
            end
257
        end
258
      end
259

260
    quote do
261
      unquote(clause) ->
262
        {len, unquote(vars.bytes)} = Protox.Varint.decode(unquote(vars.bytes))
660✔
263

264
        {unquote(vars.delimited), rest} = Protox.Decode.parse_delimited(unquote(vars.bytes), len)
660✔
265
        {[unquote(update_field)], rest}
266
    end
267
  end
268

269
  defp make_update_field(value, %Field{kind: :map} = field, vars, _wrap_value) do
270
    quote do
271
      {entry_key, entry_value} = unquote(value)
272

273
      {unquote(field.name),
95✔
274
       Map.put(unquote(vars.msg).unquote(field.name), entry_key, entry_value)}
95✔
275
    end
276
  end
277

278
  defp make_update_field(
279
         value,
280
         %Field{kind: %OneOf{}, type: {:message, _}} = field,
281
         vars,
282
         _wrap_value
283
       ) do
284
    case field.label do
5✔
285
      :proto3_optional ->
×
286
        quote do
287
          # It's unclear if we should merge the value here or not. For now, conformance tests
288
          # pass without this.
289
          {unquote(field.name), unquote(value)}
×
290
        end
291

292
      _ ->
293
        quote do
294
          case unquote(vars.msg).unquote(field.kind.parent) do
5✔
295
            {unquote(field.name), previous_value} ->
5✔
296
              {unquote(field.kind.parent),
5✔
297
               {unquote(field.name), Protox.MergeMessage.merge(previous_value, unquote(value))}}
5✔
298

299
            _ ->
300
              {unquote(field.kind.parent), {unquote(field.name), unquote(value)}}
5✔
301
          end
302
        end
303
    end
304
  end
305

306
  defp make_update_field(value, %Field{kind: %OneOf{}} = field, _vars, _wrap_value) do
307
    case field.label do
45✔
308
      :proto3_optional ->
×
309
        quote(do: {unquote(field.name), unquote(value)})
×
310

311
      _ ->
45✔
312
        quote(do: {unquote(field.kind.parent), {unquote(field.name), unquote(value)}})
45✔
313
    end
314
  end
315

316
  defp make_update_field(
120✔
317
         value,
318
         %Field{kind: %Scalar{}, type: {:message, _}} = field,
319
         vars,
320
         _wrap_value
321
       ) do
322
    quote do
323
      {
324
        unquote(field.name),
120✔
325
        Protox.MergeMessage.merge(unquote(vars.msg).unquote(field.name), unquote(value))
120✔
326
      }
327
    end
328
  end
329

330
  defp make_update_field(value, %Field{kind: %Scalar{}} = field, _vars, _wrap_value) do
375✔
331
    quote(do: {unquote(field.name), unquote(value)})
375✔
332
  end
333

334
  defp make_update_field(value, %Field{} = field, vars, true = _wrap_value) do
335✔
335
    quote do
336
      {unquote(field.name), unquote(vars.msg).unquote(field.name) ++ [unquote(value)]}
335✔
337
    end
338
  end
339

340
  defp make_update_field(value, %Field{} = field, vars, false = _wrap_value) do
215✔
341
    quote do
342
      {unquote(field.name), unquote(vars.msg).unquote(field.name) ++ unquote(value)}
215✔
343
    end
344
  end
345

346
  defp make_parse_delimited(bytes_var, :bytes) do
347
    quote(do: unquote(bytes_var))
5✔
348
  end
349

350
  defp make_parse_delimited(bytes_var, :string) do
351
    quote(do: Protox.Decode.validate_string!(unquote(bytes_var)))
352
  end
353

354
  defp make_parse_delimited(bytes_var, {:enum, mod}) do
355
    quote(do: Protox.Decode.parse_repeated_enum([], unquote(bytes_var), unquote(mod)))
356
  end
357

358
  defp make_parse_delimited(bytes_var, {:message, mod}) do
359
    quote(do: unquote(mod).decode!(unquote(bytes_var)))
360
  end
361

362
  defp make_parse_delimited(bytes_var, :bool) do
363
    quote(do: Protox.Decode.parse_repeated_bool([], unquote(bytes_var)))
364
  end
365

366
  defp make_parse_delimited(bytes_var, :int32) do
367
    quote(do: Protox.Decode.parse_repeated_int32([], unquote(bytes_var)))
368
  end
369

370
  defp make_parse_delimited(bytes_var, :uint32) do
371
    quote(do: Protox.Decode.parse_repeated_uint32([], unquote(bytes_var)))
372
  end
373

374
  defp make_parse_delimited(bytes_var, :sint32) do
375
    quote(do: Protox.Decode.parse_repeated_sint32([], unquote(bytes_var)))
376
  end
377

378
  defp make_parse_delimited(bytes_var, :int64) do
379
    quote(do: Protox.Decode.parse_repeated_int64([], unquote(bytes_var)))
380
  end
381

382
  defp make_parse_delimited(bytes_var, :uint64) do
383
    quote(do: Protox.Decode.parse_repeated_uint64([], unquote(bytes_var)))
384
  end
385

386
  defp make_parse_delimited(bytes_var, :sint64) do
387
    quote(do: Protox.Decode.parse_repeated_sint64([], unquote(bytes_var)))
388
  end
389

390
  defp make_parse_delimited(bytes_var, :fixed32) do
391
    quote(do: Protox.Decode.parse_repeated_fixed32([], unquote(bytes_var)))
392
  end
393

394
  defp make_parse_delimited(bytes_var, :fixed64) do
395
    quote(do: Protox.Decode.parse_repeated_fixed64([], unquote(bytes_var)))
396
  end
397

398
  defp make_parse_delimited(bytes_var, :sfixed32) do
399
    quote(do: Protox.Decode.parse_repeated_sfixed32([], unquote(bytes_var)))
400
  end
401

402
  defp make_parse_delimited(bytes_var, :sfixed64) do
403
    quote(do: Protox.Decode.parse_repeated_sfixed64([], unquote(bytes_var)))
404
  end
405

406
  defp make_parse_delimited(bytes_var, :float) do
407
    quote(do: Protox.Decode.parse_repeated_float([], unquote(bytes_var)))
408
  end
409

410
  defp make_parse_delimited(bytes_var, :double) do
411
    quote(do: Protox.Decode.parse_repeated_double([], unquote(bytes_var)))
412
  end
413

414
  defp make_parse_delimited(bytes_var, {key_type, value_type}) do
415
    unset_map_value =
95✔
416
      case value_type do
417
        {:message, msg_type} -> quote(do: struct(unquote(msg_type)))
418
        _ -> quote(do: Protox.Default.default(unquote(value_type)))
419
      end
420

421
    parser_fun_name = make_map_decode_fun_name(key_type, value_type)
95✔
422

423
    quote do
424
      {map_key, map_value} = unquote(parser_fun_name)({:unset, :unset}, unquote(bytes_var))
425

426
      map_key =
427
        case map_key do
428
          :unset -> Protox.Default.default(unquote(key_type))
429
          _ -> map_key
430
        end
431

432
      map_value =
433
        case map_value do
434
          :unset -> unquote(unset_map_value)
435
          _ -> map_value
436
        end
437

438
      {map_key, map_value}
439
    end
440
  end
441

442
  defp make_parse_single(bytes_var, :double) do
443
    quote(do: Protox.Decode.parse_double(unquote(bytes_var)))
444
  end
445

446
  defp make_parse_single(bytes_var, :float) do
447
    quote(do: Protox.Decode.parse_float(unquote(bytes_var)))
448
  end
449

450
  defp make_parse_single(bytes_var, :sfixed64) do
451
    quote(do: Protox.Decode.parse_sfixed64(unquote(bytes_var)))
452
  end
453

454
  defp make_parse_single(bytes_var, :fixed64) do
455
    quote(do: Protox.Decode.parse_fixed64(unquote(bytes_var)))
456
  end
457

458
  defp make_parse_single(bytes_var, :sfixed32) do
459
    quote(do: Protox.Decode.parse_sfixed32(unquote(bytes_var)))
460
  end
461

462
  defp make_parse_single(bytes_var, :fixed32) do
463
    quote(do: Protox.Decode.parse_fixed32(unquote(bytes_var)))
464
  end
465

466
  defp make_parse_single(bytes_var, :bool) do
467
    quote(do: Protox.Decode.parse_bool(unquote(bytes_var)))
468
  end
469

470
  defp make_parse_single(bytes_var, :sint32) do
471
    quote(do: Protox.Decode.parse_sint32(unquote(bytes_var)))
472
  end
473

474
  defp make_parse_single(bytes_var, :sint64) do
475
    quote(do: Protox.Decode.parse_sint64(unquote(bytes_var)))
476
  end
477

478
  defp make_parse_single(bytes_var, :uint32) do
479
    quote(do: Protox.Decode.parse_uint32(unquote(bytes_var)))
480
  end
481

482
  defp make_parse_single(bytes_var, :uint64) do
483
    quote(do: Protox.Decode.parse_uint64(unquote(bytes_var)))
484
  end
485

486
  defp make_parse_single(bytes_var, :int32) do
487
    quote(do: Protox.Decode.parse_int32(unquote(bytes_var)))
488
  end
489

490
  defp make_parse_single(bytes_var, :int64) do
491
    quote(do: Protox.Decode.parse_int64(unquote(bytes_var)))
492
  end
493

494
  defp make_parse_single(bytes_var, {:enum, mod}) do
495
    quote(do: Protox.Decode.parse_enum(unquote(bytes_var), unquote(mod)))
496
  end
497

498
  defp make_parse_map_entries_funs(vars, fields) do
499
    {maps, _other_fields} = Protox.Defs.split_maps(fields)
90✔
500

501
    maps
502
    |> Enum.map(fn %Field{kind: :map} = field ->
503
      key_type = elem(field.type, 0)
95✔
504
      value_type = elem(field.type, 1)
95✔
505

506
      fun_name = make_map_decode_fun_name(key_type, value_type)
95✔
507

508
      key_parser = make_parse_map_entry(vars, key_type)
95✔
509
      value_parser = make_parse_map_entry(vars, value_type)
95✔
510

511
      code =
95✔
512
        quote do
513
          defp unquote(fun_name)(map_entry, <<>>) do
514
            map_entry
515
          end
516

517
          # https://developers.google.com/protocol-buffers/docs/proto3#backwards-compatibility
518
          # Maps are equivalent to:
519
          #   message MapFieldEntry {
520
          #     key_type key = 1;
521
          #     value_type value = 2;
522
          #   }
523
          # repeated MapFieldEntry map_field = N;
524
          #
525
          defp unquote(fun_name)({entry_key, entry_value}, unquote(vars.bytes)) do
95✔
526
            {map_entry, unquote(vars.rest)} =
95✔
527
              case Protox.Decode.parse_key(unquote(vars.bytes)) do
95✔
528
                # key
529
                {1, _, unquote(vars.rest)} ->
95✔
530
                  {res, unquote(vars.rest)} = unquote(key_parser)
95✔
531
                  {{res, entry_value}, unquote(vars.rest)}
95✔
532

533
                # value
534
                {2, _, unquote(vars.rest)} ->
95✔
535
                  {res, unquote(vars.rest)} = unquote(value_parser)
95✔
536
                  {{entry_key, res}, unquote(vars.rest)}
95✔
537

538
                {tag, wire_type, unquote(vars.rest)} ->
95✔
539
                  {_, unquote(vars.rest)} =
95✔
540
                    Protox.Decode.parse_unknown(tag, wire_type, unquote(vars.rest))
95✔
541

542
                  {{entry_key, entry_value}, unquote(vars.rest)}
95✔
543
              end
544

545
            unquote(fun_name)(map_entry, unquote(vars.rest))
95✔
546
          end
547
        end
548

549
      {fun_name, code}
550
    end)
551
    |> Enum.sort(fn {lhs_fun_name, _}, {rhs_fun_name, _} -> lhs_fun_name < rhs_fun_name end)
310✔
552
    |> Enum.dedup_by(fn {fun_name, _} -> fun_name end)
95✔
553
    |> Enum.map(fn {_, code} -> code end)
90✔
554
  end
555

556
  defp make_map_decode_fun_name(key_type, value_type) do
557
    value_name =
190✔
558
      case value_type do
559
        {:message, sub_msg} -> "msg_#{Atom.to_string(sub_msg)}"
20✔
560
        {:enum, enum} -> "enum_#{Atom.to_string(enum)}"
20✔
561
        ty -> "#{Atom.to_string(ty)}"
150✔
562
      end
563

564
    value_name =
190✔
565
      value_name
566
      |> Macro.underscore()
567
      |> String.replace("/", "_")
568

569
    String.to_atom("parse_#{Atom.to_string(key_type)}_#{value_name}")
190✔
570
  end
571

572
  defp make_parse_map_entry(vars, type) do
573
    parse_delimited =
190✔
574
      quote do
575
        {len, new_rest} = Protox.Varint.decode(unquote(vars.rest))
190✔
576
        {unquote(vars.delimited), new_rest} = Protox.Decode.parse_delimited(new_rest, len)
190✔
577

578
        {unquote(make_parse_delimited(vars.delimited, type)), new_rest}
190✔
579
      end
580

581
    case type do
190✔
582
      :string -> parse_delimited
35✔
583
      :bytes -> parse_delimited
5✔
584
      {:message, _} -> parse_delimited
10✔
585
      _ -> make_parse_single(vars.rest, type)
140✔
586
    end
587
  end
588

589
  # Compute at compile time the varint representation of a field tag and wire type.
590
  defp make_key_bytes(%Field{} = field) do
591
    # We need to convert the type to something recognized
592
    # by Protox.Encode.make_key_bytes/2.
593
    ty =
1,190✔
594
      case field.kind do
1,190✔
595
        :map -> :map_entry
×
596
        :packed -> :packed
805✔
597
        _ -> field.type
385✔
598
      end
599

600
    Protox.Encode.make_key_bytes(field.tag, ty) |> elem(0) |> IO.iodata_to_binary()
1,190✔
601
  end
602
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