1use std::collections::HashMap;
4use std::hash::Hash;
5use std::rc::Rc;
6
7use all_the_same::all_the_same;
8use derive_more::From;
9use ustr::Ustr;
10
11use serde::{Deserialize, Serialize};
12use tsify::Tsify;
13use wasm_bindgen::prelude::*;
14
15use catlog::dbl::theory;
16use catlog::dbl::theory::{DblTheory as _, TabMorType, TabObType};
17use catlog::one::Path;
18
19#[derive(Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize, Tsify)]
21#[serde(tag = "tag", content = "content")]
22#[tsify(into_wasm_abi, from_wasm_abi)]
23pub enum ObType {
24 Basic(Ustr),
26
27 Tabulator(Box<MorType>),
29}
30
31#[derive(Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize, Tsify)]
33#[serde(tag = "tag", content = "content")]
34#[tsify(into_wasm_abi, from_wasm_abi)]
35pub enum MorType {
36 Basic(Ustr),
38
39 Composite(Vec<MorType>),
41
42 Hom(Box<ObType>),
44}
45
46impl From<Ustr> for ObType {
48 fn from(value: Ustr) -> Self {
49 ObType::Basic(value)
50 }
51}
52
53impl From<Path<Ustr, Ustr>> for MorType {
55 fn from(mor: Path<Ustr, Ustr>) -> Self {
56 match mor {
57 Path::Id(v) => MorType::Hom(Box::new(ObType::Basic(v))),
58 Path::Seq(edges) => {
59 if edges.len() == 1 {
60 MorType::Basic(edges.head)
61 } else {
62 MorType::Composite(edges.into_iter().map(MorType::Basic).collect())
63 }
64 }
65 }
66 }
67}
68
69impl TryFrom<ObType> for Ustr {
71 type Error = String;
72
73 fn try_from(ob_type: ObType) -> Result<Self, Self::Error> {
74 match ob_type {
75 ObType::Basic(name) => Ok(name),
76 _ => Err(format!("Cannot cast object type for discrete double theory: {ob_type:#?}")),
77 }
78 }
79}
80
81impl TryFrom<MorType> for Path<Ustr, Ustr> {
83 type Error = String;
84
85 fn try_from(mor_type: MorType) -> Result<Self, Self::Error> {
86 match mor_type {
87 MorType::Basic(name) => Ok(name.into()),
88 MorType::Composite(fs) => {
89 let fs: Result<Vec<_>, _> = fs.into_iter().map(|f| f.try_into()).collect();
90 let path = Path::from_vec(fs?).ok_or("Composite should not be empty")?;
91 Ok(path.flatten())
92 }
93 MorType::Hom(x) => (*x).try_into().map(Path::Id),
94 }
95 }
96}
97
98impl From<TabObType<Ustr, Ustr>> for ObType {
100 fn from(ob_type: TabObType<Ustr, Ustr>) -> Self {
101 match ob_type {
102 TabObType::Basic(name) => ObType::Basic(name),
103 TabObType::Tabulator(m) => ObType::Tabulator(Box::new((*m).into())),
104 }
105 }
106}
107
108impl From<TabMorType<Ustr, Ustr>> for MorType {
110 fn from(mor_type: TabMorType<Ustr, Ustr>) -> Self {
111 match mor_type {
112 TabMorType::Basic(name) => MorType::Basic(name),
113 TabMorType::Hom(x) => MorType::Hom(Box::new((*x).into())),
114 }
115 }
116}
117
118impl TryFrom<ObType> for TabObType<Ustr, Ustr> {
120 type Error = String;
121
122 fn try_from(ob_type: ObType) -> Result<Self, Self::Error> {
123 match ob_type {
124 ObType::Basic(name) => Ok(TabObType::Basic(name)),
125 ObType::Tabulator(m) => (*m).try_into().map(|m| TabObType::Tabulator(Box::new(m))),
126 }
127 }
128}
129
130impl TryFrom<MorType> for TabMorType<Ustr, Ustr> {
132 type Error = String;
133
134 fn try_from(mor_type: MorType) -> Result<Self, Self::Error> {
135 match mor_type {
136 MorType::Basic(name) => Ok(TabMorType::Basic(name)),
137 MorType::Composite(_) => {
138 Err("Composites not yet implemented for tabulator theories".into())
139 }
140 MorType::Hom(x) => (*x).try_into().map(|x| TabMorType::Hom(Box::new(x))),
141 }
142 }
143}
144
145#[derive(From)]
153pub enum DblTheoryBox {
154 Discrete(Rc<theory::UstrDiscreteDblTheory>),
155 DiscreteTab(Rc<theory::UstrDiscreteTabTheory>),
156}
157
158#[wasm_bindgen]
161pub struct DblTheory(#[wasm_bindgen(skip)] pub DblTheoryBox);
162
163#[wasm_bindgen]
164impl DblTheory {
165 #[wasm_bindgen(getter)]
167 pub fn kind(&self) -> String {
168 match &self.0 {
170 DblTheoryBox::Discrete(_) => "Discrete",
171 DblTheoryBox::DiscreteTab(_) => "DiscreteTab",
172 }
173 .into()
174 }
175
176 #[wasm_bindgen]
178 pub fn src(&self, mor_type: MorType) -> Result<ObType, String> {
179 all_the_same!(match &self.0 {
180 DblTheoryBox::[Discrete, DiscreteTab](th) => {
181 let m = mor_type.try_into()?;
182 Ok(th.src_type(&m).into())
183 }
184 })
185 }
186
187 #[wasm_bindgen]
189 pub fn tgt(&self, mor_type: MorType) -> Result<ObType, String> {
190 all_the_same!(match &self.0 {
191 DblTheoryBox::[Discrete, DiscreteTab](th) => {
192 let m = mor_type.try_into()?;
193 Ok(th.tgt_type(&m).into())
194 }
195 })
196 }
197}
198
199#[wasm_bindgen]
205#[derive(Clone, Default)]
206pub struct ObTypeIndex(HashMap<ObType, usize>);
207
208#[wasm_bindgen]
209impl ObTypeIndex {
210 #[wasm_bindgen(constructor)]
212 pub fn new() -> Self {
213 Default::default()
214 }
215
216 #[wasm_bindgen]
218 pub fn get(&self, x: &ObType) -> Option<usize> {
219 self.0.get(x).copied()
220 }
221
222 #[wasm_bindgen]
224 pub fn set(&mut self, x: ObType, i: usize) {
225 self.0.insert(x, i);
226 }
227}
228
229#[wasm_bindgen]
235#[derive(Clone, Default)]
236pub struct MorTypeIndex(HashMap<MorType, usize>);
237
238#[wasm_bindgen]
239impl MorTypeIndex {
240 #[wasm_bindgen(constructor)]
242 pub fn new() -> Self {
243 Default::default()
244 }
245
246 #[wasm_bindgen]
248 pub fn get(&self, m: &MorType) -> Option<usize> {
249 self.0.get(m).copied()
250 }
251
252 #[wasm_bindgen]
254 pub fn set(&mut self, m: MorType, i: usize) {
255 self.0.insert(m, i);
256 }
257}