1use crate::{Error, prelude::*};
2use canic_cdk::utils::time::now_secs;
3use std::{any::Any, collections::BTreeMap};
4
5#[remain::sorted]
10#[derive(Clone, Debug, Serialize)]
11pub enum SchemaNode {
12 Canister(Canister),
13 Entity(Entity),
14 Enum(Enum),
15 List(List),
16 Map(Map),
17 Newtype(Newtype),
18 Record(Record),
19 Sanitizer(Sanitizer),
20 Set(Set),
21 Store(Store),
22 Tuple(Tuple),
23 Validator(Validator),
24}
25
26impl SchemaNode {
27 #[must_use]
28 pub fn get_type(&self) -> Option<Box<dyn TypeNode>> {
29 match self {
30 Self::Entity(n) => Some(Box::new(n.clone())),
31 Self::Enum(n) => Some(Box::new(n.clone())),
32 Self::List(n) => Some(Box::new(n.clone())),
33 Self::Map(n) => Some(Box::new(n.clone())),
34 Self::Newtype(n) => Some(Box::new(n.clone())),
35 Self::Record(n) => Some(Box::new(n.clone())),
36 Self::Set(n) => Some(Box::new(n.clone())),
37 Self::Tuple(n) => Some(Box::new(n.clone())),
38 _ => {
39 None
41 }
42 }
43 }
44}
45
46impl SchemaNode {
47 const fn def(&self) -> &Def {
48 match self {
49 Self::Canister(n) => &n.def,
50 Self::Entity(n) => &n.def,
51 Self::Enum(n) => &n.def,
52 Self::List(n) => &n.def,
53 Self::Map(n) => &n.def,
54 Self::Newtype(n) => &n.def,
55 Self::Record(n) => &n.def,
56 Self::Sanitizer(n) => &n.def,
57 Self::Set(n) => &n.def,
58 Self::Store(n) => &n.def,
59 Self::Tuple(n) => &n.def,
60 Self::Validator(n) => &n.def,
61 }
62 }
63}
64
65impl MacroNode for SchemaNode {
66 fn as_any(&self) -> &dyn Any {
67 match self {
68 Self::Canister(n) => n.as_any(),
69 Self::Entity(n) => n.as_any(),
70 Self::Enum(n) => n.as_any(),
71 Self::List(n) => n.as_any(),
72 Self::Map(n) => n.as_any(),
73 Self::Newtype(n) => n.as_any(),
74 Self::Record(n) => n.as_any(),
75 Self::Sanitizer(n) => n.as_any(),
76 Self::Set(n) => n.as_any(),
77 Self::Store(n) => n.as_any(),
78 Self::Tuple(n) => n.as_any(),
79 Self::Validator(n) => n.as_any(),
80 }
81 }
82}
83
84impl ValidateNode for SchemaNode {}
85
86impl VisitableNode for SchemaNode {
87 fn drive<V: Visitor>(&self, v: &mut V) {
88 match self {
89 Self::Canister(n) => n.accept(v),
90 Self::Entity(n) => n.accept(v),
91 Self::Enum(n) => n.accept(v),
92 Self::List(n) => n.accept(v),
93 Self::Map(n) => n.accept(v),
94 Self::Newtype(n) => n.accept(v),
95 Self::Record(n) => n.accept(v),
96 Self::Sanitizer(n) => n.accept(v),
97 Self::Set(n) => n.accept(v),
98 Self::Store(n) => n.accept(v),
99 Self::Tuple(n) => n.accept(v),
100 Self::Validator(n) => n.accept(v),
101 }
102 }
103}
104
105#[derive(Clone, Debug, Serialize)]
110pub struct Schema {
111 pub nodes: BTreeMap<String, SchemaNode>,
112 pub hash: &'static str,
113 pub timestamp: u64,
114}
115
116impl Schema {
117 #[must_use]
118 pub fn new() -> Self {
119 Self {
120 nodes: BTreeMap::new(),
121 hash: "",
122 timestamp: now_secs(),
123 }
124 }
125
126 pub fn insert_node(&mut self, node: SchemaNode) {
128 self.nodes.insert(node.def().path(), node);
129 }
130
131 #[must_use]
133 pub fn get_node<'a>(&'a self, path: &str) -> Option<&'a SchemaNode> {
134 self.nodes.get(path)
135 }
136
137 pub fn try_get_node<'a>(&'a self, path: &str) -> Result<&'a SchemaNode, Error> {
139 let node = self
140 .get_node(path)
141 .ok_or_else(|| NodeError::PathNotFound(path.to_string()))?;
142
143 Ok(node)
144 }
145
146 pub fn cast_node<'a, T: 'static>(&'a self, path: &str) -> Result<&'a T, Error> {
148 let node = self.try_get_node(path)?;
149
150 node.as_any()
151 .downcast_ref::<T>()
152 .ok_or_else(|| NodeError::IncorrectNodeType(path.to_string()).into())
153 }
154
155 pub fn check_node_as<T: 'static>(&self, path: &str) -> Result<(), Error> {
157 self.cast_node::<T>(path).map(|_| ())
158 }
159
160 pub fn get_nodes<T: 'static>(&self) -> impl Iterator<Item = (&str, &T)> {
162 self.nodes
163 .iter()
164 .filter_map(|(key, node)| node.as_any().downcast_ref::<T>().map(|n| (key.as_str(), n)))
165 }
166
167 pub fn get_node_values<T: 'static>(&'_ self) -> impl Iterator<Item = &'_ T> + '_ {
169 self.nodes
170 .values()
171 .filter_map(|node| node.as_any().downcast_ref::<T>())
172 }
173
174 pub fn filter_nodes<'a, T: 'static>(
177 &'a self,
178 predicate: impl Fn(&T) -> bool + 'a,
179 ) -> impl Iterator<Item = (&'a str, &'a T)> + 'a {
180 self.nodes.iter().filter_map(move |(key, node)| {
181 node.as_any()
182 .downcast_ref::<T>()
183 .filter(|target| predicate(target))
184 .map(|target| (key.as_str(), target))
185 })
186 }
187}
188
189impl Default for Schema {
190 fn default() -> Self {
191 Self::new()
192 }
193}
194
195impl ValidateNode for Schema {}
196
197impl VisitableNode for Schema {
198 fn drive<V: Visitor>(&self, v: &mut V) {
199 for node in self.nodes.values() {
200 node.accept(v);
201 }
202 }
203}