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
use crate::rust::prelude::*;
use crate::*;

mod type_kind;
mod type_metadata;
mod type_validation;

pub use type_kind::*;
pub use type_metadata::*;
pub use type_validation::*;

/// Combines all data about a Type:
/// * `kind` - The type's [`TypeKind`] - this is essentially the definition of the structure of the type,
///   and includes the type's `ValueKind` as well as the [`TypeKind`] of any child types.
/// * `metadata` - The type's [`TypeMetadata`] which includes the name of the type and any of its fields or variants.
/// * `validation` - The type's [`TypeValidation`] which includes extra validation instructions for the type.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct TypeData<C: CustomTypeKind<L>, L: SchemaTypeLink> {
    pub kind: TypeKind<C, L>,
    pub metadata: TypeMetadata,
    pub validation: TypeValidation<C::CustomTypeValidation>,
}

impl<C: CustomTypeKind<L>, L: SchemaTypeLink> TypeData<C, L> {
    pub fn new(kind: TypeKind<C, L>, metadata: TypeMetadata) -> Self {
        Self {
            kind,
            metadata,
            validation: TypeValidation::None,
        }
    }

    pub fn unnamed(kind: TypeKind<C, L>) -> Self {
        Self {
            kind,
            metadata: TypeMetadata::unnamed(),
            validation: TypeValidation::None,
        }
    }

    pub fn no_child_names(kind: TypeKind<C, L>, name: &'static str) -> Self {
        Self {
            kind,
            metadata: TypeMetadata::no_child_names(name),
            validation: TypeValidation::None,
        }
    }

    pub fn struct_with_unit_fields(name: &'static str) -> Self {
        Self::new(
            TypeKind::Tuple {
                field_types: crate::rust::vec![],
            },
            TypeMetadata::no_child_names(name),
        )
    }

    pub fn struct_with_unnamed_fields(name: &'static str, field_types: Vec<L>) -> Self {
        Self::new(
            TypeKind::Tuple { field_types },
            TypeMetadata::no_child_names(name),
        )
    }

    pub fn struct_with_named_fields(name: &'static str, fields: Vec<(&'static str, L)>) -> Self {
        let (field_names, field_types): (Vec<_>, _) = fields.into_iter().unzip();
        Self::new(
            TypeKind::Tuple { field_types },
            TypeMetadata::struct_fields(name, &field_names),
        )
    }

    pub fn enum_variants(name: &'static str, variants: IndexMap<u8, TypeData<C, L>>) -> Self {
        let (variant_naming, variant_tuple_schemas) = variants
            .into_iter()
            .map(|(k, variant_type_data)| {
                let variant_fields_schema = match variant_type_data.kind {
                    TypeKind::Tuple { field_types } => field_types,
                    _ => panic!("Only Tuple is allowed in Enum variant TypeData"),
                };
                ((k, variant_type_data.metadata), (k, variant_fields_schema))
            })
            .unzip();
        Self::new(
            TypeKind::Enum {
                variants: variant_tuple_schemas,
            },
            TypeMetadata::enum_variants(name, variant_naming),
        )
    }

    pub fn with_validation(self, type_validation: TypeValidation<C::CustomTypeValidation>) -> Self {
        Self {
            kind: self.kind,
            metadata: self.metadata,
            validation: type_validation,
        }
    }

    pub fn with_name(mut self, name: Option<Cow<'static, str>>) -> Self {
        self.metadata = self.metadata.with_name(name);
        self
    }
}