twilic 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.editorconfig +18 -0
- data/.gitattributes +1 -0
- data/.gitignore +9 -0
- data/.markdownlint.jsonc +22 -0
- data/Gemfile +5 -0
- data/Gemfile.lock +53 -0
- data/LICENSE +21 -0
- data/README.md +119 -0
- data/Rakefile +12 -0
- data/docs/CHANGELOG.md +31 -0
- data/docs/CONTRIBUTING.md +51 -0
- data/docs/SPEC-TEST-TRACEABILITY.md +87 -0
- data/lib/twilic/core/api.rb +30 -0
- data/lib/twilic/core/codec.rb +766 -0
- data/lib/twilic/core/dictionary.rb +236 -0
- data/lib/twilic/core/errors.rb +87 -0
- data/lib/twilic/core/interop_fixtures.rb +340 -0
- data/lib/twilic/core/model.rb +506 -0
- data/lib/twilic/core/protocol.rb +2044 -0
- data/lib/twilic/core/protocol_helpers.rb +512 -0
- data/lib/twilic/core/session.rb +461 -0
- data/lib/twilic/core/v2.rb +387 -0
- data/lib/twilic/core/wire.rb +158 -0
- data/lib/twilic/version.rb +5 -0
- data/lib/twilic.rb +147 -0
- data/package.json +14 -0
- data/pnpm-lock.yaml +723 -0
- data/twilic.gemspec +32 -0
- metadata +118 -0
|
@@ -0,0 +1,506 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Twilic
|
|
4
|
+
module Core
|
|
5
|
+
module Model
|
|
6
|
+
class MessageKind
|
|
7
|
+
Entry = Data.define(:value)
|
|
8
|
+
SCALAR = Entry.new(0x00)
|
|
9
|
+
ARRAY = Entry.new(0x01)
|
|
10
|
+
MAP = Entry.new(0x02)
|
|
11
|
+
SHAPED_OBJECT = Entry.new(0x03)
|
|
12
|
+
SCHEMA_OBJECT = Entry.new(0x04)
|
|
13
|
+
TYPED_VECTOR = Entry.new(0x05)
|
|
14
|
+
ROW_BATCH = Entry.new(0x06)
|
|
15
|
+
COLUMN_BATCH = Entry.new(0x07)
|
|
16
|
+
CONTROL = Entry.new(0x08)
|
|
17
|
+
EXT = Entry.new(0x09)
|
|
18
|
+
STATE_PATCH = Entry.new(0x0A)
|
|
19
|
+
TEMPLATE_BATCH = Entry.new(0x0B)
|
|
20
|
+
CONTROL_STREAM = Entry.new(0x0C)
|
|
21
|
+
BASE_SNAPSHOT = Entry.new(0x0D)
|
|
22
|
+
|
|
23
|
+
def self.from_byte(b)
|
|
24
|
+
case b
|
|
25
|
+
when 0x00 then SCALAR
|
|
26
|
+
when 0x01 then ARRAY
|
|
27
|
+
when 0x02 then MAP
|
|
28
|
+
when 0x03 then SHAPED_OBJECT
|
|
29
|
+
when 0x04 then SCHEMA_OBJECT
|
|
30
|
+
when 0x05 then TYPED_VECTOR
|
|
31
|
+
when 0x06 then ROW_BATCH
|
|
32
|
+
when 0x07 then COLUMN_BATCH
|
|
33
|
+
when 0x08 then CONTROL
|
|
34
|
+
when 0x09 then EXT
|
|
35
|
+
when 0x0A then STATE_PATCH
|
|
36
|
+
when 0x0B then TEMPLATE_BATCH
|
|
37
|
+
when 0x0C then CONTROL_STREAM
|
|
38
|
+
when 0x0D then BASE_SNAPSHOT
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
class ValueKind
|
|
44
|
+
Entry = Data.define(:name)
|
|
45
|
+
NULL = Entry.new(:null)
|
|
46
|
+
BOOL = Entry.new(:bool)
|
|
47
|
+
I64 = Entry.new(:i64)
|
|
48
|
+
U64 = Entry.new(:u64)
|
|
49
|
+
F64 = Entry.new(:f64)
|
|
50
|
+
STRING = Entry.new(:string)
|
|
51
|
+
BINARY = Entry.new(:binary)
|
|
52
|
+
ARRAY = Entry.new(:array)
|
|
53
|
+
MAP = Entry.new(:map)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
Value = Data.define(:kind, :bool, :i64, :u64, :f64, :str, :bin, :arr, :map) do
|
|
57
|
+
def scalar?
|
|
58
|
+
kind != ValueKind::ARRAY && kind != ValueKind::MAP
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def clone_value
|
|
62
|
+
case kind
|
|
63
|
+
when ValueKind::NULL, ValueKind::BOOL, ValueKind::I64, ValueKind::U64, ValueKind::F64, ValueKind::STRING
|
|
64
|
+
self
|
|
65
|
+
when ValueKind::BINARY
|
|
66
|
+
with(bin: bin.b.dup)
|
|
67
|
+
when ValueKind::ARRAY
|
|
68
|
+
with(arr: arr.map(&:clone_value))
|
|
69
|
+
when ValueKind::MAP
|
|
70
|
+
with(map: map.map { |e| MapEntry.new(e.key, e.value.clone_value) })
|
|
71
|
+
else
|
|
72
|
+
new(kind: ValueKind::NULL)
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
MapEntry = Data.define(:key, :value)
|
|
78
|
+
MessageMapEntry = Data.define(:key, :value)
|
|
79
|
+
|
|
80
|
+
KeyRef = Data.define(:literal, :id, :is_id) do
|
|
81
|
+
def self.literal(s)
|
|
82
|
+
new(literal: s, id: 0, is_id: false)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def self.id_ref(id)
|
|
86
|
+
new(literal: "", id: id, is_id: true)
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
class StringMode
|
|
91
|
+
Entry = Data.define(:value)
|
|
92
|
+
EMPTY = Entry.new(0)
|
|
93
|
+
LITERAL = Entry.new(1)
|
|
94
|
+
REF = Entry.new(2)
|
|
95
|
+
PREFIX_DELTA = Entry.new(3)
|
|
96
|
+
INLINE_ENUM = Entry.new(4)
|
|
97
|
+
|
|
98
|
+
def self.from_byte(b)
|
|
99
|
+
return Entry.new(b) if (0..4).cover?(b)
|
|
100
|
+
|
|
101
|
+
nil
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
StringValue = Data.define(:mode, :value, :ref_id, :prefix_len)
|
|
106
|
+
|
|
107
|
+
class ElementType
|
|
108
|
+
Entry = Data.define(:value)
|
|
109
|
+
BOOL = Entry.new(0)
|
|
110
|
+
I64 = Entry.new(1)
|
|
111
|
+
U64 = Entry.new(2)
|
|
112
|
+
F64 = Entry.new(3)
|
|
113
|
+
STRING = Entry.new(4)
|
|
114
|
+
BINARY = Entry.new(5)
|
|
115
|
+
VALUE = Entry.new(6)
|
|
116
|
+
|
|
117
|
+
def self.from_byte(b)
|
|
118
|
+
return Entry.new(b) if (0..6).cover?(b)
|
|
119
|
+
|
|
120
|
+
nil
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
class VectorCodec
|
|
125
|
+
Entry = Data.define(:value)
|
|
126
|
+
PLAIN = Entry.new(0)
|
|
127
|
+
DIRECT_BITPACK = Entry.new(1)
|
|
128
|
+
DELTA_BITPACK = Entry.new(2)
|
|
129
|
+
FOR_BITPACK = Entry.new(3)
|
|
130
|
+
DELTA_FOR_BITPACK = Entry.new(4)
|
|
131
|
+
DELTA_DELTA_BITPACK = Entry.new(5)
|
|
132
|
+
RLE = Entry.new(6)
|
|
133
|
+
PATCHED_FOR = Entry.new(7)
|
|
134
|
+
SIMPLE8B = Entry.new(8)
|
|
135
|
+
XOR_FLOAT = Entry.new(9)
|
|
136
|
+
DICTIONARY = Entry.new(10)
|
|
137
|
+
STRING_REF = Entry.new(11)
|
|
138
|
+
PREFIX_DELTA = Entry.new(12)
|
|
139
|
+
|
|
140
|
+
def self.from_byte(b)
|
|
141
|
+
return Entry.new(b) if b <= 12
|
|
142
|
+
|
|
143
|
+
nil
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
TypedVectorData = Data.define(:bools, :i64s, :u64s, :f64s, :strings, :binary, :values, :kind)
|
|
148
|
+
TypedVector = Data.define(:element_type, :codec, :data)
|
|
149
|
+
|
|
150
|
+
SchemaField = Data.define(
|
|
151
|
+
:number, :name, :logical_type, :required, :default_value, :min, :max, :enum_values
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
Schema = Data.define(:schema_id, :name, :fields)
|
|
155
|
+
|
|
156
|
+
class NullStrategy
|
|
157
|
+
Entry = Data.define(:value)
|
|
158
|
+
NONE = Entry.new(0)
|
|
159
|
+
PRESENCE_BITMAP = Entry.new(1)
|
|
160
|
+
INVERTED_PRESENCE_BITMAP = Entry.new(2)
|
|
161
|
+
ALL_PRESENT_ELIDED = Entry.new(3)
|
|
162
|
+
|
|
163
|
+
def self.from_byte(b)
|
|
164
|
+
return Entry.new(b) if (0..3).cover?(b)
|
|
165
|
+
|
|
166
|
+
nil
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
Column = Data.define(
|
|
171
|
+
:field_id, :null_strategy, :presence, :has_presence, :codec, :dictionary_id, :values
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
class ControlOpcode
|
|
175
|
+
Entry = Data.define(:value)
|
|
176
|
+
REGISTER_KEYS = Entry.new(0)
|
|
177
|
+
REGISTER_SHAPE = Entry.new(1)
|
|
178
|
+
REGISTER_STRINGS = Entry.new(2)
|
|
179
|
+
PROMOTE_STRING_FIELD_TO_ENUM = Entry.new(3)
|
|
180
|
+
RESET_TABLES = Entry.new(4)
|
|
181
|
+
RESET_STATE = Entry.new(5)
|
|
182
|
+
|
|
183
|
+
def self.from_byte(b)
|
|
184
|
+
return Entry.new(b) if (0..5).cover?(b)
|
|
185
|
+
|
|
186
|
+
nil
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
ControlMessage = Data.define(
|
|
191
|
+
:register_keys, :register_shape, :register_strings, :promote_string_field_to_enum,
|
|
192
|
+
:reset_tables, :reset_state, :opcode
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
RegisterShapeControl = Data.define(:shape_id, :keys)
|
|
196
|
+
PromoteEnumControl = Data.define(:field_identity, :values)
|
|
197
|
+
|
|
198
|
+
class PatchOpcode
|
|
199
|
+
Entry = Data.define(:value)
|
|
200
|
+
KEEP = Entry.new(0)
|
|
201
|
+
REPLACE_SCALAR = Entry.new(1)
|
|
202
|
+
REPLACE_VECTOR = Entry.new(2)
|
|
203
|
+
APPEND_VECTOR = Entry.new(3)
|
|
204
|
+
TRUNCATE_VECTOR = Entry.new(4)
|
|
205
|
+
DELETE_FIELD = Entry.new(5)
|
|
206
|
+
INSERT_FIELD = Entry.new(6)
|
|
207
|
+
STRING_REF = Entry.new(7)
|
|
208
|
+
PREFIX_DELTA = Entry.new(8)
|
|
209
|
+
|
|
210
|
+
def self.from_byte(b)
|
|
211
|
+
return Entry.new(b) if b <= 8
|
|
212
|
+
|
|
213
|
+
nil
|
|
214
|
+
end
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
BaseRef = Data.define(:previous, :base_id) do
|
|
218
|
+
def self.previous
|
|
219
|
+
new(previous: true, base_id: 0)
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
def self.id_ref(id)
|
|
223
|
+
new(previous: false, base_id: id)
|
|
224
|
+
end
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
PatchOperation = Data.define(:field_id, :opcode, :value)
|
|
228
|
+
|
|
229
|
+
class ControlStreamCodec
|
|
230
|
+
Entry = Data.define(:value)
|
|
231
|
+
PLAIN = Entry.new(0)
|
|
232
|
+
RLE = Entry.new(1)
|
|
233
|
+
BITPACK = Entry.new(2)
|
|
234
|
+
HUFFMAN = Entry.new(3)
|
|
235
|
+
FSE = Entry.new(4)
|
|
236
|
+
|
|
237
|
+
def self.from_byte(b)
|
|
238
|
+
return Entry.new(b) if b <= 4
|
|
239
|
+
|
|
240
|
+
nil
|
|
241
|
+
end
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
Message = Data.define(
|
|
245
|
+
:scalar, :array, :map, :shaped_object, :schema_object, :typed_vector, :row_batch,
|
|
246
|
+
:column_batch, :control, :ext, :state_patch, :template_batch, :control_stream,
|
|
247
|
+
:base_snapshot, :kind
|
|
248
|
+
) do
|
|
249
|
+
def clone_message
|
|
250
|
+
case kind
|
|
251
|
+
when MessageKind::SCALAR
|
|
252
|
+
v = scalar.clone_value
|
|
253
|
+
Model.message(kind: kind, scalar: v)
|
|
254
|
+
when MessageKind::ARRAY
|
|
255
|
+
Model.message(kind: kind, array: array.map(&:clone_value))
|
|
256
|
+
when MessageKind::MAP
|
|
257
|
+
Model.message(kind: kind, map: map.map { |e| MessageMapEntry.new(e.key, e.value.clone_value) })
|
|
258
|
+
when MessageKind::SHAPED_OBJECT
|
|
259
|
+
s = shaped_object
|
|
260
|
+
vals = s.values.map(&:clone_value)
|
|
261
|
+
pres = s.has_presence ? s.presence.dup : nil
|
|
262
|
+
Model.message(kind: kind, shaped_object: ShapedObjectMessage.new(
|
|
263
|
+
shape_id: s.shape_id, presence: pres, has_presence: s.has_presence, values: vals
|
|
264
|
+
))
|
|
265
|
+
when MessageKind::SCHEMA_OBJECT
|
|
266
|
+
s = schema_object
|
|
267
|
+
fields = s.fields.map(&:clone_value)
|
|
268
|
+
pres = s.has_presence ? s.presence.dup : nil
|
|
269
|
+
sid = s.schema_id
|
|
270
|
+
Model.message(kind: kind, schema_object: SchemaObjectMessage.new(
|
|
271
|
+
schema_id: sid, presence: pres, has_presence: s.has_presence, fields: fields
|
|
272
|
+
))
|
|
273
|
+
when MessageKind::TYPED_VECTOR
|
|
274
|
+
Model.message(kind: kind, typed_vector: Model.clone_typed_vector(typed_vector))
|
|
275
|
+
when MessageKind::ROW_BATCH
|
|
276
|
+
rows = row_batch.rows.map { |r| r.map(&:clone_value) }
|
|
277
|
+
Model.message(kind: kind, row_batch: RowBatchMessage.new(rows: rows))
|
|
278
|
+
when MessageKind::COLUMN_BATCH
|
|
279
|
+
cols = column_batch.columns.map { |c| Model.clone_column(c) }
|
|
280
|
+
Model.message(kind: kind, column_batch: ColumnBatchMessage.new(
|
|
281
|
+
count: column_batch.count, columns: cols
|
|
282
|
+
))
|
|
283
|
+
when MessageKind::CONTROL
|
|
284
|
+
Model.message(kind: kind, control: Model.clone_control(control))
|
|
285
|
+
when MessageKind::EXT
|
|
286
|
+
Model.message(kind: kind, ext: ExtMessage.new(
|
|
287
|
+
ext_type: ext.ext_type, payload: ext.payload.b.dup
|
|
288
|
+
))
|
|
289
|
+
when MessageKind::STATE_PATCH
|
|
290
|
+
sp = state_patch
|
|
291
|
+
ops = sp.operations.map do |op|
|
|
292
|
+
val = op.value ? op.value.clone_value : nil
|
|
293
|
+
PatchOperation.new(field_id: op.field_id, opcode: op.opcode, value: val)
|
|
294
|
+
end
|
|
295
|
+
lits = sp.literals.map(&:clone_value)
|
|
296
|
+
Model.message(kind: kind, state_patch: StatePatchMessage.new(
|
|
297
|
+
base_ref: sp.base_ref, operations: ops, literals: lits
|
|
298
|
+
))
|
|
299
|
+
when MessageKind::TEMPLATE_BATCH
|
|
300
|
+
tb = template_batch
|
|
301
|
+
cols = tb.columns.map { |c| Model.clone_column(c) }
|
|
302
|
+
Model.message(kind: kind, template_batch: TemplateBatchMessage.new(
|
|
303
|
+
template_id: tb.template_id, count: tb.count,
|
|
304
|
+
changed_column_mask: tb.changed_column_mask.dup, columns: cols
|
|
305
|
+
))
|
|
306
|
+
when MessageKind::CONTROL_STREAM
|
|
307
|
+
cs = control_stream
|
|
308
|
+
Model.message(kind: kind, control_stream: ControlStreamMessage.new(
|
|
309
|
+
codec: cs.codec, payload: cs.payload.b.dup
|
|
310
|
+
))
|
|
311
|
+
when MessageKind::BASE_SNAPSHOT
|
|
312
|
+
bs = base_snapshot
|
|
313
|
+
Model.message(kind: kind, base_snapshot: BaseSnapshotMessage.new(
|
|
314
|
+
base_id: bs.base_id, schema_or_shape_ref: bs.schema_or_shape_ref,
|
|
315
|
+
payload: bs.payload.clone_message
|
|
316
|
+
))
|
|
317
|
+
else
|
|
318
|
+
Model.message(kind: MessageKind::SCALAR)
|
|
319
|
+
end
|
|
320
|
+
end
|
|
321
|
+
end
|
|
322
|
+
|
|
323
|
+
ShapedObjectMessage = Data.define(:shape_id, :presence, :has_presence, :values)
|
|
324
|
+
SchemaObjectMessage = Data.define(:schema_id, :presence, :has_presence, :fields)
|
|
325
|
+
RowBatchMessage = Data.define(:rows)
|
|
326
|
+
ColumnBatchMessage = Data.define(:count, :columns)
|
|
327
|
+
ExtMessage = Data.define(:ext_type, :payload)
|
|
328
|
+
StatePatchMessage = Data.define(:base_ref, :operations, :literals)
|
|
329
|
+
TemplateBatchMessage = Data.define(:template_id, :count, :changed_column_mask, :columns)
|
|
330
|
+
ControlStreamMessage = Data.define(:codec, :payload)
|
|
331
|
+
BaseSnapshotMessage = Data.define(:base_id, :schema_or_shape_ref, :payload)
|
|
332
|
+
TemplateDescriptor = Data.define(:template_id, :field_ids, :null_strategies, :codecs)
|
|
333
|
+
|
|
334
|
+
EMPTY_MESSAGE_FIELDS = {
|
|
335
|
+
scalar: nil, array: nil, map: nil, shaped_object: nil, schema_object: nil,
|
|
336
|
+
typed_vector: nil, row_batch: nil, column_batch: nil, control: nil, ext: nil,
|
|
337
|
+
state_patch: nil, template_batch: nil, control_stream: nil, base_snapshot: nil
|
|
338
|
+
}.freeze
|
|
339
|
+
|
|
340
|
+
def self.message(kind:, **kwargs)
|
|
341
|
+
Message.new(**EMPTY_MESSAGE_FIELDS, kind: kind, **kwargs)
|
|
342
|
+
end
|
|
343
|
+
|
|
344
|
+
module_function
|
|
345
|
+
|
|
346
|
+
def null_value
|
|
347
|
+
Value.new(kind: ValueKind::NULL, bool: false, i64: 0, u64: 0, f64: 0.0,
|
|
348
|
+
str: "", bin: +"", arr: [], map: [])
|
|
349
|
+
end
|
|
350
|
+
|
|
351
|
+
def bool_value(b)
|
|
352
|
+
Value.new(kind: ValueKind::BOOL, bool: b, i64: 0, u64: 0, f64: 0.0,
|
|
353
|
+
str: "", bin: +"", arr: [], map: [])
|
|
354
|
+
end
|
|
355
|
+
|
|
356
|
+
def i64_value(n)
|
|
357
|
+
Value.new(kind: ValueKind::I64, bool: false, i64: n, u64: 0, f64: 0.0,
|
|
358
|
+
str: "", bin: +"", arr: [], map: [])
|
|
359
|
+
end
|
|
360
|
+
|
|
361
|
+
def u64_value(n)
|
|
362
|
+
Value.new(kind: ValueKind::U64, bool: false, i64: 0, u64: n, f64: 0.0,
|
|
363
|
+
str: "", bin: +"", arr: [], map: [])
|
|
364
|
+
end
|
|
365
|
+
|
|
366
|
+
def f64_value(n)
|
|
367
|
+
Value.new(kind: ValueKind::F64, bool: false, i64: 0, u64: 0, f64: n,
|
|
368
|
+
str: "", bin: +"", arr: [], map: [])
|
|
369
|
+
end
|
|
370
|
+
|
|
371
|
+
def string_value(s)
|
|
372
|
+
Value.new(kind: ValueKind::STRING, bool: false, i64: 0, u64: 0, f64: 0.0,
|
|
373
|
+
str: s, bin: +"", arr: [], map: [])
|
|
374
|
+
end
|
|
375
|
+
|
|
376
|
+
def binary_value(b)
|
|
377
|
+
Value.new(kind: ValueKind::BINARY, bool: false, i64: 0, u64: 0, f64: 0.0,
|
|
378
|
+
str: "", bin: b.b.dup, arr: [], map: [])
|
|
379
|
+
end
|
|
380
|
+
|
|
381
|
+
def array_value(items)
|
|
382
|
+
Value.new(kind: ValueKind::ARRAY, bool: false, i64: 0, u64: 0, f64: 0.0,
|
|
383
|
+
str: "", bin: +"", arr: items.map(&:clone_value), map: [])
|
|
384
|
+
end
|
|
385
|
+
|
|
386
|
+
def entry(key, value)
|
|
387
|
+
MapEntry.new(key, value)
|
|
388
|
+
end
|
|
389
|
+
|
|
390
|
+
def map_value(entries = nil, **kwargs)
|
|
391
|
+
if kwargs.any?
|
|
392
|
+
entries = kwargs.map { |k, v| MapEntry.new(k.to_s, v) }
|
|
393
|
+
elsif entries.is_a?(Hash)
|
|
394
|
+
entries = entries.map { |k, v| MapEntry.new(k.to_s, v) }
|
|
395
|
+
end
|
|
396
|
+
entries ||= []
|
|
397
|
+
Value.new(kind: ValueKind::MAP, bool: false, i64: 0, u64: 0, f64: 0.0,
|
|
398
|
+
str: "", bin: +"", arr: [],
|
|
399
|
+
map: entries.map { |e| MapEntry.new(e.key, e.value.clone_value) })
|
|
400
|
+
end
|
|
401
|
+
|
|
402
|
+
def equal(a, b)
|
|
403
|
+
return false unless a.kind == b.kind
|
|
404
|
+
|
|
405
|
+
case a.kind
|
|
406
|
+
when ValueKind::NULL then true
|
|
407
|
+
when ValueKind::BOOL then a.bool == b.bool
|
|
408
|
+
when ValueKind::I64 then a.i64 == b.i64
|
|
409
|
+
when ValueKind::U64 then a.u64 == b.u64
|
|
410
|
+
when ValueKind::F64 then a.f64 == b.f64
|
|
411
|
+
when ValueKind::STRING then a.str == b.str
|
|
412
|
+
when ValueKind::BINARY then a.bin == b.bin
|
|
413
|
+
when ValueKind::ARRAY
|
|
414
|
+
return false unless a.arr.length == b.arr.length
|
|
415
|
+
|
|
416
|
+
a.arr.each_with_index.all? { |v, i| equal(v, b.arr[i]) }
|
|
417
|
+
when ValueKind::MAP
|
|
418
|
+
return false unless a.map.length == b.map.length
|
|
419
|
+
|
|
420
|
+
a.map.each_with_index.all? do |e, i|
|
|
421
|
+
e.key == b.map[i].key && equal(e.value, b.map[i].value)
|
|
422
|
+
end
|
|
423
|
+
else
|
|
424
|
+
false
|
|
425
|
+
end
|
|
426
|
+
end
|
|
427
|
+
|
|
428
|
+
def clone_typed_vector(tv)
|
|
429
|
+
return nil unless tv
|
|
430
|
+
|
|
431
|
+
data = tv.data
|
|
432
|
+
out_data = case tv.element_type
|
|
433
|
+
when ElementType::BOOL
|
|
434
|
+
TypedVectorData.new(bools: data.bools.dup, i64s: [], u64s: [], f64s: [],
|
|
435
|
+
strings: [], binary: [], values: [], kind: tv.element_type)
|
|
436
|
+
when ElementType::I64
|
|
437
|
+
TypedVectorData.new(bools: [], i64s: data.i64s.dup, u64s: [], f64s: [],
|
|
438
|
+
strings: [], binary: [], values: [], kind: tv.element_type)
|
|
439
|
+
when ElementType::U64
|
|
440
|
+
TypedVectorData.new(bools: [], i64s: [], u64s: data.u64s.dup, f64s: [],
|
|
441
|
+
strings: [], binary: [], values: [], kind: tv.element_type)
|
|
442
|
+
when ElementType::F64
|
|
443
|
+
TypedVectorData.new(bools: [], i64s: [], u64s: [], f64s: data.f64s.dup,
|
|
444
|
+
strings: [], binary: [], values: [], kind: tv.element_type)
|
|
445
|
+
when ElementType::STRING
|
|
446
|
+
TypedVectorData.new(bools: [], i64s: [], u64s: [], f64s: [],
|
|
447
|
+
strings: data.strings.dup, binary: [], values: [],
|
|
448
|
+
kind: tv.element_type)
|
|
449
|
+
when ElementType::BINARY
|
|
450
|
+
TypedVectorData.new(bools: [], i64s: [], u64s: [], f64s: [],
|
|
451
|
+
strings: [], binary: data.binary.map(&:b), values: [],
|
|
452
|
+
kind: tv.element_type)
|
|
453
|
+
when ElementType::VALUE
|
|
454
|
+
TypedVectorData.new(bools: [], i64s: [], u64s: [], f64s: [],
|
|
455
|
+
strings: [], binary: [],
|
|
456
|
+
values: data.values.map(&:clone_value), kind: tv.element_type)
|
|
457
|
+
else
|
|
458
|
+
TypedVectorData.new(bools: [], i64s: [], u64s: [], f64s: [],
|
|
459
|
+
strings: [], binary: [], values: [], kind: tv.element_type)
|
|
460
|
+
end
|
|
461
|
+
TypedVector.new(element_type: tv.element_type, codec: tv.codec, data: out_data)
|
|
462
|
+
end
|
|
463
|
+
|
|
464
|
+
def clone_column(c)
|
|
465
|
+
pres = c.has_presence ? c.presence.dup : nil
|
|
466
|
+
dict_id = c.dictionary_id
|
|
467
|
+
Column.new(
|
|
468
|
+
field_id: c.field_id, null_strategy: c.null_strategy, presence: pres,
|
|
469
|
+
has_presence: c.has_presence, codec: c.codec, dictionary_id: dict_id,
|
|
470
|
+
values: clone_typed_vector_data(c.values)
|
|
471
|
+
)
|
|
472
|
+
end
|
|
473
|
+
|
|
474
|
+
def clone_typed_vector_data(d)
|
|
475
|
+
TypedVectorData.new(
|
|
476
|
+
bools: d.bools.dup, i64s: d.i64s.dup, u64s: d.u64s.dup, f64s: d.f64s.dup,
|
|
477
|
+
strings: d.strings.dup, binary: d.binary.map(&:b), values: d.values.map(&:clone_value),
|
|
478
|
+
kind: d.kind
|
|
479
|
+
)
|
|
480
|
+
end
|
|
481
|
+
|
|
482
|
+
def clone_control(c)
|
|
483
|
+
return nil unless c
|
|
484
|
+
|
|
485
|
+
rs = if c.register_shape
|
|
486
|
+
RegisterShapeControl.new(
|
|
487
|
+
shape_id: c.register_shape.shape_id,
|
|
488
|
+
keys: c.register_shape.keys.dup
|
|
489
|
+
)
|
|
490
|
+
end
|
|
491
|
+
pe = if c.promote_string_field_to_enum
|
|
492
|
+
PromoteEnumControl.new(
|
|
493
|
+
field_identity: c.promote_string_field_to_enum.field_identity,
|
|
494
|
+
values: c.promote_string_field_to_enum.values.dup
|
|
495
|
+
)
|
|
496
|
+
end
|
|
497
|
+
ControlMessage.new(
|
|
498
|
+
register_keys: c.register_keys.dup, register_shape: rs,
|
|
499
|
+
register_strings: c.register_strings.dup,
|
|
500
|
+
promote_string_field_to_enum: pe, reset_tables: c.reset_tables,
|
|
501
|
+
reset_state: c.reset_state, opcode: c.opcode
|
|
502
|
+
)
|
|
503
|
+
end
|
|
504
|
+
end
|
|
505
|
+
end
|
|
506
|
+
end
|