1use derive_more::From;
46use ref_cast::RefCast;
47use std::ops::Range;
48
49use super::graph::{EdgeGraph, VDblGraph};
50use super::tree::DblTree;
51use crate::dbl::DblNode;
52use crate::one::{Category, Path, tree};
53
54pub trait VDblCategory {
58 type Ob: Eq + Clone;
60
61 type Arr: Eq + Clone;
63
64 type Pro: Eq + Clone;
66
67 type Cell: Eq + Clone;
69
70 fn has_ob(&self, ob: &Self::Ob) -> bool;
72
73 fn has_arrow(&self, arr: &Self::Arr) -> bool;
75
76 fn has_proarrow(&self, pro: &Self::Pro) -> bool;
78
79 fn has_cell(&self, cell: &Self::Cell) -> bool;
81
82 fn dom(&self, f: &Self::Arr) -> Self::Ob;
84
85 fn cod(&self, f: &Self::Arr) -> Self::Ob;
87
88 fn src(&self, m: &Self::Pro) -> Self::Ob;
90
91 fn tgt(&self, m: &Self::Pro) -> Self::Ob;
93
94 fn cell_dom(&self, cell: &Self::Cell) -> Path<Self::Ob, Self::Pro>;
96
97 fn cell_cod(&self, cell: &Self::Cell) -> Self::Pro;
99
100 fn cell_src(&self, cell: &Self::Cell) -> Self::Arr;
102
103 fn cell_tgt(&self, cell: &Self::Cell) -> Self::Arr;
105
106 fn arity(&self, cell: &Self::Cell) -> usize {
110 self.cell_dom(cell).len()
111 }
112
113 fn compose(&self, path: Path<Self::Ob, Self::Arr>) -> Self::Arr;
115
116 fn compose2(&self, f: Self::Arr, g: Self::Arr) -> Self::Arr {
118 self.compose(Path::pair(f, g))
119 }
120
121 fn id(&self, x: Self::Ob) -> Self::Arr {
123 self.compose(Path::empty(x))
124 }
125
126 fn compose_cells(&self, tree: DblTree<Self::Arr, Self::Pro, Self::Cell>) -> Self::Cell;
128
129 fn compose_cells2(
131 &self, αs: impl IntoIterator<Item = Self::Cell>, β: Self::Cell
132 ) -> Self::Cell
133 where
134 Self: Sized,
135 {
136 let graph = UnderlyingDblGraph::ref_cast(self);
137 self.compose_cells(DblTree::two_level(αs, β, graph))
138 }
139
140 fn id_cell(&self, m: Self::Pro) -> Self::Cell {
142 self.compose_cells(DblTree::empty(m))
143 }
144}
145
146pub trait VDCWithComposites: VDblCategory {
154 fn has_composite(&self, path: &Path<Self::Ob, Self::Pro>) -> bool {
159 self.composite(path.clone()).is_some()
160 }
161
162 fn has_unit(&self, x: &Self::Ob) -> bool {
167 self.unit(x.clone()).is_some()
168 }
169
170 fn composite_ext(&self, path: Path<Self::Ob, Self::Pro>) -> Option<Self::Cell>;
174
175 fn composite2_ext(&self, m: Self::Pro, n: Self::Pro) -> Option<Self::Cell> {
177 self.composite_ext(Path::pair(m, n))
178 }
179
180 fn composite(&self, path: Path<Self::Ob, Self::Pro>) -> Option<Self::Pro> {
185 self.composite_ext(path).map(|α| self.cell_cod(&α))
186 }
187
188 fn composite2(&self, m: Self::Pro, n: Self::Pro) -> Option<Self::Pro> {
190 self.composite(Path::pair(m, n))
191 }
192
193 fn unit_ext(&self, x: Self::Ob) -> Option<Self::Cell> {
198 self.composite_ext(Path::empty(x))
199 }
200
201 fn unit(&self, x: Self::Ob) -> Option<Self::Pro> {
206 self.unit_ext(x).map(|α| self.cell_cod(&α))
207 }
208
209 fn unit_arrow(&self, f: Self::Arr) -> Option<Self::Cell> {
215 let y = self.cod(&f);
216 let y_ext = self.unit_ext(y)?;
217 let cell = self.compose_cells(DblTree(
218 tree::OpenTree::linear(vec![DblNode::Spine(f), DblNode::Cell(y_ext)]).unwrap(),
219 ));
220 self.through_unit(cell, 0)
221 }
222
223 fn through_composite(&self, cell: Self::Cell, range: Range<usize>) -> Option<Self::Cell>;
229
230 fn through_unit(&self, cell: Self::Cell, index: usize) -> Option<Self::Cell> {
235 self.through_composite(cell, index..index)
236 }
237}
238
239#[derive(From, RefCast)]
241#[repr(transparent)]
242pub struct UnderlyingCategory<VDC>(pub VDC);
243
244impl<VDC: VDblCategory> Category for UnderlyingCategory<VDC> {
245 type Ob = VDC::Ob;
246 type Mor = VDC::Arr;
247
248 fn has_ob(&self, x: &Self::Ob) -> bool {
249 self.0.has_ob(x)
250 }
251 fn has_mor(&self, f: &Self::Mor) -> bool {
252 self.0.has_arrow(f)
253 }
254 fn dom(&self, f: &Self::Mor) -> Self::Ob {
255 self.0.dom(f)
256 }
257 fn cod(&self, f: &Self::Mor) -> Self::Ob {
258 self.0.cod(f)
259 }
260 fn compose(&self, path: Path<Self::Ob, Self::Mor>) -> Self::Mor {
261 self.0.compose(path)
262 }
263 fn compose2(&self, f: Self::Mor, g: Self::Mor) -> Self::Mor {
264 self.0.compose2(f, g)
265 }
266 fn id(&self, x: Self::Ob) -> Self::Mor {
267 self.0.id(x)
268 }
269}
270
271#[derive(From, RefCast)]
273#[repr(transparent)]
274pub struct UnderlyingDblGraph<VDC>(pub VDC);
275
276impl<VDC: VDblCategory> VDblGraph for UnderlyingDblGraph<VDC> {
277 type V = VDC::Ob;
278 type E = VDC::Arr;
279 type ProE = VDC::Pro;
280 type Sq = VDC::Cell;
281
282 fn has_vertex(&self, v: &Self::V) -> bool {
283 self.0.has_ob(v)
284 }
285 fn has_edge(&self, e: &Self::E) -> bool {
286 self.0.has_arrow(e)
287 }
288 fn has_proedge(&self, p: &Self::ProE) -> bool {
289 self.0.has_proarrow(p)
290 }
291 fn has_square(&self, sq: &Self::Sq) -> bool {
292 self.0.has_cell(sq)
293 }
294
295 fn dom(&self, e: &Self::E) -> Self::V {
296 self.0.dom(e)
297 }
298 fn cod(&self, e: &Self::E) -> Self::V {
299 self.0.cod(e)
300 }
301 fn src(&self, p: &Self::ProE) -> Self::V {
302 self.0.src(p)
303 }
304 fn tgt(&self, p: &Self::ProE) -> Self::V {
305 self.0.tgt(p)
306 }
307
308 fn square_dom(&self, sq: &Self::Sq) -> Path<Self::V, Self::ProE> {
309 self.0.cell_dom(sq)
310 }
311 fn square_cod(&self, sq: &Self::Sq) -> Self::ProE {
312 self.0.cell_cod(sq)
313 }
314 fn square_src(&self, sq: &Self::Sq) -> Self::E {
315 self.0.cell_src(sq)
316 }
317 fn square_tgt(&self, sq: &Self::Sq) -> Self::E {
318 self.0.cell_tgt(sq)
319 }
320 fn arity(&self, sq: &Self::Sq) -> usize {
321 self.0.arity(sq)
322 }
323}
324
325#[derive(From, RefCast)]
333#[repr(transparent)]
334pub struct FreeVDblCategory<G: VDblGraph>(pub G);
335
336impl<G: VDblGraph> VDblCategory for FreeVDblCategory<G>
337where
338 G::ProE: std::fmt::Debug,
339{
340 type Ob = G::V;
341 type Arr = Path<G::V, G::E>;
342 type Pro = G::ProE;
343 type Cell = DblTree<G::E, G::ProE, G::Sq>;
344
345 fn has_ob(&self, ob: &Self::Ob) -> bool {
346 self.0.has_vertex(ob)
347 }
348 fn has_arrow(&self, path: &Self::Arr) -> bool {
349 path.contained_in(EdgeGraph::ref_cast(&self.0))
350 }
351 fn has_proarrow(&self, pro: &Self::Pro) -> bool {
352 self.0.has_proedge(pro)
353 }
354 fn has_cell(&self, tree: &Self::Cell) -> bool {
355 tree.contained_in(&self.0)
356 }
357
358 fn dom(&self, path: &Self::Arr) -> Self::Ob {
359 path.src(EdgeGraph::ref_cast(&self.0))
360 }
361 fn cod(&self, path: &Self::Arr) -> Self::Ob {
362 path.tgt(EdgeGraph::ref_cast(&self.0))
363 }
364 fn src(&self, m: &Self::Pro) -> Self::Ob {
365 self.0.src(m)
366 }
367 fn tgt(&self, m: &Self::Pro) -> Self::Ob {
368 self.0.tgt(m)
369 }
370
371 fn cell_dom(&self, tree: &Self::Cell) -> Path<Self::Ob, Self::Pro> {
372 tree.dom(&self.0)
373 }
374 fn cell_cod(&self, tree: &Self::Cell) -> Self::Pro {
375 tree.cod(&self.0)
376 }
377 fn cell_src(&self, tree: &Self::Cell) -> Self::Arr {
378 tree.src(&self.0)
379 }
380 fn cell_tgt(&self, tree: &Self::Cell) -> Self::Arr {
381 tree.tgt(&self.0)
382 }
383 fn arity(&self, tree: &Self::Cell) -> usize {
384 tree.arity(&self.0)
385 }
386
387 fn compose(&self, path: Path<Self::Ob, Self::Arr>) -> Self::Arr {
388 path.flatten_in(EdgeGraph::ref_cast(&self.0))
389 .expect("Path of paths should be valid before flattening")
390 }
391 fn compose_cells(&self, tree: DblTree<Self::Arr, Self::Pro, Self::Cell>) -> Self::Cell {
392 tree.flatten()
393 }
394}
395
396pub struct WalkingCategory();
407
408impl VDblCategory for WalkingCategory {
409 type Ob = ();
410 type Arr = ();
411 type Pro = ();
412 type Cell = usize;
413
414 fn has_ob(&self, _: &Self::Ob) -> bool {
415 true
416 }
417 fn has_arrow(&self, _: &Self::Arr) -> bool {
418 true
419 }
420 fn has_proarrow(&self, _: &Self::Pro) -> bool {
421 true
422 }
423 fn has_cell(&self, _: &Self::Cell) -> bool {
424 true
425 }
426
427 fn dom(&self, _: &Self::Arr) -> Self::Ob {}
428 fn cod(&self, _: &Self::Arr) -> Self::Ob {}
429 fn src(&self, _: &Self::Pro) -> Self::Ob {}
430 fn tgt(&self, _: &Self::Pro) -> Self::Ob {}
431
432 fn cell_dom(&self, n: &Self::Cell) -> Path<Self::Ob, Self::Pro> {
433 Path::repeat_n((), (), *n)
434 }
435 fn cell_cod(&self, _: &Self::Cell) -> Self::Pro {}
436 fn cell_src(&self, _: &Self::Cell) -> Self::Arr {}
437 fn cell_tgt(&self, _: &Self::Cell) -> Self::Arr {}
438
439 fn compose(&self, _: Path<Self::Ob, Self::Arr>) -> Self::Arr {}
440 fn compose_cells(&self, tree: DblTree<Self::Arr, Self::Pro, Self::Cell>) -> Self::Cell {
441 tree.dom(UnderlyingDblGraph::ref_cast(self)).len()
442 }
443}
444
445impl VDCWithComposites for WalkingCategory {
446 fn composite_ext(&self, path: Path<Self::Ob, Self::Pro>) -> Option<Self::Cell> {
448 Some(path.len())
449 }
450
451 fn through_composite(&self, n: Self::Cell, range: Range<usize>) -> Option<Self::Cell> {
452 Some(n + 1 - range.len())
453 }
454}
455
456#[allow(non_snake_case)]
457pub mod WalkingBimodule {
458 use super::super::graph::ProedgeGraph;
466 use super::*;
467
468 pub struct Main();
470
471 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
473 pub enum Ob {
474 Left,
476 Right,
478 }
479
480 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
482 pub enum Pro {
483 Left,
485 Middle,
487 Right,
489 }
490
491 impl Pro {
492 fn src(self) -> Ob {
493 match self {
494 Pro::Left => Ob::Left,
495 Pro::Middle => Ob::Left,
496 Pro::Right => Ob::Right,
497 }
498 }
499
500 fn tgt(self) -> Ob {
501 match self {
502 Pro::Left => Ob::Left,
503 Pro::Middle => Ob::Right,
504 Pro::Right => Ob::Right,
505 }
506 }
507 }
508
509 impl VDblCategory for Main {
510 type Ob = Ob;
511 type Arr = Ob;
512 type Pro = Pro;
513 type Cell = Path<Ob, Pro>;
514
515 fn has_ob(&self, _: &Self::Ob) -> bool {
516 true
517 }
518 fn has_arrow(&self, _: &Self::Arr) -> bool {
519 true
520 }
521 fn has_proarrow(&self, _: &Self::Pro) -> bool {
522 true
523 }
524 fn has_cell(&self, path: &Path<Ob, Pro>) -> bool {
525 path.contained_in(ProedgeGraph::ref_cast(UnderlyingDblGraph::ref_cast(self)))
526 }
527
528 fn dom(&self, f: &Self::Arr) -> Self::Ob {
529 *f
530 }
531 fn cod(&self, f: &Self::Arr) -> Self::Ob {
532 *f
533 }
534 fn src(&self, m: &Self::Pro) -> Self::Ob {
535 m.src()
536 }
537 fn tgt(&self, m: &Self::Pro) -> Self::Ob {
538 m.tgt()
539 }
540
541 fn cell_dom(&self, path: &Path<Ob, Pro>) -> Path<Self::Ob, Self::Pro> {
542 path.clone()
543 }
544 fn cell_cod(&self, path: &Path<Ob, Pro>) -> Self::Pro {
545 assert!(self.has_cell(path));
546 match path {
547 Path::Id(Ob::Left) => Pro::Left,
548 Path::Id(Ob::Right) => Pro::Right,
549 Path::Seq(pros) => {
550 *pros.iter().find(|m| **m == Pro::Middle).unwrap_or_else(|| pros.first())
551 }
552 }
553 }
554 fn cell_src(&self, path: &Path<Ob, Pro>) -> Self::Arr {
555 path.src(ProedgeGraph::ref_cast(UnderlyingDblGraph::ref_cast(self)))
556 }
557 fn cell_tgt(&self, path: &Path<Ob, Pro>) -> Self::Arr {
558 path.tgt(ProedgeGraph::ref_cast(UnderlyingDblGraph::ref_cast(self)))
559 }
560
561 fn compose(&self, path: Path<Self::Ob, Self::Arr>) -> Self::Arr {
562 match path {
563 Path::Id(x) => x,
564 Path::Seq(arrows) => *arrows.first(),
565 }
566 }
567 fn compose_cells(&self, tree: DblTree<Self::Arr, Self::Pro, Self::Cell>) -> Self::Cell {
568 let path = tree.dom(UnderlyingDblGraph::ref_cast(self));
569 assert!(self.has_cell(&path));
570 path
571 }
572 }
573
574 impl VDCWithComposites for Main {
575 fn composite_ext(&self, path: Path<Self::Ob, Self::Pro>) -> Option<Self::Cell> {
577 Some(path)
578 }
579
580 fn through_composite(&self, path: Self::Cell, range: Range<usize>) -> Option<Self::Cell> {
581 let graph = ProedgeGraph::ref_cast(UnderlyingDblGraph::ref_cast(self));
582 Some(path.replace_subpath(graph, range, |subpath| self.cell_cod(&subpath).into()))
583 }
584 }
585}
586
587#[allow(non_snake_case)]
588pub mod WalkingFunctor {
589 use super::super::graph::{EdgeGraph, ProedgeGraph};
595 use super::*;
596
597 pub struct Main();
599
600 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
602 pub enum Ob {
603 Zero,
605 One,
607 }
608
609 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
611 pub enum Arr {
612 Zero,
614 One,
616 Arrow,
618 }
619
620 impl Arr {
621 fn dom(self) -> Ob {
622 match self {
623 Arr::Zero => Ob::Zero,
624 Arr::Arrow => Ob::Zero,
625 Arr::One => Ob::One,
626 }
627 }
628
629 fn cod(self) -> Ob {
630 match self {
631 Arr::Zero => Ob::Zero,
632 Arr::Arrow => Ob::One,
633 Arr::One => Ob::One,
634 }
635 }
636 }
637
638 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
640 pub enum Cell {
641 Zero(usize),
643 One(usize),
645 Arrow(usize),
647 }
648
649 impl Cell {
650 fn with_src_and_tgt(f: Arr, n: usize) -> Self {
651 match f {
652 Arr::Zero => Cell::Zero(n),
653 Arr::Arrow => Cell::Arrow(n),
654 Arr::One => Cell::One(n),
655 }
656 }
657
658 fn dom(self) -> Path<Ob, Ob> {
659 let (ob, n) = match self {
660 Cell::Zero(n) => (Ob::Zero, n),
661 Cell::Arrow(n) => (Ob::Zero, n),
662 Cell::One(n) => (Ob::One, n),
663 };
664 Path::repeat_n(ob, ob, n)
665 }
666
667 fn cod(self) -> Ob {
668 match self {
669 Cell::Zero(_) => Ob::Zero,
670 Cell::Arrow(_) => Ob::One,
671 Cell::One(_) => Ob::One,
672 }
673 }
674
675 fn src(self) -> Arr {
676 match self {
677 Cell::Zero(_) => Arr::Zero,
678 Cell::Arrow(_) => Arr::Arrow,
679 Cell::One(_) => Arr::One,
680 }
681 }
682
683 fn tgt(self) -> Arr {
684 self.src()
685 }
686
687 fn map<F>(self, f: F) -> Self
688 where
689 F: FnOnce(usize) -> usize,
690 {
691 match self {
692 Cell::Zero(n) => Cell::Zero(f(n)),
693 Cell::Arrow(n) => Cell::Arrow(f(n)),
694 Cell::One(n) => Cell::One(f(n)),
695 }
696 }
697 }
698
699 impl VDblCategory for Main {
700 type Ob = Ob;
701 type Arr = Arr;
702 type Pro = Ob;
703 type Cell = Cell;
704
705 fn has_ob(&self, _: &Self::Ob) -> bool {
706 true
707 }
708 fn has_arrow(&self, _: &Self::Arr) -> bool {
709 true
710 }
711 fn has_proarrow(&self, _: &Self::Pro) -> bool {
712 true
713 }
714 fn has_cell(&self, _: &Self::Cell) -> bool {
715 true
716 }
717
718 fn dom(&self, f: &Self::Arr) -> Self::Ob {
719 f.dom()
720 }
721 fn cod(&self, f: &Self::Arr) -> Self::Ob {
722 f.cod()
723 }
724 fn src(&self, m: &Self::Pro) -> Self::Ob {
725 *m
726 }
727 fn tgt(&self, m: &Self::Pro) -> Self::Ob {
728 *m
729 }
730
731 fn cell_dom(&self, cell: &Self::Cell) -> Path<Self::Ob, Self::Pro> {
732 cell.dom()
733 }
734 fn cell_cod(&self, cell: &Self::Cell) -> Self::Pro {
735 cell.cod()
736 }
737 fn cell_src(&self, cell: &Self::Cell) -> Self::Arr {
738 cell.src()
739 }
740 fn cell_tgt(&self, cell: &Self::Cell) -> Self::Arr {
741 cell.tgt()
742 }
743
744 fn compose(&self, path: Path<Self::Ob, Self::Arr>) -> Self::Arr {
745 assert!(path.contained_in(EdgeGraph::ref_cast(UnderlyingDblGraph::ref_cast(self))));
746 match path {
747 Path::Id(Ob::Zero) => Arr::Zero,
748 Path::Id(Ob::One) => Arr::One,
749 Path::Seq(arrows) => {
750 *arrows.iter().find(|f| **f == Arr::Arrow).unwrap_or_else(|| arrows.first())
751 }
752 }
753 }
754 fn compose_cells(&self, tree: DblTree<Self::Arr, Self::Pro, Self::Cell>) -> Self::Cell {
755 let graph = UnderlyingDblGraph::ref_cast(self);
756 let (f, g) = (self.compose(tree.src(graph)), self.compose(tree.tgt(graph)));
757 assert_eq!(f, g, "Cells in walking functor have the same source and target");
758 Cell::with_src_and_tgt(f, tree.arity(graph))
759 }
760 }
761
762 impl VDCWithComposites for Main {
763 fn composite_ext(&self, path: Path<Self::Ob, Self::Pro>) -> Option<Self::Cell> {
764 let graph = ProedgeGraph::ref_cast(UnderlyingDblGraph::ref_cast(self));
765 let (x, y) = (path.src(graph), path.tgt(graph));
766 assert_eq!(x, y, "Paths in walking functor have the same source and target");
767 Some(Cell::with_src_and_tgt(self.id(x), path.len()))
768 }
769
770 fn through_composite(&self, cell: Self::Cell, range: Range<usize>) -> Option<Self::Cell> {
771 Some(cell.map(|n| n + 1 - range.len()))
772 }
773 }
774}
775
776#[cfg(test)]
777mod tests {
778 use super::*;
779
780 #[test]
781 fn walking_category() {
782 let vdc = WalkingCategory();
783 assert!(vdc.has_unit(&()));
784 assert_eq!(vdc.unit(()), Some(()));
785 assert_eq!(vdc.unit_ext(()), Some(0));
786 assert_eq!(vdc.through_unit(2, 1), Some(3));
787 assert_eq!(vdc.cell_dom(&0), Path::empty(()));
788 assert_eq!(vdc.cell_dom(&2), Path::pair((), ()));
789 }
790
791 #[test]
792 fn walking_bimodule() {
793 use WalkingBimodule::{Ob, Pro};
794
795 let vdc = WalkingBimodule::Main();
796 assert!(vdc.has_unit(&Ob::Left));
797 assert_eq!(vdc.unit(Ob::Left), Some(Pro::Left));
798 let ext = vdc.unit_ext(Ob::Left).unwrap();
799 assert_eq!(vdc.cell_dom(&ext), Path::empty(Ob::Left));
800 assert_eq!(vdc.cell_cod(&ext), Pro::Left);
801
802 let path = Path::from_vec(vec![Pro::Left, Pro::Middle, Pro::Right]).unwrap();
803 assert!(vdc.has_cell(&Path::single(Pro::Middle)));
804 assert!(vdc.has_cell(&path));
805 assert!(!vdc.has_cell(&Path::pair(Pro::Left, Pro::Right)));
806 assert_eq!(vdc.composite(Path::empty(Ob::Left)), Some(Pro::Left));
807 assert_eq!(vdc.composite(Path::empty(Ob::Right)), Some(Pro::Right));
808 assert_eq!(vdc.composite(path), Some(Pro::Middle));
809
810 assert_eq!(
811 vdc.through_unit(Pro::Middle.into(), 0),
812 Some(Path::pair(Pro::Left, Pro::Middle))
813 );
814 assert_eq!(
815 vdc.through_unit(Pro::Middle.into(), 1),
816 Some(Path::pair(Pro::Middle, Pro::Right))
817 );
818 }
819
820 #[test]
821 fn walking_functor() {
822 use WalkingFunctor::{Arr, Cell, Ob};
823
824 let vdc = WalkingFunctor::Main();
825 let cell = Cell::Arrow(2);
826 assert_eq!(vdc.cell_dom(&cell), Path::pair(Ob::Zero, Ob::Zero));
827 assert_eq!(vdc.cell_cod(&cell), Ob::One);
828 assert_eq!(vdc.cell_src(&cell), Arr::Arrow);
829 assert_eq!(vdc.cell_tgt(&cell), Arr::Arrow);
830
831 let ext = vdc.composite_ext(Path::pair(Ob::Zero, Ob::Zero)).unwrap();
832 assert_eq!(vdc.cell_src(&ext), Arr::Zero);
833 assert_eq!(vdc.cell_tgt(&ext), Arr::Zero);
834 let new_cell = vdc.compose_cells2(vec![ext, ext], cell);
835 assert_eq!(vdc.cell_dom(&new_cell).len(), 4);
836
837 assert_eq!(vdc.through_unit(Cell::Arrow(2), 1), Some(Cell::Arrow(3)));
838 }
839}