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

davidcole1340 / ext-php-rs / 16401140698

20 Jul 2025 02:13PM UTC coverage: 26.945% (+1.2%) from 25.766%
16401140698

Pull #489

github

Xenira
refactor(enum): use raii box pattern for enum values

Refs: #178
Pull Request #489: feat(enum): add basic enum support

118 of 288 new or added lines in 7 files covered. (40.97%)

1 existing line in 1 file now uncovered.

1115 of 4138 relevant lines covered (26.95%)

5.64 hits per line

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

78.57
/src/describe/mod.rs
1
//! Types used to describe downstream extensions. Used by the `cargo-php`
2
//! CLI application to generate PHP stub files used by IDEs.
3
use std::vec::Vec as StdVec;
4

5
#[cfg(feature = "enum")]
6
use crate::builders::EnumBuilder;
7
use crate::{
8
    builders::{ClassBuilder, FunctionBuilder},
9
    constant::IntoConst,
10
    flags::{DataType, MethodFlags, PropertyFlags},
11
    prelude::ModuleBuilder,
12
};
13
use abi::{Option, RString, Str, Vec};
14

15
pub mod abi;
16
mod stub;
17

18
pub use stub::ToStub;
19

20
/// A slice of strings containing documentation comments.
21
pub type DocComments = &'static [&'static str];
22

23
/// Representation of the extension used to generate PHP stubs.
24
#[repr(C)]
25
pub struct Description {
26
    /// Extension description.
27
    pub module: Module,
28
    /// ext-php-rs version.
29
    pub version: &'static str,
30
}
31

32
impl Description {
33
    /// Creates a new description.
34
    ///
35
    /// # Parameters
36
    ///
37
    /// * `module` - The extension module representation.
38
    #[must_use]
39
    pub fn new(module: Module) -> Self {
1✔
40
        Self {
41
            module,
42
            version: crate::VERSION,
43
        }
44
    }
45
}
46

47
/// Represents a set of comments on an export.
48
#[repr(C)]
49
#[derive(Debug, PartialEq)]
50
pub struct DocBlock(pub Vec<Str>);
51

52
impl From<&'static [&'static str]> for DocBlock {
53
    fn from(val: &'static [&'static str]) -> Self {
3✔
54
        Self(
55
            val.iter()
6✔
56
                .map(|s| (*s).into())
13✔
57
                .collect::<StdVec<_>>()
3✔
58
                .into(),
3✔
59
        )
60
    }
61
}
62

63
/// Represents an extension containing a set of exports.
64
#[repr(C)]
65
pub struct Module {
66
    /// Name of the extension.
67
    pub name: RString,
68
    /// Functions exported by the extension.
69
    pub functions: Vec<Function>,
70
    /// Classes exported by the extension.
71
    pub classes: Vec<Class>,
72
    #[cfg(feature = "enum")]
73
    /// Enums exported by the extension.
74
    pub enums: Vec<Enum>,
75
    /// Constants exported by the extension.
76
    pub constants: Vec<Constant>,
77
}
78

79
/// Builds a [`Module`] from a [`ModuleBuilder`].
80
/// This is used to generate the PHP stubs for the module.
81
impl From<ModuleBuilder<'_>> for Module {
82
    fn from(builder: ModuleBuilder) -> Self {
1✔
83
        let functions = builder.functions;
2✔
84
        Self {
85
            name: builder.name.into(),
2✔
86
            functions: functions
1✔
87
                .into_iter()
88
                .map(Function::from)
89
                .collect::<StdVec<_>>()
90
                .into(),
91
            classes: builder
1✔
92
                .classes
93
                .into_iter()
94
                .map(|c| c().into())
95
                .collect::<StdVec<_>>()
96
                .into(),
97
            constants: builder
1✔
98
                .constants
99
                .into_iter()
100
                .map(Constant::from)
101
                .collect::<StdVec<_>>()
102
                .into(),
103
            #[cfg(feature = "enum")]
104
            enums: builder
1✔
105
                .enums
106
                .into_iter()
107
                .map(|e| e().into())
108
                .collect::<StdVec<_>>()
109
                .into(),
110
        }
111
    }
112
}
113

114
/// Represents an exported function.
115
#[repr(C)]
116
pub struct Function {
117
    /// Name of the function.
118
    pub name: RString,
119
    /// Documentation comments for the function.
120
    pub docs: DocBlock,
121
    /// Return value of the function.
122
    pub ret: Option<Retval>,
123
    /// Parameters of the function.
124
    pub params: Vec<Parameter>,
125
}
126

127
impl From<FunctionBuilder<'_>> for Function {
128
    fn from(val: FunctionBuilder<'_>) -> Self {
2✔
129
        let ret_allow_null = val.ret_as_null;
4✔
130
        Function {
131
            name: val.name.into(),
4✔
132
            docs: DocBlock(
133
                val.docs
134
                    .iter()
135
                    .map(|d| (*d).into())
136
                    .collect::<StdVec<_>>()
137
                    .into(),
138
            ),
139
            ret: val
2✔
140
                .retval
141
                .map(|r| Retval {
142
                    ty: r,
143
                    nullable: r != DataType::Mixed && ret_allow_null,
144
                })
145
                .into(),
146
            params: val
2✔
147
                .args
148
                .into_iter()
149
                .map(Parameter::from)
150
                .collect::<StdVec<_>>()
151
                .into(),
152
        }
153
    }
154
}
155

156
/// Represents a parameter attached to an exported function or method.
157
#[repr(C)]
158
#[derive(Debug, PartialEq)]
159
pub struct Parameter {
160
    /// Name of the parameter.
161
    pub name: RString,
162
    /// Type of the parameter.
163
    pub ty: Option<DataType>,
164
    /// Whether the parameter is nullable.
165
    pub nullable: bool,
166
    /// Default value of the parameter.
167
    pub default: Option<RString>,
168
}
169

170
/// Represents an exported class.
171
#[repr(C)]
172
pub struct Class {
173
    /// Name of the class.
174
    pub name: RString,
175
    /// Documentation comments for the class.
176
    pub docs: DocBlock,
177
    /// Name of the class the exported class extends. (Not implemented #326)
178
    pub extends: Option<RString>,
179
    /// Names of the interfaces the exported class implements. (Not implemented
180
    /// #326)
181
    pub implements: Vec<RString>,
182
    /// Properties of the class.
183
    pub properties: Vec<Property>,
184
    /// Methods of the class.
185
    pub methods: Vec<Method>,
186
    /// Constants of the class.
187
    pub constants: Vec<Constant>,
188
}
189

190
impl From<ClassBuilder> for Class {
191
    fn from(val: ClassBuilder) -> Self {
1✔
192
        Self {
193
            name: val.name.into(),
2✔
194
            docs: DocBlock(
195
                val.docs
196
                    .iter()
197
                    .map(|doc| (*doc).into())
198
                    .collect::<StdVec<_>>()
199
                    .into(),
200
            ),
201
            extends: val.extends.map(|(_, stub)| stub.into()).into(),
5✔
202
            implements: val
1✔
203
                .interfaces
204
                .into_iter()
205
                .map(|(_, stub)| stub.into())
206
                .collect::<StdVec<_>>()
207
                .into(),
208
            properties: val
1✔
209
                .properties
210
                .into_iter()
211
                .map(Property::from)
212
                .collect::<StdVec<_>>()
213
                .into(),
214
            methods: val
1✔
215
                .methods
216
                .into_iter()
217
                .map(Method::from)
218
                .collect::<StdVec<_>>()
219
                .into(),
220
            constants: val
1✔
221
                .constants
222
                .into_iter()
223
                .map(|(name, _, docs)| (name, docs))
224
                .map(Constant::from)
225
                .collect::<StdVec<_>>()
226
                .into(),
227
        }
228
    }
229
}
230

231
#[cfg(feature = "enum")]
232
/// Represents an exported enum.
233
#[repr(C)]
234
#[derive(Debug, PartialEq)]
235
pub struct Enum {
236
    /// Name of the enum.
237
    pub name: RString,
238
    /// Documentation comments for the enum.
239
    pub docs: DocBlock,
240
    /// Cases of the enum.
241
    pub cases: Vec<EnumCase>,
242
    /// Backing type of the enum.
243
    pub backing_type: Option<RString>,
244
}
245

246
#[cfg(feature = "enum")]
247
impl From<EnumBuilder> for Enum {
NEW
248
    fn from(val: EnumBuilder) -> Self {
×
249
        Self {
NEW
250
            name: val.name.into(),
×
251
            docs: DocBlock(
252
                val.docs
253
                    .iter()
254
                    .map(|d| (*d).into())
255
                    .collect::<StdVec<_>>()
256
                    .into(),
257
            ),
NEW
258
            cases: val
×
259
                .cases
260
                .into_iter()
261
                .map(EnumCase::from)
262
                .collect::<StdVec<_>>()
263
                .into(),
NEW
264
            backing_type: match val.datatype {
×
265
                DataType::Long => Some("int".into()),
266
                DataType::String => Some("string".into()),
267
                _ => None,
268
            }
269
            .into(),
270
        }
271
    }
272
}
273

274
#[cfg(feature = "enum")]
275
/// Represents a case in an exported enum.
276
#[repr(C)]
277
#[derive(Debug, PartialEq)]
278
pub struct EnumCase {
279
    /// Name of the enum case.
280
    pub name: RString,
281
    /// Documentation comments for the enum case.
282
    pub docs: DocBlock,
283
    /// Value of the enum case.
284
    pub value: Option<RString>,
285
}
286

287
#[cfg(feature = "enum")]
288
impl From<&'static crate::enum_::EnumCase> for EnumCase {
NEW
289
    fn from(val: &'static crate::enum_::EnumCase) -> Self {
×
290
        Self {
NEW
291
            name: val.name.into(),
×
292
            docs: DocBlock(
293
                val.docs
294
                    .iter()
295
                    .map(|d| (*d).into())
296
                    .collect::<StdVec<_>>()
297
                    .into(),
298
            ),
NEW
299
            value: val
×
300
                .discriminant
301
                .as_ref()
302
                .map(|v| match v {
303
                    crate::enum_::Discriminant::Int(i) => i.to_string().into(),
304
                    crate::enum_::Discriminant::String(s) => format!("'{s}'").into(),
305
                })
306
                .into(),
307
        }
308
    }
309
}
310

311
/// Represents a property attached to an exported class.
312
#[repr(C)]
313
#[derive(Debug, PartialEq)]
314
pub struct Property {
315
    /// Name of the property.
316
    pub name: RString,
317
    /// Documentation comments for the property.
318
    pub docs: DocBlock,
319
    /// Type of the property (Not implemented #376)
320
    pub ty: Option<DataType>,
321
    /// Visibility of the property.
322
    pub vis: Visibility,
323
    /// Whether the property is static.
324
    pub static_: bool,
325
    /// Whether the property is nullable. (Not implemented #376)
326
    pub nullable: bool,
327
    /// Default value of the property. (Not implemented #376)
328
    pub default: Option<RString>,
329
}
330

331
impl From<(String, PropertyFlags, DocComments)> for Property {
332
    fn from(value: (String, PropertyFlags, DocComments)) -> Self {
2✔
333
        let (name, flags, docs) = value;
8✔
334
        let static_ = flags.contains(PropertyFlags::Static);
6✔
335
        let vis = Visibility::from(flags);
6✔
336
        // TODO: Implement ty #376
337
        let ty = abi::Option::None;
4✔
338
        // TODO: Implement default #376
339
        let default = abi::Option::<abi::RString>::None;
4✔
340
        // TODO: Implement nullable #376
341
        let nullable = false;
4✔
342
        let docs = docs.into();
6✔
343

344
        Self {
345
            name: name.into(),
6✔
346
            docs,
347
            ty,
348
            vis,
349
            static_,
350
            nullable,
351
            default,
352
        }
353
    }
354
}
355

356
/// Represents a method attached to an exported class.
357
#[repr(C)]
358
#[derive(Debug, PartialEq)]
359
pub struct Method {
360
    /// Name of the method.
361
    pub name: RString,
362
    /// Documentation comments for the method.
363
    pub docs: DocBlock,
364
    /// Type of the method.
365
    pub ty: MethodType,
366
    /// Parameters of the method.
367
    pub params: Vec<Parameter>,
368
    /// Return value of the method.
369
    pub retval: Option<Retval>,
370
    /// Whether the method is static.
371
    pub r#static: bool,
372
    /// Visibility of the method.
373
    pub visibility: Visibility,
374
}
375

376
impl From<(FunctionBuilder<'_>, MethodFlags)> for Method {
377
    fn from(val: (FunctionBuilder<'_>, MethodFlags)) -> Self {
2✔
378
        let (builder, flags) = val;
6✔
379
        let ret_allow_null = builder.ret_as_null;
4✔
380
        Method {
381
            name: builder.name.into(),
4✔
382
            docs: DocBlock(
383
                builder
384
                    .docs
385
                    .iter()
386
                    .map(|d| (*d).into())
387
                    .collect::<StdVec<_>>()
388
                    .into(),
389
            ),
390
            retval: builder
2✔
391
                .retval
392
                .map(|r| Retval {
393
                    ty: r,
394
                    nullable: r != DataType::Mixed && ret_allow_null,
395
                })
396
                .into(),
397
            params: builder
2✔
398
                .args
399
                .into_iter()
400
                .map(Into::into)
401
                .collect::<StdVec<_>>()
402
                .into(),
403
            ty: flags.into(),
4✔
404
            r#static: flags.contains(MethodFlags::Static),
4✔
405
            visibility: flags.into(),
4✔
406
        }
407
    }
408
}
409

410
/// Represents a value returned from a function or method.
411
#[repr(C)]
412
#[derive(Debug, PartialEq)]
413
pub struct Retval {
414
    /// Type of the return value.
415
    pub ty: DataType,
416
    /// Whether the return value is nullable.
417
    pub nullable: bool,
418
}
419

420
/// Enumerator used to differentiate between methods.
421
#[repr(C)]
422
#[derive(Clone, Copy, Debug, PartialEq)]
423
pub enum MethodType {
424
    /// A member method.
425
    Member,
426
    /// A static method.
427
    Static,
428
    /// A constructor.
429
    Constructor,
430
}
431

432
impl From<MethodFlags> for MethodType {
433
    fn from(value: MethodFlags) -> Self {
8✔
434
        if value.contains(MethodFlags::IsConstructor) {
16✔
435
            return Self::Constructor;
2✔
436
        }
437
        if value.contains(MethodFlags::Static) {
438
            return Self::Static;
3✔
439
        }
440

441
        Self::Member
442
    }
443
}
444

445
/// Enumerator used to differentiate between different method and property
446
/// visibilties.
447
#[repr(C)]
448
#[derive(Clone, Copy, Debug, PartialEq)]
449
pub enum Visibility {
450
    /// Private visibility.
451
    Private,
452
    /// Protected visibility.
453
    Protected,
454
    /// Public visibility.
455
    Public,
456
}
457

458
impl From<PropertyFlags> for Visibility {
459
    fn from(value: PropertyFlags) -> Self {
7✔
460
        if value.contains(PropertyFlags::Protected) {
14✔
461
            return Self::Protected;
3✔
462
        }
463
        if value.contains(PropertyFlags::Private) {
464
            return Self::Private;
1✔
465
        }
466

467
        Self::Public
468
    }
469
}
470

471
impl From<MethodFlags> for Visibility {
472
    fn from(value: MethodFlags) -> Self {
7✔
473
        if value.contains(MethodFlags::Protected) {
14✔
474
            return Self::Protected;
4✔
475
        }
476

477
        if value.contains(MethodFlags::Private) {
478
            return Self::Private;
1✔
479
        }
480

481
        Self::Public
482
    }
483
}
484

485
/// Represents an exported constant, stand alone or attached to a class.
486
#[repr(C)]
487
pub struct Constant {
488
    /// Name of the constant.
489
    pub name: RString,
490
    /// Documentation comments for the constant.
491
    pub docs: DocBlock,
492
    /// Value of the constant.
493
    pub value: Option<RString>,
494
}
495

496
impl From<(String, DocComments)> for Constant {
497
    fn from(val: (String, DocComments)) -> Self {
×
498
        let (name, docs) = val;
×
499
        Constant {
500
            name: name.into(),
×
501
            value: abi::Option::None,
502
            docs: docs.into(),
×
503
        }
504
    }
505
}
506

507
impl From<(String, Box<dyn IntoConst + Send>, DocComments)> for Constant {
508
    fn from(val: (String, Box<dyn IntoConst + Send + 'static>, DocComments)) -> Self {
×
509
        let (name, _, docs) = val;
×
510
        Constant {
511
            name: name.into(),
×
512
            value: abi::Option::None,
513
            docs: docs.into(),
×
514
        }
515
    }
516
}
517

518
#[cfg(test)]
519
mod tests {
520
    #![cfg_attr(windows, feature(abi_vectorcall))]
521
    use super::*;
522

523
    use crate::{args::Arg, test::test_function};
524

525
    #[test]
526
    fn test_new_description() {
527
        let module = Module {
528
            name: "test".into(),
529
            functions: vec![].into(),
530
            classes: vec![].into(),
531
            constants: vec![].into(),
532
            #[cfg(feature = "enum")]
533
            enums: vec![].into(),
534
        };
535

536
        let description = Description::new(module);
537
        assert_eq!(description.version, crate::VERSION);
538
        assert_eq!(description.module.name, "test".into());
539
    }
540

541
    #[test]
542
    fn test_doc_block_from() {
543
        let docs: &'static [&'static str] = &["doc1", "doc2"];
544
        let docs: DocBlock = docs.into();
545
        assert_eq!(docs.0.len(), 2);
546
        assert_eq!(docs.0[0], "doc1".into());
547
        assert_eq!(docs.0[1], "doc2".into());
548
    }
549

550
    #[test]
551
    fn test_module_from() {
552
        let builder = ModuleBuilder::new("test", "test_version")
553
            .function(FunctionBuilder::new("test_function", test_function));
554
        let module: Module = builder.into();
555
        assert_eq!(module.name, "test".into());
556
        assert_eq!(module.functions.len(), 1);
557
        assert_eq!(module.classes.len(), 0);
558
        assert_eq!(module.constants.len(), 0);
559
    }
560

561
    #[test]
562
    fn test_function_from() {
563
        let builder = FunctionBuilder::new("test_function", test_function)
564
            .docs(&["doc1", "doc2"])
565
            .arg(Arg::new("foo", DataType::Long))
566
            .returns(DataType::Bool, true, true);
567
        let function: Function = builder.into();
568
        assert_eq!(function.name, "test_function".into());
569
        assert_eq!(function.docs.0.len(), 2);
570
        assert_eq!(
571
            function.params,
572
            vec![Parameter {
573
                name: "foo".into(),
574
                ty: Option::Some(DataType::Long),
575
                nullable: false,
576
                default: Option::None,
577
            }]
578
            .into()
579
        );
580
        assert_eq!(
581
            function.ret,
582
            Option::Some(Retval {
583
                ty: DataType::Bool,
584
                nullable: true,
585
            })
586
        );
587
    }
588

589
    #[test]
590
    fn test_class_from() {
591
        let builder = ClassBuilder::new("TestClass")
592
            .docs(&["doc1", "doc2"])
593
            .extends((|| todo!(), "BaseClass"))
594
            .implements((|| todo!(), "Interface1"))
595
            .implements((|| todo!(), "Interface2"))
596
            .property("prop1", PropertyFlags::Public, &["doc1"])
597
            .method(
598
                FunctionBuilder::new("test_function", test_function),
599
                MethodFlags::Protected,
600
            );
601
        let class: Class = builder.into();
602

603
        assert_eq!(class.name, "TestClass".into());
604
        assert_eq!(class.docs.0.len(), 2);
605
        assert_eq!(class.extends, Option::Some("BaseClass".into()));
606
        assert_eq!(
607
            class.implements,
608
            vec!["Interface1".into(), "Interface2".into()].into()
609
        );
610
        assert_eq!(class.properties.len(), 1);
611
        assert_eq!(
612
            class.properties[0],
613
            Property {
614
                name: "prop1".into(),
615
                docs: DocBlock(vec!["doc1".into()].into()),
616
                ty: Option::None,
617
                vis: Visibility::Public,
618
                static_: false,
619
                nullable: false,
620
                default: Option::None,
621
            }
622
        );
623
        assert_eq!(class.methods.len(), 1);
624
        assert_eq!(
625
            class.methods[0],
626
            Method {
627
                name: "test_function".into(),
628
                docs: DocBlock(vec![].into()),
629
                ty: MethodType::Member,
630
                params: vec![].into(),
631
                retval: Option::None,
632
                r#static: false,
633
                visibility: Visibility::Protected,
634
            }
635
        );
636
    }
637

638
    #[test]
639
    fn test_property_from() {
640
        let docs: &'static [&'static str] = &["doc1", "doc2"];
641
        let property: Property =
642
            ("test_property".to_string(), PropertyFlags::Protected, docs).into();
643
        assert_eq!(property.name, "test_property".into());
644
        assert_eq!(property.docs.0.len(), 2);
645
        assert_eq!(property.vis, Visibility::Protected);
646
        assert!(!property.static_);
647
        assert!(!property.nullable);
648
    }
649

650
    #[test]
651
    fn test_method_from() {
652
        let builder = FunctionBuilder::new("test_method", test_function)
653
            .docs(&["doc1", "doc2"])
654
            .arg(Arg::new("foo", DataType::Long))
655
            .returns(DataType::Bool, true, true);
656
        let method: Method = (builder, MethodFlags::Static | MethodFlags::Protected).into();
657
        assert_eq!(method.name, "test_method".into());
658
        assert_eq!(method.docs.0.len(), 2);
659
        assert_eq!(
660
            method.params,
661
            vec![Parameter {
662
                name: "foo".into(),
663
                ty: Option::Some(DataType::Long),
664
                nullable: false,
665
                default: Option::None,
666
            }]
667
            .into()
668
        );
669
        assert_eq!(
670
            method.retval,
671
            Option::Some(Retval {
672
                ty: DataType::Bool,
673
                nullable: true,
674
            })
675
        );
676
        assert!(method.r#static);
677
        assert_eq!(method.visibility, Visibility::Protected);
678
        assert_eq!(method.ty, MethodType::Static);
679
    }
680

681
    #[test]
682
    fn test_ty_from() {
683
        let r#static: MethodType = MethodFlags::Static.into();
684
        assert_eq!(r#static, MethodType::Static);
685

686
        let constructor: MethodType = MethodFlags::IsConstructor.into();
687
        assert_eq!(constructor, MethodType::Constructor);
688

689
        let member: MethodType = MethodFlags::Public.into();
690
        assert_eq!(member, MethodType::Member);
691

692
        let mixed: MethodType = (MethodFlags::Protected | MethodFlags::Static).into();
693
        assert_eq!(mixed, MethodType::Static);
694

695
        let both: MethodType = (MethodFlags::Static | MethodFlags::IsConstructor).into();
696
        assert_eq!(both, MethodType::Constructor);
697

698
        let empty: MethodType = MethodFlags::empty().into();
699
        assert_eq!(empty, MethodType::Member);
700
    }
701

702
    #[test]
703
    fn test_prop_visibility_from() {
704
        let private: Visibility = PropertyFlags::Private.into();
705
        assert_eq!(private, Visibility::Private);
706

707
        let protected: Visibility = PropertyFlags::Protected.into();
708
        assert_eq!(protected, Visibility::Protected);
709

710
        let public: Visibility = PropertyFlags::Public.into();
711
        assert_eq!(public, Visibility::Public);
712

713
        let mixed: Visibility = (PropertyFlags::Protected | PropertyFlags::Static).into();
714
        assert_eq!(mixed, Visibility::Protected);
715

716
        let empty: Visibility = PropertyFlags::empty().into();
717
        assert_eq!(empty, Visibility::Public);
718
    }
719

720
    #[test]
721
    fn test_method_visibility_from() {
722
        let private: Visibility = MethodFlags::Private.into();
723
        assert_eq!(private, Visibility::Private);
724

725
        let protected: Visibility = MethodFlags::Protected.into();
726
        assert_eq!(protected, Visibility::Protected);
727

728
        let public: Visibility = MethodFlags::Public.into();
729
        assert_eq!(public, Visibility::Public);
730

731
        let mixed: Visibility = (MethodFlags::Protected | MethodFlags::Static).into();
732
        assert_eq!(mixed, Visibility::Protected);
733

734
        let empty: Visibility = MethodFlags::empty().into();
735
        assert_eq!(empty, Visibility::Public);
736
    }
737
}
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