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}