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