catlog_wasm/
theory.rs

1//! Wasm bindings for double theories.
2
3use std::collections::HashMap;
4use std::hash::Hash;
5use std::sync::Arc;
6
7use all_the_same::all_the_same;
8use derive_more::From;
9use ustr::Ustr;
10
11use serde::{Deserialize, Serialize};
12use tsify_next::Tsify;
13use wasm_bindgen::prelude::*;
14
15use catlog::dbl::theory;
16use catlog::dbl::theory::{DblTheory as _, TabMorType, TabObType};
17use catlog::one::fin_category::*;
18
19/// Object type in a double theory.
20#[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 or generating object type.
25    Basic(Ustr),
26
27    /// Tabulator of a morphism type.
28    Tabulator(Box<MorType>),
29}
30
31/// Morphism type in a double theory.
32#[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 or generating morphism type.
37    Basic(Ustr),
38
39    /// Hom type on an object type.
40    Hom(Box<ObType>),
41}
42
43/// Convert from object type in a discrete double theory.
44impl From<Ustr> for ObType {
45    fn from(value: Ustr) -> Self {
46        ObType::Basic(value)
47    }
48}
49
50/// Convert from morphism type in a discrete double theory.
51impl From<FinMor<Ustr, Ustr>> for MorType {
52    fn from(mor: FinMor<Ustr, Ustr>) -> Self {
53        match mor {
54            FinMor::Generator(e) => MorType::Basic(e),
55            FinMor::Id(v) => MorType::Hom(Box::new(ObType::Basic(v))),
56        }
57    }
58}
59
60/// Convert into object type in a discrete double theory.
61impl TryFrom<ObType> for Ustr {
62    type Error = String;
63
64    fn try_from(ob_type: ObType) -> Result<Self, Self::Error> {
65        match ob_type {
66            ObType::Basic(name) => Ok(name),
67            _ => Err(format!("Cannot cast object type for discrete double theory: {:#?}", ob_type)),
68        }
69    }
70}
71
72/// Convert into morphism type in a discrete double theory.
73impl TryFrom<MorType> for FinMor<Ustr, Ustr> {
74    type Error = String;
75
76    fn try_from(mor_type: MorType) -> Result<Self, Self::Error> {
77        match mor_type {
78            MorType::Basic(name) => Ok(FinMor::Generator(name)),
79            MorType::Hom(x) => (*x).try_into().map(FinMor::Id),
80        }
81    }
82}
83
84/// Convert from object type in a discrete tabulator theory.
85impl From<TabObType<Ustr, Ustr>> for ObType {
86    fn from(ob_type: TabObType<Ustr, Ustr>) -> Self {
87        match ob_type {
88            TabObType::Basic(name) => ObType::Basic(name),
89            TabObType::Tabulator(m) => ObType::Tabulator(Box::new((*m).into())),
90        }
91    }
92}
93
94/// Convert from morphism type in a discrete tabulator theory.
95impl From<TabMorType<Ustr, Ustr>> for MorType {
96    fn from(mor_type: TabMorType<Ustr, Ustr>) -> Self {
97        match mor_type {
98            TabMorType::Basic(name) => MorType::Basic(name),
99            TabMorType::Hom(x) => MorType::Hom(Box::new((*x).into())),
100        }
101    }
102}
103
104/// Convert into object type in a discrete tabulator theory.
105impl TryFrom<ObType> for TabObType<Ustr, Ustr> {
106    type Error = String;
107
108    fn try_from(ob_type: ObType) -> Result<Self, Self::Error> {
109        match ob_type {
110            ObType::Basic(name) => Ok(TabObType::Basic(name)),
111            ObType::Tabulator(m) => (*m).try_into().map(|m| TabObType::Tabulator(Box::new(m))),
112        }
113    }
114}
115
116/// Convert into morphism type in a discrete tabulator theory.
117impl TryFrom<MorType> for TabMorType<Ustr, Ustr> {
118    type Error = String;
119
120    fn try_from(mor_type: MorType) -> Result<Self, Self::Error> {
121        match mor_type {
122            MorType::Basic(name) => Ok(TabMorType::Basic(name)),
123            MorType::Hom(x) => (*x).try_into().map(|x| TabMorType::Hom(Box::new(x))),
124        }
125    }
126}
127
128/** A box containing a double theory of any kind.
129
130Ideally the Wasm-bound [`DblTheory`] would just have a type parameter for the
131underlying double theory, but `wasm-bindgen` does not support
132[generics](https://github.com/rustwasm/wasm-bindgen/issues/3309). Instead, we
133explicitly enumerate the supported kinds of double theories in this enum.
134 */
135#[derive(From)]
136pub enum DblTheoryBox {
137    Discrete(Arc<theory::UstrDiscreteDblTheory>),
138    DiscreteTab(Arc<theory::UstrDiscreteTabTheory>),
139}
140
141/** Wasm bindings for a double theory.
142 */
143#[wasm_bindgen]
144pub struct DblTheory(#[wasm_bindgen(skip)] pub DblTheoryBox);
145
146#[wasm_bindgen]
147impl DblTheory {
148    /// Kind of double theory ("double doctrine").
149    #[wasm_bindgen(getter)]
150    pub fn kind(&self) -> String {
151        // TODO: Should return an enum so that we get type defs.
152        match &self.0 {
153            DblTheoryBox::Discrete(_) => "Discrete",
154            DblTheoryBox::DiscreteTab(_) => "DiscreteTab",
155        }
156        .into()
157    }
158
159    /// Source of a morphism type.
160    #[wasm_bindgen]
161    pub fn src(&self, mor_type: MorType) -> Result<ObType, String> {
162        all_the_same!(match &self.0 {
163            DblTheoryBox::[Discrete, DiscreteTab](th) => {
164                let m = mor_type.try_into()?;
165                Ok(th.src_type(&m).into())
166            }
167        })
168    }
169
170    /// Target of a morphism type.
171    #[wasm_bindgen]
172    pub fn tgt(&self, mor_type: MorType) -> Result<ObType, String> {
173        all_the_same!(match &self.0 {
174            DblTheoryBox::[Discrete, DiscreteTab](th) => {
175                let m = mor_type.try_into()?;
176                Ok(th.tgt_type(&m).into())
177            }
178        })
179    }
180}
181
182/** Mapping from object types to numerical indices.
183
184Like [`MorTypeIndex`], this struct just compensates for the lack of hash maps
185with arbitrary keys in JavaScript.
186 */
187#[wasm_bindgen]
188#[derive(Clone, Default)]
189pub struct ObTypeIndex(HashMap<ObType, usize>);
190
191#[wasm_bindgen]
192impl ObTypeIndex {
193    /// Creates a new object type index.
194    #[wasm_bindgen(constructor)]
195    pub fn new() -> Self {
196        Default::default()
197    }
198
199    /// Gets the index of an object type, if set.
200    #[wasm_bindgen]
201    pub fn get(&self, x: &ObType) -> Option<usize> {
202        self.0.get(x).copied()
203    }
204
205    /// Sets the index of an object type.
206    #[wasm_bindgen]
207    pub fn set(&mut self, x: ObType, i: usize) {
208        self.0.insert(x, i);
209    }
210}
211
212/** Mapping from morphism types to numerical indices.
213
214Like [`ObTypeIndex`], this struct just compensates for the lack of hash maps
215with arbitrary keys in JavaScript.
216 */
217#[wasm_bindgen]
218#[derive(Clone, Default)]
219pub struct MorTypeIndex(HashMap<MorType, usize>);
220
221#[wasm_bindgen]
222impl MorTypeIndex {
223    /// Creates a new morphism type index.
224    #[wasm_bindgen(constructor)]
225    pub fn new() -> Self {
226        Default::default()
227    }
228
229    /// Gets the index of a morphism type, if set.
230    #[wasm_bindgen]
231    pub fn get(&self, m: &MorType) -> Option<usize> {
232        self.0.get(m).copied()
233    }
234
235    /// Sets the index of a morphism type.
236    #[wasm_bindgen]
237    pub fn set(&mut self, m: MorType, i: usize) {
238        self.0.insert(m, i);
239    }
240}