y-rb 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/y.rb ADDED
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Y
4
+ end
data/lib/y_rb.so ADDED
Binary file
data/src/lib.rs ADDED
@@ -0,0 +1,248 @@
1
+ mod util;
2
+ mod yarray;
3
+ mod ydoc;
4
+ mod ymap;
5
+ mod ytext;
6
+ mod ytransaction;
7
+ mod yxml;
8
+
9
+ #[macro_use]
10
+ extern crate rutie;
11
+
12
+ use rutie::{Module, Object};
13
+
14
+ module!(Y);
15
+
16
+ #[allow(non_snake_case)]
17
+ #[no_mangle]
18
+ pub extern "C" fn Init_yrb() {
19
+ Module::new("Y").define(|module| {
20
+ module.define_nested_class("Array", None).define(|klass| {
21
+ klass.def_private("yarray_each", yarray::yarray_each);
22
+ klass.def_private("yarray_get", yarray::yarray_get);
23
+ klass.def_private("yarray_insert", yarray::yarray_insert);
24
+ klass.def_private(
25
+ "yarray_insert_range",
26
+ yarray::yarray_insert_range,
27
+ );
28
+ klass.def_private("yarray_length", yarray::yarray_length);
29
+ klass.def_private("yarray_observe", yarray::yarray_observe);
30
+ klass.def_private("yarray_push_back", yarray::yarray_push_back);
31
+ klass.def_private("yarray_push_front", yarray::yarray_push_front);
32
+ klass.def_private("yarray_remove", yarray::yarray_remove);
33
+ klass.def_private(
34
+ "yarray_remove_range",
35
+ yarray::yarray_remove_range,
36
+ );
37
+ klass.def_private("yarray_to_a", yarray::yarray_to_a);
38
+ klass.def_private("yarray_unobserve", yarray::yarray_unobserve);
39
+ });
40
+
41
+ module.define_nested_class("Doc", None).define(|klass| {
42
+ klass.def_self("new", ydoc::ydoc_new);
43
+ klass.def_private("ydoc_transact", ydoc::ydoc_transact);
44
+ klass.def_private("ydoc_encode_diff_v1", ydoc::ydoc_encode_diff_v1);
45
+ });
46
+
47
+ module.define_nested_class("Map", None).define(|klass| {
48
+ klass.def_private("ymap_clear", ymap::ymap_clear);
49
+ klass.def_private("ymap_contains", ymap::ymap_contains);
50
+ klass.def_private("ymap_each", ymap::ymap_each);
51
+ klass.def_private("ymap_get", ymap::ymap_get);
52
+ klass.def_private("ymap_insert", ymap::ymap_insert);
53
+ klass.def_private("ymap_observe", ymap::ymap_observe);
54
+ klass.def_private("ymap_remove", ymap::ymap_remove);
55
+ klass.def_private("ymap_size", ymap::ymap_size);
56
+ klass.def_private("ymap_to_h", ymap::ymap_to_hash);
57
+ klass.def_private("ymap_unobserve", ymap::ymap_unobserve);
58
+ });
59
+
60
+ module
61
+ .define_nested_class("SubscriptionID", None)
62
+ .define(|_klass| {});
63
+
64
+ module.define_nested_class("Text", None).define(|klass| {
65
+ klass.def_private("ytext_insert", ytext::ytext_insert);
66
+ klass.def_private("ytext_insert_embed", ytext::ytext_insert_embed);
67
+ klass.def_private(
68
+ "ytext_insert_embed_with_attrs",
69
+ ytext::ytext_insert_embed_with_attributes,
70
+ );
71
+ klass.def_private(
72
+ "ytext_insert_with_attrs",
73
+ ytext::ytext_insert_with_attributes,
74
+ );
75
+ klass.def_private("ytext_remove_range", ytext::ytext_remove_range);
76
+ klass.def_private("ytext_format", ytext::ytext_format);
77
+ klass.def_private("ytext_length", ytext::ytext_length);
78
+ klass.def_private("ytext_observe", ytext::ytext_observe);
79
+ klass.def_private("ytext_push", ytext::ytext_push);
80
+ klass.def_private("ytext_to_s", ytext::ytext_to_string);
81
+ klass.def_private("ytext_unobserve", ytext::ytext_unobserve);
82
+ });
83
+
84
+ module
85
+ .define_nested_class("Transaction", None)
86
+ .define(|klass| {
87
+ klass.def_private(
88
+ "ytransaction_apply_update",
89
+ ytransaction::ytransaction_apply_update,
90
+ );
91
+ klass.def_private(
92
+ "ytransaction_commit",
93
+ ytransaction::ytransaction_commit,
94
+ );
95
+ klass.def_private(
96
+ "ytransaction_get_array",
97
+ ytransaction::ytransaction_get_array,
98
+ );
99
+ klass.def_private(
100
+ "ytransaction_get_map",
101
+ ytransaction::ytransaction_get_map,
102
+ );
103
+ klass.def_private(
104
+ "ytransaction_get_text",
105
+ ytransaction::ytransaction_get_text,
106
+ );
107
+ klass.def_private(
108
+ "ytransaction_get_xml_element",
109
+ ytransaction::ytransaction_get_xml_element,
110
+ );
111
+ klass.def_private(
112
+ "ytransaction_get_xml_text",
113
+ ytransaction::ytransaction_get_xml_text,
114
+ );
115
+ klass.def_private(
116
+ "ytransaction_state_vector",
117
+ ytransaction::ytransaction_state_vector,
118
+ );
119
+ });
120
+
121
+ module
122
+ .define_nested_class("XMLElement", None)
123
+ .define(|klass| {
124
+ klass.def_private(
125
+ "yxml_element_attributes",
126
+ yxml::yxml_element_attributes,
127
+ );
128
+ klass.def_private(
129
+ "yxml_element_first_child",
130
+ yxml::yxml_element_first_child,
131
+ );
132
+ klass.def_private("yxml_element_get", yxml::yxml_element_get);
133
+ klass.def_private(
134
+ "yxml_element_get_attribute",
135
+ yxml::yxml_element_get_attribute,
136
+ );
137
+ klass.def_private(
138
+ "yxml_element_insert_attribute",
139
+ yxml::yxml_element_insert_attribute,
140
+ );
141
+ klass.def_private(
142
+ "yxml_element_insert_element",
143
+ yxml::yxml_element_insert_element,
144
+ );
145
+ klass.def_private(
146
+ "yxml_element_insert_text",
147
+ yxml::yxml_element_insert_text,
148
+ );
149
+ klass.def_private(
150
+ "yxml_element_next_sibling",
151
+ yxml::yxml_element_next_sibling,
152
+ );
153
+ klass.def_private(
154
+ "yxml_element_observe",
155
+ yxml::yxml_element_observe,
156
+ );
157
+ klass.def_private(
158
+ "yxml_element_parent",
159
+ yxml::yxml_element_parent,
160
+ );
161
+ klass.def_private(
162
+ "yxml_element_prev_sibling",
163
+ yxml::yxml_element_prev_sibling,
164
+ );
165
+ klass.def_private(
166
+ "yxml_element_push_elem_back",
167
+ yxml::yxml_element_push_elem_back,
168
+ );
169
+ klass.def_private(
170
+ "yxml_element_push_elem_front",
171
+ yxml::yxml_element_push_elem_front,
172
+ );
173
+ klass.def_private(
174
+ "yxml_element_push_text_back",
175
+ yxml::yxml_element_push_text_back,
176
+ );
177
+ klass.def_private(
178
+ "yxml_element_push_text_front",
179
+ yxml::yxml_element_push_text_front,
180
+ );
181
+ klass.def_private(
182
+ "yxml_element_remove_attribute",
183
+ yxml::yxml_element_remove_attribute,
184
+ );
185
+ klass.def_private(
186
+ "yxml_element_remove_range",
187
+ yxml::yxml_element_remove_range,
188
+ );
189
+ klass.def_private("yxml_element_size", yxml::yxml_element_size);
190
+ klass.def_private("yxml_element_tag", yxml::yxml_element_tag);
191
+ klass.def_private(
192
+ "yxml_element_to_s",
193
+ yxml::yxml_element_to_string,
194
+ );
195
+ klass.def_private(
196
+ "yxml_element_unobserve",
197
+ yxml::yxml_element_unobserve,
198
+ );
199
+ });
200
+
201
+ module.define_nested_class("XMLText", None).define(|klass| {
202
+ klass.def_private(
203
+ "yxml_text_attributes",
204
+ yxml::yxml_text_attributes,
205
+ );
206
+ klass.def_private("yxml_text_format", yxml::yxml_text_format);
207
+ klass.def_private(
208
+ "yxml_text_get_attribute",
209
+ yxml::yxml_text_get_attribute,
210
+ );
211
+ klass.def_private("yxml_text_insert", yxml::yxml_text_insert);
212
+ klass.def_private(
213
+ "yxml_text_insert_attribute",
214
+ yxml::yxml_text_insert_attribute,
215
+ );
216
+ klass.def_private(
217
+ "yxml_text_insert_embed",
218
+ yxml::yxml_text_insert_embed,
219
+ );
220
+ klass.def_private(
221
+ "yxml_text_insert_embed_with_attrs",
222
+ yxml::yxml_text_insert_embed_with_attributes,
223
+ );
224
+ klass.def_private(
225
+ "yxml_text_insert_with_attrs",
226
+ yxml::yxml_text_insert_with_attributes,
227
+ );
228
+ klass.def_private("yxml_text_length", yxml::yxml_text_length);
229
+ klass.def_private(
230
+ "yxml_text_next_sibling",
231
+ yxml::yxml_text_next_sibling,
232
+ );
233
+ klass.def_private("yxml_text_observe", yxml::yxml_text_observe);
234
+ klass.def_private("yxml_text_parent", yxml::yxml_text_parent);
235
+ klass.def_private(
236
+ "yxml_text_prev_sibling",
237
+ yxml::yxml_text_prev_sibling,
238
+ );
239
+ klass.def_private("yxml_text_push", yxml::yxml_text_push);
240
+ klass.def_private(
241
+ "yxml_text_remove_range",
242
+ yxml::yxml_text_remove_range,
243
+ );
244
+ klass.def_private("yxml_text_to_s", yxml::yxml_text_to_string);
245
+ klass.def_private("yxml_text_unobserve", yxml::yxml_text_unobserve);
246
+ });
247
+ });
248
+ }
data/src/util.rs ADDED
@@ -0,0 +1,148 @@
1
+ use crate::ymap::MAP_WRAPPER;
2
+ use crate::ytext::TEXT_WRAPPER;
3
+ use crate::yxml::{XML_ELEMENT_WRAPPER, XML_TEXT_WRAPPER};
4
+ use lib0::any::Any;
5
+ use rutie::{
6
+ AnyException, AnyObject, Array, Boolean, Exception, Fixnum, Float, Hash,
7
+ Integer, Module, NilClass, Object, RString, Symbol,
8
+ };
9
+ use std::borrow::Borrow;
10
+ use std::collections::HashMap;
11
+ use std::convert::TryFrom;
12
+ use std::rc::Rc;
13
+ use yrs::types::{Attrs, Value};
14
+
15
+ pub(crate) fn convert_vecu8_to_array(vec: Vec<u8>) -> Array {
16
+ let mut array = Array::new();
17
+
18
+ for i in vec {
19
+ array.push(Fixnum::new(i64::from(i)));
20
+ }
21
+
22
+ array
23
+ }
24
+
25
+ pub(crate) fn convert_array_to_vecu8(arr: Array) -> Vec<u8> {
26
+ arr.into_iter()
27
+ .map(|val| val.try_convert_to::<Fixnum>().unwrap().to_u32())
28
+ .map(|val| u8::try_from(val).unwrap())
29
+ .collect()
30
+ }
31
+
32
+ pub(crate) fn map_any_type_to_ruby(input: &Any) -> AnyObject {
33
+ match input {
34
+ Any::Null => NilClass::new().to_any_object(),
35
+ Any::Undefined => NilClass::new().to_any_object(),
36
+ Any::Bool(b) => Boolean::new(*b).to_any_object(),
37
+ Any::Number(f) => Float::new(*f).to_any_object(),
38
+ Any::BigInt(i) => Integer::new(*i).to_any_object(),
39
+ Any::String(s) => RString::new_utf8(s.as_ref()).to_any_object(),
40
+ // TODO convert buffer into an array of Fixnum
41
+ Any::Buffer(_b) => Array::new().to_any_object(),
42
+ Any::Array(a) => {
43
+ let values = a.iter().map(|n| map_any_type_to_ruby(n));
44
+ Array::from_iter(values).to_any_object()
45
+ }
46
+ Any::Map(m) => {
47
+ let mut h = Hash::new();
48
+ m.iter().for_each(|(k, v)| {
49
+ let key = Symbol::new(k.as_ref());
50
+ let val = map_any_type_to_ruby(v);
51
+ h.store(key, val);
52
+ ()
53
+ });
54
+ h.to_any_object()
55
+ }
56
+ }
57
+ }
58
+
59
+ // This function gets reported as unused.
60
+ pub(crate) fn map_yrs_value_to_ruby(value: Value) -> AnyObject {
61
+ match value {
62
+ Value::Any(v) => map_any_type_to_ruby(v.borrow()),
63
+ Value::YArray(a) => {
64
+ let values = a.iter().map(|n| map_yrs_value_to_ruby(n));
65
+ Array::from_iter(values).to_any_object()
66
+ }
67
+ Value::YMap(m) => Module::from_existing("Y")
68
+ .get_nested_class("Text")
69
+ .wrap_data(m, &*MAP_WRAPPER),
70
+ Value::YText(t) => Module::from_existing("Y")
71
+ .get_nested_class("Text")
72
+ .wrap_data(t, &*TEXT_WRAPPER),
73
+ Value::YXmlElement(x) => Module::from_existing("Y")
74
+ .get_nested_class("XMLElement")
75
+ .wrap_data(x, &*XML_ELEMENT_WRAPPER),
76
+ Value::YXmlText(x) => Module::from_existing("Y")
77
+ .get_nested_class("XMLText")
78
+ .wrap_data(x, &*XML_TEXT_WRAPPER),
79
+ }
80
+ }
81
+
82
+ pub(crate) fn map_ruby_type_to_rust(
83
+ input: AnyObject,
84
+ ) -> Result<Any, AnyException> {
85
+ if let Ok(_v) = input.try_convert_to::<NilClass>() {
86
+ return Ok(Any::Null);
87
+ } else if let Ok(v) = input.try_convert_to::<Boolean>() {
88
+ return Ok(Any::Bool(v.to_bool()));
89
+ } else if let Ok(v) = input.try_convert_to::<Float>() {
90
+ return Ok(Any::Number(v.to_f64()));
91
+ } else if let Ok(v) = input.try_convert_to::<Fixnum>() {
92
+ return Ok(Any::BigInt(v.to_i64()));
93
+ } else if let Ok(v) = input.try_convert_to::<Integer>() {
94
+ return Ok(Any::BigInt(v.to_i64()));
95
+ } else if let Ok(v) = input.try_convert_to::<RString>() {
96
+ return Ok(Any::String(Box::from(v.to_str())));
97
+ } else if let Ok(v) = input.try_convert_to::<Array>() {
98
+ let arr: Vec<Any> = v
99
+ .into_iter()
100
+ .map(|value| map_ruby_type_to_rust(value).unwrap())
101
+ .collect();
102
+ return Ok(Any::Array(arr.into_boxed_slice()));
103
+ } else if let Ok(v) = input.try_convert_to::<Hash>() {
104
+ let m = map_hash_to_rust(v);
105
+ return Ok(Any::Map(Box::from(m)));
106
+ }
107
+
108
+ Err(AnyException::new(
109
+ "TypeError",
110
+ Some("cannot map input type"),
111
+ ))
112
+ }
113
+
114
+ // This function gets reported as unused.
115
+ pub(crate) fn map_hash_to_rust(input: Hash) -> HashMap<String, Any> {
116
+ let mut m = HashMap::with_capacity(input.length());
117
+ input.each(|key, value| {
118
+ if let Ok(v) = map_ruby_type_to_rust(value) {
119
+ if let Ok(k) = key.try_convert_to::<RString>() {
120
+ m.insert(k.to_string(), v);
121
+ } else if let Ok(k) = key.try_convert_to::<Symbol>() {
122
+ m.insert(k.to_string(), v);
123
+ }
124
+ }
125
+ });
126
+ m
127
+ }
128
+
129
+ pub(crate) fn map_hash_to_attrs(input: Hash) -> Attrs {
130
+ let attributes = map_hash_to_rust(input);
131
+ let mut attrs = Attrs::with_capacity(attributes.len());
132
+ for (k, v) in attributes {
133
+ attrs.insert(Rc::from(k), v);
134
+ }
135
+ attrs
136
+ }
137
+
138
+ pub(crate) fn map_attrs_to_hash(attrs: Attrs) -> Hash {
139
+ let mut h = Hash::new();
140
+
141
+ for (key, val) in attrs {
142
+ let key = Symbol::new(key.as_ref());
143
+ let value = map_any_type_to_ruby(val.borrow());
144
+ h.store(key, value);
145
+ }
146
+
147
+ h
148
+ }
data/src/yarray.rs ADDED
@@ -0,0 +1,184 @@
1
+ use crate::util::{map_ruby_type_to_rust, map_yrs_value_to_ruby};
2
+ use crate::ytransaction::{YTransaction, TRANSACTION_WRAPPER};
3
+ use rutie::{
4
+ AnyObject, Array as RArray, Fixnum, Hash, Integer, NilClass, Object, Proc,
5
+ Symbol, VM,
6
+ };
7
+ use yrs::types::{Change, Value};
8
+ use yrs::{Array, SubscriptionId};
9
+
10
+ wrappable_struct!(Array, ArrayWrapper, ARRAY_WRAPPER);
11
+ class!(YArray);
12
+
13
+ #[rustfmt::skip]
14
+ methods!(
15
+ YArray,
16
+ rtself,
17
+ fn yarray_each(block: Proc) -> NilClass {
18
+ let b = block.map_err(|e| VM::raise_ex(e)).unwrap();
19
+
20
+ let a: &Array = rtself.get_data(&*ARRAY_WRAPPER);
21
+
22
+ a
23
+ .iter()
24
+ .for_each(|val| {
25
+ let args = [map_yrs_value_to_ruby(val)];
26
+ b.call(&args);
27
+ });
28
+
29
+ NilClass::new()
30
+ },
31
+ fn yarray_get(index: Fixnum) -> AnyObject {
32
+ let i = index.map_err(|e| VM::raise_ex(e)).unwrap();
33
+
34
+ let arr: &Array = rtself.get_data(&*ARRAY_WRAPPER);
35
+ let val = arr.get(i.to_u32());
36
+
37
+ map_yrs_value_to_ruby(val.unwrap())
38
+ },
39
+ fn yarray_insert(
40
+ transaction: YTransaction,
41
+ index: Fixnum,
42
+ value: AnyObject) -> NilClass {
43
+ let mut txn = transaction.map_err(|e| VM::raise_ex(e)).unwrap();
44
+ let tx = txn.get_data_mut(&*TRANSACTION_WRAPPER);
45
+
46
+ let i = index.map_err(|e| VM::raise_ex(e)).unwrap();
47
+
48
+ let val = value.map_err(|e| VM::raise_ex(e)).unwrap();
49
+ let v = map_ruby_type_to_rust(val).unwrap();
50
+
51
+ let arr: &Array = rtself.get_data(&*ARRAY_WRAPPER);
52
+ arr.insert(tx, i.to_u32(), v);
53
+
54
+ NilClass::new()
55
+ },
56
+ fn yarray_insert_range(
57
+ transaction: YTransaction,
58
+ index: Fixnum,
59
+ values: RArray) -> NilClass {
60
+ let mut txn = transaction.map_err(|e| VM::raise_ex(e)).unwrap();
61
+ let tx = txn.get_data_mut(&*TRANSACTION_WRAPPER);
62
+
63
+ let i = index.map_err(|e| VM::raise_ex(e)).unwrap();
64
+
65
+ let values = values.map_err(|e| VM::raise_ex(e)).unwrap();
66
+ let mapped_values = values
67
+ .into_iter()
68
+ .map(|value| map_ruby_type_to_rust(value).unwrap() )
69
+ .collect::<Vec<_>>();
70
+
71
+ let arr: &Array = rtself.get_data(&*ARRAY_WRAPPER);
72
+ arr.insert_range(tx, i.to_u32(), mapped_values);
73
+
74
+ NilClass::new()
75
+ },
76
+ fn yarray_length() -> Fixnum {
77
+ let arr: &Array = rtself.get_data(&*ARRAY_WRAPPER);
78
+ Fixnum::new(i64::from(arr.len()))
79
+ },
80
+ fn yarray_observe(callback: Proc) -> Integer {
81
+ let c = callback.map_err(|e| VM::raise_ex(e)).unwrap();
82
+
83
+ let arr: &mut Array = rtself.get_data_mut(&*ARRAY_WRAPPER);
84
+ let subscription_id: SubscriptionId = arr
85
+ .observe(move |transaction, array_event| {
86
+ let delta = array_event.delta(transaction);
87
+ let mut changes: Vec<AnyObject> = Vec::new();
88
+
89
+ for change in delta {
90
+ match change {
91
+ Change::Added(v) => {
92
+ let mut payload = Hash::new();
93
+ let values = v.iter().map(|v| map_yrs_value_to_ruby(v.clone()) ).collect::<Vec<_>>();
94
+ payload.store(Symbol::new("added"), RArray::from_iter(values));
95
+
96
+ changes.push(payload.to_any_object());
97
+ },
98
+ Change::Retain(position) => {
99
+ let mut payload = Hash::new();
100
+ payload.store(Symbol::new("retain"), Integer::from(*position));
101
+
102
+ changes.push(payload.to_any_object());
103
+ },
104
+ Change::Removed(position) => {
105
+ let mut payload = Hash::new();
106
+ payload.store(Symbol::new("removed"), Integer::from(*position));
107
+
108
+ changes.push(payload.to_any_object());
109
+ }
110
+ }
111
+ }
112
+
113
+ let args = &[RArray::from_iter(changes).to_any_object()];
114
+ c.call(args);
115
+ })
116
+ .into();
117
+
118
+ Integer::from(subscription_id)
119
+ },
120
+ fn yarray_push_back(transaction: YTransaction, value: AnyObject) -> NilClass {
121
+ let mut txn = transaction.map_err(|e| VM::raise_ex(e)).unwrap();
122
+ let tx = txn.get_data_mut(&*TRANSACTION_WRAPPER);
123
+
124
+ let val = value.map_err(|e| VM::raise_ex(e)).unwrap();
125
+ let v = map_ruby_type_to_rust(val).unwrap();
126
+
127
+ let arr: &Array = rtself.get_data(&*ARRAY_WRAPPER);
128
+ arr.push_back(tx, v);
129
+
130
+ NilClass::new()
131
+ },
132
+ fn yarray_push_front(transaction: YTransaction, value: AnyObject) -> NilClass {
133
+ let mut txn = transaction.map_err(|e| VM::raise_ex(e)).unwrap();
134
+ let tx = txn.get_data_mut(&*TRANSACTION_WRAPPER);
135
+
136
+ let val = value.map_err(|e| VM::raise_ex(e)).unwrap();
137
+ let v = map_ruby_type_to_rust(val).unwrap();
138
+
139
+ let arr: &Array = rtself.get_data(&*ARRAY_WRAPPER);
140
+ arr.push_front(tx, v);
141
+
142
+ NilClass::new()
143
+ },
144
+ fn yarray_remove(transaction: YTransaction, index: Fixnum) -> NilClass {
145
+ let mut txn = transaction.map_err(|e| VM::raise_ex(e)).unwrap();
146
+ let tx = txn.get_data_mut(&*TRANSACTION_WRAPPER);
147
+
148
+ let i = index.map_err(|e| VM::raise_ex(e)).unwrap();
149
+
150
+ let arr: &Array = rtself.get_data(&*ARRAY_WRAPPER);
151
+ arr.remove(tx, i.to_u32());
152
+
153
+ NilClass::new()
154
+ },
155
+ fn yarray_remove_range(
156
+ transaction: YTransaction,
157
+ index: Fixnum,
158
+ length: Fixnum) -> NilClass {
159
+ let mut txn = transaction.map_err(|e| VM::raise_ex(e)).unwrap();
160
+ let tx = txn.get_data_mut(&*TRANSACTION_WRAPPER);
161
+
162
+ let i = index.map_err(|e| VM::raise_ex(e)).unwrap();
163
+ let l = length.map_err(|e| VM::raise_ex(e)).unwrap();
164
+
165
+ let arr: &Array = rtself.get_data(&*ARRAY_WRAPPER);
166
+ arr.remove_range(tx, i.to_u32(), l.to_u32());
167
+
168
+ NilClass::new()
169
+ },
170
+ fn yarray_to_a() -> RArray {
171
+ let v: &Array = rtself.get_data(&*ARRAY_WRAPPER);
172
+ map_yrs_value_to_ruby(Value::YArray(v.clone()))
173
+ .try_convert_to::<RArray>()
174
+ .unwrap()
175
+ }
176
+ fn yarray_unobserve(subscription_id: Integer) -> NilClass {
177
+ let s = subscription_id.map_err(|e| VM::raise_ex(e)).unwrap();
178
+
179
+ let arr: &mut Array = rtself.get_data_mut(&*ARRAY_WRAPPER);
180
+ arr.unobserve(s.into());
181
+
182
+ NilClass::new()
183
+ }
184
+ );
data/src/ydoc.rs ADDED
@@ -0,0 +1,65 @@
1
+ use crate::util::{convert_array_to_vecu8, convert_vecu8_to_array};
2
+ use crate::ytransaction::TRANSACTION_WRAPPER;
3
+ use rutie::rubysys::class;
4
+ use rutie::types::{Argc, Value};
5
+ use rutie::util::str_to_cstring;
6
+ use rutie::{AnyObject, Array, Integer, Module, Object};
7
+ use std::mem;
8
+ use yrs::updates::decoder::Decode;
9
+ use yrs::{Doc, OffsetKind, Options, StateVector};
10
+
11
+ wrappable_struct!(Doc, DocWrapper, DOC_WRAPPER);
12
+ class!(YDoc);
13
+
14
+ methods!(
15
+ YDoc,
16
+ rtself,
17
+ fn ydoc_transact() -> AnyObject {
18
+ let doc = rtself.get_data(&*DOC_WRAPPER);
19
+ let transaction = doc.transact();
20
+
21
+ Module::from_existing("Y")
22
+ .get_nested_class("Transaction")
23
+ .wrap_data(transaction, &*TRANSACTION_WRAPPER)
24
+ },
25
+ fn ydoc_encode_diff_v1(state_vector: Array) -> Array {
26
+ let mut doc: &Doc = rtself.get_data_mut(&*DOC_WRAPPER);
27
+ let state_vector_encoded: Vec<u8> =
28
+ convert_array_to_vecu8(state_vector.unwrap());
29
+ let sv = &StateVector::decode_v1(state_vector_encoded.as_slice());
30
+
31
+ let update = doc.encode_state_as_update_v1(sv);
32
+
33
+ convert_vecu8_to_array(update)
34
+ }
35
+ );
36
+
37
+ pub extern "C" fn ydoc_new(
38
+ argc: Argc,
39
+ argv: *const AnyObject,
40
+ _rtself: AnyObject,
41
+ ) -> AnyObject {
42
+ let args = Value::from(0);
43
+
44
+ unsafe {
45
+ let p_argv: *const Value = mem::transmute(argv);
46
+
47
+ class::rb_scan_args(argc, p_argv, str_to_cstring("*").as_ptr(), &args)
48
+ };
49
+
50
+ let arguments = Array::from(args);
51
+ let client_id = arguments.at(0).try_convert_to::<Integer>();
52
+
53
+ let mut options = Options::default();
54
+ if let Ok(c_id) = client_id {
55
+ options.client_id = c_id.into();
56
+ };
57
+ // make sure we treat offsets for codepoints not bytes
58
+ options.offset_kind = OffsetKind::Utf32;
59
+
60
+ let doc = Doc::with_options(options);
61
+
62
+ Module::from_existing("Y")
63
+ .get_nested_class("Doc")
64
+ .wrap_data(doc, &*DOC_WRAPPER)
65
+ }