icydb_schema/node/
enum.rs1use crate::prelude::*;
2use canic_utils::case::{Case, Casing};
3use std::ops::Not;
4
5#[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 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 if un_count > 1 {
46 err!(
47 errs,
48 "there should not be more than one unspecified variant"
49 );
50 }
51
52 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 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#[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 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}