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

bblanchon / ArduinoJson / 18653349747

20 Oct 2025 12:56PM UTC coverage: 99.34% (-0.08%) from 99.417%
18653349747

push

github

bblanchon
Return `bool` from all built-in `toJson` converters

104 of 108 new or added lines in 8 files covered. (96.3%)

3 existing lines in 2 files now uncovered.

3916 of 3942 relevant lines covered (99.34%)

10349.1 hits per line

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

99.36
/src/ArduinoJson/Variant/VariantImpl.hpp
1
// ArduinoJson - https://arduinojson.org
2
// Copyright © 2014-2025, Benoit BLANCHON
3
// MIT License
4

5
#pragma once
6

7
#include <ArduinoJson/Collection/CollectionIterator.hpp>
8
#include <ArduinoJson/Memory/ResourceManager.hpp>
9
#include <ArduinoJson/Misc/SerializedValue.hpp>
10
#include <ArduinoJson/Numbers/convertNumber.hpp>
11
#include <ArduinoJson/Strings/JsonString.hpp>
12
#include <ArduinoJson/Strings/StringAdapters.hpp>
13
#include <ArduinoJson/Variant/VariantData.hpp>
14

15
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
16

17
// HACK: large functions are implemented in static function to give opportunity
18
// to the compiler to optimize the `this` pointer away.
19
class VariantImpl {
20
 public:
21
  using iterator = CollectionIterator;
22

23
  VariantImpl() : data_(nullptr), resources_(nullptr) {}
559✔
24

25
  VariantImpl(VariantData* data, ResourceManager* resources)
225,463✔
26
      : data_(data), resources_(resources) {}
225,463✔
27

28
  VariantData* data() const {
216,690✔
29
    return data_;
216,690✔
30
  }
31

32
  ResourceManager* resources() const {
224,571✔
33
    return resources_;
224,571✔
34
  }
35

36
  template <typename TVisitor>
37
  typename TVisitor::result_type accept(TVisitor& visit) {
5,329✔
38
    return accept(visit, data_, resources_);
5,329✔
39
  }
40

41
  template <typename TVisitor>
42
  static typename TVisitor::result_type accept(TVisitor& visit,
139,510✔
43
                                               VariantData* data,
44
                                               ResourceManager* resources) {
45
    if (!data)
139,510✔
46
      return visit.visit(nullptr);
170✔
47

48
#if ARDUINOJSON_USE_8_BYTE_POOL
49
    auto eightByteValue = getEightByte(data, resources);
139,340✔
50
#endif
51
    switch (data->type) {
139,340✔
52
      case VariantType::Float:
121✔
53
        return visit.visit(data->content.asFloat);
121✔
54

55
#if ARDUINOJSON_USE_DOUBLE
56
      case VariantType::Double:
16✔
57
        return visit.visit(eightByteValue->asDouble);
16✔
58
#endif
59

60
      case VariantType::Array:
982✔
61
        return visit.visitArray(data);
982✔
62

63
      case VariantType::Object:
2,679✔
64
        return visit.visitObject(data);
2,679✔
65

66
      case VariantType::TinyString:
341✔
67
        return visit.visit(JsonString(data->content.asTinyString));
341✔
68

69
      case VariantType::LongString:
1,783✔
70
        return visit.visit(JsonString(data->content.asStringNode->data,
3,566✔
71
                                      data->content.asStringNode->length));
3,566✔
72

73
      case VariantType::RawString:
129✔
74
        return visit.visit(RawString(data->content.asStringNode->data,
258✔
75
                                     data->content.asStringNode->length));
258✔
76

77
      case VariantType::Int32:
1,184✔
78
        return visit.visit(static_cast<JsonInteger>(data->content.asInt32));
1,184✔
79

80
      case VariantType::Uint32:
256✔
81
        return visit.visit(static_cast<JsonUInt>(data->content.asUint32));
256✔
82

83
#if ARDUINOJSON_USE_LONG_LONG
84
      case VariantType::Int64:
7✔
85
        return visit.visit(eightByteValue->asInt64);
7✔
86

87
      case VariantType::Uint64:
8✔
88
        return visit.visit(eightByteValue->asUint64);
8✔
89
#endif
90

91
      case VariantType::Boolean:
607✔
92
        return visit.visit(data->content.asBoolean != 0);
607✔
93

94
      default:
131,227✔
95
        return visit.visit(nullptr);
131,227✔
96
    }
97
  }
98

99
  VariantData* addNewElement() {
611✔
100
    if (!isArray())
611✔
101
      return nullptr;
8✔
102
    return addNewElement(data_, resources_);
603✔
103
  }
104

105
  static VariantData* addNewElement(VariantData*, ResourceManager*);
106

107
  static void addElement(Slot<VariantData> slot, VariantData*,
108
                         ResourceManager*);
109

110
  template <typename TAdaptedString>
111
  VariantData* addMember(TAdaptedString key) {
112
    if (!isObject())
113
      return nullptr;
114
    return addMember(key, data_, resources_);
115
  }
116

117
  template <typename TAdaptedString>
118
  static VariantData* addMember(TAdaptedString key, VariantData*,
119
                                ResourceManager*);
120

121
  VariantData* addPair(VariantData** value) {
122
    if (isNull())
123
      return nullptr;
124
    return addPair(value, data_, resources_);
125
  }
126

127
  static VariantData* addPair(VariantData** value, VariantData*,
128
                              ResourceManager*);
129

130
  bool asBoolean() const {
1,254✔
131
    return asBoolean(data_, resources_);
1,254✔
132
  }
133

134
  static bool asBoolean(VariantData* data, ResourceManager* resources) {
1,254✔
135
    if (!data)
1,254✔
136
      return false;
699✔
137

138
#if ARDUINOJSON_USE_8_BYTE_POOL
139
    auto eightByteValue = getEightByte(data, resources);
555✔
140
#endif
141
    switch (data->type) {
555✔
142
      case VariantType::Boolean:
305✔
143
        return data->content.asBoolean;
305✔
144
      case VariantType::Uint32:
6✔
145
      case VariantType::Int32:
146
        return data->content.asUint32 != 0;
6✔
147
      case VariantType::Float:
2✔
148
        return data->content.asFloat != 0;
2✔
149
#if ARDUINOJSON_USE_DOUBLE
150
      case VariantType::Double:
4✔
151
        return eightByteValue->asDouble != 0;
4✔
152
#endif
153
      case VariantType::Null:
6✔
154
        return false;
6✔
155
#if ARDUINOJSON_USE_LONG_LONG
156
      case VariantType::Uint64:
2✔
157
      case VariantType::Int64:
158
        return eightByteValue->asUint64 != 0;
2✔
159
#endif
160
      default:
230✔
161
        return true;
230✔
162
    }
163
  }
164

165
  template <typename T>
166
  T asFloat() const {
55✔
167
    return asFloat<T>(data_, resources_);
55✔
168
  }
169

170
  template <typename T>
171
  static T asFloat(VariantData* data, ResourceManager* resources) {
55✔
172
    if (!data)
55✔
173
      return 0.0;
1✔
174

175
    static_assert(is_floating_point<T>::value, "T must be a floating point");
176
#if ARDUINOJSON_USE_8_BYTE_POOL
177
    auto eightByteValue = getEightByte(data, resources);
54✔
178
#endif
179
    const char* str = nullptr;
54✔
180
    switch (data->type) {
54✔
181
      case VariantType::Boolean:
2✔
182
        return static_cast<T>(data->content.asBoolean);
2✔
183
      case VariantType::Uint32:
2✔
184
        return static_cast<T>(data->content.asUint32);
2✔
185
      case VariantType::Int32:
4✔
186
        return static_cast<T>(data->content.asInt32);
4✔
187
#if ARDUINOJSON_USE_LONG_LONG
188
      case VariantType::Uint64:
1✔
189
        return static_cast<T>(eightByteValue->asUint64);
1✔
190
      case VariantType::Int64:
1✔
191
        return static_cast<T>(eightByteValue->asInt64);
1✔
192
#endif
193
      case VariantType::TinyString:
2✔
194
        str = data->content.asTinyString;
2✔
195
        break;
2✔
196
      case VariantType::LongString:
1✔
197
        str = data->content.asStringNode->data;
1✔
198
        break;
1✔
199
      case VariantType::Float:
18✔
200
        return static_cast<T>(data->content.asFloat);
18✔
201
#if ARDUINOJSON_USE_DOUBLE
202
      case VariantType::Double:
21✔
203
        return static_cast<T>(eightByteValue->asDouble);
21✔
204
#endif
205
      default:
2✔
206
        return 0.0;
2✔
207
    }
208

209
    ARDUINOJSON_ASSERT(str != nullptr);
210
    return parseNumber<T>(str);
3✔
211
  }
212

213
  template <typename T>
214
  T asIntegral() const {
203✔
215
    return asIntegral<T>(data_, resources_);
203✔
216
  }
217

218
  template <typename T>
219
  static T asIntegral(VariantData* data, ResourceManager* resources) {
203✔
220
    if (!data)
203✔
221
      return 0;
5✔
222

223
    static_assert(is_integral<T>::value, "T must be an integral type");
224
#if ARDUINOJSON_USE_8_BYTE_POOL
225
    auto eightByteValue = getEightByte(data, resources);
198✔
226
#endif
227
    const char* str = nullptr;
198✔
228
    switch (data->type) {
198✔
229
      case VariantType::Boolean:
2✔
230
        return data->content.asBoolean;
2✔
231
      case VariantType::Uint32:
66✔
232
        return convertNumber<T>(data->content.asUint32);
66✔
233
      case VariantType::Int32:
83✔
234
        return convertNumber<T>(data->content.asInt32);
83✔
235
#if ARDUINOJSON_USE_LONG_LONG
236
      case VariantType::Uint64:
10✔
237
        return convertNumber<T>(eightByteValue->asUint64);
10✔
238
      case VariantType::Int64:
11✔
239
        return convertNumber<T>(eightByteValue->asInt64);
11✔
240
#endif
241
      case VariantType::TinyString:
3✔
242
        str = data->content.asTinyString;
3✔
243
        break;
3✔
244
      case VariantType::LongString:
6✔
245
        str = data->content.asStringNode->data;
6✔
246
        break;
6✔
247
      case VariantType::Float:
5✔
248
        return convertNumber<T>(data->content.asFloat);
5✔
249
#if ARDUINOJSON_USE_DOUBLE
250
      case VariantType::Double:
10✔
251
        return convertNumber<T>(eightByteValue->asDouble);
10✔
252
#endif
253
      default:
2✔
254
        return 0;
2✔
255
    }
256

257
    ARDUINOJSON_ASSERT(str != nullptr);
258
    return parseNumber<T>(str);
9✔
259
  }
260

261
  iterator at(size_t index) const;
262

263
  iterator createIterator() const {
1,512✔
264
    if (!isCollection())
1,512✔
265
      return iterator();
10✔
266
    return createIterator(data_, resources_);
1,502✔
267
  }
268

269
  static iterator createIterator(VariantData*, ResourceManager*);
270

271
#if ARDUINOJSON_USE_8_BYTE_POOL
272
  static const EightByteValue* getEightByte(VariantData* data,
140,295✔
273
                                            ResourceManager* resources) {
274
    ARDUINOJSON_ASSERT(data != nullptr);
275
    ARDUINOJSON_ASSERT(resources != nullptr);
276
    return data->type & VariantTypeBits::EightByteBit
140,295✔
277
               ? resources->getEightByte(data->content.asSlotId)
140,295✔
278
               : 0;
140,295✔
279
  }
280
#endif
281

282
  VariantData* getOrAddElement(size_t index);
283

284
  VariantData* getElement(size_t index) const;
285

286
  template <typename TAdaptedString>
287
  VariantData* getMember(TAdaptedString key) const {
2,663✔
288
    if (!isObject())
2,663✔
289
      return nullptr;
57✔
290
    return getMember(key, data_, resources_);
2,606✔
291
  }
292

293
  template <typename TAdaptedString>
294
  static VariantData* getMember(TAdaptedString key, VariantData*,
295
                                ResourceManager*);
296

297
  template <typename TAdaptedString>
298
  VariantData* getOrAddMember(TAdaptedString key) {
950✔
299
    if (!isObject())
950✔
300
      return nullptr;
3✔
301
    return getOrAddMember(key, data_, resources_);
947✔
302
  }
303

304
  template <typename TAdaptedString>
305
  static VariantData* getOrAddMember(TAdaptedString key, VariantData*,
306
                                     ResourceManager*);
307

308
  bool isArray() const {
67,791✔
309
    return type() == VariantType::Array;
67,791✔
310
  }
311

312
  bool isCollection() const {
1,932✔
313
    return type() & VariantTypeBits::CollectionMask;
1,932✔
314
  }
315

316
  template <typename T>
317
  bool isInteger() const {
167✔
318
    return isInteger<T>(data_, resources_);
167✔
319
  }
320

321
  template <typename T>
322
  static bool isInteger(VariantData* data, ResourceManager* resources) {
167✔
323
    if (!data)
167✔
324
      return false;
16✔
325

326
#if ARDUINOJSON_USE_LONG_LONG
327
    auto eightByteValue = getEightByte(data, resources);
148✔
328
#else
329
    (void)resources;
330
#endif
331
    switch (data->type) {
151✔
332
      case VariantType::Uint32:
11✔
333
        return canConvertNumber<T>(data->content.asUint32);
11✔
334

335
      case VariantType::Int32:
65✔
336
        return canConvertNumber<T>(data->content.asInt32);
65✔
337

338
#if ARDUINOJSON_USE_LONG_LONG
339
      case VariantType::Uint64:
3✔
340
        return canConvertNumber<T>(eightByteValue->asUint64);
3✔
341

342
      case VariantType::Int64:
4✔
343
        return canConvertNumber<T>(eightByteValue->asInt64);
4✔
344
#endif
345

346
      default:
68✔
347
        return false;
68✔
348
    }
349
  }
350

351
  bool isNull() const {
2,911✔
352
    return type() == VariantType::Null;
2,911✔
353
  }
354

355
  bool isObject() const {
3,690✔
356
    return type() == VariantType::Object;
3,690✔
357
  }
358

359
  size_t nesting() const;
360

361
  void removeElement(size_t index);
362

363
  void removeElement(CollectionIterator it) {
22✔
364
    removeOne(it);
22✔
365
  }
22✔
366

367
  template <typename TAdaptedString>
368
  void removeMember(TAdaptedString key) {
31✔
369
    removePair(findKey(key));
31✔
370
  }
31✔
371

372
  void removeMember(CollectionIterator it) {
4✔
373
    removePair(it);
4✔
374
  }
4✔
375

376
  bool setBoolean(bool value) {
250✔
377
    if (!data_)
250✔
378
      return false;
2✔
379
    clear(data_, resources_);
248✔
380
    data_->setBoolean(value);
248✔
381
    return true;
248✔
382
  }
383

384
  template <typename T>
385
  bool setFloat(T value) {
73✔
386
    if (!data_)
73✔
387
      return false;
1✔
388
    clear(data_, resources_);
72✔
389
    return setFloat(value, data_, resources_);
72✔
390
  }
391

392
  template <typename T>
393
  static enable_if_t<sizeof(T) == 4, bool> setFloat(T value, VariantData* data,
90✔
394
                                                    ResourceManager*) {
395
    ARDUINOJSON_ASSERT(data != nullptr);
396
    ARDUINOJSON_ASSERT(data->type == VariantType::Null);
397
    data->type = VariantType::Float;
90✔
398
    data->content.asFloat = value;
90✔
399
    return true;
90✔
400
  }
401

402
  template <typename T>
403
  static enable_if_t<sizeof(T) == 8, bool> setFloat(
79✔
404
      T value, VariantData* data, ResourceManager* resources) {
405
    ARDUINOJSON_ASSERT(data != nullptr);
406
    ARDUINOJSON_ASSERT(data->type == VariantType::Null);
407
    ARDUINOJSON_ASSERT(resources != nullptr);
408

409
    float valueAsFloat = static_cast<float>(value);
79✔
410

411
#if ARDUINOJSON_USE_DOUBLE
412
    if (value == valueAsFloat) {
77✔
413
      data->type = VariantType::Float;
32✔
414
      data->content.asFloat = valueAsFloat;
32✔
415
    } else {
416
      auto slot = resources->allocEightByte();
45✔
417
      if (!slot)
45✔
418
        return false;
3✔
419
      data->type = VariantType::Double;
42✔
420
      data->content.asSlotId = slot.id();
42✔
421
      slot->asDouble = value;
42✔
422
    }
423
#else
424
    data->type = VariantType::Float;
2✔
425
    data->content.asFloat = valueAsFloat;
2✔
426
#endif
427
    return true;
76✔
428
  }
429

430
  template <typename T>
431
  bool setInteger(T value) {
1,433✔
432
    if (!data_)
1,433✔
433
      return false;
16✔
434
    clear(data_, resources_);
1,417✔
435
    return setInteger(value, data_, resources_);
1,417✔
436
  }
437

438
  template <typename T>
439
  static enable_if_t<is_signed<T>::value, bool> setInteger(
1,548✔
440
      T value, VariantData* data, ResourceManager* resources) {
441
    ARDUINOJSON_ASSERT(data != nullptr);
442
    ARDUINOJSON_ASSERT(data->type == VariantType::Null);
443
    ARDUINOJSON_ASSERT(resources != nullptr);
444

445
    if (canConvertNumber<int32_t>(value)) {
1,548✔
446
      data->type = VariantType::Int32;
1,531✔
447
      data->content.asInt32 = static_cast<int32_t>(value);
1,531✔
448
    }
449
#if ARDUINOJSON_USE_LONG_LONG
450
    else {
451
      auto slot = resources->allocEightByte();
17✔
452
      if (!slot)
17✔
453
        return false;
3✔
454
      data->type = VariantType::Int64;
14✔
455
      data->content.asSlotId = slot.id();
14✔
456
      slot->asInt64 = value;
14✔
457
    }
458
#else
459
    (void)resources;
460
#endif
461
    return true;
1,545✔
462
  }
463

464
  template <typename T>
465
  static enable_if_t<is_unsigned<T>::value, bool> setInteger(
2,299✔
466
      T value, VariantData* data, ResourceManager* resources) {
467
    ARDUINOJSON_ASSERT(data != nullptr);
468
    ARDUINOJSON_ASSERT(data->type == VariantType::Null);
469
    ARDUINOJSON_ASSERT(resources != nullptr);
470

471
    if (canConvertNumber<uint32_t>(value)) {
2,299✔
472
      data->type = VariantType::Uint32;
2,282✔
473
      data->content.asUint32 = static_cast<uint32_t>(value);
2,282✔
474
    }
475
#if ARDUINOJSON_USE_LONG_LONG
476
    else {
477
      auto slot = resources->allocEightByte();
16✔
478
      if (!slot)
16✔
479
        return false;
3✔
480
      data->type = VariantType::Uint64;
13✔
481
      data->content.asSlotId = slot.id();
13✔
482
      slot->asUint64 = value;
13✔
483
    }
484
#else
485
    (void)resources;
486
#endif
487
    return true;
2,296✔
488
  }
489

490
  template <typename TAdaptedString>
491
  bool setRawString(TAdaptedString value) {
36✔
492
    if (!data_)
36✔
493
      return false;
2✔
494
    clear(data_, resources_);
34✔
495
    auto dup = resources_->saveString(adaptString(value.data(), value.size()));
34✔
496
    if (!dup)
34✔
497
      return false;
4✔
498
    data_->setRawString(dup);
30✔
499
    return true;
30✔
500
  }
501

502
  template <typename TAdaptedString>
503
  bool setString(TAdaptedString value) {
66,121✔
504
    if (!data_)
66,121✔
505
      return false;
5✔
506
    clear(data_, resources_);
66,116✔
507
    return setString(value, data_, resources_);
66,116✔
508
  }
509

510
  template <typename TAdaptedString>
511
  static bool setString(TAdaptedString value, VariantData* data,
67,025✔
512
                        ResourceManager* resources) {
513
    ARDUINOJSON_ASSERT(data != nullptr);
514
    ARDUINOJSON_ASSERT(data->type == VariantType::Null);
515
    ARDUINOJSON_ASSERT(resources != nullptr);
516

517
    if (value.isNull())
67,025✔
518
      return true;  // TODO: should this be moved up to the member function?
65,552✔
519

520
    if (isTinyString(value, value.size())) {
1,473✔
521
      data->setTinyString(value);
412✔
522
      return true;
412✔
523
    }
524

525
    auto dup = resources->saveString(value);
1,061✔
526
    if (dup) {
1,061✔
527
      data->setLongString(dup);
1,049✔
528
      return true;
1,049✔
529
    }
530

531
    return false;
12✔
532
  }
533

534
  size_t size() const {
369✔
535
    if (!isCollection())
369✔
536
      return 0;
23✔
537

538
    return size(data_, resources_);
346✔
539
  }
540

541
  static size_t size(VariantData* data, ResourceManager* resources) {
365✔
542
    ARDUINOJSON_ASSERT(data != nullptr);
543
    ARDUINOJSON_ASSERT(data->isCollection());
544
    ARDUINOJSON_ASSERT(resources != nullptr);
545

546
    size_t n = 0;
365✔
547
    for (auto it = createIterator(data, resources); !it.done();
132,494✔
548
         it.move(resources))
132,129✔
549
      n++;
132,129✔
550

551
    if (data->type == VariantType::Object) {
365✔
552
      ARDUINOJSON_ASSERT((n % 2) == 0);
553
      n /= 2;
267✔
554
    }
555

556
    return n;
365✔
557
  }
558

559
  bool toArray() {
78✔
560
    if (!data_)
78✔
UNCOV
561
      return false;
×
562
    clear(data_, resources_);
78✔
563
    data_->toArray();
78✔
564
    return true;
78✔
565
  }
566

567
  bool toObject() {
109✔
568
    if (!data_)
109✔
UNCOV
569
      return false;
×
570
    clear(data_, resources_);
109✔
571
    data_->toObject();
109✔
572
    return true;
109✔
573
  }
574

575
  VariantType type() const {
76,324✔
576
    return data_ ? data_->type : VariantType::Null;
76,324✔
577
  }
578

579
  // Release the resources used by this variant and set it to null.
580
  bool clear() {
48✔
581
    if (!data_)
48✔
582
      return false;
1✔
583
    clear(data_, resources_);
47✔
584
    return true;
47✔
585
  }
586

587
  static void clear(VariantData* data, ResourceManager* resources) {
68,531✔
588
    ARDUINOJSON_ASSERT(data != nullptr);
589
    ARDUINOJSON_ASSERT(resources != nullptr);
590

591
    if (data->type & VariantTypeBits::OwnedStringBit)
68,531✔
592
      resources->dereferenceString(data->content.asStringNode->data);
45✔
593

594
#if ARDUINOJSON_USE_8_BYTE_POOL
595
    if (data->type & VariantTypeBits::EightByteBit)
68,531✔
596
      resources->freeEightByte(data->content.asSlotId);
3✔
597
#endif
598

599
    if (data->type & VariantTypeBits::CollectionMask)
68,531✔
600
      empty(data, resources);
17✔
601

602
    data->type = VariantType::Null;
68,531✔
603
  }
68,531✔
604

605
  void empty() {
51✔
606
    if (!isCollection())
51✔
607
      return;
2✔
608
    empty(data_, resources_);
49✔
609
  }
610

611
  static void empty(VariantData*, ResourceManager*);
612

613
  static void freeVariant(Slot<VariantData> slot, ResourceManager* resources) {
368✔
614
    clear(slot.ptr(), resources);
368✔
615
    resources->freeVariant(slot);
368✔
616
  }
368✔
617

618
 private:
619
  VariantData* data_;
620
  ResourceManager* resources_;
621

622
  template <typename TAdaptedString>
623
  iterator findKey(TAdaptedString key) const {
31✔
624
    if (!isObject())
31✔
625
      return iterator();
3✔
626
    return findKey(key, data_, resources_);
28✔
627
  }
628

629
  template <typename TAdaptedString>
630
  static iterator findKey(TAdaptedString key, VariantData*, ResourceManager*);
631

632
  static void appendPair(Slot<VariantData> key, Slot<VariantData> value,
633
                         VariantData*, ResourceManager*);
634

635
  void removeOne(iterator it);
636
  void removePair(iterator it);
637

638
  Slot<VariantData> getPreviousSlot(VariantData*) const;
639
};
640

641
ARDUINOJSON_END_PRIVATE_NAMESPACE
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

© 2025 Coveralls, Inc