unibuf 0.1.0 → 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.
- checksums.yaml +4 -4
- data/.rubocop_todo.yml +178 -330
- data/CODE_OF_CONDUCT.md +132 -0
- data/README.adoc +443 -254
- data/docs/CAPNPROTO.adoc +436 -0
- data/docs/FLATBUFFERS.adoc +430 -0
- data/docs/PROTOBUF.adoc +515 -0
- data/docs/TXTPROTO.adoc +369 -0
- data/lib/unibuf/commands/convert.rb +60 -2
- data/lib/unibuf/commands/schema.rb +68 -11
- data/lib/unibuf/errors.rb +23 -26
- data/lib/unibuf/models/capnproto/enum_definition.rb +72 -0
- data/lib/unibuf/models/capnproto/field_definition.rb +81 -0
- data/lib/unibuf/models/capnproto/interface_definition.rb +70 -0
- data/lib/unibuf/models/capnproto/method_definition.rb +81 -0
- data/lib/unibuf/models/capnproto/schema.rb +84 -0
- data/lib/unibuf/models/capnproto/struct_definition.rb +96 -0
- data/lib/unibuf/models/capnproto/union_definition.rb +62 -0
- data/lib/unibuf/models/flatbuffers/enum_definition.rb +69 -0
- data/lib/unibuf/models/flatbuffers/field_definition.rb +88 -0
- data/lib/unibuf/models/flatbuffers/schema.rb +102 -0
- data/lib/unibuf/models/flatbuffers/struct_definition.rb +70 -0
- data/lib/unibuf/models/flatbuffers/table_definition.rb +73 -0
- data/lib/unibuf/models/flatbuffers/union_definition.rb +60 -0
- data/lib/unibuf/models/message.rb +10 -0
- data/lib/unibuf/models/values/scalar_value.rb +2 -2
- data/lib/unibuf/parsers/binary/wire_format_parser.rb +199 -19
- data/lib/unibuf/parsers/capnproto/binary_parser.rb +267 -0
- data/lib/unibuf/parsers/capnproto/grammar.rb +272 -0
- data/lib/unibuf/parsers/capnproto/list_reader.rb +208 -0
- data/lib/unibuf/parsers/capnproto/pointer_decoder.rb +163 -0
- data/lib/unibuf/parsers/capnproto/processor.rb +348 -0
- data/lib/unibuf/parsers/capnproto/segment_reader.rb +131 -0
- data/lib/unibuf/parsers/capnproto/struct_reader.rb +199 -0
- data/lib/unibuf/parsers/flatbuffers/binary_parser.rb +325 -0
- data/lib/unibuf/parsers/flatbuffers/grammar.rb +235 -0
- data/lib/unibuf/parsers/flatbuffers/processor.rb +299 -0
- data/lib/unibuf/parsers/textproto/grammar.rb +1 -1
- data/lib/unibuf/parsers/textproto/processor.rb +10 -0
- data/lib/unibuf/serializers/binary_serializer.rb +218 -0
- data/lib/unibuf/serializers/capnproto/binary_serializer.rb +402 -0
- data/lib/unibuf/serializers/capnproto/list_writer.rb +199 -0
- data/lib/unibuf/serializers/capnproto/pointer_encoder.rb +118 -0
- data/lib/unibuf/serializers/capnproto/segment_builder.rb +124 -0
- data/lib/unibuf/serializers/capnproto/struct_writer.rb +139 -0
- data/lib/unibuf/serializers/flatbuffers/binary_serializer.rb +167 -0
- data/lib/unibuf/validators/type_validator.rb +1 -1
- data/lib/unibuf/version.rb +1 -1
- data/lib/unibuf.rb +27 -0
- 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
|