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,177 @@
1
+ use crate::utils::map_rhash_to_attrs;
2
+ use crate::yvalue::YValue;
3
+ use crate::yxml_fragment::YXmlFragment;
4
+ use crate::{YTransaction, YXmlElement};
5
+ use magnus::{Error, IntoValue, RHash, Value};
6
+ use std::cell::RefCell;
7
+ use yrs::{Any, GetString, Text, Xml, XmlNode, XmlTextRef};
8
+
9
+ #[magnus::wrap(class = "Y::XMLText")]
10
+ pub(crate) struct YXmlText(pub(crate) RefCell<XmlTextRef>);
11
+
12
+ /// SAFETY: This is safe because we only access this data when the GVL is held.
13
+ unsafe impl Send for YXmlText {}
14
+
15
+ impl YXmlText {
16
+ pub(crate) fn yxml_text_attributes(&self, transaction: &YTransaction) -> RHash {
17
+ let tx = transaction.transaction();
18
+ let tx = tx.as_ref().unwrap();
19
+
20
+ RHash::from_iter(self.0.borrow().attributes(tx))
21
+ }
22
+ pub(crate) fn yxml_text_format(
23
+ &self,
24
+ transaction: &YTransaction,
25
+ index: u32,
26
+ length: u32,
27
+ attrs: RHash,
28
+ ) -> Result<(), Error> {
29
+ let mut tx = transaction.transaction();
30
+ let tx = tx.as_mut().unwrap();
31
+
32
+ map_rhash_to_attrs(attrs).map(|a| self.0.borrow_mut().format(tx, index, length, a))
33
+ }
34
+ pub(crate) fn yxml_text_get_attribute(
35
+ &self,
36
+ transaction: &YTransaction,
37
+ name: String,
38
+ ) -> Option<String> {
39
+ let tx = transaction.transaction();
40
+ let tx = tx.as_ref().unwrap();
41
+
42
+ self.0.borrow().get_attribute(tx, name.as_str())
43
+ }
44
+ pub(crate) fn yxml_text_insert(&self, transaction: &YTransaction, index: u32, content: String) {
45
+ let mut tx = transaction.transaction();
46
+ let tx = tx.as_mut().unwrap();
47
+
48
+ self.0.borrow_mut().insert(tx, index, content.as_str())
49
+ }
50
+ pub(crate) fn yxml_text_insert_attribute(
51
+ &self,
52
+ transaction: &YTransaction,
53
+ name: String,
54
+ value: String,
55
+ ) {
56
+ let mut tx = transaction.transaction();
57
+ let tx = tx.as_mut().unwrap();
58
+
59
+ self.0.borrow_mut().insert_attribute(tx, name, value)
60
+ }
61
+ pub(crate) fn yxml_text_insert_embed_with_attributes(
62
+ &self,
63
+ transaction: &YTransaction,
64
+ index: u32,
65
+ content: Value,
66
+ attrs: RHash,
67
+ ) -> Result<(), Error> {
68
+ let mut tx = transaction.transaction();
69
+ let tx = tx.as_mut().unwrap();
70
+
71
+ let yvalue = YValue::from(content);
72
+ let avalue = Any::from(yvalue);
73
+
74
+ map_rhash_to_attrs(attrs)
75
+ .map(|a| {
76
+ self.0
77
+ .borrow_mut()
78
+ .insert_embed_with_attributes(tx, index, avalue, a)
79
+ })
80
+ .map(|_| ())
81
+ }
82
+ pub(crate) fn yxml_text_insert_embed(
83
+ &self,
84
+ transaction: &YTransaction,
85
+ index: u32,
86
+ embed: Value,
87
+ ) {
88
+ let mut tx = transaction.transaction();
89
+ let tx = tx.as_mut().unwrap();
90
+
91
+ self.0
92
+ .borrow_mut()
93
+ .insert_embed(tx, index, Any::from(YValue::from(embed)));
94
+ }
95
+ pub(crate) fn yxml_text_insert_with_attributes(
96
+ &self,
97
+ transaction: &YTransaction,
98
+ index: u32,
99
+ content: String,
100
+ attrs: RHash,
101
+ ) -> Result<(), Error> {
102
+ let mut tx = transaction.transaction();
103
+ let tx = tx.as_mut().unwrap();
104
+
105
+ map_rhash_to_attrs(attrs).map(|a| {
106
+ self.0
107
+ .borrow_mut()
108
+ .insert_with_attributes(tx, index, content.as_str(), a);
109
+ })
110
+ }
111
+ pub(crate) fn yxml_text_length(&self, transaction: &YTransaction) -> u32 {
112
+ let tx = transaction.transaction();
113
+ let tx = tx.as_ref().unwrap();
114
+
115
+ self.0.borrow().len(tx)
116
+ }
117
+ pub(crate) fn yxml_text_next_sibling(&self, transaction: &YTransaction) -> Option<Value> {
118
+ let tx = transaction.transaction();
119
+ let tx = tx.as_ref().unwrap();
120
+
121
+ self.0.borrow().siblings(tx).next().map(|item| match item {
122
+ XmlNode::Element(el) => YXmlElement(RefCell::from(el)).into_value(),
123
+ XmlNode::Fragment(fragment) => YXmlFragment(RefCell::from(fragment)).into_value(),
124
+ XmlNode::Text(text) => YXmlText(RefCell::from(text)).into_value(),
125
+ })
126
+ }
127
+ pub(crate) fn yxml_text_parent(&self) -> Option<Value> {
128
+ self.0.borrow().parent().map(|item| match item {
129
+ XmlNode::Element(el) => YXmlElement(RefCell::from(el)).into_value(),
130
+ XmlNode::Fragment(fragment) => YXmlFragment(RefCell::from(fragment)).into_value(),
131
+ XmlNode::Text(text) => YXmlText(RefCell::from(text)).into_value(),
132
+ })
133
+ }
134
+ pub(crate) fn yxml_text_prev_sibling(&self, transaction: &YTransaction) -> Option<Value> {
135
+ let tx = transaction.transaction();
136
+ let tx = tx.as_ref().unwrap();
137
+
138
+ self.0
139
+ .borrow()
140
+ .siblings(tx)
141
+ .next_back()
142
+ .map(|item| match item {
143
+ XmlNode::Element(el) => YXmlElement(RefCell::from(el)).into_value(),
144
+ XmlNode::Fragment(fragment) => YXmlFragment(RefCell::from(fragment)).into_value(),
145
+ XmlNode::Text(text) => YXmlText(RefCell::from(text)).into_value(),
146
+ })
147
+ }
148
+ pub(crate) fn yxml_text_push(&self, transaction: &YTransaction, content: String) {
149
+ let mut tx = transaction.transaction();
150
+ let tx = tx.as_mut().unwrap();
151
+
152
+ self.0.borrow_mut().push(tx, content.as_str())
153
+ }
154
+ pub(crate) fn yxml_text_remove_range(
155
+ &self,
156
+ transaction: &YTransaction,
157
+ index: u32,
158
+ length: u32,
159
+ ) {
160
+ let mut tx = transaction.transaction();
161
+ let tx = tx.as_mut().unwrap();
162
+
163
+ self.0.borrow_mut().remove_range(tx, index, length)
164
+ }
165
+ pub(crate) fn yxml_text_to_s(&self, transaction: &YTransaction) -> String {
166
+ let tx = transaction.transaction();
167
+ let tx = tx.as_ref().unwrap();
168
+
169
+ self.0.borrow().get_string(tx)
170
+ }
171
+ }
172
+
173
+ impl From<XmlTextRef> for YXmlText {
174
+ fn from(v: XmlTextRef) -> Self {
175
+ YXmlText(RefCell::from(v))
176
+ }
177
+ }
data/lib/3.1/yrb.so ADDED
Binary file
data/lib/3.2/yrb.so ADDED
Binary file
data/lib/3.3/yrb.so ADDED
Binary file
data/lib/3.4/yrb.so ADDED
Binary file
data/lib/y/array.rb ADDED
@@ -0,0 +1,371 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Y
4
+ # An array can be used to store and retrieve elements.
5
+ #
6
+ # The array is the replicated counterpart to a Ruby Array. It supports a
7
+ # subset of the Ruby Array operations, like adding, getting and deleting
8
+ # values by position or ranges.
9
+ #
10
+ # Someone should not instantiate an array directly, but use {Y::Doc#get_array}
11
+ # instead.
12
+ #
13
+ # @example
14
+ # doc = Y::Doc.new
15
+ # array = doc.get_array("my array")
16
+ #
17
+ # array << 1
18
+ # array.push(2)
19
+ # array.concat([3, 4, 5])
20
+ #
21
+ # array.to_a == [1, 2, 3, 4, 5] # true
22
+ class Array # rubocop:disable Metrics/ClassLength
23
+ include Enumerable
24
+
25
+ # @!attribute [r] document
26
+ #
27
+ # @return [Y::Doc] The document this array belongs to
28
+ attr_accessor :document
29
+
30
+ # Create a new array instance
31
+ #
32
+ # @param doc [Y::Doc]
33
+ def initialize(doc = nil)
34
+ @document = doc || Y::Doc.new
35
+
36
+ super()
37
+ end
38
+
39
+ # Retrieves element at position
40
+ #
41
+ # @return [true, false, Float, Integer, String, Array, Hash]
42
+ def [](index)
43
+ document.current_transaction { |tx| yarray_get(tx, index) }
44
+ end
45
+
46
+ # Inserts value at position
47
+ #
48
+ # @param index [Integer]
49
+ # @param value [true, false, Float, Integer, String, Array, Hash]
50
+ # @return [void]
51
+ def []=(index, value)
52
+ document.current_transaction { |tx| yarray_insert(tx, index, value) }
53
+ end
54
+
55
+ # Adds an element to the end of the array
56
+ #
57
+ # @param value [true, false, Float, Integer, String, ::Array, Hash]
58
+ # @return [void]
59
+ def <<(value, *values)
60
+ document.current_transaction do |tx|
61
+ yarray_push_back(tx, value)
62
+ values.each { |v| yarray_push_back(tx, v) }
63
+ end
64
+ end
65
+
66
+ # Attach listener to array changes
67
+ #
68
+ # @example Listen to changes in array type
69
+ # local = Y::Doc.new
70
+ #
71
+ # arr = local.get_array("my array")
72
+ # arr.attach { |delta| pp delta }
73
+ #
74
+ # local.transact do
75
+ # arr << 1
76
+ # end
77
+ #
78
+ # @param block [Block]
79
+ # @return [Integer]
80
+ def attach(&block)
81
+ raise "provide block" unless block
82
+
83
+ yarray_observe(block.to_proc)
84
+ end
85
+
86
+ # Adds to array all elements from each Array in `other_arrays`.
87
+ #
88
+ # If one of the arguments isn't an Array, it is silently ignored.
89
+ #
90
+ # @example Add multiple values to array
91
+ # doc = Y::Doc.new
92
+ # arr = doc.get_array("my array")
93
+ # arr.concat([1, 2, 3])
94
+ #
95
+ # arr.to_a == [1, 2, 3] # true
96
+ #
97
+ # @param other_arrays [Array<Array<Object>>]
98
+ # @return [void]
99
+ def concat(*other_arrays)
100
+ document.current_transaction do |tx|
101
+ combined = other_arrays.reduce([]) do |values, arr|
102
+ values.concat(arr) if arr.is_a?(::Array)
103
+ end
104
+
105
+ yarray_insert_range(tx, yarray_length(tx), combined)
106
+ end
107
+ end
108
+
109
+ # Detach listener
110
+ #
111
+ # @param subscription_id [Integer]
112
+ # @return [void]
113
+ def detach(subscription_id)
114
+ yarray_unobserve(subscription_id)
115
+ end
116
+
117
+ # @return [void]
118
+ def each(...)
119
+ document.current_transaction { |tx| yarray_each(tx, ...) }
120
+ end
121
+
122
+ # Check if the array is empty
123
+ #
124
+ # @return [true, false]
125
+ def empty?
126
+ size.zero?
127
+ end
128
+
129
+ # Returns first element in array if there is at least one
130
+ #
131
+ # @return [true, false, Float, Integer, String, ::Array, Hash, nil]
132
+ def first
133
+ document.current_transaction { |tx| yarray_get(tx, 0) }
134
+ end
135
+
136
+ # Returns last element in array if there is at least one element
137
+ #
138
+ # @return [true, false, Float, Integer, String, ::Array, Hash, nil]
139
+ def last
140
+ document.current_transaction do |tx|
141
+ len = yarray_length(tx)
142
+ return yarray_get(tx, len - 1) if len.positive?
143
+
144
+ nil
145
+ end
146
+ end
147
+
148
+ # rubocop:disable Naming/MethodParameterName
149
+
150
+ # Removes last (n) element(s) from array
151
+ #
152
+ # @param n [Integer, nil] Number of elements to remove
153
+ # @return [void]
154
+ def pop(n = nil)
155
+ document.current_transaction do |tx|
156
+ len = yarray_length(tx)
157
+ yarray_remove(tx, len - 1) if n.nil?
158
+ yarray_remove_range(tx, len - n, n) unless n.nil?
159
+ end
160
+ end
161
+
162
+ # rubocop:enable Naming/MethodParameterName
163
+
164
+ alias push <<
165
+
166
+ # rubocop:disable Naming/MethodParameterName
167
+
168
+ # Removes first (n) element(s) from array
169
+ #
170
+ # @param n [Integer, nil] Number of elements to remove
171
+ # @return [void]
172
+ def shift(n = nil)
173
+ document.current_transaction do |tx|
174
+ yarray_remove(tx, 0) if n.nil?
175
+
176
+ yarray_remove_range(tx, 0, n) unless nil?
177
+ end
178
+ end
179
+
180
+ # rubocop:enable Naming/MethodParameterName
181
+
182
+ # Size of array
183
+ #
184
+ # @return [Integer]
185
+ def size
186
+ document.current_transaction { |tx| yarray_length(tx) }
187
+ end
188
+
189
+ alias length size
190
+
191
+ # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
192
+
193
+ # Removes one or more elements from array
194
+ #
195
+ # **Attention:** In comparison to Array#slice, {Array#slice!} will not
196
+ # return the values that got removed. Even this being technically
197
+ # possible, it requires us to read the elements before removing them, which
198
+ # is not desirable in most situations.
199
+ #
200
+ # @example Removes a single element
201
+ # doc = Y::Doc.new
202
+ #
203
+ # arr = doc.get_text("my array")
204
+ # arr << 1
205
+ # arr << 2
206
+ # arr << 3
207
+ #
208
+ # arr.slice!(1)
209
+ #
210
+ # arr.to_a == [1, 3] # true
211
+ #
212
+ # @overload slice!(n)
213
+ # Removes nth element from array
214
+ #
215
+ # @overload slice!(start, length)
216
+ # Removes a range of elements
217
+ #
218
+ # @overload slice!(range)
219
+ # Removes a range of elements
220
+ #
221
+ # @return [void]
222
+ def slice!(*args)
223
+ document.current_transaction do |tx| # rubocop:disable Metrics/BlockLength
224
+ if args.empty?
225
+ raise ArgumentError,
226
+ "Provide one of `index`, `range`, `start, length` as arguments"
227
+ end
228
+
229
+ if args.size == 1
230
+ arg = args.first
231
+
232
+ if arg.is_a?(Range)
233
+ if arg.exclude_end?
234
+ yarray_remove_range(tx, arg.first,
235
+ arg.last - arg.first)
236
+ end
237
+ unless arg.exclude_end?
238
+ yarray_remove_range(tx, arg.first,
239
+ arg.last + 1 - arg.first)
240
+ end
241
+ return nil
242
+ end
243
+
244
+ if arg.is_a?(Numeric)
245
+ yarray_remove(tx, arg.to_int)
246
+ return nil
247
+ end
248
+ end
249
+
250
+ if args.size == 2
251
+ first, second = args
252
+
253
+ if first.is_a?(Numeric) && second.is_a?(Numeric)
254
+ yarray_remove_range(tx, first, second)
255
+ return nil
256
+ end
257
+ end
258
+
259
+ raise ArgumentError, "Please check your arguments, can't slice."
260
+ end
261
+ end
262
+
263
+ # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
264
+
265
+ # Convert this array to a Ruby Array
266
+ #
267
+ # @return [Array<true, false, Float, Integer, String, ::Array, Hash>]
268
+ def to_a
269
+ document.current_transaction { |tx| yarray_to_a(tx) }
270
+ end
271
+
272
+ # Adds an element to the beginning of the array
273
+ #
274
+ # @return [void]
275
+ def unshift(value)
276
+ document.current_transaction { |tx| yarray_push_front(tx, value) }
277
+ end
278
+
279
+ alias prepend unshift
280
+
281
+ # @!method yarray_each(proc)
282
+ # Iterates over all elements in Array by calling the provided proc
283
+ # with the value as argument.
284
+ #
285
+ # @param proc [Proc<Object>] A proc that is called for every element
286
+ # @!visibility private
287
+
288
+ # @!method yarray_get(transaction, index)
289
+ # Retrieves content as specified index
290
+ #
291
+ # @param index [Integer]
292
+ # @return [Object]
293
+ # @!visibility private
294
+
295
+ # @!method yarray_insert(transaction, index, content)
296
+ # Inserts content at specified index
297
+ #
298
+ # @param transaction [Y::Transaction]
299
+ # @param index [Integer]
300
+ # @param content [Boolean, Float, Integer, Array, Hash, Text]
301
+ # @return [void]
302
+ # @!visibility private
303
+
304
+ # @!method yarray_insert_range(transaction, index, arr)
305
+ # Inserts all elements of a given array at specified index
306
+ #
307
+ # @param transaction [Y::Transaction]
308
+ # @param index [Integer]
309
+ # @param arr [Array<Boolean, Float, Integer, Array, Hash, Text>]
310
+ # @return [void]
311
+ # @!visibility private
312
+
313
+ # @!method yarray_length(transaction)
314
+ # Returns length of array
315
+ #
316
+ # @param transaction [Y::Transaction]
317
+ # @return [Integer] Length of array
318
+ # @!visibility private
319
+
320
+ # @!method yarray_push_back(transaction, value)
321
+ # Adds an element to the end of the array
322
+ #
323
+ # @param transaction [Y::Transaction]
324
+ # @param value [Object]
325
+ # @return [void]
326
+ # @!visibility private
327
+
328
+ # @!method yarray_push_front(transaction, value)
329
+ # Adds an element to the front of the array
330
+ #
331
+ # @param transaction [Y::Transaction]
332
+ # @param value [Object]
333
+ # @return [void]
334
+ # @!visibility private
335
+
336
+ # @!method yarray_observe(proc)
337
+ #
338
+ # @param proc [Proc]
339
+ # @return [Integer]
340
+ # @!visibility private
341
+
342
+ # @!method yarray_remove(transaction, index)
343
+ # Removes a single element from array at index
344
+ #
345
+ # @param transaction [Y::Transaction]
346
+ # @param index [Integer]
347
+ # @return [void]
348
+ # @!visibility private
349
+
350
+ # @!method yarray_remove_range(transaction, index, length)
351
+ # Removes a range of elements from array
352
+ #
353
+ # @param transaction [Y::Transaction]
354
+ # @param index [Integer]
355
+ # @param length [Integer]
356
+ # @return [void]
357
+ # @!visibility private
358
+
359
+ # @!method yarray_to_a(transaction)
360
+ # Transforms the array into a Ruby array
361
+ # @param transaction [Y::Transaction]
362
+ # @return [Array]
363
+ # @!visibility private
364
+
365
+ # @!method yarray_unobserve(subscription_id)
366
+ #
367
+ # @param subscription_id [Integer]
368
+ # @return [void]
369
+ # @!visibility private
370
+ end
371
+ end