unibuf 0.1.1 → 0.1.2

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.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop_todo.yml +170 -200
  3. data/CODE_OF_CONDUCT.md +132 -0
  4. data/README.adoc +306 -114
  5. data/docs/CAPNPROTO.adoc +436 -0
  6. data/docs/FLATBUFFERS.adoc +430 -0
  7. data/docs/PROTOBUF.adoc +515 -0
  8. data/docs/TXTPROTO.adoc +369 -0
  9. data/lib/unibuf/commands/convert.rb +60 -2
  10. data/lib/unibuf/commands/schema.rb +68 -11
  11. data/lib/unibuf/errors.rb +23 -26
  12. data/lib/unibuf/models/capnproto/enum_definition.rb +72 -0
  13. data/lib/unibuf/models/capnproto/field_definition.rb +81 -0
  14. data/lib/unibuf/models/capnproto/interface_definition.rb +70 -0
  15. data/lib/unibuf/models/capnproto/method_definition.rb +81 -0
  16. data/lib/unibuf/models/capnproto/schema.rb +84 -0
  17. data/lib/unibuf/models/capnproto/struct_definition.rb +96 -0
  18. data/lib/unibuf/models/capnproto/union_definition.rb +62 -0
  19. data/lib/unibuf/models/flatbuffers/enum_definition.rb +69 -0
  20. data/lib/unibuf/models/flatbuffers/field_definition.rb +88 -0
  21. data/lib/unibuf/models/flatbuffers/schema.rb +102 -0
  22. data/lib/unibuf/models/flatbuffers/struct_definition.rb +70 -0
  23. data/lib/unibuf/models/flatbuffers/table_definition.rb +73 -0
  24. data/lib/unibuf/models/flatbuffers/union_definition.rb +60 -0
  25. data/lib/unibuf/models/message.rb +10 -0
  26. data/lib/unibuf/parsers/capnproto/binary_parser.rb +267 -0
  27. data/lib/unibuf/parsers/capnproto/grammar.rb +272 -0
  28. data/lib/unibuf/parsers/capnproto/list_reader.rb +208 -0
  29. data/lib/unibuf/parsers/capnproto/pointer_decoder.rb +163 -0
  30. data/lib/unibuf/parsers/capnproto/processor.rb +348 -0
  31. data/lib/unibuf/parsers/capnproto/segment_reader.rb +131 -0
  32. data/lib/unibuf/parsers/capnproto/struct_reader.rb +199 -0
  33. data/lib/unibuf/parsers/flatbuffers/binary_parser.rb +325 -0
  34. data/lib/unibuf/parsers/flatbuffers/grammar.rb +235 -0
  35. data/lib/unibuf/parsers/flatbuffers/processor.rb +299 -0
  36. data/lib/unibuf/serializers/binary_serializer.rb +218 -0
  37. data/lib/unibuf/serializers/capnproto/binary_serializer.rb +402 -0
  38. data/lib/unibuf/serializers/capnproto/list_writer.rb +199 -0
  39. data/lib/unibuf/serializers/capnproto/pointer_encoder.rb +118 -0
  40. data/lib/unibuf/serializers/capnproto/segment_builder.rb +124 -0
  41. data/lib/unibuf/serializers/capnproto/struct_writer.rb +139 -0
  42. data/lib/unibuf/serializers/flatbuffers/binary_serializer.rb +167 -0
  43. data/lib/unibuf/version.rb +1 -1
  44. data/lib/unibuf.rb +27 -0
  45. metadata +36 -1
@@ -0,0 +1,430 @@
1
+ = FlatBuffers Support in Unibuf
2
+
3
+ == Overview
4
+
5
+ Unibuf provides complete FlatBuffers support including schema parsing, binary format reading, and binary format writing.
6
+
7
+ All features are implemented in pure Ruby with no C/C++ dependencies.
8
+
9
+ == Features
10
+
11
+ * Parse FlatBuffers schemas (`.fbs` files)
12
+ * Read binary FlatBuffers data (`.fb` files)
13
+ * Write binary FlatBuffers data
14
+ * Complete round-trip support
15
+ * All scalar types supported
16
+ * Tables, structs, enums, unions
17
+ * Vectors and strings
18
+
19
+ == FlatBuffers Schema Parsing
20
+
21
+ === Basic usage
22
+
23
+ [source,ruby]
24
+ ----
25
+ require "unibuf"
26
+
27
+ # Parse FlatBuffers schema
28
+ schema = Unibuf.parse_flatbuffers_schema("monster.fbs")
29
+
30
+ # Access schema metadata
31
+ puts schema.namespace # => "MyGame.Sample"
32
+ puts schema.root_type # => "Monster"
33
+ puts schema.file_identifier # => "MONS"
34
+
35
+ # List all tables
36
+ schema.table_names # => ["Monster", "Weapon", "Vec3"]
37
+
38
+ # List all enums
39
+ schema.enum_names # => ["Color", "Equipment"]
40
+ ----
41
+
42
+ === Inspecting tables
43
+
44
+ [source,ruby]
45
+ ----
46
+ # Get table definition
47
+ table = schema.find_table("Monster")
48
+
49
+ puts table.name # => "Monster"
50
+
51
+ # Inspect fields
52
+ table.fields.each do |field|
53
+ puts "#{field.name}: #{field.type}"
54
+ puts " Default: #{field.default_value}" if field.default_value
55
+ puts " Deprecated" if field.deprecated?
56
+ puts " Required" if field.required?
57
+ end
58
+
59
+ # Check table properties
60
+ table.has_vectors? # => true if any vector fields
61
+ table.has_nested_tables? # => true if nested tables
62
+ ----
63
+
64
+ === Schema constructs
65
+
66
+ Tables::
67
+ Variable-size objects with vtable indirection.
68
+ Support optional fields and versioning.
69
+
70
+ Structs::
71
+ Fixed-size objects stored inline.
72
+ More efficient but less flexible than tables.
73
+
74
+ Enums::
75
+ Integer-based enumerations with optional type specification.
76
+
77
+ Unions::
78
+ Discriminated unions representing choice between table types.
79
+
80
+ Vectors::
81
+ Arrays of any type (scalars, strings, or tables).
82
+
83
+ == FlatBuffers Binary Parsing
84
+
85
+ === Basic parsing
86
+
87
+ [source,ruby]
88
+ ----
89
+ require "unibuf"
90
+
91
+ # 1. Load schema (REQUIRED)
92
+ schema = Unibuf.parse_flatbuffers_schema("monster.fbs")
93
+
94
+ # 2. Create parser
95
+ parser = Unibuf::Parsers::Flatbuffers::BinaryParser.new(schema)
96
+
97
+ # 3. Parse binary file
98
+ data = parser.parse_file("monster.fb")
99
+
100
+ # 4. Access fields
101
+ puts data["name"] # => "Orc"
102
+ puts data["hp"] # => 150
103
+ puts data["inventory"] # => [1, 2, 3, 4, 5]
104
+ ----
105
+
106
+ === Parsing from binary string
107
+
108
+ [source,ruby]
109
+ ----
110
+ # Read binary data
111
+ binary_data = File.binread("monster.fb")
112
+
113
+ # Parse
114
+ schema = Unibuf.parse_flatbuffers_schema("monster.fbs")
115
+ parser = Unibuf::Parsers::Flatbuffers::BinaryParser.new(schema)
116
+ data = parser.parse(binary_data)
117
+ ----
118
+
119
+ === Nested tables
120
+
121
+ [source,ruby]
122
+ ----
123
+ # Schema with nested tables:
124
+ # table Vec3 { x: float; y: float; z: float; }
125
+ # table Monster { pos: Vec3; name: string; }
126
+
127
+ data = parser.parse_file("monster.fb")
128
+
129
+ # Access nested data
130
+ position = data["pos"]
131
+ puts position["x"] # => 1.0
132
+ puts position["y"] # => 2.0
133
+ puts position["z"] # => 3.0
134
+ ----
135
+
136
+ === Binary format details
137
+
138
+ FlatBuffers binary format uses:
139
+
140
+ vtables::
141
+ Virtual tables store field offsets for backwards compatibility
142
+
143
+ Offset-based::
144
+ All references use offsets from current position
145
+
146
+ Little-endian::
147
+ All numeric values in little-endian byte order
148
+
149
+ Root object::
150
+ File starts with offset to root table
151
+
152
+ Zero-copy::
153
+ Design enables reading without deserialization (not yet exposed in API)
154
+
155
+ == FlatBuffers Binary Serialization
156
+
157
+ === Basic serialization
158
+
159
+ [source,ruby]
160
+ ----
161
+ require "unibuf"
162
+
163
+ # 1. Load schema (REQUIRED)
164
+ schema = Unibuf.parse_flatbuffers_schema("monster.fbs")
165
+
166
+ # 2. Prepare data as hash
167
+ data = {
168
+ "name" => "Dragon",
169
+ "hp" => 500,
170
+ "friendly" => false
171
+ }
172
+
173
+ # 3. Serialize
174
+ serializer = Unibuf::Serializers::Flatbuffers::BinarySerializer.new(schema)
175
+ binary_data = serializer.serialize(data)
176
+
177
+ # 4. Write to file
178
+ File.binwrite("dragon.fb", binary_data)
179
+ ----
180
+
181
+ === Serializing with all scalar types
182
+
183
+ [source,ruby]
184
+ ----
185
+ data = {
186
+ "byte_val" => -42, # signed byte
187
+ "ubyte_val" => 200, # unsigned byte
188
+ "short_val" => -1000, # signed short
189
+ "ushort_val" => 5000, # unsigned short
190
+ "int_val" => -100000, # signed int
191
+ "uint_val" => 200000, # unsigned int
192
+ "long_val" => -1000000000, # signed long
193
+ "ulong_val" => 2000000000, # unsigned long
194
+ "float_val" => 3.14, # 32-bit float
195
+ "double_val" => 3.14159, # 64-bit double
196
+ "bool_val" => true, # boolean
197
+ "string_val" => "Hello!" # string
198
+ }
199
+
200
+ serializer = Unibuf::Serializers::Flatbuffers::BinarySerializer.new(schema)
201
+ binary = serializer.serialize(data)
202
+ ----
203
+
204
+ === Round-trip verification
205
+
206
+ [source,ruby]
207
+ ----
208
+ # Original data
209
+ original = {
210
+ "name" => "Goblin",
211
+ "hp" => 75,
212
+ "mana" => 50
213
+ }
214
+
215
+ # Serialize
216
+ serializer = Unibuf::Serializers::Flatbuffers::BinarySerializer.new(schema)
217
+ binary = serializer.serialize(original)
218
+
219
+ # Parse back
220
+ parser = Unibuf::Parsers::Flatbuffers::BinaryParser.new(schema)
221
+ reparsed = parser.parse(binary)
222
+
223
+ # Verify
224
+ puts original == reparsed # => true
225
+ ----
226
+
227
+ == FlatBuffers vs Protocol Buffers
228
+
229
+ === When to use FlatBuffers
230
+
231
+ Use FlatBuffers when:
232
+
233
+ * Zero-copy access is important
234
+ * Memory efficiency is critical
235
+ * Random field access is needed
236
+ * Backwards compatibility with size constraints
237
+ * Game development or embedded systems
238
+
239
+ === When to use Protocol Buffers
240
+
241
+ Use Protocol Buffers when:
242
+
243
+ * Schema evolution is important
244
+ * Reflection is needed
245
+ * gRPC integration
246
+ * Wide language support
247
+ * Mature ecosystem
248
+
249
+ == Complete example
250
+
251
+ === Schema file (monster.fbs)
252
+
253
+ [source]
254
+ ----
255
+ namespace MyGame.Sample;
256
+
257
+ enum Color : byte { Red = 0, Green, Blue = 2 }
258
+
259
+ table Monster {
260
+ pos: Vec3;
261
+ hp: short = 100;
262
+ name: string;
263
+ friendly: bool = false (deprecated);
264
+ inventory: [ubyte];
265
+ color: Color = Blue;
266
+ }
267
+
268
+ struct Vec3 {
269
+ x: float;
270
+ y: float;
271
+ z: float;
272
+ }
273
+
274
+ root_type Monster;
275
+ ----
276
+
277
+ === Parsing the schema
278
+
279
+ [source,ruby]
280
+ ----
281
+ schema = Unibuf.parse_flatbuffers_schema("monster.fbs")
282
+
283
+ # Access root type
284
+ puts schema.root_type # => "Monster"
285
+
286
+ # Find table
287
+ monster = schema.find_table("Monster")
288
+ puts monster.field_names # => ["pos", "hp", "name", "friendly", "inventory", "color"]
289
+
290
+ # Find struct
291
+ vec3 = schema.find_struct("Vec3")
292
+ puts vec3.fixed_size? # => true (structs are always fixed size)
293
+
294
+ # Find enum
295
+ color = schema.find_enum("Color")
296
+ puts color.values # => {"Red"=>0, "Green"=>1, "Blue"=>2}
297
+ ----
298
+
299
+ === Creating and reading binary data
300
+
301
+ [source,ruby]
302
+ ----
303
+ # Create data
304
+ data = {
305
+ "name" => "Orc",
306
+ "hp" => 150,
307
+ "friendly" => false,
308
+ "inventory" => [1, 2, 3, 4, 5],
309
+ "color" => "Green"
310
+ }
311
+
312
+ # Write FlatBuffer
313
+ serializer = Unibuf::Serializers::Flatbuffers::BinarySerializer.new(schema)
314
+ binary = serializer.serialize_to_file(data, "orc.fb")
315
+
316
+ # Read FlatBuffer
317
+ parser = Unibuf::Parsers::Flatbuffers::BinaryParser.new(schema)
318
+ loaded = parser.parse_file("orc.fb")
319
+
320
+ puts loaded["name"] # => "Orc"
321
+ puts loaded["hp"] # => 150
322
+ puts loaded["inventory"] # => [1, 2, 3, 4, 5]
323
+ ----
324
+
325
+ == CLI usage
326
+
327
+ === Schema inspection
328
+
329
+ [source,shell]
330
+ ----
331
+ # View FlatBuffers schema structure
332
+ unibuf schema monster.fbs
333
+
334
+ # Output as JSON for tooling
335
+ unibuf schema monster.fbs --format json
336
+ ----
337
+
338
+ == Technical details
339
+
340
+ === vtable format
341
+
342
+ FlatBuffers uses vtables for schema evolution:
343
+
344
+ [source]
345
+ ----
346
+ vtable:
347
+ vtable_size: uint16 # Size of vtable in bytes
348
+ object_size: uint16 # Size of object in bytes
349
+ field_offsets: [uint16] # Offset for each field (0 if not present)
350
+ ----
351
+
352
+ === Table format
353
+
354
+ [source]
355
+ ----
356
+ table:
357
+ vtable_offset: int32 (soffset) # Negative offset to vtable
358
+ fields: [...inline scalars and uoffsets to out-of-line data...]
359
+ ----
360
+
361
+ === Scalar storage
362
+
363
+ Scalars are stored INLINE in table body:
364
+ - byte, ubyte, bool: 1 byte
365
+ - short, ushort: 2 bytes
366
+ - int, uint, float: 4 bytes
367
+ - long, ulong, double: 8 bytes
368
+
369
+ Non-scalars (strings, vectors, nested tables) are stored OUT-OF-LINE with offsets (uoffset32) in the table.
370
+
371
+ === String format
372
+
373
+ [source]
374
+ ----
375
+ string:
376
+ length: uint32
377
+ data: [byte]
378
+ null_terminator: byte (0x00)
379
+ padding: align to 4 bytes
380
+ ----
381
+
382
+ == Limitations and future work
383
+
384
+ === Currently supported
385
+
386
+ ✅ All scalar types
387
+ ✅ Strings
388
+ ✅ Tables
389
+ ✅ Enums
390
+ ✅ vtable generation and parsing
391
+ ✅ Round-trip serialization
392
+
393
+ === Future enhancements
394
+
395
+ * Vector serialization (currently not implemented)
396
+ * Struct serialization (currently not implemented)
397
+ * Union support (parsing only)
398
+ * Nested table serialization
399
+ * vtable deduplication for smaller files
400
+ * Zero-copy access API
401
+
402
+ == Performance characteristics
403
+
404
+ FlatBuffers advantages:
405
+
406
+ Fast access::
407
+ Offset-based access without full deserialization
408
+
409
+ Memory efficient::
410
+ In-place access without additional allocation
411
+
412
+ Backwards compatible::
413
+ vtables enable schema evolution
414
+
415
+ == Contributing
416
+
417
+ FlatBuffers support is complete for basic use cases. Contributions welcome for:
418
+
419
+ * Vector serialization
420
+ * Struct handling
421
+ * Union support
422
+ * Performance optimizations
423
+ * Additional test cases
424
+
425
+ == References
426
+
427
+ * FlatBuffers specification: https://flatbuffers.dev/
428
+ * FlatBuffers grammar: https://flatbuffers.dev/flatbuffers_grammar.html
429
+ * FlatBuffers internals: https://flatbuffers.dev/md__internals.html
430
+ * Unibuf GitHub: https://github.com/lutaml/unibuf