Skip to main content

icydb_model/build/
mod.rs

1#[cfg(not(target_arch = "wasm32"))]
2mod actor;
3
4use crate::{
5    ThisError,
6    node::{Schema, SchemaGraphError},
7    prelude::*,
8};
9use std::sync::{LazyLock, RwLock, RwLockReadGuard};
10
11#[cfg(not(target_arch = "wasm32"))]
12pub use actor::generate;
13
14#[cfg(not(target_arch = "wasm32"))]
15use crate::{Error, node::SchemaNode, schema_validate::validate_schema};
16#[cfg(not(target_arch = "wasm32"))]
17use std::sync::{Mutex, RwLockWriteGuard};
18
19///
20/// BuildError
21///
22/// Error returned when the process-global schema graph fails validation before
23/// build-time code generation.
24///
25
26#[derive(Debug, ThisError)]
27pub enum BuildError {
28    /// Constructor registration did not produce one unique collecting graph.
29    #[error(transparent)]
30    Graph(#[from] SchemaGraphError),
31
32    /// Whole-graph validation rejected the collected declarations.
33    #[error("validation failed: {0}")]
34    Validation(ErrorTree),
35}
36
37/// Process-global schema graph used during build-time code generation.
38static SCHEMA: LazyLock<RwLock<Schema>> = LazyLock::new(|| RwLock::new(Schema::new()));
39/// Serializes constructor registration with validation and sealing.
40#[cfg(not(target_arch = "wasm32"))]
41static REGISTRATION_GATE: Mutex<()> = Mutex::new(());
42
43/// Acquire a write guard to the global schema during build-time codegen.
44///
45/// # Panics
46///
47/// Panics if the process-global schema lock has been poisoned.
48#[cfg(not(target_arch = "wasm32"))]
49pub(crate) fn schema_write() -> RwLockWriteGuard<'static, Schema> {
50    SCHEMA
51        .write()
52        .expect("schema RwLock poisoned while acquiring write lock")
53}
54
55/// Register one constructor-produced declaration in the collecting graph.
56///
57/// This is the only non-test mutation entrypoint generated declarations use.
58/// Duplicate and late registrations remain recorded until graph sealing.
59///
60/// # Panics
61///
62/// Panics if the process-global registration gate or schema lock is poisoned.
63#[cfg(not(target_arch = "wasm32"))]
64pub fn register_node(node: SchemaNode) {
65    let _registration = REGISTRATION_GATE
66        .lock()
67        .expect("schema registration gate poisoned while registering node");
68    schema_write().insert_node(node);
69}
70
71/// Read the schema graph without triggering validation.
72pub(crate) fn schema_read() -> RwLockReadGuard<'static, Schema> {
73    SCHEMA
74        .read()
75        .expect("schema RwLock poisoned while acquiring read lock")
76}
77
78/// Read the immutable global schema after validating and sealing it.
79///
80/// # Errors
81///
82/// Returns a typed graph or whole-graph validation failure.
83///
84/// # Panics
85///
86/// Panics if the process-global registration gate or schema lock is poisoned.
87#[cfg(not(target_arch = "wasm32"))]
88pub fn get_schema() -> Result<RwLockReadGuard<'static, Schema>, Error> {
89    let _registration = REGISTRATION_GATE
90        .lock()
91        .expect("schema registration gate poisoned while sealing graph");
92    {
93        let schema = schema_read();
94        if !schema.is_sealed() {
95            validate_schema(&schema).map_err(BuildError::Validation)?;
96        }
97    }
98    {
99        let mut schema = schema_write();
100        schema.seal().map_err(BuildError::Graph)?;
101    }
102
103    Ok(schema_read())
104}