1use std::collections::HashMap;
4use std::rc::Rc;
5
6use all_the_same::all_the_same;
7use derive_more::{From, TryInto};
8use ustr::Ustr;
9
10use wasm_bindgen::prelude::*;
11
12use catcolab_document_types::current::theory::*;
13use catlog::dbl::theory::{
14 self, DblTheory as _, ModalMorType, ModalObOp, ModalObType, ModeApp, NonUnital, TabMorType,
15 TabObOp, TabObType, Unital,
16};
17use catlog::one::{Path, QualifiedPath, ShortPath};
18use catlog::tt::{
19 self,
20 notebook_elab::{demote_modality, promote_modality},
21};
22use catlog::zero::{NameSegment, QualifiedName};
23
24use super::notation::*;
25
26impl CanElaborate<ObType, QualifiedName> for Elaborator {
28 fn elab(&self, ob_type: &ObType) -> Result<QualifiedName, String> {
29 match ob_type {
30 ObType::Basic(id) => Ok((*id).into()),
31 _ => Err(format!("Cannot use object type in discrete double theory: {ob_type:#?}")),
32 }
33 }
34}
35
36impl CanElaborate<MorType, QualifiedPath> for Elaborator {
38 fn elab(&self, mor_type: &MorType) -> Result<QualifiedPath, String> {
39 match mor_type {
40 MorType::Basic(id) => Ok(Path::single((*id).into())),
41 MorType::Composite(fs) => {
42 let fs: Result<Vec<_>, _> = fs.iter().map(|f| self.elab(f)).collect();
43 let path = Path::from_vec(fs?).ok_or("Composite should not be empty")?;
44 Ok(path.flatten())
45 }
46 MorType::Hom(ob_type) => Ok(Path::Id(self.elab(ob_type.as_ref())?)),
47 _ => Err(format!("Cannot use morphsim type in discrete double theory: {mor_type:#?}")),
48 }
49 }
50}
51
52impl CanElaborate<ObOp, QualifiedName> for Elaborator {
54 fn elab(&self, op: &ObOp) -> Result<QualifiedName, String> {
55 Err(format!("Cannot use operation in discrete double theory: {op:#?}"))
56 }
57}
58
59impl CanElaborate<ObType, TabObType> for Elaborator {
61 fn elab(&self, ob_type: &ObType) -> Result<TabObType, String> {
62 match ob_type {
63 ObType::Basic(id) => Ok(TabObType::Basic((*id).into())),
64 ObType::Tabulator(mor_type) => {
65 Ok(TabObType::Tabulator(Box::new(self.elab(mor_type.as_ref())?)))
66 }
67 _ => Err(format!("Cannot use object type in discrete tabulator theory: {ob_type:#?}")),
68 }
69 }
70}
71
72impl CanElaborate<MorType, TabMorType> for Elaborator {
74 fn elab(&self, mor_type: &MorType) -> Result<TabMorType, String> {
75 match mor_type {
76 MorType::Basic(id) => Ok(TabMorType::Basic((*id).into())),
77 MorType::Composite(_) => {
78 Err("Composites not yet implemented for tabulator theories".into())
79 }
80 MorType::Hom(ob_type) => Ok(TabMorType::Hom(Box::new(self.elab(ob_type.as_ref())?))),
81 _ => {
82 Err(format!("Cannot use morphism type in discrete tabulator theory: {mor_type:#?}"))
83 }
84 }
85 }
86}
87
88impl CanElaborate<ObOp, TabObOp> for Elaborator {
90 fn elab(&self, op: &ObOp) -> Result<TabObOp, String> {
91 Err(format!("Cannot use operation in discrete tabulator theory: {op:#?}"))
92 }
93}
94
95impl CanElaborate<ObType, ModalObType> for Elaborator {
97 fn elab(&self, ob_type: &ObType) -> Result<ModalObType, String> {
98 match ob_type {
99 ObType::Basic(id) => Ok(ModeApp::new((*id).into())),
100 ObType::ModeApp { modality, ob_type } => Ok({
101 let ob_type: ModalObType = self.elab(ob_type.as_ref())?;
102 ob_type.apply(promote_modality(*modality))
103 }),
104 _ => Err(format!("Cannot use object type in modal theory: {ob_type:#?}")),
105 }
106 }
107}
108
109impl CanElaborate<MorType, ModalMorType> for Elaborator {
111 fn elab(&self, mor_type: &MorType) -> Result<ModalMorType, String> {
112 match mor_type {
113 MorType::Basic(id) => Ok(ModeApp::new((*id).into()).into()),
114 MorType::Hom(ob_type) => Ok(ShortPath::Zero(self.elab(ob_type.as_ref())?)),
115 MorType::ModeApp { modality, mor_type } => Ok({
116 let mor_type: ModalMorType = self.elab(mor_type.as_ref())?;
117 mor_type.apply(promote_modality(*modality))
118 }),
119 _ => Err(format!("Cannot use morphism type in modal theory: {mor_type:#?}")),
120 }
121 }
122}
123
124impl CanElaborate<ObOp, ModalObOp> for Elaborator {
126 fn elab(&self, op: &ObOp) -> Result<ModalObOp, String> {
127 match op {
128 ObOp::Basic(id) => Ok(ModalObOp::generator((*id).into())),
129 }
130 }
131}
132
133pub(crate) fn expect_single_name(name: &QualifiedName) -> Ustr {
134 match name.only() {
135 Some(NameSegment::Text(text)) => text,
136 _ => panic!("Only singleton names are currently supported in notebook types"),
137 }
138}
139
140impl CanQuote<QualifiedName, ObType> for Quoter {
142 fn quote(&self, name: &QualifiedName) -> ObType {
143 ObType::Basic(expect_single_name(name))
144 }
145}
146
147impl CanQuote<QualifiedPath, MorType> for Quoter {
149 fn quote(&self, path: &QualifiedPath) -> MorType {
150 match path {
151 Path::Id(v) => MorType::Hom(Box::new(ObType::Basic(expect_single_name(v)))),
152 Path::Seq(edges) => {
153 if edges.len() == 1 {
154 MorType::Basic(expect_single_name(&edges.head))
155 } else {
156 MorType::Composite(
157 edges.iter().map(|e| MorType::Basic(expect_single_name(e))).collect(),
158 )
159 }
160 }
161 }
162 }
163}
164
165impl CanQuote<TabObType, ObType> for Quoter {
167 fn quote(&self, ob_type: &TabObType) -> ObType {
168 match ob_type {
169 TabObType::Basic(name) => ObType::Basic(expect_single_name(name)),
170 TabObType::Tabulator(mor_type) => {
171 ObType::Tabulator(Box::new(self.quote(mor_type.as_ref())))
172 }
173 }
174 }
175}
176
177impl CanQuote<TabMorType, MorType> for Quoter {
179 fn quote(&self, mor_type: &TabMorType) -> MorType {
180 match mor_type {
181 TabMorType::Basic(name) => MorType::Basic(expect_single_name(name)),
182 TabMorType::Hom(ob_type) => MorType::Hom(Box::new(self.quote(ob_type.as_ref()))),
183 }
184 }
185}
186
187impl CanQuote<ModalObType, ObType> for Quoter {
189 fn quote(&self, app: &ModalObType) -> ObType {
190 let mut quoted = ObType::Basic(expect_single_name(&app.arg));
191 for modality in &app.modalities {
192 quoted = ObType::ModeApp {
193 modality: demote_modality(*modality),
194 ob_type: quoted.into(),
195 }
196 }
197 quoted
198 }
199}
200
201impl CanQuote<ModalMorType, MorType> for Quoter {
203 fn quote(&self, mor_type: &ModalMorType) -> MorType {
204 match mor_type {
205 ShortPath::Zero(ob_type) => MorType::Hom(Box::new(self.quote(ob_type))),
206 ShortPath::One(app) => {
207 let mut quoted = MorType::Basic(expect_single_name(&app.arg));
208 for modality in &app.modalities {
209 quoted = MorType::ModeApp {
210 modality: demote_modality(*modality),
211 mor_type: quoted.into(),
212 }
213 }
214 quoted
215 }
216 }
217 }
218}
219
220#[derive(From, TryInto)]
227#[try_into(ref)]
228pub enum DblTheoryBox {
229 Discrete(Rc<theory::DiscreteDblTheory>),
231 DiscreteTab(Rc<theory::DiscreteTabTheory>),
233 ModalUnital(Rc<theory::ModalDblTheory<Unital>>),
235 ModalNonUnital(Rc<theory::ModalDblTheory<NonUnital>>),
237}
238
239#[wasm_bindgen]
241pub struct DblTheory(#[wasm_bindgen(skip)] pub DblTheoryBox);
242
243impl DblTheory {
244 pub fn discrete(&self) -> Result<&Rc<theory::DiscreteDblTheory>, String> {
246 (&self.0).try_into().map_err(|_| "Theory should be discrete".into())
247 }
248
249 pub fn try_into_tt(&self) -> Option<tt::theory::TheoryDef> {
251 match &self.0 {
252 DblTheoryBox::Discrete(th) => Some(tt::theory::TheoryDef::Discrete(th.clone())),
253 DblTheoryBox::DiscreteTab(th) => Some(tt::theory::TheoryDef::DiscreteTab(th.clone())),
254 DblTheoryBox::ModalUnital(th) => Some(tt::theory::TheoryDef::ModalUnital(th.clone())),
255 DblTheoryBox::ModalNonUnital(th) => {
256 Some(tt::theory::TheoryDef::ModalNonUnital(th.clone()))
257 }
258 }
259 }
260}
261
262#[wasm_bindgen]
263impl DblTheory {
264 #[wasm_bindgen(js_name = "hasObType")]
266 pub fn has_ob_type(&self, ob_type: ObType) -> Result<bool, String> {
267 all_the_same!(match &self.0 {
268 DblTheoryBox::[Discrete, DiscreteTab, ModalUnital, ModalNonUnital](th) => {
269 Ok(th.has_ob_type(&Elaborator.elab(&ob_type)?))
270 }
271 })
272 }
273
274 #[wasm_bindgen(js_name = "hasMorType")]
276 pub fn has_mor_type(&self, mor_type: MorType) -> Result<bool, String> {
277 all_the_same!(match &self.0 {
278 DblTheoryBox::[Discrete, DiscreteTab, ModalUnital, ModalNonUnital](th) => {
279 Ok(th.has_mor_type(&Elaborator.elab(&mor_type)?))
280 }
281 })
282 }
283
284 #[wasm_bindgen]
286 pub fn src(&self, mor_type: MorType) -> Result<ObType, String> {
287 all_the_same!(match &self.0 {
288 DblTheoryBox::[Discrete, DiscreteTab, ModalUnital, ModalNonUnital](th) => {
289 let mor_type = Elaborator.elab(&mor_type)?;
290 Ok(Quoter.quote(&th.src_type(&mor_type)))
291 }
292 })
293 }
294
295 #[wasm_bindgen]
297 pub fn tgt(&self, mor_type: MorType) -> Result<ObType, String> {
298 all_the_same!(match &self.0 {
299 DblTheoryBox::[Discrete, DiscreteTab, ModalUnital, ModalNonUnital](th) => {
300 let mor_type = Elaborator.elab(&mor_type)?;
301 Ok(Quoter.quote(&th.tgt_type(&mor_type)))
302 }
303 })
304 }
305
306 #[wasm_bindgen]
308 pub fn dom(&self, op: ObOp) -> Result<ObType, String> {
309 all_the_same!(match &self.0 {
310 DblTheoryBox::[Discrete, DiscreteTab, ModalUnital, ModalNonUnital](th) => {
311 let op = Elaborator.elab(&op)?;
312 Ok(Quoter.quote(&th.ob_op_dom(&op)))
313 }
314 })
315 }
316
317 #[wasm_bindgen]
319 pub fn cod(&self, op: ObOp) -> Result<ObType, String> {
320 all_the_same!(match &self.0 {
321 DblTheoryBox::[Discrete, DiscreteTab, ModalUnital, ModalNonUnital](th) => {
322 let op = Elaborator.elab(&op)?;
323 Ok(Quoter.quote(&th.ob_op_cod(&op)))
324 }
325 })
326 }
327}
328
329#[wasm_bindgen]
334#[derive(Clone, Default)]
335pub struct ObTypeIndex(HashMap<ObType, usize>);
336
337#[wasm_bindgen]
338impl ObTypeIndex {
339 #[wasm_bindgen(constructor)]
341 pub fn new() -> Self {
342 Default::default()
343 }
344
345 #[wasm_bindgen(js_name = "has")]
347 pub fn contains_key(&self, x: &ObType) -> bool {
348 self.0.contains_key(x)
349 }
350
351 #[wasm_bindgen]
353 pub fn get(&self, x: &ObType) -> Option<usize> {
354 self.0.get(x).copied()
355 }
356
357 #[wasm_bindgen(js_name = "set")]
359 pub fn insert(&mut self, x: ObType, i: usize) {
360 self.0.insert(x, i);
361 }
362}
363
364#[wasm_bindgen]
369#[derive(Clone, Default)]
370pub struct MorTypeIndex(HashMap<MorType, usize>);
371
372#[wasm_bindgen]
373impl MorTypeIndex {
374 #[wasm_bindgen(constructor)]
376 pub fn new() -> Self {
377 Default::default()
378 }
379
380 #[wasm_bindgen(js_name = "has")]
382 pub fn contains_key(&self, m: &MorType) -> bool {
383 self.0.contains_key(m)
384 }
385
386 #[wasm_bindgen]
388 pub fn get(&self, m: &MorType) -> Option<usize> {
389 self.0.get(m).copied()
390 }
391
392 #[wasm_bindgen(js_name = "set")]
394 pub fn insert(&mut self, m: MorType, i: usize) {
395 self.0.insert(m, i);
396 }
397}