1use crate::{Error, prelude::*};
2use canic_core::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 _ => None,
39 }
40 }
41}
42
43impl SchemaNode {
44 const fn def(&self) -> &Def {
45 match self {
46 Self::Canister(n) => &n.def,
47 Self::Entity(n) => &n.def,
48 Self::Enum(n) => &n.def,
49 Self::List(n) => &n.def,
50 Self::Map(n) => &n.def,
51 Self::Newtype(n) => &n.def,
52 Self::Record(n) => &n.def,
53 Self::Sanitizer(n) => &n.def,
54 Self::Set(n) => &n.def,
55 Self::Store(n) => &n.def,
56 Self::Tuple(n) => &n.def,
57 Self::Validator(n) => &n.def,
58 }
59 }
60}
61
62impl MacroNode for SchemaNode {
63 fn as_any(&self) -> &dyn Any {
64 match self {
65 Self::Canister(n) => n.as_any(),
66 Self::Entity(n) => n.as_any(),
67 Self::Enum(n) => n.as_any(),
68 Self::List(n) => n.as_any(),
69 Self::Map(n) => n.as_any(),
70 Self::Newtype(n) => n.as_any(),
71 Self::Record(n) => n.as_any(),
72 Self::Sanitizer(n) => n.as_any(),
73 Self::Set(n) => n.as_any(),
74 Self::Store(n) => n.as_any(),
75 Self::Tuple(n) => n.as_any(),
76 Self::Validator(n) => n.as_any(),
77 }
78 }
79}
80
81impl ValidateNode for SchemaNode {}
82
83impl VisitableNode for SchemaNode {
84 fn drive<V: Visitor>(&self, v: &mut V) {
85 match self {
86 Self::Canister(n) => n.accept(v),
87 Self::Entity(n) => n.accept(v),
88 Self::Enum(n) => n.accept(v),
89 Self::List(n) => n.accept(v),
90 Self::Map(n) => n.accept(v),
91 Self::Newtype(n) => n.accept(v),
92 Self::Record(n) => n.accept(v),
93 Self::Sanitizer(n) => n.accept(v),
94 Self::Set(n) => n.accept(v),
95 Self::Store(n) => n.accept(v),
96 Self::Tuple(n) => n.accept(v),
97 Self::Validator(n) => n.accept(v),
98 }
99 }
100}
101
102#[derive(Clone, Debug, Serialize)]
107pub struct Schema {
108 pub nodes: BTreeMap<String, SchemaNode>,
109 pub hash: &'static str,
110 pub timestamp: u64,
111}
112
113impl Schema {
114 #[must_use]
115 pub fn new() -> Self {
116 Self {
117 nodes: BTreeMap::new(),
118 hash: "",
119 timestamp: now_secs(),
120 }
121 }
122
123 pub fn insert_node(&mut self, node: SchemaNode) {
125 self.nodes.insert(node.def().path(), node);
126 }
127
128 #[must_use]
130 pub fn get_node<'a>(&'a self, path: &str) -> Option<&'a SchemaNode> {
131 self.nodes.get(path)
132 }
133
134 pub fn try_get_node<'a>(&'a self, path: &str) -> Result<&'a SchemaNode, Error> {
136 let node = self
137 .get_node(path)
138 .ok_or_else(|| NodeError::PathNotFound(path.to_string()))?;
139
140 Ok(node)
141 }
142
143 pub fn cast_node<'a, T: 'static>(&'a self, path: &str) -> Result<&'a T, Error> {
145 let node = self.try_get_node(path)?;
146
147 node.as_any()
148 .downcast_ref::<T>()
149 .ok_or_else(|| NodeError::IncorrectNodeType(path.to_string()).into())
150 }
151
152 pub fn check_node_as<T: 'static>(&self, path: &str) -> Result<(), Error> {
154 self.cast_node::<T>(path).map(|_| ())
155 }
156
157 pub fn get_nodes<T: 'static>(&self) -> impl Iterator<Item = (&str, &T)> {
159 self.nodes
160 .iter()
161 .filter_map(|(key, node)| node.as_any().downcast_ref::<T>().map(|n| (key.as_str(), n)))
162 }
163
164 pub fn get_node_values<T: 'static>(&'_ self) -> impl Iterator<Item = &'_ T> + '_ {
166 self.nodes
167 .values()
168 .filter_map(|node| node.as_any().downcast_ref::<T>())
169 }
170
171 pub fn filter_nodes<'a, T: 'static>(
174 &'a self,
175 predicate: impl Fn(&T) -> bool + 'a,
176 ) -> impl Iterator<Item = (&'a str, &'a T)> + 'a {
177 self.nodes.iter().filter_map(move |(key, node)| {
178 node.as_any()
179 .downcast_ref::<T>()
180 .filter(|target| predicate(target))
181 .map(|target| (key.as_str(), target))
182 })
183 }
184}
185
186impl Default for Schema {
187 fn default() -> Self {
188 Self::new()
189 }
190}
191
192impl ValidateNode for Schema {}
193
194impl VisitableNode for Schema {
195 fn drive<V: Visitor>(&self, v: &mut V) {
196 for node in self.nodes.values() {
197 node.accept(v);
198 }
199 }
200}