icydb_schema/node/
enum.rs

1use crate::prelude::*;
2use canic_utils::case::{Case, Casing};
3use std::ops::Not;
4
5///
6/// Enum
7///
8
9#[derive(Clone, Debug, Serialize)]
10pub struct Enum {
11    pub def: Def,
12    pub variants: &'static [EnumVariant],
13    pub ty: Type,
14}
15
16impl MacroNode for Enum {
17    fn as_any(&self) -> &dyn std::any::Any {
18        self
19    }
20}
21
22impl TypeNode for Enum {
23    fn ty(&self) -> &Type {
24        &self.ty
25    }
26}
27
28impl ValidateNode for Enum {
29    fn validate(&self) -> Result<(), ErrorTree> {
30        let mut errs = ErrorTree::new();
31
32        // check variants for unspecified
33        let mut un_count = 0;
34        let mut un_first = None;
35        for (i, variant) in self.variants.iter().enumerate() {
36            if variant.unspecified {
37                un_count += 1;
38                if un_first.is_none() {
39                    un_first = Some(i);
40                }
41            }
42        }
43
44        // Check if there's more than one unspecified variant
45        if un_count > 1 {
46            err!(
47                errs,
48                "there should not be more than one unspecified variant"
49            );
50        }
51
52        // Check if the unspecified variant is not the first in the list
53        if let Some(index) = un_first
54            && index != 0
55        {
56            err!(
57                errs,
58                "the unspecified variant must be the first in the list"
59            );
60        }
61
62        // Check for multiple defaults
63        let default_count = self.variants.iter().filter(|v| v.default).count();
64        if default_count > 1 {
65            err!(
66                errs,
67                "exactly one variant must be marked as default, found {default_count}"
68            );
69        }
70
71        errs.result()
72    }
73}
74
75impl VisitableNode for Enum {
76    fn route_key(&self) -> String {
77        self.def.path()
78    }
79
80    fn drive<V: Visitor>(&self, v: &mut V) {
81        self.def.accept(v);
82        for node in self.variants {
83            node.accept(v);
84        }
85        self.ty.accept(v);
86    }
87}
88
89///
90/// EnumVariant
91///
92
93#[derive(Clone, Debug, Serialize)]
94pub struct EnumVariant {
95    pub ident: &'static str,
96
97    #[serde(default, skip_serializing_if = "Option::is_none")]
98    pub value: Option<Value>,
99
100    #[serde(default, skip_serializing_if = "Not::not")]
101    pub default: bool,
102
103    #[serde(default, skip_serializing_if = "Not::not")]
104    pub unspecified: bool,
105}
106
107impl ValidateNode for EnumVariant {
108    fn validate(&self) -> Result<(), ErrorTree> {
109        let mut errs = ErrorTree::new();
110
111        // name
112        if !self.ident.is_case(Case::UpperCamel) {
113            err!(
114                errs,
115                "variant ident '{}' must be in UpperCamelCase",
116                self.ident
117            );
118        }
119
120        errs.result()
121    }
122}
123
124impl VisitableNode for EnumVariant {
125    fn drive<V: Visitor>(&self, v: &mut V) {
126        if let Some(node) = &self.value {
127            node.accept(v);
128        }
129    }
130}