cratestack-core 0.7.6

Rust-native schema-first framework for typed HTTP APIs, generated clients, and backend services.
Documentation
//! Model / mixin / type / enum / field IR nodes parsed out of a
//! `.cstack` file. Every IR node carries [`SourceSpan`] back-pointers
//! so consumers (parser, LSP, generators) can map errors to source
//! positions.

use serde::{Deserialize, Serialize};

use super::SourceSpan;

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Model {
    pub docs: Vec<String>,
    pub name: String,
    pub name_span: SourceSpan,
    pub fields: Vec<Field>,
    pub attributes: Vec<Attribute>,
    pub span: SourceSpan,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct MixinDecl {
    pub docs: Vec<String>,
    pub name: String,
    pub name_span: SourceSpan,
    pub fields: Vec<Field>,
    pub span: SourceSpan,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct TypeDecl {
    pub docs: Vec<String>,
    pub name: String,
    pub name_span: SourceSpan,
    pub fields: Vec<Field>,
    pub span: SourceSpan,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct EnumDecl {
    pub docs: Vec<String>,
    pub name: String,
    pub name_span: SourceSpan,
    pub variants: Vec<EnumVariant>,
    pub span: SourceSpan,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct EnumVariant {
    pub docs: Vec<String>,
    pub name: String,
    pub span: SourceSpan,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Field {
    pub docs: Vec<String>,
    pub name: String,
    pub name_span: SourceSpan,
    pub ty: TypeRef,
    pub attributes: Vec<Attribute>,
    pub span: SourceSpan,
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct TypeRef {
    pub name: String,
    pub name_span: SourceSpan,
    pub arity: TypeArity,
    pub generic_args: Vec<TypeRef>,
    /// Compile-time integer literal arguments to a parametric scalar
    /// type, e.g. the `1536` in `Vector(1536)`. Empty for every type
    /// that isn't parametric — currently only `Vector(n)` populates
    /// this (see `docs/design/extensions.md` §6). `#[serde(default)]`
    /// keeps deserialization of migration snapshots written before
    /// this field existed working unchanged.
    #[serde(default)]
    pub int_args: Vec<u32>,
}

impl TypeRef {
    pub fn is_page(&self) -> bool {
        self.name == "Page"
    }

    pub fn page_item(&self) -> Option<&TypeRef> {
        if self.is_page() {
            self.generic_args.first()
        } else {
            None
        }
    }

    pub fn is_page_input(&self) -> bool {
        self.name == "PageInput"
    }

    pub fn is_find_many(&self) -> bool {
        self.name == "FindMany"
    }

    pub fn find_many_item(&self) -> Option<&TypeRef> {
        if self.is_find_many() {
            self.generic_args.first()
        } else {
            None
        }
    }

    pub fn is_vector(&self) -> bool {
        self.name == "Vector"
    }

    /// The `n` in `Vector(n)`, if this is a well-formed vector type
    /// reference (exactly one integer argument). Validation
    /// (`cratestack-parser`) is responsible for rejecting any other
    /// shape before this is relied upon by codegen.
    pub fn vector_dim(&self) -> Option<u32> {
        if self.is_vector() {
            self.int_args.first().copied()
        } else {
            None
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum TypeArity {
    Required,
    Optional,
    List,
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Attribute {
    pub raw: String,
    pub span: SourceSpan,
}