Skip to main content

panproto_inst/
instance.rs

1//! Unified instance representation (attributed C-set).
2//!
3//! [`Instance`] is the unified enum wrapping all instance shapes:
4//! - [`WInstance`](crate::WInstance): tree-shaped (W-type)
5//! - [`FInstance`](crate::FInstance): relational (functor)
6//! - [`GInstance`](crate::GInstance): graph-shaped (most general)
7//!
8//! All three are attributed C-sets over different shape categories.
9//! The unified type enables generic code that operates on any instance
10//! shape without knowing the concrete representation.
11
12use panproto_schema::Schema;
13use serde::{Deserialize, Serialize};
14
15use crate::error::RestrictError;
16use crate::functor::FInstance;
17use crate::ginstance::GInstance;
18use crate::wtype::{CompiledMigration, WInstance};
19
20/// A unified instance wrapping all instance shapes.
21///
22/// This is the top-level instance type for generic code. Each variant
23/// preserves the optimized internal representation of its shape.
24///
25/// All three shapes are attributed C-sets:
26/// - `WType`: C = tree category (rooted, acyclic)
27/// - `Functor`: C = relational category (bipartite: tables + foreign keys)
28/// - `Graph`: C = graph category (general directed graph)
29///
30/// Each inner type implements [`AcsetOps`](crate::AcsetOps), which
31/// provides `restrict`, `extend`, `element_count`, and `shape_name`
32/// through a unified trait interface. The methods on `Instance` below
33/// dispatch to those implementations.
34#[derive(Clone, Debug, Serialize, Deserialize)]
35pub enum Instance {
36    /// Tree-shaped instance (W-type).
37    WType(WInstance),
38    /// Relational/tabular instance (set-valued functor).
39    Functor(FInstance),
40    /// Graph-shaped instance (most general form).
41    Graph(GInstance),
42}
43
44impl Instance {
45    /// Returns the shape name.
46    #[must_use]
47    pub const fn shape_name(&self) -> &'static str {
48        match self {
49            Self::WType(_) => "wtype",
50            Self::Functor(_) => "functor",
51            Self::Graph(_) => "graph",
52        }
53    }
54
55    /// Restrict this instance along a compiled migration.
56    ///
57    /// Dispatches to the shape-specific restrict pipeline.
58    ///
59    /// # Errors
60    ///
61    /// Returns an error if the restrict pipeline fails.
62    pub fn restrict(
63        &self,
64        src_schema: &Schema,
65        tgt_schema: &Schema,
66        migration: &CompiledMigration,
67    ) -> Result<Self, RestrictError> {
68        match self {
69            Self::WType(w) => {
70                let restricted = crate::wtype_restrict(w, src_schema, tgt_schema, migration)?;
71                Ok(Self::WType(restricted))
72            }
73            Self::Functor(f) => {
74                let restricted = crate::functor_restrict(f, migration)?;
75                Ok(Self::Functor(restricted))
76            }
77            Self::Graph(g) => {
78                let restricted = crate::ginstance::graph_restrict(g, migration)?;
79                Ok(Self::Graph(restricted))
80            }
81        }
82    }
83
84    /// Extend this instance along a compiled migration (`Sigma_F`).
85    ///
86    /// Dispatches to the shape-specific extend pipeline.
87    ///
88    /// # Errors
89    ///
90    /// Returns an error if the extend pipeline fails.
91    pub fn extend(
92        &self,
93        tgt_schema: &Schema,
94        migration: &CompiledMigration,
95    ) -> Result<Self, RestrictError> {
96        match self {
97            Self::WType(w) => {
98                let extended = crate::wtype_extend(w, tgt_schema, migration)?;
99                Ok(Self::WType(extended))
100            }
101            Self::Functor(f) => {
102                let extended = crate::functor_extend(f, migration)?;
103                Ok(Self::Functor(extended))
104            }
105            Self::Graph(g) => {
106                let extended = crate::ginstance::graph_extend(g, migration)?;
107                Ok(Self::Graph(extended))
108            }
109        }
110    }
111
112    /// Returns the number of elements (nodes/rows/vertices) in this instance.
113    #[must_use]
114    pub fn element_count(&self) -> usize {
115        match self {
116            Self::WType(w) => w.node_count(),
117            Self::Functor(f) => f.table_count(),
118            Self::Graph(g) => g.node_count(),
119        }
120    }
121
122    /// Try to get a reference to the inner `WInstance`.
123    #[must_use]
124    pub const fn as_wtype(&self) -> Option<&WInstance> {
125        match self {
126            Self::WType(w) => Some(w),
127            _ => None,
128        }
129    }
130
131    /// Try to get a reference to the inner `FInstance`.
132    #[must_use]
133    pub const fn as_functor(&self) -> Option<&FInstance> {
134        match self {
135            Self::Functor(f) => Some(f),
136            _ => None,
137        }
138    }
139
140    /// Try to get a reference to the inner `GInstance`.
141    #[must_use]
142    pub const fn as_graph(&self) -> Option<&GInstance> {
143        match self {
144            Self::Graph(g) => Some(g),
145            _ => None,
146        }
147    }
148}
149
150impl From<WInstance> for Instance {
151    fn from(w: WInstance) -> Self {
152        Self::WType(w)
153    }
154}
155
156impl From<FInstance> for Instance {
157    fn from(f: FInstance) -> Self {
158        Self::Functor(f)
159    }
160}
161
162impl From<GInstance> for Instance {
163    fn from(g: GInstance) -> Self {
164        Self::Graph(g)
165    }
166}