1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
use crate::arrays::*;
use crate::bools::*;
use crate::enums::*;
use crate::literals::*;
use crate::numbers::*;
use crate::objects::*;
use crate::schema::*;
use crate::strings::*;
use crate::structs::*;
use crate::tuples::*;
use crate::unions::*;

/// All possible types within a schema.
#[derive(Clone, Debug, Default, PartialEq)]
pub enum SchemaType {
    Null,
    #[default]
    Unknown,
    Array(Box<ArrayType>),
    Boolean(Box<BooleanType>),
    Enum(Box<EnumType>),
    Float(Box<FloatType>),
    Integer(Box<IntegerType>),
    Literal(Box<LiteralType>),
    Object(Box<ObjectType>),
    Reference(String),
    Struct(Box<StructType>),
    String(Box<StringType>),
    Tuple(Box<TupleType>),
    Union(Box<UnionType>),
}

impl SchemaType {
    /// Return a `default` value from the inner schema type.
    pub fn get_default(&self) -> Option<&LiteralValue> {
        match self {
            SchemaType::Boolean(inner) => inner.default.as_ref(),
            SchemaType::Enum(inner) => {
                if let Some(index) = &inner.default_index {
                    if let Some(value) = inner.values.get(*index) {
                        return Some(value);
                    }
                }

                None
            }
            SchemaType::Float(inner) => inner.default.as_ref(),
            SchemaType::Integer(inner) => inner.default.as_ref(),
            SchemaType::String(inner) => inner.default.as_ref(),
            SchemaType::Union(inner) => {
                if let Some(index) = &inner.default_index {
                    if let Some(value) = inner.variants_types.get(*index) {
                        return value.get_default();
                    }
                }

                for variant in &inner.variants_types {
                    if let Some(value) = variant.get_default() {
                        return Some(value);
                    }
                }

                None
            }
            _ => None,
        }
    }

    /// Return true if the schema is an explicit null.
    pub fn is_null(&self) -> bool {
        matches!(self, SchemaType::Null)
    }

    /// Return true if the schema is nullable (a union with a null).
    pub fn is_nullable(&self) -> bool {
        if let SchemaType::Union(uni) = self {
            return uni.has_null();
        }

        false
    }

    /// Return true if the schema is a reference.
    pub fn is_reference(&self) -> bool {
        matches!(self, SchemaType::Reference(_))
    }

    /// Return true if the schema is a struct.
    pub fn is_struct(&self) -> bool {
        matches!(self, SchemaType::Struct(_))
    }

    /// Set the `default` of the inner schema type.
    pub fn set_default(&mut self, default: LiteralValue) {
        match self {
            SchemaType::Boolean(ref mut inner) => {
                inner.default = Some(default);
            }
            SchemaType::Float(ref mut inner) => {
                inner.default = Some(default);
            }
            SchemaType::Integer(ref mut inner) => {
                inner.default = Some(default);
            }
            SchemaType::String(ref mut inner) => {
                inner.default = Some(default);
            }
            _ => {}
        };
    }

    /// Add a field to the type if it's a struct.
    pub fn add_field(&mut self, key: &str, value: impl Into<Schema>) {
        if let SchemaType::Struct(map) = self {
            map.fields.insert(key.to_owned(), Box::new(value.into()));
        }
    }
}

impl From<SchemaType> for Schema {
    fn from(val: SchemaType) -> Self {
        Schema::new(val)
    }
}