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