Skip to main content

icydb_schema/node/
mod.rs

1mod arg;
2mod canister;
3mod def;
4mod entity;
5mod r#enum;
6mod field;
7mod index;
8mod item;
9mod list;
10mod map;
11mod newtype;
12mod primary_key;
13mod record;
14mod sanitizer;
15mod schema;
16mod set;
17mod store;
18mod tuple;
19mod r#type;
20mod validator;
21mod value;
22
23use crate::{
24    prelude::*,
25    visit::{Event, Visitor},
26};
27use std::any::Any;
28use thiserror::Error as ThisError;
29
30pub use arg::*;
31pub use canister::*;
32pub use def::*;
33pub use entity::*;
34pub use r#enum::*;
35pub use field::*;
36pub use index::*;
37pub use item::*;
38pub use list::*;
39pub use map::*;
40pub use newtype::*;
41pub use primary_key::*;
42pub use record::*;
43pub use sanitizer::*;
44pub use schema::*;
45pub use set::*;
46pub use store::*;
47pub use tuple::*;
48pub use r#type::*;
49pub use validator::*;
50pub use value::*;
51
52const RESERVED_INTERNAL_MEMORY_ID: u8 = u8::MAX;
53
54///
55/// NodeError
56///
57/// Error raised when schema-node lookup or downcasting crosses an invalid
58/// boundary.
59///
60
61#[derive(Debug, ThisError)]
62pub enum NodeError {
63    #[error("{0} is an incorrect node type")]
64    IncorrectNodeType(String),
65
66    #[error("path not found: {0}")]
67    PathNotFound(String),
68}
69
70///
71/// NODE TRAITS
72///
73
74///
75/// MacroNode
76///
77/// Shared trait implemented by every schema node emitted by macro/codegen
78/// surfaces.
79/// `as_any` keeps downcasting local to the schema-node boundary.
80///
81
82pub trait MacroNode: Any {
83    fn as_any(&self) -> &dyn Any;
84}
85
86///
87/// TypeNode
88///
89/// Shared trait for schema nodes that expose one canonical runtime `Type`.
90///
91
92pub trait TypeNode: MacroNode {
93    fn ty(&self) -> &Type;
94}
95
96///
97/// ValidateNode
98///
99/// Trait implemented by schema nodes that can validate their own local
100/// invariants against the process-global schema graph.
101///
102
103pub trait ValidateNode {
104    fn validate(&self) -> Result<(), ErrorTree> {
105        Ok(())
106    }
107}
108
109///
110/// VisitableNode
111///
112/// Trait implemented by schema nodes that participate in recursive visitor
113/// traversal.
114///
115
116pub trait VisitableNode: ValidateNode {
117    // Route key contributes one node-local path segment to the visitor path.
118    fn route_key(&self) -> String {
119        String::new()
120    }
121
122    // Drive the enter/children/exit visitor sequence for this node.
123    fn accept<V: Visitor>(&self, visitor: &mut V) {
124        visitor.push(&self.route_key());
125        visitor.visit(self, Event::Enter);
126        self.drive(visitor);
127        visitor.visit(self, Event::Exit);
128        visitor.pop();
129    }
130
131    // Visit child nodes in canonical order.
132    fn drive<V: Visitor>(&self, _: &mut V) {}
133}
134
135// Validate one memory id against the declared canister range.
136pub(crate) fn validate_memory_id_in_range(
137    errs: &mut ErrorTree,
138    label: &str,
139    memory_id: u8,
140    min: u8,
141    max: u8,
142) {
143    if memory_id < min || memory_id > max {
144        err!(errs, "{label} {memory_id} outside of range {min}-{max}");
145    }
146}
147
148// Reject memory id values reserved by stable-structures internals.
149pub(crate) fn validate_memory_id_not_reserved(errs: &mut ErrorTree, label: &str, memory_id: u8) {
150    if memory_id == RESERVED_INTERNAL_MEMORY_ID {
151        err!(
152            errs,
153            "{label} {memory_id} is reserved for stable-structures internals",
154        );
155    }
156}