catcolab_document_types/v2/
notebook.rs1use crate::v1;
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::v2::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 };
60 cell_contents.insert(id, cell);
61 cell_order.push(id);
62 }
63 Notebook { cell_contents, cell_order }
64 })
65 .boxed()
66 }
67
68 impl Arbitrary for ModelNotebook {
69 type Parameters = ();
70 type Strategy = BoxedStrategy<Self>;
71
72 fn arbitrary_with(_: Self::Parameters) -> Self::Strategy {
73 arb_notebook(any::<super::super::model_judgment::ModelJudgment>())
74 .prop_map(ModelNotebook)
75 .boxed()
76 }
77 }
78}
79
80impl<T> Notebook<T> {
81 pub fn cells(&self) -> impl Iterator<Item = &NotebookCell<T>> {
82 self.cell_order.iter().filter_map(|id| self.cell_contents.get(id))
83 }
84
85 pub fn formal_content(&self) -> impl Iterator<Item = &T> {
86 self.cells().filter_map(|cell| match cell {
87 NotebookCell::Formal { content, .. } => Some(content),
88 _ => None,
89 })
90 }
91
92 pub fn migrate_from_v1(old: v1::Notebook<T>) -> Self {
97 let v1::Notebook { cell_contents, cell_order } = old;
98
99 let mut new_contents = HashMap::with_capacity(cell_contents.len());
100 for (id, cell) in cell_contents {
101 if let Some(new_cell) = NotebookCell::migrate_from_v1(cell) {
102 new_contents.insert(id, new_cell);
103 }
104 }
105
106 let new_order: Vec<Uuid> =
109 cell_order.into_iter().filter(|id| new_contents.contains_key(id)).collect();
110
111 Notebook {
112 cell_contents: new_contents,
113 cell_order: new_order,
114 }
115 }
116}