catcolab_document_types/v1/
notebook.rs1use crate::v0;
2
3use super::cell::NotebookCell;
4
5use serde::{Deserialize, Serialize};
6use std::collections::HashMap;
7use tsify::Tsify;
8use uuid::Uuid;
9
10#[derive(PartialEq, Eq, Debug, Serialize, Deserialize, Tsify)]
11#[tsify(into_wasm_abi, from_wasm_abi, hashmap_as_object)]
12pub struct Notebook<T> {
13 #[serde(rename = "cellContents")]
14 pub cell_contents: HashMap<Uuid, NotebookCell<T>>,
15 #[serde(rename = "cellOrder")]
16 pub cell_order: Vec<Uuid>,
17}
18
19#[derive(PartialEq, Eq, Debug, Serialize, Deserialize, Tsify)]
20#[tsify(into_wasm_abi, from_wasm_abi)]
21pub struct ModelNotebook(pub Notebook<super::model_judgment::ModelJudgment>);
22
23#[derive(PartialEq, Eq, Debug, Serialize, Deserialize, Tsify)]
24#[tsify(into_wasm_abi, from_wasm_abi)]
25pub struct DiagramNotebook(pub Notebook<super::diagram_judgment::DiagramJudgment>);
26
27#[cfg(feature = "property-tests")]
29pub(crate) mod arbitrary {
30 use super::*;
31 use crate::v0::cell::arbitrary::arb_notebook_cell;
32 use proptest::prelude::*;
33
34 fn arb_uuid() -> BoxedStrategy<Uuid> {
35 any::<u128>().prop_map(Uuid::from_u128).boxed()
36 }
37
38 pub fn arb_notebook<T: std::fmt::Debug + 'static>(
43 arb_t: impl Strategy<Value = T> + Clone + 'static,
44 ) -> BoxedStrategy<Notebook<T>> {
45 prop::collection::vec((arb_uuid(), arb_notebook_cell(arb_t)), 0..6)
46 .prop_map(|entries| {
47 let mut cell_contents = HashMap::new();
48 let mut cell_order = Vec::new();
49 for (id, cell) in entries {
50 let cell = match cell {
53 NotebookCell::RichText { content, .. } => {
54 NotebookCell::RichText { id, content }
55 }
56 NotebookCell::Formal { content, .. } => {
57 NotebookCell::Formal { id, content }
58 }
59 NotebookCell::Stem { .. } => NotebookCell::Stem { id },
60 };
61 cell_contents.insert(id, cell);
62 cell_order.push(id);
63 }
64 Notebook { cell_contents, cell_order }
65 })
66 .boxed()
67 }
68
69 impl Arbitrary for ModelNotebook {
70 type Parameters = ();
71 type Strategy = BoxedStrategy<Self>;
72
73 fn arbitrary_with(_: Self::Parameters) -> Self::Strategy {
74 arb_notebook(any::<super::super::model_judgment::ModelJudgment>())
75 .prop_map(ModelNotebook)
76 .boxed()
77 }
78 }
79}
80
81impl<T> Notebook<T> {
82 pub fn cells(&self) -> impl Iterator<Item = &NotebookCell<T>> {
83 self.cell_order.iter().filter_map(|id| self.cell_contents.get(id))
84 }
85
86 pub fn formal_content(&self) -> impl Iterator<Item = &T> {
87 self.cells().filter_map(|cell| match cell {
88 NotebookCell::Formal { content, .. } => Some(content),
89 _ => None,
90 })
91 }
92
93 pub fn migrate_from_v0(old: v0::Notebook<T>) -> Self {
94 let mut cell_contents = HashMap::new();
95 let mut cell_order = Vec::new();
96
97 for old_cell in old.cells {
98 let id = match old_cell {
99 v0::NotebookCell::RichText { id, .. }
100 | v0::NotebookCell::Formal { id, .. }
101 | v0::NotebookCell::Stem { id } => id,
102 };
103
104 cell_order.push(id);
105 cell_contents.insert(id, old_cell);
106 }
107
108 Notebook { cell_contents, cell_order }
109 }
110}