icydb_schema/build/
mod.rs

1pub mod reserved;
2pub mod validate;
3
4use crate::{
5    Error, ThisError,
6    node::{Schema, VisitableNode},
7    prelude::*,
8    visit::ValidateVisitor,
9};
10use std::sync::{LazyLock, OnceLock, RwLock, RwLockReadGuard, RwLockWriteGuard};
11
12///
13/// BuildError
14///
15
16#[derive(Debug, ThisError)]
17pub enum BuildError {
18    #[error("validation failed: {0}")]
19    Validation(ErrorTree),
20}
21
22///
23/// SCHEMA
24/// the static data structure
25///
26
27static SCHEMA: LazyLock<RwLock<Schema>> = LazyLock::new(|| RwLock::new(Schema::new()));
28
29static SCHEMA_VALIDATED: OnceLock<bool> = OnceLock::new();
30
31/// Acquire a write guard to the global schema during build-time codegen.
32pub fn schema_write() -> RwLockWriteGuard<'static, Schema> {
33    SCHEMA
34        .write()
35        .expect("schema RwLock poisoned while acquiring write lock")
36}
37
38// schema_read
39// just reads the schema directly without validation
40pub(crate) fn schema_read() -> RwLockReadGuard<'static, Schema> {
41    SCHEMA
42        .read()
43        .expect("schema RwLock poisoned while acquiring read lock")
44}
45
46/// Read the global schema, validating it exactly once per process.
47pub fn get_schema() -> Result<RwLockReadGuard<'static, Schema>, Error> {
48    let schema = schema_read();
49    validate(&schema).map_err(BuildError::Validation)?;
50
51    Ok(schema)
52}
53
54// validate
55fn validate(schema: &Schema) -> Result<(), ErrorTree> {
56    if *SCHEMA_VALIDATED.get_or_init(|| false) {
57        return Ok(());
58    }
59
60    // validate
61    let mut visitor = ValidateVisitor::new();
62    schema.accept(&mut visitor);
63    visitor.errors.result()?;
64
65    SCHEMA_VALIDATED.set(true).ok();
66
67    Ok(())
68}