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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
use crate::SchemaFingerprint;
use std::ops::Deref;
use std::sync::Arc;
use uuid::Uuid;

#[derive(Debug)]
pub struct SchemaEnumSymbol {
    name: String,
    symbol_uuid: Uuid,
    aliases: Box<[String]>,
}

impl SchemaEnumSymbol {
    pub fn new(
        name: String,
        symbol_uuid: Uuid,
        aliases: Box<[String]>,
    ) -> Self {
        SchemaEnumSymbol {
            name,
            symbol_uuid,
            aliases,
        }
    }

    pub fn name(&self) -> &str {
        &self.name
    }

    pub fn symbol_uuid(&self) -> Uuid {
        self.symbol_uuid
    }

    pub fn aliases(&self) -> &[String] {
        &self.aliases
    }
}

#[derive(Debug)]
pub struct SchemaEnumInner {
    name: String,
    type_uuid: Uuid,
    fingerprint: SchemaFingerprint,
    aliases: Box<[String]>,
    symbols: Box<[SchemaEnumSymbol]>,
}

#[derive(Clone, Debug)]
pub struct SchemaEnum {
    inner: Arc<SchemaEnumInner>,
}

impl Deref for SchemaEnum {
    type Target = SchemaEnumInner;

    fn deref(&self) -> &Self::Target {
        &*self.inner
    }
}

impl SchemaEnum {
    pub fn new(
        name: String,
        type_uuid: Uuid,
        fingerprint: SchemaFingerprint,
        aliases: Box<[String]>,
        symbols: Box<[SchemaEnumSymbol]>,
    ) -> Self {
        assert!(!symbols.is_empty());

        // Check names are unique
        for i in 0..symbols.len() {
            for j in 0..i {
                assert_ne!(symbols[i].name, symbols[j].name);
            }
        }

        let inner = SchemaEnumInner {
            name,
            type_uuid,
            fingerprint,
            aliases,
            symbols,
        };

        SchemaEnum {
            inner: Arc::new(inner),
        }
    }

    pub fn name(&self) -> &str {
        &self.name
    }

    pub fn type_uuid(&self) -> Uuid {
        self.type_uuid
    }

    pub fn aliases(&self) -> &[String] {
        &self.aliases
    }

    pub fn symbols(&self) -> &[SchemaEnumSymbol] {
        &*self.symbols
    }

    pub fn default_value(&self) -> &SchemaEnumSymbol {
        &self.symbols[0]
    }

    pub fn fingerprint(&self) -> SchemaFingerprint {
        self.fingerprint
    }

    pub fn find_symbol_from_name(
        &self,
        name: &str,
    ) -> Option<&SchemaEnumSymbol> {
        for symbol in &*self.symbols {
            if symbol.name() == name {
                return Some(symbol);
            }

            for alias in symbol.aliases() {
                if alias == name {
                    return Some(symbol);
                }
            }
        }

        None
    }

    pub fn find_symbol_from_uuid(
        &self,
        uuid: Uuid,
    ) -> Option<&SchemaEnumSymbol> {
        self.symbols.iter().find(|x| x.symbol_uuid == uuid)
    }
}