1#![allow(clippy::match_same_arms)]
2use std::{
3 collections::{BTreeMap, BTreeSet, btree_map::Keys},
4 fmt::Display,
5};
6
7use serde::{Deserialize, Serialize};
8
9pub mod subset;
10pub mod subtypes;
11
12pub trait Similar<Rhs: ?Sized = Self> {
14 #[must_use]
16 fn similar(&self, other: &Rhs) -> Option<Value>;
17}
18
19#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
23pub enum Value {
24 Null,
26
27 Bool {
29 optional: bool,
31 },
32
33 Number {
35 optional: bool,
37 },
38 String {
40 optional: bool,
42 },
43 Array {
45 r#type: Box<Value>,
47 optional: bool,
49 },
50
51 Object {
53 content: BTreeMap<String, Value>,
55 optional: bool,
57 },
58
59 OneOf {
62 variants: BTreeSet<Value>,
64 optional: bool,
66 },
67
68 Tuple {
71 elements: Vec<Value>,
73 optional: bool,
75 },
76}
77
78impl Value {
79 #[must_use]
81 pub const fn is_optional(&self) -> bool {
82 match self {
83 Value::Null => true,
84 Value::Bool { optional } => *optional,
85 Value::Number { optional } => *optional,
86 Value::String { optional } => *optional,
87 Value::Array { optional, .. } => *optional,
88 Value::Object { optional, .. } => *optional,
89 Value::OneOf { optional, .. } => *optional,
90 Value::Tuple { optional, .. } => *optional,
91 }
92 }
93
94 #[allow(clippy::wrong_self_convention)]
95 pub(crate) fn as_optional(self) -> Self {
96 match self {
97 Value::Null => Value::Null,
98 Value::Bool { .. } => Value::Bool { optional: true },
99 Value::Number { .. } => Value::Number { optional: true },
100 Value::String { .. } => Value::String { optional: true },
101 Value::Array { r#type, .. } => Value::Array {
102 optional: true,
103 r#type,
104 },
105 Value::Object { content, .. } => Value::Object {
106 optional: true,
107 content,
108 },
109 Value::OneOf { variants, .. } => Value::OneOf {
110 optional: true,
111 variants,
112 },
113 Value::Tuple { elements, .. } => Value::Tuple {
114 optional: true,
115 elements,
116 },
117 }
118 }
119
120 #[allow(clippy::wrong_self_convention)]
121 pub(crate) fn as_non_optional(self) -> Self {
122 match self {
123 Value::Null => Value::Null,
124 Value::Bool { .. } => Value::Bool { optional: false },
125 Value::Number { .. } => Value::Number { optional: false },
126 Value::String { .. } => Value::String { optional: false },
127 Value::Array { r#type, .. } => Value::Array {
128 optional: false,
129 r#type,
130 },
131 Value::Object { content, .. } => Value::Object {
132 optional: false,
133 content,
134 },
135 Value::OneOf { variants, .. } => Value::OneOf {
136 optional: false,
137 variants,
138 },
139 Value::Tuple { elements, .. } => Value::Tuple {
140 optional: false,
141 elements,
142 },
143 }
144 }
145
146 pub(crate) const fn to_optional_mut(&mut self) {
147 match self {
148 Value::Null => (),
149 Value::Bool { optional } => {
150 *optional = true;
151 }
152 Value::Number { optional } => {
153 *optional = true;
154 }
155 Value::String { optional } => {
156 *optional = true;
157 }
158 Value::Array { optional, .. } => {
159 *optional = true;
160 }
161 Value::Object { optional, .. } => {
162 *optional = true;
163 }
164 Value::OneOf { optional, .. } => {
165 *optional = true;
166 }
167 Value::Tuple { optional, .. } => {
168 *optional = true;
169 }
170 }
171 }
172
173 #[must_use]
175 pub fn keys(&self) -> Option<Keys<String, Value>> {
176 if let Self::Object { content, .. } = self {
177 Some(content.keys())
178 } else {
179 None
180 }
181 }
182
183 #[must_use]
185 pub const fn is_null(&self) -> bool {
186 matches!(self, Self::Null)
187 }
188
189 #[must_use]
191 pub const fn is_boolean(&self) -> bool {
192 matches!(self, Self::Bool { .. })
193 }
194
195 #[must_use]
197 pub const fn is_number(&self) -> bool {
198 matches!(self, Self::Number { .. })
199 }
200
201 #[must_use]
203 pub const fn is_string(&self) -> bool {
204 matches!(self, Self::String { .. })
205 }
206
207 #[must_use]
209 pub const fn is_array(&self) -> bool {
210 matches!(self, Self::Array { .. })
211 }
212
213 #[must_use]
215 pub const fn is_tuple(&self) -> bool {
216 matches!(self, Self::Tuple { .. })
217 }
218
219 #[must_use]
221 pub const fn is_object(&self) -> bool {
222 matches!(self, Self::Object { .. })
223 }
224
225 #[must_use]
227 pub const fn is_oneof(&self) -> bool {
228 matches!(self, Self::OneOf { .. })
229 }
230}
231
232impl Display for Value {
233 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
234 match self {
235 Value::Null => write!(f, "Null"),
236 Value::Bool { optional } => write!(
237 f,
238 "{}",
239 if *optional {
240 "Option<Boolean>"
241 } else {
242 "Boolean"
243 }
244 ),
245 Value::Number { optional } => write!(
246 f,
247 "{}",
248 if *optional {
249 "Option<Number>"
250 } else {
251 "Number"
252 }
253 ),
254 Value::String { optional } => write!(
255 f,
256 "{}",
257 if *optional {
258 "Option<String>"
259 } else {
260 "String"
261 }
262 ),
263 Value::Array { r#type, optional } => {
264 if *optional {
265 write!(f, "Option<Array<{type}>>")
266 } else {
267 write!(f, "Array<{type}>")
268 }
269 }
270 Value::Object { content, optional } => {
271 if *optional {
272 write!(f, "Option<Object{{{}}}>", display_object_content(content))
273 } else {
274 write!(f, "Object{{{}}}", display_object_content(content))
275 }
276 }
277 Value::OneOf { variants, optional } => {
278 let variants = variants
279 .iter()
280 .map(ToString::to_string)
281 .collect::<Vec<_>>()
282 .join(" | ");
283 if *optional {
284 write!(f, "Option<OneOf[{variants}]>",)
285 } else {
286 write!(f, "OneOf[{variants}]",)
287 }
288 }
289 Value::Tuple { elements, optional } => {
290 let elements = elements
291 .iter()
292 .map(ToString::to_string)
293 .collect::<Vec<_>>()
294 .join(", ");
295 if *optional {
296 write!(f, "Option<Tuple({elements})>",)
297 } else {
298 write!(f, "Tuple({elements})",)
299 }
300 }
301 }
302 }
303}
304
305impl Similar for Value {
306 fn similar(&self, other: &Self) -> Option<Value> {
307 match (self, other) {
308 (Value::Null, Value::Null) => Some(Value::Null),
309 (Value::Bool { optional }, Value::Bool { optional: opt }) => Some(Value::Bool {
310 optional: *optional || *opt,
311 }),
312 (Value::Number { optional }, Value::Number { optional: opt }) => Some(Value::Number {
313 optional: *optional || *opt,
314 }),
315 (Value::String { optional }, Value::String { optional: opt }) => Some(Value::String {
316 optional: *optional || *opt,
317 }),
318 (
319 Value::Array { r#type, optional },
320 Value::Array {
321 r#type: ty,
322 optional: opt,
323 },
324 ) if ty == r#type => Some(Value::Array {
325 r#type: ty.clone(),
326 optional: *optional || *opt,
327 }),
328 (
329 Value::Object { content, optional },
330 Value::Object {
331 content: cont,
332 optional: opt,
333 },
334 ) if cont == content => Some(Value::Object {
335 content: content.clone(),
336 optional: *optional || *opt,
337 }),
338 (
339 Value::OneOf { variants, optional },
340 Value::OneOf {
341 variants: var,
342 optional: opt,
343 },
344 ) if var == variants => Some(Value::OneOf {
345 variants: variants.clone(),
346 optional: *optional || *opt,
347 }),
348 (
349 Value::Tuple { elements, optional },
350 Value::Tuple {
351 elements: ty,
352 optional: opt,
353 },
354 ) if ty == elements => Some(Value::Tuple {
355 elements: ty.clone(),
356 optional: *optional || *opt,
357 }),
358 _ => None,
359 }
360 }
361}
362
363fn display_object_content(content: &BTreeMap<String, Value>) -> String {
364 content
365 .iter()
366 .map(|(key, value)| {
367 if key
368 .chars()
369 .all(|char| char.is_alphanumeric() || char == '_' || char == '-')
370 {
371 format!("{key}: {value}")
372 } else {
373 format!("\"{key}\": {value}")
374 }
375 })
376 .collect::<Vec<_>>()
377 .join(", ")
378}
379
380#[cfg(test)]
381mod tests {
382 use super::*;
383
384 #[test]
385 fn is_optional_returns_true_when_values_are_optional() {
386 assert!(Value::Null.is_optional());
387 assert!(Value::Bool { optional: true }.is_optional());
388 assert!(Value::Number { optional: true }.is_optional());
389 assert!(Value::String { optional: true }.is_optional());
390 assert!(
391 Value::Array {
392 optional: true,
393 r#type: Box::new(Value::Null)
394 }
395 .is_optional()
396 );
397 assert!(
398 Value::Tuple {
399 optional: true,
400 elements: vec![Value::Null]
401 }
402 .is_optional()
403 );
404 assert!(
405 Value::Object {
406 optional: true,
407 content: BTreeMap::default()
408 }
409 .is_optional()
410 );
411 assert!(
412 Value::OneOf {
413 optional: true,
414 variants: BTreeSet::default()
415 }
416 .is_optional()
417 );
418 }
419
420 #[test]
421 fn is_optional_returns_false_when_values_are_not_optional() {
422 assert!(!Value::Bool { optional: false }.is_optional());
423 assert!(!Value::Number { optional: false }.is_optional());
424 assert!(!Value::String { optional: false }.is_optional());
425 assert!(
426 !Value::Array {
427 optional: false,
428 r#type: Box::new(Value::Null)
429 }
430 .is_optional()
431 );
432 assert!(
433 !Value::Tuple {
434 optional: false,
435 elements: vec![Value::Null]
436 }
437 .is_optional()
438 );
439 assert!(
440 !Value::Object {
441 optional: false,
442 content: BTreeMap::default()
443 }
444 .is_optional()
445 );
446 assert!(
447 !Value::OneOf {
448 optional: false,
449 variants: BTreeSet::default()
450 }
451 .is_optional()
452 );
453 }
454
455 #[test]
456 fn as_optional_returns_optional_version_of_values() {
457 assert!(Value::Bool { optional: false }.as_optional().is_optional());
458 assert!(
459 Value::Number { optional: false }
460 .as_optional()
461 .is_optional()
462 );
463 assert!(
464 Value::String { optional: false }
465 .as_optional()
466 .is_optional()
467 );
468 assert!(
469 Value::Array {
470 optional: false,
471 r#type: Box::new(Value::Null)
472 }
473 .as_optional()
474 .is_optional()
475 );
476 assert!(
477 Value::Object {
478 optional: false,
479 content: BTreeMap::default()
480 }
481 .as_optional()
482 .is_optional()
483 );
484 assert!(
485 Value::OneOf {
486 optional: false,
487 variants: BTreeSet::default()
488 }
489 .as_optional()
490 .is_optional()
491 );
492 assert!(
493 Value::Tuple {
494 optional: false,
495 elements: vec![Value::Null]
496 }
497 .as_optional()
498 .is_optional()
499 );
500 }
501
502 #[test]
503 fn keys_returns_keys_only_for_object() {
504 assert!(Value::Null.keys().is_none());
505 assert!(Value::Bool { optional: true }.keys().is_none());
506 assert!(Value::Number { optional: true }.keys().is_none());
507 assert!(Value::String { optional: true }.keys().is_none());
508 assert!(
509 Value::Array {
510 optional: true,
511 r#type: Box::new(Value::Null)
512 }
513 .keys()
514 .is_none()
515 );
516 assert!(
517 Value::OneOf {
518 optional: true,
519 variants: BTreeSet::default()
520 }
521 .keys()
522 .is_none()
523 );
524 assert!(
525 Value::Tuple {
526 optional: true,
527 elements: Vec::default()
528 }
529 .keys()
530 .is_none()
531 );
532 assert_eq!(
533 Value::Object {
534 optional: true,
535 content: [
536 ("key_1".to_string(), Value::Null),
537 ("key_2".to_string(), Value::Null),
538 ]
539 .into()
540 }
541 .keys()
542 .unwrap()
543 .collect::<Vec<_>>(),
544 vec!["key_1", "key_2"]
545 );
546 }
547
548 #[test]
549 fn to_string_for_optional_values() {
550 assert_eq!(Value::Null.to_string(), "Null");
551 assert_eq!(
552 Value::Bool { optional: true }.to_string(),
553 "Option<Boolean>"
554 );
555 assert_eq!(
556 Value::Number { optional: true }.to_string(),
557 "Option<Number>"
558 );
559 assert_eq!(
560 Value::String { optional: true }.to_string(),
561 "Option<String>"
562 );
563 assert_eq!(
564 Value::Array {
565 optional: true,
566 r#type: Box::new(Value::Null)
567 }
568 .to_string(),
569 "Option<Array<Null>>"
570 );
571 assert_eq!(
572 Value::Object {
573 optional: true,
574 content: BTreeMap::default()
575 }
576 .to_string(),
577 "Option<Object{}>"
578 );
579 assert_eq!(
580 Value::Object {
581 optional: true,
582 content: [
583 ("key_1".to_string(), Value::Null),
584 ("key_2".to_string(), Value::Number { optional: true }),
585 ("key_3".to_string(), Value::Number { optional: false })
586 ]
587 .into()
588 }
589 .to_string(),
590 "Option<Object{key_1: Null, key_2: Option<Number>, key_3: Number}>"
591 );
592 assert_eq!(
593 Value::OneOf {
594 optional: true,
595 variants: [
596 Value::Null,
597 Value::Number { optional: true },
598 Value::Number { optional: false }
599 ]
600 .into()
601 }
602 .to_string(),
603 "Option<OneOf[Null | Number | Option<Number>]>"
604 );
605 assert_eq!(
606 Value::Tuple {
607 optional: true,
608 elements: [
609 Value::Null,
610 Value::Number { optional: true },
611 Value::Number { optional: false }
612 ]
613 .into()
614 }
615 .to_string(),
616 "Option<Tuple(Null, Option<Number>, Number)>"
617 );
618 }
619
620 #[test]
621 fn to_string_for_non_optional_values() {
622 assert_eq!(Value::Bool { optional: false }.to_string(), "Boolean");
623 assert_eq!(Value::Number { optional: false }.to_string(), "Number");
624 assert_eq!(Value::String { optional: false }.to_string(), "String");
625 assert_eq!(
626 Value::Array {
627 optional: false,
628 r#type: Box::new(Value::Null)
629 }
630 .to_string(),
631 "Array<Null>"
632 );
633 assert_eq!(
634 Value::Object {
635 optional: false,
636 content: BTreeMap::default()
637 }
638 .to_string(),
639 "Object{}"
640 );
641 assert_eq!(
642 Value::Object {
643 optional: false,
644 content: [
645 ("key_1".to_string(), Value::Null),
646 ("key_2".to_string(), Value::Number { optional: true }),
647 ("key_3".to_string(), Value::Number { optional: false })
648 ]
649 .into()
650 }
651 .to_string(),
652 "Object{key_1: Null, key_2: Option<Number>, key_3: Number}"
653 );
654 assert_eq!(
655 Value::OneOf {
656 optional: false,
657 variants: [
658 Value::Null,
659 Value::Number { optional: false },
660 Value::Number { optional: true }
661 ]
662 .into()
663 }
664 .to_string(),
665 "OneOf[Null | Number | Option<Number>]"
666 );
667 assert_eq!(
668 Value::Tuple {
669 optional: false,
670 elements: [
671 Value::Null,
672 Value::Number { optional: true },
673 Value::Number { optional: false }
674 ]
675 .into()
676 }
677 .to_string(),
678 "Tuple(Null, Option<Number>, Number)"
679 );
680 }
681
682 #[test]
683 fn to_optional_mut_transforms_value_inline_as_ref_mut() {
684 let mut v = Value::Bool { optional: false };
685 assert!(!v.is_optional());
686 v.to_optional_mut();
687 assert!(v.is_optional());
688 let mut v = Value::Number { optional: false };
689 assert!(!v.is_optional());
690 v.to_optional_mut();
691 assert!(v.is_optional());
692 let mut v = Value::String { optional: false };
693 assert!(!v.is_optional());
694 v.to_optional_mut();
695 assert!(v.is_optional());
696 }
697
698 #[test]
699 fn parse_multiple_keys() {
700 let map = [
701 ("key_value_1".to_string(), Value::Null),
702 ("key-value-1".to_string(), Value::Null),
703 ("KeyValue1".to_string(), Value::Null),
704 ("key value 1".to_string(), Value::Null),
705 ("key_value?".to_string(), Value::Null),
706 ("key_value!".to_string(), Value::Null),
707 ]
708 .into();
709
710 let s = display_object_content(&map);
711
712 assert_eq!(
713 s,
714 "KeyValue1: Null, \"key value 1\": Null, key-value-1: Null, \"key_value!\": Null, \"key_value?\": Null, key_value_1: Null"
715 );
716 }
717}