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,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Unibuf
4
+ module Models
5
+ module Capnproto
6
+ # Represents a Cap'n Proto field definition
7
+ class FieldDefinition
8
+ attr_reader :name, :ordinal, :type, :default_value
9
+
10
+ def initialize(attributes = {})
11
+ @name = attributes[:name] || attributes["name"]
12
+ @ordinal = attributes[:ordinal] || attributes["ordinal"]
13
+ @type = attributes[:type] || attributes["type"]
14
+ @default_value = attributes[:default_value] ||
15
+ attributes["default_value"]
16
+ end
17
+
18
+ # Type classification
19
+ def primitive_type?
20
+ type.is_a?(String) && PRIMITIVE_TYPES.include?(type)
21
+ end
22
+
23
+ def generic_type?
24
+ type.is_a?(Hash) && type.key?(:generic)
25
+ end
26
+
27
+ def user_type?
28
+ type.is_a?(String) && !primitive_type?
29
+ end
30
+
31
+ def list_type?
32
+ generic_type? && type[:generic] == "List"
33
+ end
34
+
35
+ def element_type
36
+ return nil unless list_type?
37
+
38
+ type[:element_type]
39
+ end
40
+
41
+ # Validation
42
+ def valid?
43
+ validate!
44
+ true
45
+ rescue ValidationError
46
+ false
47
+ end
48
+
49
+ def validate!
50
+ raise ValidationError, "Field name required" unless name
51
+ raise ValidationError, "Field ordinal required" unless ordinal
52
+ raise ValidationError, "Field type required" unless type
53
+
54
+ if ordinal.to_i.negative?
55
+ raise ValidationError,
56
+ "Ordinal must be non-negative"
57
+ end
58
+
59
+ true
60
+ end
61
+
62
+ def to_h
63
+ {
64
+ name: name,
65
+ ordinal: ordinal,
66
+ type: type,
67
+ default_value: default_value,
68
+ }
69
+ end
70
+
71
+ PRIMITIVE_TYPES = %w[
72
+ Void Bool
73
+ Int8 Int16 Int32 Int64
74
+ UInt8 UInt16 UInt32 UInt64
75
+ Float32 Float64
76
+ AnyPointer
77
+ ].freeze
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Unibuf
4
+ module Models
5
+ module Capnproto
6
+ # Represents a Cap'n Proto interface definition (for RPC)
7
+ class InterfaceDefinition
8
+ attr_reader :name, :methods, :annotations
9
+
10
+ def initialize(attributes = {})
11
+ @name = attributes[:name] || attributes["name"]
12
+ @methods = Array(attributes[:methods] || attributes["methods"])
13
+ @annotations = Array(
14
+ attributes[:annotations] || attributes["annotations"],
15
+ )
16
+ end
17
+
18
+ # Queries
19
+ def find_method(name)
20
+ methods.find { |m| m.name == name }
21
+ end
22
+
23
+ def method_names
24
+ methods.map(&:name)
25
+ end
26
+
27
+ def ordinals
28
+ methods.map(&:ordinal)
29
+ end
30
+
31
+ # Validation
32
+ def valid?
33
+ validate!
34
+ true
35
+ rescue ValidationError
36
+ false
37
+ end
38
+
39
+ def validate!
40
+ raise ValidationError, "Interface name required" unless name
41
+
42
+ if methods.empty?
43
+ raise ValidationError,
44
+ "Interface must have at least one method"
45
+ end
46
+
47
+ # Check for duplicate ordinals
48
+ ordinal_counts = ordinals.tally
49
+ duplicates = ordinal_counts.select { |_ord, count| count > 1 }
50
+ unless duplicates.empty?
51
+ raise ValidationError,
52
+ "Duplicate ordinals in interface '#{name}': #{duplicates.keys.join(', ')}"
53
+ end
54
+
55
+ methods.each(&:validate!)
56
+
57
+ true
58
+ end
59
+
60
+ def to_h
61
+ {
62
+ name: name,
63
+ methods: methods.map(&:to_h),
64
+ annotations: annotations,
65
+ }
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Unibuf
4
+ module Models
5
+ module Capnproto
6
+ # Represents a Cap'n Proto method definition (RPC)
7
+ class MethodDefinition
8
+ attr_reader :name, :ordinal, :params, :results
9
+
10
+ def initialize(attributes = {})
11
+ @name = attributes[:name] || attributes["name"]
12
+ @ordinal = attributes[:ordinal] || attributes["ordinal"]
13
+ @params = Array(attributes[:params] || attributes["params"])
14
+ @results = Array(attributes[:results] || attributes["results"])
15
+ end
16
+
17
+ # Queries
18
+ def param_names
19
+ params.map { |p| p[:name] }
20
+ end
21
+
22
+ def result_names
23
+ results.map { |r| r[:name] }
24
+ end
25
+
26
+ def find_param(name)
27
+ params.find { |p| p[:name] == name }
28
+ end
29
+
30
+ def find_result(name)
31
+ results.find { |r| r[:name] == name }
32
+ end
33
+
34
+ # Validation
35
+ def valid?
36
+ validate!
37
+ true
38
+ rescue ValidationError
39
+ false
40
+ end
41
+
42
+ def validate!
43
+ raise ValidationError, "Method name required" unless name
44
+ raise ValidationError, "Method ordinal required" unless ordinal
45
+
46
+ if ordinal.to_i.negative?
47
+ raise ValidationError,
48
+ "Ordinal must be non-negative"
49
+ end
50
+
51
+ # Validate params
52
+ params.each do |param|
53
+ unless param[:name] && param[:type]
54
+ raise ValidationError,
55
+ "Method parameter must have name and type"
56
+ end
57
+ end
58
+
59
+ # Validate results
60
+ results.each do |result|
61
+ unless result[:name] && result[:type]
62
+ raise ValidationError,
63
+ "Method result must have name and type"
64
+ end
65
+ end
66
+
67
+ true
68
+ end
69
+
70
+ def to_h
71
+ {
72
+ name: name,
73
+ ordinal: ordinal,
74
+ params: params,
75
+ results: results,
76
+ }
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Unibuf
4
+ module Models
5
+ module Capnproto
6
+ # Represents a Cap'n Proto schema (.capnp file)
7
+ class Schema
8
+ attr_reader :file_id, :usings, :structs, :enums, :interfaces,
9
+ :constants
10
+
11
+ def initialize(attributes = {})
12
+ @file_id = attributes[:file_id] || attributes["file_id"]
13
+ @usings = Array(attributes[:usings] || attributes["usings"])
14
+ @structs = Array(attributes[:structs] || attributes["structs"])
15
+ @enums = Array(attributes[:enums] || attributes["enums"])
16
+ @interfaces = Array(
17
+ attributes[:interfaces] || attributes["interfaces"],
18
+ )
19
+ @constants = Array(
20
+ attributes[:constants] || attributes["constants"],
21
+ )
22
+ end
23
+
24
+ # Queries
25
+ def find_struct(name)
26
+ structs.find { |s| s.name == name }
27
+ end
28
+
29
+ def find_enum(name)
30
+ enums.find { |e| e.name == name }
31
+ end
32
+
33
+ def find_interface(name)
34
+ interfaces.find { |i| i.name == name }
35
+ end
36
+
37
+ def find_type(name)
38
+ find_struct(name) || find_enum(name) || find_interface(name)
39
+ end
40
+
41
+ def struct_names
42
+ structs.map(&:name)
43
+ end
44
+
45
+ def enum_names
46
+ enums.map(&:name)
47
+ end
48
+
49
+ def interface_names
50
+ interfaces.map(&:name)
51
+ end
52
+
53
+ # Validation
54
+ def valid?
55
+ validate!
56
+ true
57
+ rescue ValidationError
58
+ false
59
+ end
60
+
61
+ def validate!
62
+ raise ValidationError, "File ID required" unless file_id
63
+
64
+ structs.each(&:validate!)
65
+ enums.each(&:validate!)
66
+ interfaces.each(&:validate!)
67
+
68
+ true
69
+ end
70
+
71
+ def to_h
72
+ {
73
+ file_id: file_id,
74
+ usings: usings,
75
+ structs: structs.map(&:to_h),
76
+ enums: enums.map(&:to_h),
77
+ interfaces: interfaces.map(&:to_h),
78
+ constants: constants,
79
+ }
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,96 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Unibuf
4
+ module Models
5
+ module Capnproto
6
+ # Represents a Cap'n Proto struct definition
7
+ class StructDefinition
8
+ attr_reader :name, :fields, :unions, :groups, :nested_structs,
9
+ :nested_enums, :nested_interfaces, :annotations
10
+
11
+ def initialize(attributes = {})
12
+ @name = attributes[:name] || attributes["name"]
13
+ @fields = Array(attributes[:fields] || attributes["fields"])
14
+ @unions = Array(attributes[:unions] || attributes["unions"])
15
+ @groups = Array(attributes[:groups] || attributes["groups"])
16
+ @nested_structs = Array(
17
+ attributes[:nested_structs] || attributes["nested_structs"],
18
+ )
19
+ @nested_enums = Array(
20
+ attributes[:nested_enums] || attributes["nested_enums"],
21
+ )
22
+ @nested_interfaces = Array(
23
+ attributes[:nested_interfaces] || attributes["nested_interfaces"],
24
+ )
25
+ @annotations = Array(
26
+ attributes[:annotations] || attributes["annotations"],
27
+ )
28
+ end
29
+
30
+ # Queries
31
+ def find_field(name)
32
+ fields.find { |f| f.name == name }
33
+ end
34
+
35
+ def find_union(name)
36
+ unions.find { |u| u.name == name }
37
+ end
38
+
39
+ def field_names
40
+ fields.map(&:name)
41
+ end
42
+
43
+ def ordinals
44
+ fields.map(&:ordinal)
45
+ end
46
+
47
+ def max_ordinal
48
+ ordinals.max || -1
49
+ end
50
+
51
+ # Validation
52
+ def valid?
53
+ validate!
54
+ true
55
+ rescue ValidationError
56
+ false
57
+ end
58
+
59
+ def validate!
60
+ raise ValidationError, "Struct name required" unless name
61
+
62
+ if fields.empty? && unions.empty?
63
+ raise ValidationError,
64
+ "Struct must have at least one field"
65
+ end
66
+
67
+ # Check for duplicate ordinals
68
+ ordinal_counts = ordinals.tally
69
+ duplicates = ordinal_counts.select { |_ord, count| count > 1 }
70
+ unless duplicates.empty?
71
+ raise ValidationError,
72
+ "Duplicate ordinals in struct '#{name}': #{duplicates.keys.join(', ')}"
73
+ end
74
+
75
+ fields.each(&:validate!)
76
+ unions.each(&:validate!)
77
+
78
+ true
79
+ end
80
+
81
+ def to_h
82
+ {
83
+ name: name,
84
+ fields: fields.map(&:to_h),
85
+ unions: unions.map(&:to_h),
86
+ groups: groups.map(&:to_h),
87
+ nested_structs: nested_structs.map(&:to_h),
88
+ nested_enums: nested_enums.map(&:to_h),
89
+ nested_interfaces: nested_interfaces.map(&:to_h),
90
+ annotations: annotations,
91
+ }
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Unibuf
4
+ module Models
5
+ module Capnproto
6
+ # Represents a Cap'n Proto union definition (discriminated union)
7
+ class UnionDefinition
8
+ attr_reader :fields
9
+
10
+ def initialize(attributes = {})
11
+ @fields = Array(attributes[:fields] || attributes["fields"])
12
+ end
13
+
14
+ # Queries
15
+ def field_names
16
+ fields.map(&:name)
17
+ end
18
+
19
+ def ordinals
20
+ fields.map(&:ordinal)
21
+ end
22
+
23
+ def find_field(name)
24
+ fields.find { |f| f.name == name }
25
+ end
26
+
27
+ # Validation
28
+ def valid?
29
+ validate!
30
+ true
31
+ rescue ValidationError
32
+ false
33
+ end
34
+
35
+ def validate!
36
+ if fields.length < 2
37
+ raise ValidationError,
38
+ "Union must have at least two fields"
39
+ end
40
+
41
+ # Check for duplicate ordinals
42
+ ordinal_counts = ordinals.tally
43
+ duplicates = ordinal_counts.select { |_ord, count| count > 1 }
44
+ unless duplicates.empty?
45
+ raise ValidationError,
46
+ "Duplicate ordinals in union: #{duplicates.keys.join(', ')}"
47
+ end
48
+
49
+ fields.each(&:validate!)
50
+
51
+ true
52
+ end
53
+
54
+ def to_h
55
+ {
56
+ fields: fields.map(&:to_h),
57
+ }
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Unibuf
4
+ module Models
5
+ module Flatbuffers
6
+ # Represents a FlatBuffers enum definition
7
+ class EnumDefinition
8
+ attr_reader :name, :type, :values, :metadata
9
+
10
+ def initialize(attributes = {})
11
+ @name = attributes[:name] || attributes["name"]
12
+ @type = attributes[:type] || attributes["type"] || "int"
13
+ @values = attributes[:values] || attributes["values"] || {}
14
+ @metadata = attributes[:metadata] || attributes["metadata"] || {}
15
+ end
16
+
17
+ # Queries
18
+ def find_value_by_name(value_name)
19
+ values[value_name]
20
+ end
21
+
22
+ def find_name_by_value(value)
23
+ values.key(value)
24
+ end
25
+
26
+ def value_names
27
+ values.keys
28
+ end
29
+
30
+ def value_numbers
31
+ values.values
32
+ end
33
+
34
+ # Validation
35
+ def valid?
36
+ validate!
37
+ true
38
+ rescue ValidationError
39
+ false
40
+ end
41
+
42
+ def validate!
43
+ raise ValidationError, "Enum name required" unless name
44
+
45
+ if values.empty?
46
+ raise ValidationError,
47
+ "Enum must have at least one value"
48
+ end
49
+
50
+ # Check for duplicate values
51
+ if values.values.uniq.size != values.values.size
52
+ raise ValidationError, "Enum '#{name}' has duplicate values"
53
+ end
54
+
55
+ true
56
+ end
57
+
58
+ def to_h
59
+ {
60
+ name: name,
61
+ type: type,
62
+ values: values,
63
+ metadata: metadata,
64
+ }
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,88 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Unibuf
4
+ module Models
5
+ module Flatbuffers
6
+ # Represents a field in a FlatBuffers table or struct
7
+ class FieldDefinition
8
+ attr_reader :name, :type, :default_value, :metadata
9
+
10
+ def initialize(attributes = {})
11
+ @name = attributes[:name] || attributes["name"]
12
+ @type = attributes[:type] || attributes["type"]
13
+ @default_value = attributes[:default_value] || attributes["default_value"]
14
+ @metadata = attributes[:metadata] || attributes["metadata"] || {}
15
+ end
16
+
17
+ # Type classification
18
+ def scalar?
19
+ SCALAR_TYPES.include?(type)
20
+ end
21
+
22
+ def vector?
23
+ type.is_a?(Hash) && type[:vector]
24
+ end
25
+
26
+ def user_type?
27
+ !scalar? && !vector?
28
+ end
29
+
30
+ def type_kind
31
+ return :vector if vector?
32
+ return :scalar if scalar?
33
+
34
+ # Assume user type (table, struct, enum)
35
+ :table
36
+ end
37
+
38
+ def vector_element_type
39
+ return nil unless vector?
40
+
41
+ type[:vector]
42
+ end
43
+
44
+ # Metadata queries
45
+ def deprecated?
46
+ metadata[:deprecated] == true
47
+ end
48
+
49
+ def required?
50
+ metadata[:required] == true
51
+ end
52
+
53
+ def id
54
+ metadata[:id]
55
+ end
56
+
57
+ # Validation
58
+ def valid?
59
+ validate!
60
+ true
61
+ rescue ValidationError
62
+ false
63
+ end
64
+
65
+ def validate!
66
+ raise ValidationError, "Field name required" unless name
67
+ raise ValidationError, "Field type required" unless type
68
+
69
+ true
70
+ end
71
+
72
+ def to_h
73
+ {
74
+ name: name,
75
+ type: type,
76
+ default_value: default_value,
77
+ metadata: metadata,
78
+ }.compact
79
+ end
80
+
81
+ SCALAR_TYPES = %w[
82
+ byte ubyte short ushort int uint long ulong
83
+ float double bool
84
+ ].freeze
85
+ end
86
+ end
87
+ end
88
+ end