ywasm/
collection.rs

1use crate::transaction::{ImplicitTransaction, YTransaction};
2use crate::Result;
3use gloo_utils::format::JsValueSerdeExt;
4use std::ops::Deref;
5use wasm_bindgen::JsValue;
6use yrs::{BranchID, Doc, Hook, ReadTxn, SharedRef, Transact, Transaction, TransactionMut};
7
8pub enum SharedCollection<P, S> {
9    Integrated(Integrated<S>),
10    Prelim(P),
11}
12
13impl<P, S: SharedRef + 'static> SharedCollection<P, S> {
14    #[inline]
15    pub fn prelim(prelim: P) -> Self {
16        SharedCollection::Prelim(prelim)
17    }
18
19    #[inline]
20    pub fn integrated(shared_ref: S, doc: Doc) -> Self {
21        SharedCollection::Integrated(Integrated::new(shared_ref, doc))
22    }
23
24    pub fn id(&self) -> crate::Result<JsValue> {
25        match self {
26            SharedCollection::Prelim(_) => {
27                Err(JsValue::from_str(crate::js::errors::INVALID_PRELIM_OP))
28            }
29            SharedCollection::Integrated(c) => {
30                let branch_id = c.hook.id();
31                JsValue::from_serde(branch_id).map_err(|e| JsValue::from_str(&e.to_string()))
32            }
33        }
34    }
35
36    pub fn try_integrated(&self) -> Result<(&BranchID, &Doc)> {
37        match self {
38            SharedCollection::Integrated(i) => {
39                let branch_id = i.hook.id();
40                let doc = &i.doc;
41                Ok((branch_id, doc))
42            }
43            SharedCollection::Prelim(_) => {
44                Err(JsValue::from_str(crate::js::errors::INVALID_PRELIM_OP))
45            }
46        }
47    }
48
49    #[inline]
50    pub fn is_prelim(&self) -> bool {
51        match self {
52            SharedCollection::Prelim(_) => true,
53            SharedCollection::Integrated(_) => false,
54        }
55    }
56
57    pub fn is_alive(&self, txn: &YTransaction) -> bool {
58        match self {
59            SharedCollection::Prelim(_) => true,
60            SharedCollection::Integrated(col) => {
61                let desc = &col.hook;
62                desc.get(txn.deref()).is_some()
63            }
64        }
65    }
66
67    #[inline]
68    pub fn branch_id(&self) -> Option<&BranchID> {
69        match self {
70            SharedCollection::Prelim(_) => None,
71            SharedCollection::Integrated(v) => Some(v.hook.id()),
72        }
73    }
74}
75
76pub struct Integrated<S> {
77    pub hook: Hook<S>,
78    pub doc: Doc,
79}
80
81impl<S: SharedRef + 'static> Integrated<S> {
82    pub fn new(shared_ref: S, doc: Doc) -> Self {
83        let desc = shared_ref.hook();
84        Integrated { hook: desc, doc }
85    }
86
87    pub fn readonly<F, T>(&self, txn: &ImplicitTransaction, f: F) -> Result<T>
88    where
89        F: FnOnce(&S, &TransactionMut<'_>) -> Result<T>,
90    {
91        match YTransaction::from_implicit(txn)? {
92            Some(txn) => {
93                let txn: &TransactionMut = &*txn;
94                let shared_ref = self.resolve(txn)?;
95                f(&shared_ref, txn)
96            }
97            None => {
98                let txn = self.transact_mut()?;
99                let shared_ref = self.resolve(&txn)?;
100                f(&shared_ref, &txn)
101            }
102        }
103    }
104
105    pub fn mutably<F, T>(&self, mut txn: ImplicitTransaction, f: F) -> Result<T>
106    where
107        F: FnOnce(&S, &mut TransactionMut<'_>) -> Result<T>,
108    {
109        match YTransaction::from_implicit_mut(&mut txn)? {
110            Some(mut txn) => {
111                let txn = txn.as_mut()?;
112                let shared_ref = self.resolve(txn)?;
113                f(&shared_ref, txn)
114            }
115            None => {
116                let mut txn = self.transact_mut()?;
117                let shared_ref = self.resolve(&mut txn)?;
118                f(&shared_ref, &mut txn)
119            }
120        }
121    }
122
123    pub fn resolve<T: ReadTxn>(&self, txn: &T) -> Result<S> {
124        match self.hook.get(txn) {
125            Some(shared_ref) => Ok(shared_ref),
126            None => Err(JsValue::from_str(crate::js::errors::REF_DISPOSED)),
127        }
128    }
129
130    pub fn transact(&self) -> Result<Transaction> {
131        match self.doc.try_transact() {
132            Ok(tx) => Ok(tx),
133            Err(_) => Err(JsValue::from_str(crate::js::errors::ANOTHER_RW_TX)),
134        }
135    }
136
137    pub fn transact_mut(&self) -> Result<TransactionMut> {
138        match self.doc.try_transact_mut() {
139            Ok(tx) => Ok(tx),
140            Err(_) => Err(JsValue::from_str(crate::js::errors::ANOTHER_TX)),
141        }
142    }
143}