Skip to main content

panproto_schema/
protocol.rs

1//! Protocol definition.
2//!
3//! A [`Protocol`] identifies which schema theory and instance theory a
4//! particular data format uses, together with well-formedness rules
5//! for edges and the set of recognized vertex/constraint kinds.
6
7use panproto_gat::CompositionSpec;
8use serde::{Deserialize, Serialize};
9
10/// A well-formedness rule for edges of a given kind.
11///
12/// When `src_kinds` is non-empty, only vertices whose kind appears in the
13/// list may serve as the source of an edge of this kind. An empty list
14/// means any vertex kind is allowed. The same applies to `tgt_kinds`.
15#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
16pub struct EdgeRule {
17    /// The edge kind this rule governs (e.g., `"prop"`, `"record-schema"`).
18    pub edge_kind: String,
19    /// Permitted source vertex kinds (empty = any).
20    pub src_kinds: Vec<String>,
21    /// Permitted target vertex kinds (empty = any).
22    pub tgt_kinds: Vec<String>,
23}
24
25/// Identifies the schema and instance theories for a data-format protocol,
26/// together with structural well-formedness rules.
27///
28/// Protocols are the Level-1 configuration objects that drive schema
29/// construction and validation. Each protocol names a schema theory GAT
30/// and an instance theory GAT (both defined in `panproto-protocols`),
31/// and supplies edge rules, recognized vertex kinds, and constraint sorts.
32#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
33#[allow(clippy::struct_excessive_bools)]
34pub struct Protocol {
35    /// Human-readable protocol name (e.g., `"atproto"`, `"sql"`).
36    pub name: String,
37    /// Name of the schema theory GAT in the theory registry.
38    pub schema_theory: String,
39    /// Name of the instance theory GAT in the theory registry.
40    pub instance_theory: String,
41    /// Composition recipe that produced the schema theory.
42    pub schema_composition: Option<CompositionSpec>,
43    /// Composition recipe that produced the instance theory.
44    pub instance_composition: Option<CompositionSpec>,
45    /// Well-formedness rules for each edge kind.
46    pub edge_rules: Vec<EdgeRule>,
47    /// Vertex kinds that are considered "object-like" (containers).
48    pub obj_kinds: Vec<String>,
49    /// Recognized constraint sorts (e.g., `"maxLength"`, `"format"`).
50    pub constraint_sorts: Vec<String>,
51
52    // -- structural feature flags (all default to false) --
53    /// Whether this protocol uses ordered collections (`ThOrder`).
54    #[serde(default)]
55    pub has_order: bool,
56    /// Whether this protocol has coproduct/union types (`ThCoproduct`).
57    #[serde(default)]
58    pub has_coproducts: bool,
59    /// Whether this protocol supports recursive types (`ThRecursion`).
60    #[serde(default)]
61    pub has_recursion: bool,
62    /// Whether this protocol has causal/temporal ordering (`ThCausal`).
63    #[serde(default)]
64    pub has_causal: bool,
65    /// Whether this protocol uses nominal identity (`ThNominal`).
66    #[serde(default)]
67    pub nominal_identity: bool,
68
69    // -- enrichment feature flags (all default to false) --
70    /// Whether this protocol supports default value expressions (`ThValued`).
71    #[serde(default)]
72    pub has_defaults: bool,
73    /// Whether this protocol supports type coercion expressions (`ThCoercible`).
74    #[serde(default)]
75    pub has_coercions: bool,
76    /// Whether this protocol supports merge/split expressions (`ThMergeable`).
77    #[serde(default)]
78    pub has_mergers: bool,
79    /// Whether this protocol supports conflict resolution policies (`ThPolicied`).
80    #[serde(default)]
81    pub has_policies: bool,
82}
83
84impl Protocol {
85    /// Returns the [`EdgeRule`] for the given edge kind, if one exists.
86    #[must_use]
87    pub fn find_edge_rule(&self, edge_kind: &str) -> Option<&EdgeRule> {
88        self.edge_rules.iter().find(|r| r.edge_kind == edge_kind)
89    }
90
91    /// Returns `true` if `kind` is a recognized vertex kind in this protocol.
92    ///
93    /// The set of recognized kinds is the union of all kinds mentioned in
94    /// edge rules (both source and target) plus `obj_kinds`.
95    #[must_use]
96    pub fn is_known_vertex_kind(&self, kind: &str) -> bool {
97        if self.obj_kinds.iter().any(|k| k == kind) {
98            return true;
99        }
100        for rule in &self.edge_rules {
101            if rule.src_kinds.iter().any(|k| k == kind) {
102                return true;
103            }
104            if rule.tgt_kinds.iter().any(|k| k == kind) {
105                return true;
106            }
107        }
108        false
109    }
110}