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

naomijub / serde_json_shape / 15685826407

16 Jun 2025 04:01PM UTC coverage: 60.646% (+3.0%) from 57.679%
15685826407

push

github

web-flow
subset, from_sources, improve readme (#1)

* subset, improve readme

* is_superset of

* partial impl of from_sources

161 of 313 new or added lines in 6 files covered. (51.44%)

4 existing lines in 1 file now uncovered.

319 of 526 relevant lines covered (60.65%)

2.45 hits per line

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

30.51
/src/value/subtypes.rs
1
use crate::value::Value;
2

3
/// Simple helper phantom struct to determine if `JsonShape` is of specific subtype `Null`.
4
pub struct Null;
5
/// Simple helper phantom struct to determine if `JsonShape` is of specific subtype `Number`.
6
pub struct Number;
7
/// Simple helper phantom struct to determine if `JsonShape` is of specific subtype `Boolean`.
8
pub struct Boolean;
9
/// Simple helper phantom struct to determine if `JsonShape` is of specific subtype `String`.
10
pub struct String;
11
/// Simple helper phantom struct to determine if `JsonShape` is of specific subtype `Array`.
12
pub struct Array;
13
/// Simple helper phantom struct to determine if `JsonShape` is of specific subtype `Object`.
14
pub struct Object;
15
/// Simple helper phantom struct to determine if `JsonShape` is of specific subtype `OneOf`.
16
pub struct OneOf;
17

18
/// Simple helper struct to determine if `JsonShape` is of specific optional subtype.
19
pub struct Optional<U>(std::marker::PhantomData<U>);
20

21
mod private {
22
    use crate::value::Value;
23

24
    pub trait Sealed {}
25
    impl Sealed for Value {}
26
}
27

28
/// Checks if [`JsonShape`] is an Array of `T`
29
pub trait IsArrayOf<T>: private::Sealed {
30
    /// Checks if [`JsonShape`] is an Array of `T`
31
    /// - `value.is_array_of::<Null>()`.
32
    #[allow(dead_code)]
33
    fn is_array_of(&self) -> bool;
34
}
35

36
/// Checks if [`JsonShape`] is `OneOf` containing `T`
37
pub trait IsOneOf<T>: private::Sealed {
38
    /// Checks if [`JsonShape`] is `OneOf` containing `T`
39
    /// - `value.is_one_of::<Null>()`.
40
    fn is_one_of(&self) -> bool;
41
}
42

43
/// Checks if [`JsonShape`] is `Object` containing `key: &str` and  `value: T`
44
pub trait IsObjectOf<T>: private::Sealed {
45
    /// Checks if [`JsonShape`] is `Object` containing `key: &str` and  `value: T`
46
    /// - `value.is_object_of::<Null>("key_1")`.
47
    #[allow(dead_code)]
48
    fn is_object_of(&self, key: &str) -> bool;
49
}
50

51
// ARRAY
52
impl IsArrayOf<Null> for Value {
53
    fn is_array_of(&self) -> bool {
1✔
54
        if let Value::Array { r#type, .. } = self {
1✔
55
            **r#type == Value::Null
2✔
56
        } else {
NEW
57
            false
×
58
        }
59
    }
60
}
61

62
impl IsArrayOf<Number> for Value {
63
    fn is_array_of(&self) -> bool {
1✔
64
        if let Value::Array { r#type, .. } = self {
1✔
65
            matches!(**r#type, Value::Number { optional: false })
2✔
66
        } else {
NEW
67
            false
×
68
        }
69
    }
70
}
71

72
impl IsArrayOf<Optional<Number>> for Value {
NEW
73
    fn is_array_of(&self) -> bool {
×
NEW
74
        if let Value::Array { r#type, .. } = self {
×
NEW
75
            matches!(**r#type, Value::Number { optional: true })
×
76
        } else {
NEW
77
            false
×
78
        }
79
    }
80
}
81

82
impl IsArrayOf<String> for Value {
83
    fn is_array_of(&self) -> bool {
1✔
84
        if let Value::Array { r#type, .. } = self {
1✔
85
            matches!(**r#type, Value::String { optional: false })
2✔
86
        } else {
NEW
87
            false
×
88
        }
89
    }
90
}
91

92
impl IsArrayOf<Optional<String>> for Value {
NEW
93
    fn is_array_of(&self) -> bool {
×
NEW
94
        if let Value::Array { r#type, .. } = self {
×
NEW
95
            matches!(**r#type, Value::String { optional: true })
×
96
        } else {
NEW
97
            false
×
98
        }
99
    }
100
}
101

102
impl IsArrayOf<Boolean> for Value {
103
    fn is_array_of(&self) -> bool {
1✔
104
        if let Value::Array { r#type, .. } = self {
1✔
105
            matches!(**r#type, Value::Bool { optional: false })
2✔
106
        } else {
NEW
107
            false
×
108
        }
109
    }
110
}
111

112
impl IsArrayOf<Optional<Boolean>> for Value {
NEW
113
    fn is_array_of(&self) -> bool {
×
NEW
114
        if let Value::Array { r#type, .. } = self {
×
NEW
115
            matches!(**r#type, Value::Bool { optional: true })
×
116
        } else {
NEW
117
            false
×
118
        }
119
    }
120
}
121

122
impl IsArrayOf<Array> for Value {
NEW
123
    fn is_array_of(&self) -> bool {
×
NEW
124
        if let Value::Array { r#type, .. } = self {
×
NEW
125
            matches!(
×
NEW
126
                **r#type,
×
127
                Value::Array {
128
                    optional: false,
129
                    ..
130
                }
131
            )
132
        } else {
NEW
133
            false
×
134
        }
135
    }
136
}
137

138
impl IsArrayOf<Optional<Array>> for Value {
NEW
139
    fn is_array_of(&self) -> bool {
×
NEW
140
        if let Value::Array { r#type, .. } = self {
×
NEW
141
            matches!(**r#type, Value::Array { optional: true, .. })
×
142
        } else {
NEW
143
            false
×
144
        }
145
    }
146
}
147

148
impl IsArrayOf<Object> for Value {
NEW
149
    fn is_array_of(&self) -> bool {
×
NEW
150
        if let Value::Array { r#type, .. } = self {
×
NEW
151
            matches!(
×
NEW
152
                **r#type,
×
153
                Value::Object {
154
                    optional: false,
155
                    ..
156
                }
157
            )
158
        } else {
NEW
159
            false
×
160
        }
161
    }
162
}
163

164
impl IsArrayOf<Optional<Object>> for Value {
NEW
165
    fn is_array_of(&self) -> bool {
×
NEW
166
        if let Value::Array { r#type, .. } = self {
×
NEW
167
            matches!(**r#type, Value::Object { optional: true, .. })
×
168
        } else {
NEW
169
            false
×
170
        }
171
    }
172
}
173

174
impl IsArrayOf<OneOf> for Value {
NEW
175
    fn is_array_of(&self) -> bool {
×
NEW
176
        if let Value::Array { r#type, .. } = self {
×
NEW
177
            matches!(
×
NEW
178
                **r#type,
×
179
                Value::OneOf {
180
                    optional: false,
181
                    ..
182
                }
183
            )
184
        } else {
NEW
185
            false
×
186
        }
187
    }
188
}
189

190
impl IsArrayOf<Optional<OneOf>> for Value {
NEW
191
    fn is_array_of(&self) -> bool {
×
NEW
192
        if let Value::Array { r#type, .. } = self {
×
NEW
193
            matches!(**r#type, Value::OneOf { optional: true, .. })
×
194
        } else {
NEW
195
            false
×
196
        }
197
    }
198
}
199

200
// OneOf
201
impl IsOneOf<Null> for Value {
NEW
202
    fn is_one_of(&self) -> bool {
×
NEW
203
        if let Value::OneOf { variants, .. } = self {
×
NEW
204
            variants.contains(&Value::Null)
×
205
        } else {
NEW
206
            false
×
207
        }
208
    }
209
}
210

211
impl IsOneOf<Number> for Value {
212
    fn is_one_of(&self) -> bool {
1✔
213
        if let Value::OneOf { variants, .. } = self {
1✔
214
            variants
215
                .iter()
216
                .any(|variant| matches!(&variant, &Value::Number { optional: false }))
3✔
217
        } else {
218
            false
1✔
219
        }
220
    }
221
}
222

223
impl IsOneOf<String> for Value {
224
    fn is_one_of(&self) -> bool {
1✔
225
        if let Value::OneOf { variants, .. } = self {
1✔
226
            variants
227
                .iter()
228
                .any(|variant| matches!(&variant, &Value::String { optional: false }))
3✔
229
        } else {
230
            false
1✔
231
        }
232
    }
233
}
234

235
impl IsOneOf<Boolean> for Value {
236
    fn is_one_of(&self) -> bool {
1✔
237
        if let Value::OneOf { variants, .. } = self {
2✔
238
            variants
239
                .iter()
240
                .any(|variant| matches!(&variant, &Value::Bool { optional: false }))
3✔
241
        } else {
242
            false
1✔
243
        }
244
    }
245
}
246

247
impl IsOneOf<Array> for Value {
NEW
248
    fn is_one_of(&self) -> bool {
×
NEW
249
        if let Value::OneOf { variants, .. } = self {
×
NEW
250
            variants.iter().any(|variant| {
×
NEW
251
                matches!(
×
NEW
252
                    &variant,
×
253
                    &Value::Array {
254
                        optional: false,
255
                        ..
256
                    }
257
                )
258
            })
259
        } else {
NEW
260
            false
×
261
        }
262
    }
263
}
264

265
impl IsOneOf<Object> for Value {
NEW
266
    fn is_one_of(&self) -> bool {
×
NEW
267
        if let Value::OneOf { variants, .. } = self {
×
NEW
268
            variants.iter().any(|variant| {
×
NEW
269
                matches!(
×
NEW
270
                    &variant,
×
271
                    &Value::Object {
272
                        optional: false,
273
                        ..
274
                    }
275
                )
276
            })
277
        } else {
NEW
278
            false
×
279
        }
280
    }
281
}
282

283
impl IsOneOf<OneOf> for Value {
NEW
284
    fn is_one_of(&self) -> bool {
×
NEW
285
        if let Value::OneOf { variants, .. } = self {
×
NEW
286
            variants.iter().any(|variant| {
×
NEW
287
                matches!(
×
NEW
288
                    &variant,
×
289
                    &Value::OneOf {
290
                        optional: false,
291
                        ..
292
                    }
293
                )
294
            })
295
        } else {
NEW
296
            false
×
297
        }
298
    }
299
}
300

301
impl IsOneOf<Optional<Number>> for Value {
302
    fn is_one_of(&self) -> bool {
2✔
303
        if let Value::OneOf { variants, .. } = self {
2✔
304
            variants
305
                .iter()
306
                .any(|variant| matches!(&variant, &Value::Number { optional: true }))
3✔
307
        } else {
308
            false
2✔
309
        }
310
    }
311
}
312

313
impl IsOneOf<Optional<String>> for Value {
314
    fn is_one_of(&self) -> bool {
1✔
315
        if let Value::OneOf { variants, .. } = self {
1✔
316
            variants
317
                .iter()
318
                .any(|variant| matches!(&variant, &Value::String { optional: true }))
3✔
319
        } else {
320
            false
1✔
321
        }
322
    }
323
}
324

325
impl IsOneOf<Optional<Boolean>> for Value {
326
    fn is_one_of(&self) -> bool {
1✔
327
        if let Value::OneOf { variants, .. } = self {
1✔
328
            variants
329
                .iter()
330
                .any(|variant| matches!(&variant, &Value::Bool { optional: true }))
3✔
331
        } else {
332
            false
1✔
333
        }
334
    }
335
}
336

337
impl IsOneOf<Optional<Array>> for Value {
NEW
338
    fn is_one_of(&self) -> bool {
×
NEW
339
        if let Value::OneOf { variants, .. } = self {
×
340
            variants
341
                .iter()
NEW
342
                .any(|variant| matches!(&variant, &Value::Array { optional: true, .. }))
×
343
        } else {
NEW
344
            false
×
345
        }
346
    }
347
}
348

349
impl IsOneOf<Optional<Object>> for Value {
NEW
350
    fn is_one_of(&self) -> bool {
×
NEW
351
        if let Value::OneOf { variants, .. } = self {
×
352
            variants
353
                .iter()
NEW
354
                .any(|variant| matches!(&variant, &Value::Object { optional: true, .. }))
×
355
        } else {
NEW
356
            false
×
357
        }
358
    }
359
}
360

361
impl IsOneOf<Optional<OneOf>> for Value {
NEW
362
    fn is_one_of(&self) -> bool {
×
NEW
363
        if let Value::OneOf { variants, .. } = self {
×
364
            variants
365
                .iter()
NEW
366
                .any(|variant| matches!(&variant, &Value::OneOf { optional: true, .. }))
×
367
        } else {
NEW
368
            false
×
369
        }
370
    }
371
}
372

373
// Object
374
impl IsObjectOf<Null> for Value {
NEW
375
    fn is_object_of(&self, key: &str) -> bool {
×
NEW
376
        if let Value::Object { content, .. } = self {
×
377
            content
378
                .iter()
NEW
379
                .any(|(k, value)| k == key && matches!(&value, &Value::Null))
×
380
        } else {
NEW
381
            false
×
382
        }
383
    }
384
}
385

386
impl IsObjectOf<Number> for Value {
387
    fn is_object_of(&self, key: &str) -> bool {
1✔
388
        if let Value::Object { content, .. } = self {
1✔
389
            content
390
                .iter()
391
                .any(|(k, value)| k == key && matches!(&value, &Value::Number { optional: false }))
3✔
392
        } else {
NEW
393
            false
×
394
        }
395
    }
396
}
397

398
impl IsObjectOf<String> for Value {
399
    fn is_object_of(&self, key: &str) -> bool {
1✔
400
        if let Value::Object { content, .. } = self {
1✔
401
            content
402
                .iter()
403
                .any(|(k, value)| k == key && matches!(&value, &Value::String { optional: false }))
3✔
404
        } else {
NEW
405
            false
×
406
        }
407
    }
408
}
409

410
impl IsObjectOf<Boolean> for Value {
411
    fn is_object_of(&self, key: &str) -> bool {
1✔
412
        if let Value::Object { content, .. } = self {
1✔
413
            content
414
                .iter()
415
                .any(|(k, value)| k == key && matches!(&value, &Value::Bool { optional: false }))
3✔
416
        } else {
NEW
417
            false
×
418
        }
419
    }
420
}
421

422
impl IsObjectOf<Array> for Value {
NEW
423
    fn is_object_of(&self, key: &str) -> bool {
×
NEW
424
        if let Value::Object { content, .. } = self {
×
NEW
425
            content.iter().any(|(k, value)| {
×
NEW
426
                k == key
×
NEW
427
                    && matches!(
×
NEW
428
                        &value,
×
429
                        &Value::Array {
430
                            optional: false,
431
                            ..
432
                        }
433
                    )
434
            })
435
        } else {
NEW
436
            false
×
437
        }
438
    }
439
}
440

441
impl IsObjectOf<Object> for Value {
NEW
442
    fn is_object_of(&self, key: &str) -> bool {
×
NEW
443
        if let Value::Object { content, .. } = self {
×
NEW
444
            content.iter().any(|(k, value)| {
×
NEW
445
                k == key
×
NEW
446
                    && matches!(
×
NEW
447
                        &value,
×
448
                        &Value::Object {
449
                            optional: false,
450
                            ..
451
                        }
452
                    )
453
            })
454
        } else {
NEW
455
            false
×
456
        }
457
    }
458
}
459

460
impl IsObjectOf<OneOf> for Value {
NEW
461
    fn is_object_of(&self, key: &str) -> bool {
×
NEW
462
        if let Value::Object { content, .. } = self {
×
NEW
463
            content.iter().any(|(k, value)| {
×
NEW
464
                k == key
×
NEW
465
                    && matches!(
×
NEW
466
                        &value,
×
467
                        &Value::OneOf {
468
                            optional: false,
469
                            ..
470
                        }
471
                    )
472
            })
473
        } else {
NEW
474
            false
×
475
        }
476
    }
477
}
478

479
impl IsObjectOf<Optional<Number>> for Value {
480
    fn is_object_of(&self, key: &str) -> bool {
1✔
481
        if let Value::Object { content, .. } = self {
1✔
482
            content
483
                .iter()
484
                .any(|(k, value)| k == key && matches!(&value, &Value::Number { optional: true }))
3✔
485
        } else {
NEW
486
            false
×
487
        }
488
    }
489
}
490

491
impl IsObjectOf<Optional<String>> for Value {
492
    fn is_object_of(&self, key: &str) -> bool {
1✔
493
        if let Value::Object { content, .. } = self {
1✔
494
            content
495
                .iter()
496
                .any(|(k, value)| k == key && matches!(&value, &Value::String { optional: true }))
3✔
497
        } else {
NEW
498
            false
×
499
        }
500
    }
501
}
502

503
impl IsObjectOf<Optional<Boolean>> for Value {
504
    fn is_object_of(&self, key: &str) -> bool {
1✔
505
        if let Value::Object { content, .. } = self {
1✔
506
            content
507
                .iter()
508
                .any(|(k, value)| k == key && matches!(&value, &Value::Bool { optional: true }))
3✔
509
        } else {
NEW
510
            false
×
511
        }
512
    }
513
}
514

515
impl IsObjectOf<Optional<Array>> for Value {
NEW
516
    fn is_object_of(&self, key: &str) -> bool {
×
NEW
517
        if let Value::Object { content, .. } = self {
×
NEW
518
            content.iter().any(|(k, value)| {
×
NEW
519
                k == key && matches!(&value, &Value::Array { optional: true, .. })
×
520
            })
521
        } else {
NEW
522
            false
×
523
        }
524
    }
525
}
526

527
impl IsObjectOf<Optional<Object>> for Value {
NEW
528
    fn is_object_of(&self, key: &str) -> bool {
×
NEW
529
        if let Value::Object { content, .. } = self {
×
NEW
530
            content.iter().any(|(k, value)| {
×
NEW
531
                k == key && matches!(&value, &Value::Object { optional: true, .. })
×
532
            })
533
        } else {
NEW
534
            false
×
535
        }
536
    }
537
}
538

539
impl IsObjectOf<Optional<OneOf>> for Value {
NEW
540
    fn is_object_of(&self, key: &str) -> bool {
×
NEW
541
        if let Value::Object { content, .. } = self {
×
NEW
542
            content.iter().any(|(k, value)| {
×
NEW
543
                k == key && matches!(&value, &Value::OneOf { optional: true, .. })
×
544
            })
545
        } else {
NEW
546
            false
×
547
        }
548
    }
549
}
550

551
#[cfg(test)]
552
mod tests {
553
    use super::*;
554

555
    #[test]
556
    fn is_array_of_null() {
557
        assert!(IsArrayOf::<Null>::is_array_of(&Value::Array {
558
            r#type: Box::new(Value::Null),
559
            optional: false
560
        }));
561
        assert!(!IsArrayOf::<Null>::is_array_of(&Value::Array {
562
            r#type: Box::new(Value::Number { optional: true }),
563
            optional: false
564
        }));
565
    }
566

567
    #[test]
568
    fn is_array_of_number() {
569
        assert!(IsArrayOf::<Number>::is_array_of(&Value::Array {
570
            r#type: Box::new(Value::Number { optional: false }),
571
            optional: false
572
        }));
573
        assert!(!IsArrayOf::<Number>::is_array_of(&Value::Array {
574
            r#type: Box::new(Value::Bool { optional: true }),
575
            optional: false
576
        }));
577
    }
578

579
    #[test]
580
    fn is_array_of_string() {
581
        assert!(IsArrayOf::<String>::is_array_of(&Value::Array {
582
            r#type: Box::new(Value::String { optional: false }),
583
            optional: false
584
        }));
585
        assert!(!IsArrayOf::<String>::is_array_of(&Value::Array {
586
            r#type: Box::new(Value::Bool { optional: true }),
587
            optional: false
588
        }));
589
    }
590

591
    #[test]
592
    fn is_array_of_bool() {
593
        assert!(IsArrayOf::<Boolean>::is_array_of(&Value::Array {
594
            r#type: Box::new(Value::Bool { optional: false }),
595
            optional: false
596
        }));
597
        assert!(!IsArrayOf::<Boolean>::is_array_of(&Value::Array {
598
            r#type: Box::new(Value::String { optional: true }),
599
            optional: false
600
        }));
601
    }
602

603
    #[test]
604
    fn is_oneof_of_number() {
605
        assert!(IsOneOf::<Optional<Number>>::is_one_of(&Value::OneOf {
606
            variants: [
607
                Value::Number { optional: true },
608
                Value::Bool { optional: true },
609
                Value::String { optional: true }
610
            ]
611
            .into(),
612
            optional: false
613
        }));
614
        assert!(IsOneOf::<Number>::is_one_of(&Value::OneOf {
615
            variants: [
616
                Value::Number { optional: false },
617
                Value::Bool { optional: false },
618
                Value::String { optional: false }
619
            ]
620
            .into(),
621
            optional: false
622
        }));
623
    }
624

625
    #[test]
626
    fn is_oneof_of_bool() {
627
        assert!(IsOneOf::<Optional<Boolean>>::is_one_of(&Value::OneOf {
628
            variants: [
629
                Value::Number { optional: true },
630
                Value::Bool { optional: true },
631
                Value::String { optional: true }
632
            ]
633
            .into(),
634
            optional: false
635
        }));
636
        assert!(IsOneOf::<Boolean>::is_one_of(&Value::OneOf {
637
            variants: [
638
                Value::Number { optional: false },
639
                Value::Bool { optional: false },
640
                Value::String { optional: false }
641
            ]
642
            .into(),
643
            optional: false
644
        }));
645
    }
646

647
    #[test]
648
    fn is_oneof_of_string() {
649
        assert!(IsOneOf::<Optional<String>>::is_one_of(&Value::OneOf {
650
            variants: [
651
                Value::Number { optional: true },
652
                Value::Bool { optional: true },
653
                Value::String { optional: true }
654
            ]
655
            .into(),
656
            optional: false
657
        }));
658
        assert!(IsOneOf::<String>::is_one_of(&Value::OneOf {
659
            variants: [
660
                Value::Number { optional: false },
661
                Value::Bool { optional: false },
662
                Value::String { optional: false }
663
            ]
664
            .into(),
665
            optional: false
666
        }));
667
    }
668

669
    #[test]
670
    fn is_object_of_number() {
671
        assert!(IsObjectOf::<Number>::is_object_of(
672
            &Value::Object {
673
                content: [("key".to_string(), Value::Number { optional: false })].into(),
674
                optional: false
675
            },
676
            "key"
677
        ));
678

679
        assert!(IsObjectOf::<Optional<Number>>::is_object_of(
680
            &Value::Object {
681
                content: [("key".to_string(), Value::Number { optional: true })].into(),
682
                optional: false
683
            },
684
            "key"
685
        ));
686
    }
687

688
    #[test]
689
    fn is_object_of_string() {
690
        assert!(IsObjectOf::<String>::is_object_of(
691
            &Value::Object {
692
                content: [("key".to_string(), Value::String { optional: false })].into(),
693
                optional: false
694
            },
695
            "key"
696
        ));
697

698
        assert!(IsObjectOf::<Optional<String>>::is_object_of(
699
            &Value::Object {
700
                content: [("key".to_string(), Value::String { optional: true })].into(),
701
                optional: false
702
            },
703
            "key"
704
        ));
705
    }
706

707
    #[test]
708
    fn is_object_of_bool() {
709
        assert!(IsObjectOf::<Boolean>::is_object_of(
710
            &Value::Object {
711
                content: [("key".to_string(), Value::Bool { optional: false })].into(),
712
                optional: false
713
            },
714
            "key"
715
        ));
716

717
        assert!(IsObjectOf::<Optional<Boolean>>::is_object_of(
718
            &Value::Object {
719
                content: [("key".to_string(), Value::Bool { optional: true })].into(),
720
                optional: false
721
            },
722
            "key"
723
        ));
724
    }
725
}
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