y-rb 0.6.0-x86_64-linux-gnu

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,175 @@
1
+ use crate::utils::{convert_yvalue_to_ruby_value, indifferent_hash_key};
2
+ use crate::yvalue::YValue;
3
+ use crate::YTransaction;
4
+ use magnus::block::Proc;
5
+ use magnus::{exception, Error, RArray, RHash, Symbol, Value};
6
+ use std::cell::RefCell;
7
+ use yrs::types::{EntryChange, Value as YrsValue};
8
+ use yrs::{Any, Map, MapRef, Observable};
9
+
10
+ #[magnus::wrap(class = "Y::Map")]
11
+ pub(crate) struct YMap(pub(crate) RefCell<MapRef>);
12
+
13
+ /// SAFETY: This is safe because we only access this data when the GVL is held.
14
+ unsafe impl Send for YMap {}
15
+
16
+ impl YMap {
17
+ pub(crate) fn ymap_clear(&self, transaction: &YTransaction) {
18
+ let mut tx = transaction.transaction();
19
+ let tx = tx.as_mut().unwrap();
20
+
21
+ self.0.borrow_mut().clear(tx)
22
+ }
23
+ pub(crate) fn ymap_contains(&self, transaction: &YTransaction, key: Value) -> bool {
24
+ let tx = transaction.transaction();
25
+ let tx = tx.as_ref().unwrap();
26
+
27
+ match indifferent_hash_key(key) {
28
+ None => false,
29
+ Some(k) => self.0.borrow().contains_key(tx, k.as_str()),
30
+ }
31
+ }
32
+
33
+ pub(crate) fn ymap_each(&self, transaction: &YTransaction, proc: Proc) {
34
+ let tx = transaction.transaction();
35
+ let tx = tx.as_ref().unwrap();
36
+ self.0.borrow().iter(tx).for_each(|(key, val)| {
37
+ let k = key.to_string();
38
+ let v = *convert_yvalue_to_ruby_value(val, tx).0.borrow();
39
+ proc.call::<(String, Value), Value>((k, v))
40
+ .expect("cannot iterate map");
41
+ })
42
+ }
43
+
44
+ pub(crate) fn ymap_get(&self, transaction: &YTransaction, key: Value) -> Option<Value> {
45
+ let tx = transaction.transaction();
46
+ let tx = tx.as_ref().unwrap();
47
+
48
+ indifferent_hash_key(key)
49
+ .map(|k| self.0.borrow().get(tx, k.as_str()))
50
+ .map(|v| v.unwrap_or(YrsValue::Any(Any::Undefined)))
51
+ .map(|v| *convert_yvalue_to_ruby_value(v, tx).0.borrow())
52
+ }
53
+ pub(crate) fn ymap_insert(
54
+ &self,
55
+ transaction: &YTransaction,
56
+ key: Value,
57
+ value: Value,
58
+ ) -> Result<(), Error> {
59
+ let mut tx = transaction.transaction();
60
+ let tx = tx.as_mut().unwrap();
61
+
62
+ match indifferent_hash_key(key) {
63
+ None => Err(Error::new(
64
+ exception::runtime_error(),
65
+ "invalid key type, make sure it is either of type Symbol or String",
66
+ )),
67
+ Some(k) => {
68
+ let v = Any::from(YValue::from(value));
69
+ self.0.borrow_mut().insert(tx, k, v);
70
+
71
+ Ok(())
72
+ }
73
+ }
74
+ }
75
+ pub(crate) fn ymap_observe(&self, block: Proc) -> u32 {
76
+ let change_inserted = Symbol::new("inserted").as_static();
77
+ let change_updated = Symbol::new("updated").as_static();
78
+ let change_removed = Symbol::new("removed").as_static();
79
+ self.0
80
+ .borrow_mut()
81
+ .observe(move |transaction, map_event| {
82
+ let delta = map_event.keys(transaction);
83
+ let changes = RArray::with_capacity(delta.len());
84
+
85
+ for (key, change) in delta {
86
+ match change {
87
+ EntryChange::Inserted(v) => {
88
+ let h = RHash::new();
89
+ h.aset(Symbol::new(key), *YValue::from(v.clone()).0.borrow())
90
+ .expect("cannot add change::inserted");
91
+
92
+ let payload = RHash::new();
93
+ payload
94
+ .aset(change_inserted, h)
95
+ .expect("cannot add change::inserted");
96
+
97
+ changes.push(payload).expect("cannot push changes::payload");
98
+ }
99
+ EntryChange::Updated(old, new) => {
100
+ let values = RArray::with_capacity(2);
101
+ values
102
+ .push(*YValue::from(old.clone()).0.borrow())
103
+ .expect("cannot push change::updated");
104
+ values
105
+ .push(*YValue::from(new.clone()).0.borrow())
106
+ .expect("cannot push change::updated");
107
+
108
+ let h = RHash::new();
109
+ h.aset(Symbol::new(key), values)
110
+ .expect("cannot push change::updated");
111
+
112
+ let payload = RHash::new();
113
+ payload
114
+ .aset(change_updated, h)
115
+ .expect("cannot push change::updated");
116
+
117
+ changes.push(payload).expect("cannot push changes::payload");
118
+ }
119
+ EntryChange::Removed(v) => {
120
+ let h = RHash::new();
121
+ h.aset(Symbol::new(key), *YValue::from(v.clone()).0.borrow())
122
+ .expect("cannot push change::removed");
123
+
124
+ let payload = RHash::new();
125
+ payload
126
+ .aset(change_removed, h)
127
+ .expect("cannot push change::removed");
128
+
129
+ changes.push(payload).expect("cannot push changes::payload");
130
+ }
131
+ }
132
+ }
133
+
134
+ block
135
+ .call::<(RArray,), Value>((changes,))
136
+ .expect("cannot call block");
137
+ })
138
+ .into()
139
+ }
140
+ pub(crate) fn ymap_remove(&self, transaction: &YTransaction, key: Value) -> Option<Value> {
141
+ let mut tx = transaction.transaction();
142
+ let tx = tx.as_mut().unwrap();
143
+
144
+ indifferent_hash_key(key)
145
+ .map(|k| self.0.borrow().remove(tx, k.as_str()))
146
+ .map(|v| v.unwrap_or(YrsValue::Any(Any::Undefined)))
147
+ .map(|v| *YValue::from(v).0.borrow())
148
+ }
149
+ pub(crate) fn ymap_size(&self, transaction: &YTransaction) -> u32 {
150
+ let tx = transaction.transaction();
151
+ let tx = tx.as_ref().unwrap();
152
+
153
+ self.0.borrow().len(tx)
154
+ }
155
+ pub(crate) fn ymap_to_h(&self, transaction: &YTransaction) -> RHash {
156
+ let tx = transaction.transaction();
157
+ let tx = tx.as_ref().unwrap();
158
+
159
+ RHash::from_iter(
160
+ self.0
161
+ .borrow()
162
+ .iter(tx)
163
+ .map(move |(k, v)| (k.to_string(), *YValue::from(v).0.borrow())),
164
+ )
165
+ }
166
+ pub(crate) fn ymap_unobserve(&self, subscription_id: u32) {
167
+ self.0.borrow_mut().unobserve(subscription_id);
168
+ }
169
+ }
170
+
171
+ impl From<MapRef> for YMap {
172
+ fn from(v: MapRef) -> Self {
173
+ YMap(RefCell::from(v))
174
+ }
175
+ }
@@ -0,0 +1,235 @@
1
+ use crate::yattrs::YAttrs;
2
+ use crate::ydiff::YDiff;
3
+ use crate::yvalue::YValue;
4
+ use crate::YTransaction;
5
+ use magnus::block::Proc;
6
+ use magnus::value::Qnil;
7
+ use magnus::RArray;
8
+ pub(crate) use magnus::{Error, IntoValue, RHash, Symbol, Value};
9
+ use std::cell::RefCell;
10
+ use yrs::types::text::YChange;
11
+ use yrs::types::Delta;
12
+ use yrs::{Any, GetString, Observable, Text, TextRef};
13
+
14
+ #[magnus::wrap(class = "Y::Text")]
15
+ pub(crate) struct YText(pub(crate) RefCell<TextRef>);
16
+
17
+ /// SAFETY: This is safe because we only access this data when the GVL is held.
18
+ unsafe impl Send for YText {}
19
+
20
+ impl YText {
21
+ pub(crate) fn ytext_diff(&self, transaction: &YTransaction) -> RArray {
22
+ let tx = transaction.transaction();
23
+ let tx = tx.as_ref().unwrap();
24
+
25
+ RArray::from_iter(
26
+ self.0
27
+ .borrow()
28
+ .diff(tx, YChange::identity)
29
+ .iter()
30
+ .map(move |diff| {
31
+ let yvalue = YValue::from(diff.insert.clone());
32
+ let insert = yvalue.0.into_inner();
33
+ let attributes = diff.attributes.as_ref().map_or_else(
34
+ || None,
35
+ |boxed_attrs| {
36
+ let attributes = RHash::new();
37
+ for (key, value) in boxed_attrs.iter() {
38
+ let key = key.to_string();
39
+ let value = YValue::from(value.clone()).0.into_inner();
40
+ attributes.aset(key, value).expect("cannot add value");
41
+ }
42
+ Some(attributes)
43
+ },
44
+ );
45
+ YDiff {
46
+ ydiff_insert: insert,
47
+ ydiff_attrs: attributes,
48
+ }
49
+ .into_value()
50
+ }),
51
+ )
52
+ }
53
+ pub(crate) fn ytext_format(
54
+ &self,
55
+ transaction: &YTransaction,
56
+ index: u32,
57
+ length: u32,
58
+ attrs: RHash,
59
+ ) {
60
+ let mut tx = transaction.transaction();
61
+ let tx = tx.as_mut().unwrap();
62
+
63
+ let a = YAttrs::from(attrs);
64
+
65
+ self.0
66
+ .borrow_mut()
67
+ .format(tx, index, length, a.0.into_inner())
68
+ }
69
+ pub(crate) fn ytext_insert(&self, transaction: &YTransaction, index: u32, chunk: String) {
70
+ let mut tx = transaction.transaction();
71
+ let tx = tx.as_mut().unwrap();
72
+
73
+ self.0.borrow_mut().insert(tx, index, chunk.as_str())
74
+ }
75
+ pub(crate) fn ytext_insert_embed(
76
+ &self,
77
+ transaction: &YTransaction,
78
+ index: u32,
79
+ content: Value,
80
+ ) {
81
+ let mut tx = transaction.transaction();
82
+ let tx = tx.as_mut().unwrap();
83
+
84
+ let yvalue = YValue::from(content);
85
+ let avalue = Any::from(yvalue);
86
+
87
+ self.0.borrow_mut().insert_embed(tx, index, avalue);
88
+ }
89
+ pub(crate) fn ytext_insert_embed_with_attributes(
90
+ &self,
91
+ transaction: &YTransaction,
92
+ index: u32,
93
+ embed: Value,
94
+ attrs: RHash,
95
+ ) {
96
+ let mut tx = transaction.transaction();
97
+ let tx = tx.as_mut().unwrap();
98
+
99
+ let yvalue = YValue::from(embed);
100
+ let avalue = Any::from(yvalue);
101
+
102
+ let a = YAttrs::from(attrs);
103
+
104
+ self.0
105
+ .borrow_mut()
106
+ .insert_embed_with_attributes(tx, index, avalue, a.0.into_inner());
107
+ }
108
+ pub(crate) fn ytext_insert_with_attributes(
109
+ &self,
110
+ transaction: &YTransaction,
111
+ index: u32,
112
+ chunk: String,
113
+ attrs: RHash,
114
+ ) {
115
+ let mut tx = transaction.transaction();
116
+ let tx = tx.as_mut().unwrap();
117
+
118
+ let a = YAttrs::from(attrs);
119
+
120
+ self.0
121
+ .borrow_mut()
122
+ .insert_with_attributes(tx, index, chunk.as_str(), a.0.into_inner())
123
+ }
124
+ pub(crate) fn ytext_length(&self, transaction: &YTransaction) -> u32 {
125
+ let tx = transaction.transaction();
126
+ let tx = tx.as_ref().unwrap();
127
+
128
+ self.0.borrow().len(tx)
129
+ }
130
+ pub(crate) fn ytext_observe(&self, block: Proc) -> Result<u32, Error> {
131
+ let delta_insert = Symbol::new("insert").to_static();
132
+ let delta_retain = Symbol::new("retain").to_static();
133
+ let delta_delete = Symbol::new("delete").to_static();
134
+ let attributes = Symbol::new("attributes").to_static();
135
+
136
+ // let mut error: Option<Error> = None;
137
+ let subscription_id = self
138
+ .0
139
+ .borrow_mut()
140
+ .observe(move |transaction, text_event| {
141
+ let delta = text_event.delta(transaction);
142
+ let (_, errors): (Vec<_>, Vec<_>) = delta
143
+ .iter()
144
+ .map(|change| match change {
145
+ Delta::Inserted(value, attrs) => {
146
+ let yvalue = YValue::from(value.clone());
147
+ let payload = RHash::new();
148
+ payload
149
+ .aset(delta_insert, yvalue.0.into_inner())
150
+ .map(|()| match attrs {
151
+ Some(a) => a
152
+ .clone()
153
+ .into_iter()
154
+ .map(|(key, val)| {
155
+ let yvalue = YValue::from(val);
156
+ (key.to_string(), yvalue.0.into_inner())
157
+ })
158
+ .collect::<RHash>()
159
+ .into(),
160
+ None => None,
161
+ })
162
+ .map(|attrs_hash| attrs_hash.map(|v| payload.aset(attributes, v)))
163
+ .map(|_| block.call::<(RHash,), Qnil>((payload,)))
164
+ }
165
+ Delta::Retain(index, attrs) => {
166
+ let payload = RHash::new();
167
+
168
+ let yvalue = YValue::from(*index);
169
+
170
+ payload
171
+ .aset(delta_retain, yvalue.0.into_inner())
172
+ .map(|()| match attrs {
173
+ Some(a) => a
174
+ .clone()
175
+ .into_iter()
176
+ .map(|(key, val)| {
177
+ let yvalue = YValue::from(val);
178
+ (key.to_string(), yvalue.0.into_inner())
179
+ })
180
+ .collect::<RHash>()
181
+ .into(),
182
+ None => None,
183
+ })
184
+ .map(|attrs_hash| attrs_hash.map(|v| payload.aset(attributes, v)))
185
+ .map(|_| block.call::<(RHash,), Qnil>((payload,)))
186
+ }
187
+ Delta::Deleted(index) => {
188
+ let payload = RHash::new();
189
+
190
+ let yvalue = YValue::from(*index);
191
+
192
+ payload
193
+ .aset(delta_delete, yvalue.0.into_inner())
194
+ .map(|()| block.call::<(RHash,), Qnil>((payload,)))
195
+ }
196
+ })
197
+ .partition(Result::is_ok);
198
+
199
+ if !errors.is_empty() {
200
+ // todo: make sure we respect errors and let the method fail by
201
+ // by returning a Result containing an Error
202
+ }
203
+ })
204
+ .into();
205
+
206
+ Ok(subscription_id)
207
+ }
208
+ pub(crate) fn ytext_push(&self, transaction: &YTransaction, chunk: String) {
209
+ let mut tx = transaction.transaction();
210
+ let tx = tx.as_mut().unwrap();
211
+
212
+ self.0.borrow_mut().push(tx, chunk.as_str())
213
+ }
214
+ pub(crate) fn ytext_remove_range(&self, transaction: &YTransaction, start: u32, length: u32) {
215
+ let mut tx = transaction.transaction();
216
+ let tx = tx.as_mut().unwrap();
217
+
218
+ self.0.borrow_mut().remove_range(tx, start, length)
219
+ }
220
+ pub(crate) fn ytext_to_s(&self, transaction: &YTransaction) -> String {
221
+ let mut tx = transaction.transaction();
222
+ let tx = tx.as_mut().unwrap();
223
+
224
+ self.0.borrow().get_string(tx)
225
+ }
226
+ pub(crate) fn ytext_unobserve(&self, subscription_id: u32) {
227
+ self.0.borrow_mut().unobserve(subscription_id);
228
+ }
229
+ }
230
+
231
+ impl From<TextRef> for YText {
232
+ fn from(v: TextRef) -> Self {
233
+ YText(RefCell::from(v))
234
+ }
235
+ }
@@ -0,0 +1,127 @@
1
+ use crate::yarray::YArray;
2
+ use crate::ymap::YMap;
3
+ use crate::ytext::YText;
4
+ use crate::yxml_element::YXmlElement;
5
+ use crate::yxml_fragment::YXmlFragment;
6
+ use crate::yxml_text::YXmlText;
7
+ use magnus::{exception, Error};
8
+ use std::cell::{RefCell, RefMut};
9
+ use yrs::updates::decoder::Decode;
10
+ use yrs::updates::encoder::Encode;
11
+ use yrs::{ReadTxn, TransactionMut, Update};
12
+
13
+ #[magnus::wrap(class = "Y::Transaction")]
14
+ pub(crate) struct YTransaction(pub(crate) RefCell<Option<TransactionMut<'static>>>);
15
+
16
+ /// SAFETY: This is safe because we only access this data when the GVL is held.
17
+ unsafe impl Send for YTransaction {}
18
+
19
+ impl YTransaction {}
20
+
21
+ impl<'doc> From<TransactionMut<'doc>> for YTransaction {
22
+ fn from(txn: TransactionMut<'doc>) -> Self {
23
+ let txn: TransactionMut<'static> = unsafe { std::mem::transmute(txn) };
24
+ YTransaction(RefCell::from(Some(txn)))
25
+ }
26
+ }
27
+
28
+ // API which is eventually publicly exposed
29
+ impl YTransaction {
30
+ pub(crate) fn ytransaction_apply_update(&self, update: Vec<u8>) -> Result<(), Error> {
31
+ Update::decode_v1(update.as_slice())
32
+ .map_err(|error| {
33
+ Error::new(
34
+ exception::runtime_error(),
35
+ format!("cannot decode update: {:?}", error),
36
+ )
37
+ })
38
+ .map(|u| self.transaction().as_mut().unwrap().apply_update(u))
39
+ }
40
+
41
+ pub(crate) fn ytransaction_apply_update_v2(&self, update: Vec<u8>) -> Result<(), Error> {
42
+ Update::decode_v2(update.as_slice())
43
+ .map_err(|error| {
44
+ Error::new(
45
+ exception::runtime_error(),
46
+ format!("cannot decode update: {:?}", error),
47
+ )
48
+ })
49
+ .map(|u| self.transaction().as_mut().unwrap().apply_update(u))
50
+ }
51
+
52
+ pub(crate) fn ytransaction_commit(&self) {
53
+ self.transaction().as_mut().unwrap().commit();
54
+ }
55
+
56
+ pub(crate) fn ytransaction_get_array(&self, name: String) -> Option<YArray> {
57
+ self.transaction()
58
+ .as_ref()
59
+ .unwrap()
60
+ .get_array(name.as_str())
61
+ .map(YArray::from)
62
+ }
63
+
64
+ pub(crate) fn ytransaction_get_map(&self, name: String) -> Option<YMap> {
65
+ self.transaction()
66
+ .as_ref()
67
+ .unwrap()
68
+ .get_map(name.as_str())
69
+ .map(YMap::from)
70
+ }
71
+
72
+ pub(crate) fn ytransaction_get_text(&self, name: String) -> Option<YText> {
73
+ self.transaction()
74
+ .as_ref()
75
+ .unwrap()
76
+ .get_text(name.as_str())
77
+ .map(YText::from)
78
+ }
79
+
80
+ pub(crate) fn ytransaction_get_xml_element(&self, name: String) -> Option<YXmlElement> {
81
+ self.transaction()
82
+ .as_ref()
83
+ .unwrap()
84
+ .get_xml_element(name.as_str())
85
+ .map(YXmlElement::from)
86
+ }
87
+
88
+ pub(crate) fn ytransaction_get_xml_fragment(&self, name: String) -> Option<YXmlFragment> {
89
+ self.transaction()
90
+ .as_ref()
91
+ .unwrap()
92
+ .get_xml_fragment(name.as_str())
93
+ .map(YXmlFragment::from)
94
+ }
95
+
96
+ pub(crate) fn ytransaction_get_xml_text(&self, name: String) -> Option<YXmlText> {
97
+ self.transaction()
98
+ .as_ref()
99
+ .unwrap()
100
+ .get_xml_text(name.as_str())
101
+ .map(YXmlText::from)
102
+ }
103
+
104
+ pub(crate) fn ytransaction_state_vector(&self) -> Vec<u8> {
105
+ self.transaction()
106
+ .as_ref()
107
+ .unwrap()
108
+ .state_vector()
109
+ .encode_v1()
110
+ }
111
+
112
+ pub(crate) fn ytransaction_state_vector_v2(&self) -> Vec<u8> {
113
+ self.transaction()
114
+ .as_ref()
115
+ .unwrap()
116
+ .state_vector()
117
+ .encode_v2()
118
+ }
119
+
120
+ pub(crate) fn ytransaction_free(&self) {
121
+ self.0.replace(None);
122
+ }
123
+
124
+ pub(crate) fn transaction(&self) -> RefMut<'_, Option<TransactionMut<'static>>> {
125
+ self.0.borrow_mut()
126
+ }
127
+ }