protostar 0.1.0.beta1

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 (223) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +60 -0
  3. data/LICENSE.txt +21 -0
  4. data/README.md +647 -0
  5. data/THIRD_PARTY_NOTICES.md +61 -0
  6. data/exe/protoc-gen-protostar +7 -0
  7. data/exe/protostar +7 -0
  8. data/lib/protostar/builder/generator.rb +71 -0
  9. data/lib/protostar/builder/sink.rb +35 -0
  10. data/lib/protostar/builder.rb +965 -0
  11. data/lib/protostar/cli.rb +267 -0
  12. data/lib/protostar/codec/decode_generator.rb +199 -0
  13. data/lib/protostar/codec/decoder.rb +296 -0
  14. data/lib/protostar/codec/encode_generator.rb +224 -0
  15. data/lib/protostar/codec/encoder.rb +121 -0
  16. data/lib/protostar/codec/sizer.rb +91 -0
  17. data/lib/protostar/codec.rb +15 -0
  18. data/lib/protostar/compiler/ast.rb +193 -0
  19. data/lib/protostar/compiler/emitters/descriptor_set.rb +57 -0
  20. data/lib/protostar/compiler/emitters/google_ruby.rb +103 -0
  21. data/lib/protostar/compiler/emitters/grpc.rb +175 -0
  22. data/lib/protostar/compiler/emitters/protostar_rbs.rb +252 -0
  23. data/lib/protostar/compiler/emitters/rbs.rb +394 -0
  24. data/lib/protostar/compiler/emitters/ruby.rb +503 -0
  25. data/lib/protostar/compiler/emitters.rb +268 -0
  26. data/lib/protostar/compiler/include/LICENSE +32 -0
  27. data/lib/protostar/compiler/include/google/protobuf/any.proto +106 -0
  28. data/lib/protostar/compiler/include/google/protobuf/api.proto +229 -0
  29. data/lib/protostar/compiler/include/google/protobuf/compiler/plugin.proto +180 -0
  30. data/lib/protostar/compiler/include/google/protobuf/cpp_features.proto +87 -0
  31. data/lib/protostar/compiler/include/google/protobuf/descriptor.proto +1532 -0
  32. data/lib/protostar/compiler/include/google/protobuf/duration.proto +115 -0
  33. data/lib/protostar/compiler/include/google/protobuf/empty.proto +51 -0
  34. data/lib/protostar/compiler/include/google/protobuf/field_mask.proto +243 -0
  35. data/lib/protostar/compiler/include/google/protobuf/java_features.proto +132 -0
  36. data/lib/protostar/compiler/include/google/protobuf/source_context.proto +48 -0
  37. data/lib/protostar/compiler/include/google/protobuf/struct.proto +111 -0
  38. data/lib/protostar/compiler/include/google/protobuf/timestamp.proto +145 -0
  39. data/lib/protostar/compiler/include/google/protobuf/type.proto +217 -0
  40. data/lib/protostar/compiler/include/google/protobuf/wrappers.proto +157 -0
  41. data/lib/protostar/compiler/lexer.rb +659 -0
  42. data/lib/protostar/compiler/linker.rb +894 -0
  43. data/lib/protostar/compiler/option_interpreter.rb +363 -0
  44. data/lib/protostar/compiler/parser.rb +1696 -0
  45. data/lib/protostar/compiler/retention.rb +104 -0
  46. data/lib/protostar/compiler/run.rb +184 -0
  47. data/lib/protostar/compiler/source_info.rb +161 -0
  48. data/lib/protostar/compiler/symbol_table.rb +223 -0
  49. data/lib/protostar/compiler/text_format.rb +340 -0
  50. data/lib/protostar/compiler/validator.rb +944 -0
  51. data/lib/protostar/compiler.rb +304 -0
  52. data/lib/protostar/diagnostics/codes.rb +1307 -0
  53. data/lib/protostar/diagnostics/formats.rb +64 -0
  54. data/lib/protostar/diagnostics/renderer.rb +240 -0
  55. data/lib/protostar/diagnostics/source.rb +153 -0
  56. data/lib/protostar/diagnostics.rb +117 -0
  57. data/lib/protostar/dsl.rb +367 -0
  58. data/lib/protostar/enum.rb +70 -0
  59. data/lib/protostar/errors.rb +23 -0
  60. data/lib/protostar/google/protobuf/any_pb.rb +90 -0
  61. data/lib/protostar/google/protobuf/api_pb.rb +199 -0
  62. data/lib/protostar/google/protobuf/compiler/plugin_pb.rb +168 -0
  63. data/lib/protostar/google/protobuf/descriptor_pb.rb +1239 -0
  64. data/lib/protostar/google/protobuf/duration_pb.rb +99 -0
  65. data/lib/protostar/google/protobuf/empty_pb.rb +36 -0
  66. data/lib/protostar/google/protobuf/field_mask_pb.rb +228 -0
  67. data/lib/protostar/google/protobuf/source_context_pb.rb +33 -0
  68. data/lib/protostar/google/protobuf/struct_pb.rb +91 -0
  69. data/lib/protostar/google/protobuf/timestamp_pb.rb +129 -0
  70. data/lib/protostar/google/protobuf/type_pb.rb +202 -0
  71. data/lib/protostar/google/protobuf/wrappers_pb.rb +125 -0
  72. data/lib/protostar/google_protobuf_shim.rb +24 -0
  73. data/lib/protostar/json/encoder.rb +340 -0
  74. data/lib/protostar/json/errors.rb +34 -0
  75. data/lib/protostar/json/parser.rb +437 -0
  76. data/lib/protostar/json/path.rb +39 -0
  77. data/lib/protostar/json.rb +95 -0
  78. data/lib/protostar/lint/command.rb +197 -0
  79. data/lib/protostar/lint/config.rb +98 -0
  80. data/lib/protostar/lint/context.rb +126 -0
  81. data/lib/protostar/lint/directives.rb +56 -0
  82. data/lib/protostar/lint/fixer.rb +165 -0
  83. data/lib/protostar/lint/naming.rb +54 -0
  84. data/lib/protostar/lint/rule.rb +120 -0
  85. data/lib/protostar/lint/rules/comment_enum.rb +31 -0
  86. data/lib/protostar/lint/rules/comment_enum_value.rb +32 -0
  87. data/lib/protostar/lint/rules/comment_field.rb +33 -0
  88. data/lib/protostar/lint/rules/comment_message.rb +31 -0
  89. data/lib/protostar/lint/rules/comment_rpc.rb +31 -0
  90. data/lib/protostar/lint/rules/comment_service.rb +31 -0
  91. data/lib/protostar/lint/rules/edition_recommended.rb +31 -0
  92. data/lib/protostar/lint/rules/enum_first_value_zero.rb +34 -0
  93. data/lib/protostar/lint/rules/enum_pascal_case.rb +25 -0
  94. data/lib/protostar/lint/rules/enum_value_prefix.rb +38 -0
  95. data/lib/protostar/lint/rules/enum_value_upper_snake_case.rb +28 -0
  96. data/lib/protostar/lint/rules/enum_zero_value_suffix.rb +41 -0
  97. data/lib/protostar/lint/rules/field_lower_snake_case.rb +34 -0
  98. data/lib/protostar/lint/rules/field_not_required.rb +39 -0
  99. data/lib/protostar/lint/rules/field_number_reuse_risk.rb +45 -0
  100. data/lib/protostar/lint/rules/field_numbers_hot_range.rb +44 -0
  101. data/lib/protostar/lint/rules/file_lower_snake_case.rb +27 -0
  102. data/lib/protostar/lint/rules/import_no_public.rb +29 -0
  103. data/lib/protostar/lint/rules/import_no_weak.rb +28 -0
  104. data/lib/protostar/lint/rules/import_used.rb +33 -0
  105. data/lib/protostar/lint/rules/message_pascal_case.rb +27 -0
  106. data/lib/protostar/lint/rules/no_deprecated_features.rb +50 -0
  107. data/lib/protostar/lint/rules/no_groups.rb +34 -0
  108. data/lib/protostar/lint/rules/oneof_lower_snake_case.rb +27 -0
  109. data/lib/protostar/lint/rules/package_defined.rb +28 -0
  110. data/lib/protostar/lint/rules/package_directory_match.rb +33 -0
  111. data/lib/protostar/lint/rules/package_lower_snake_case.rb +28 -0
  112. data/lib/protostar/lint/rules/package_same_directory.rb +39 -0
  113. data/lib/protostar/lint/rules/package_version_suffix.rb +31 -0
  114. data/lib/protostar/lint/rules/reserved_names_with_numbers.rb +44 -0
  115. data/lib/protostar/lint/rules/rpc_pascal_case.rb +25 -0
  116. data/lib/protostar/lint/rules/rpc_request_response_unique.rb +40 -0
  117. data/lib/protostar/lint/rules/rpc_request_standard_name.rb +32 -0
  118. data/lib/protostar/lint/rules/rpc_response_standard_name.rb +31 -0
  119. data/lib/protostar/lint/rules/service_pascal_case.rb +25 -0
  120. data/lib/protostar/lint/rules/service_suffix.rb +28 -0
  121. data/lib/protostar/lint/rules/syntax_specified.rb +35 -0
  122. data/lib/protostar/lint/runner.rb +135 -0
  123. data/lib/protostar/lint.rb +122 -0
  124. data/lib/protostar/message/accessors.rb +86 -0
  125. data/lib/protostar/message/coercion.rb +171 -0
  126. data/lib/protostar/message/field_info.rb +145 -0
  127. data/lib/protostar/message/reflection.rb +149 -0
  128. data/lib/protostar/message.rb +572 -0
  129. data/lib/protostar/plugin.rb +94 -0
  130. data/lib/protostar/schema/default_value.rb +113 -0
  131. data/lib/protostar/schema/descriptor.rb +41 -0
  132. data/lib/protostar/schema/draft/copy.rb +88 -0
  133. data/lib/protostar/schema/draft/resolution.rb +177 -0
  134. data/lib/protostar/schema/draft.rb +779 -0
  135. data/lib/protostar/schema/enum.rb +106 -0
  136. data/lib/protostar/schema/extension_range.rb +37 -0
  137. data/lib/protostar/schema/features.rb +153 -0
  138. data/lib/protostar/schema/field.rb +201 -0
  139. data/lib/protostar/schema/file.rb +217 -0
  140. data/lib/protostar/schema/freezer.rb +61 -0
  141. data/lib/protostar/schema/message.rb +104 -0
  142. data/lib/protostar/schema/oneof.rb +38 -0
  143. data/lib/protostar/schema/options.rb +367 -0
  144. data/lib/protostar/schema/pool.rb +179 -0
  145. data/lib/protostar/schema/proto.rb +576 -0
  146. data/lib/protostar/schema/resolver.rb +118 -0
  147. data/lib/protostar/schema/service.rb +89 -0
  148. data/lib/protostar/schema/source_info.rb +53 -0
  149. data/lib/protostar/schema.rb +65 -0
  150. data/lib/protostar/short_names/any.rb +7 -0
  151. data/lib/protostar/short_names/duration.rb +7 -0
  152. data/lib/protostar/short_names/empty.rb +7 -0
  153. data/lib/protostar/short_names/field_mask.rb +7 -0
  154. data/lib/protostar/short_names/struct.rb +9 -0
  155. data/lib/protostar/short_names/timestamp.rb +7 -0
  156. data/lib/protostar/short_names/wrappers.rb +15 -0
  157. data/lib/protostar/text/extensions.rb +114 -0
  158. data/lib/protostar/text/parser.rb +439 -0
  159. data/lib/protostar/text/printer.rb +304 -0
  160. data/lib/protostar/text/tokenizer.rb +116 -0
  161. data/lib/protostar/text.rb +67 -0
  162. data/lib/protostar/types.rb +152 -0
  163. data/lib/protostar/unknown_field.rb +58 -0
  164. data/lib/protostar/version.rb +5 -0
  165. data/lib/protostar/view/generator.rb +298 -0
  166. data/lib/protostar/view/map.rb +194 -0
  167. data/lib/protostar/view/repeated.rb +143 -0
  168. data/lib/protostar/view/scan.rb +183 -0
  169. data/lib/protostar/view.rb +283 -0
  170. data/lib/protostar/well_known/any.rb +52 -0
  171. data/lib/protostar/well_known/duration.rb +53 -0
  172. data/lib/protostar/well_known/list_value.rb +63 -0
  173. data/lib/protostar/well_known/struct.rb +55 -0
  174. data/lib/protostar/well_known/timestamp.rb +64 -0
  175. data/lib/protostar/well_known/value.rb +60 -0
  176. data/lib/protostar/well_known.rb +38 -0
  177. data/lib/protostar/wire/io_source.rb +40 -0
  178. data/lib/protostar/wire/reader.rb +254 -0
  179. data/lib/protostar/wire/writer.rb +201 -0
  180. data/lib/protostar/wire.rb +96 -0
  181. data/lib/protostar.rb +95 -0
  182. data/shims/google-protobuf/lib/google/protobuf/any_pb.rb +17 -0
  183. data/shims/google-protobuf/lib/google/protobuf/api_pb.rb +22 -0
  184. data/shims/google-protobuf/lib/google/protobuf/compiler/plugin_pb.rb +25 -0
  185. data/shims/google-protobuf/lib/google/protobuf/descriptor_pb.rb +72 -0
  186. data/shims/google-protobuf/lib/google/protobuf/descriptor_pool.rb +164 -0
  187. data/shims/google-protobuf/lib/google/protobuf/descriptors.rb +553 -0
  188. data/shims/google-protobuf/lib/google/protobuf/duration_pb.rb +17 -0
  189. data/shims/google-protobuf/lib/google/protobuf/empty_pb.rb +17 -0
  190. data/shims/google-protobuf/lib/google/protobuf/field_mask_pb.rb +17 -0
  191. data/shims/google-protobuf/lib/google/protobuf/internal/convert.rb +180 -0
  192. data/shims/google-protobuf/lib/google/protobuf/internal/extensions.rb +154 -0
  193. data/shims/google-protobuf/lib/google/protobuf/internal/json.rb +104 -0
  194. data/shims/google-protobuf/lib/google/protobuf/internal/well_known.rb +140 -0
  195. data/shims/google-protobuf/lib/google/protobuf/map.rb +216 -0
  196. data/shims/google-protobuf/lib/google/protobuf/message.rb +544 -0
  197. data/shims/google-protobuf/lib/google/protobuf/message_exts.rb +41 -0
  198. data/shims/google-protobuf/lib/google/protobuf/plugin_pb.rb +4 -0
  199. data/shims/google-protobuf/lib/google/protobuf/repeated_field.rb +366 -0
  200. data/shims/google-protobuf/lib/google/protobuf/source_context_pb.rb +17 -0
  201. data/shims/google-protobuf/lib/google/protobuf/struct_pb.rb +20 -0
  202. data/shims/google-protobuf/lib/google/protobuf/timestamp_pb.rb +17 -0
  203. data/shims/google-protobuf/lib/google/protobuf/type_pb.rb +27 -0
  204. data/shims/google-protobuf/lib/google/protobuf/well_known_types.rb +37 -0
  205. data/shims/google-protobuf/lib/google/protobuf/wrappers_pb.rb +25 -0
  206. data/shims/google-protobuf/lib/google/protobuf.rb +107 -0
  207. data/shims/google-protobuf/lib/google/protobuf_ffi.rb +5 -0
  208. data/shims/google-protobuf/lib/google/protobuf_native.rb +5 -0
  209. data/sig/protostar/google/protobuf/any_pb.rbs +77 -0
  210. data/sig/protostar/google/protobuf/api_pb.rbs +242 -0
  211. data/sig/protostar/google/protobuf/compiler/plugin_pb.rbs +264 -0
  212. data/sig/protostar/google/protobuf/descriptor_pb.rbs +2220 -0
  213. data/sig/protostar/google/protobuf/duration_pb.rbs +82 -0
  214. data/sig/protostar/google/protobuf/empty_pb.rbs +18 -0
  215. data/sig/protostar/google/protobuf/field_mask_pb.rbs +170 -0
  216. data/sig/protostar/google/protobuf/source_context_pb.rbs +24 -0
  217. data/sig/protostar/google/protobuf/struct_pb.rbs +135 -0
  218. data/sig/protostar/google/protobuf/timestamp_pb.rbs +102 -0
  219. data/sig/protostar/google/protobuf/type_pb.rbs +304 -0
  220. data/sig/protostar/google/protobuf/wrappers_pb.rbs +169 -0
  221. data/sig/protostar/lint.rbs +216 -0
  222. data/sig/protostar.rbs +326 -0
  223. metadata +366 -0
@@ -0,0 +1,145 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Protostar
4
+ class Message
5
+ # Everything the runtime and the codec need about one field of a message
6
+ # class, resolved once when the class is defined: the slot it is stored
7
+ # in, its kind as a small Integer to dispatch on, precomputed tag bytes,
8
+ # the classes and enum tables it refers to. Frozen and shareable.
9
+ # @api private
10
+ class FieldInfo
11
+ # Kinds are FieldDescriptorProto.Type numbers
12
+ DOUBLE = 1
13
+ FLOAT = 2
14
+ INT64 = 3
15
+ UINT64 = 4
16
+ INT32 = 5
17
+ FIXED64 = 6
18
+ FIXED32 = 7
19
+ BOOL = 8
20
+ STRING = 9
21
+ GROUP = 10
22
+ MESSAGE = 11
23
+ BYTES = 12
24
+ UINT32 = 13
25
+ ENUM = 14
26
+ SFIXED32 = 15
27
+ SFIXED64 = 16
28
+ SINT32 = 17
29
+ SINT64 = 18
30
+
31
+ KINDS = {
32
+ double: DOUBLE, float: FLOAT, int64: INT64, uint64: UINT64, int32: INT32, fixed64: FIXED64,
33
+ fixed32: FIXED32, bool: BOOL, string: STRING, group: GROUP, message: MESSAGE, bytes: BYTES,
34
+ uint32: UINT32, enum: ENUM, sfixed32: SFIXED32, sfixed64: SFIXED64, sint32: SINT32, sint64: SINT64
35
+ }.freeze
36
+
37
+ # Byte width and unpack directive of the fixed-width kinds
38
+ FIXED = {
39
+ DOUBLE => [8, "E"], FLOAT => [4, "e"], FIXED64 => [8, "Q<"], FIXED32 => [4, "V"],
40
+ SFIXED32 => [4, "l<"], SFIXED64 => [8, "q<"]
41
+ }.transform_values(&:freeze).freeze
42
+
43
+ # @return [Schema::Field]
44
+ attr_reader :descriptor
45
+ # @return [String]
46
+ attr_reader :name
47
+ # @return [Symbol]
48
+ attr_reader :symbol
49
+ # @return [Integer]
50
+ attr_reader :number
51
+ # @return [Integer, nil] the slot in the message's value array; nil for map keys and values
52
+ attr_reader :index
53
+ # @return [Integer] one of the kind constants
54
+ attr_reader :kind
55
+ # @return [Integer] wire type of one unpacked value
56
+ attr_reader :wire_type
57
+ # @return [Boolean]
58
+ attr_reader :repeated, :packed, :packable, :presence, :map, :closed_enum, :utf8_validation, :required
59
+ # @return [Array<Integer>, nil] slots of the other members of the field's real oneof
60
+ attr_reader :siblings
61
+ # @return [Class, nil] for message and group fields
62
+ attr_reader :message_class
63
+ # @return [Module, nil] for enum fields
64
+ attr_reader :enum_module
65
+ # @return [Hash{Integer => Symbol}, nil] enum number to its first name
66
+ attr_reader :enum_names
67
+ # @return [Hash{Symbol => Integer}, nil] every enum name, aliases included, to its number
68
+ attr_reader :enum_numbers
69
+ # @return [Object] the value an unset field reads as
70
+ attr_reader :default
71
+ # @return [String] the tag of one unpacked value, varint-encoded
72
+ attr_reader :tag
73
+ # @return [String, nil] the length-delimited tag, for packable fields
74
+ attr_reader :packed_tag
75
+ # @return [String, nil] the end-group tag, for groups
76
+ attr_reader :end_tag
77
+ # @return [FieldInfo, nil] for map fields
78
+ attr_reader :key, :value
79
+
80
+ # @param field [Schema::Field]
81
+ # @param index [Integer, nil]
82
+ # @param classes [#call] resolves a Schema::Message or Schema::Enum to its Class or Module
83
+ # @param open_enums [Boolean] treat a closed enum as open
84
+ def initialize(field, index, classes, siblings: nil, open_enums: false)
85
+ @descriptor = field
86
+ @name = field.name
87
+ @symbol = field.name.to_sym
88
+ @number = field.number
89
+ @index = index
90
+ @kind = KINDS.fetch(field.type)
91
+ @wire_type = field.wire_type
92
+ @map = field.map?
93
+ @repeated = field.repeated? && !@map
94
+ @packed = field.packed?
95
+ @packable = field.packable?
96
+ @presence = field.presence?
97
+ @required = field.required?
98
+ @utf8_validation = field.utf8_validation?
99
+ @siblings = siblings
100
+ @tag = Wire.tag_bytes(@number, @wire_type)
101
+ @packed_tag = Wire.tag_bytes(@number, Wire::LENGTH_DELIMITED) if @packable
102
+ @end_tag = Wire.tag_bytes(@number, Wire::END_GROUP) if @kind == GROUP
103
+ if @map
104
+ @key = FieldInfo.new(field.map_key, nil, classes)
105
+ @value = FieldInfo.new(field.map_value, nil, classes, open_enums: open_enums)
106
+ elsif field.message_type
107
+ @message_class = classes.call(field.message_type)
108
+ end
109
+ if field.enum_type
110
+ @enum_module = classes.call(field.enum_type)
111
+ @enum_names = @enum_module.__names
112
+ @enum_numbers = @enum_module.__numbers
113
+ @closed_enum = !open_enums && field.enum_type.closed?
114
+ else
115
+ @closed_enum = false
116
+ end
117
+ @default = field.default unless @map || @repeated
118
+ # an enum default may name an alias; values are stored by their first name
119
+ @default = @enum_names[@enum_numbers.fetch(@default)] if @enum_names && @default
120
+ end
121
+
122
+ # @return [Boolean] whether the field is a message or group
123
+ def message?
124
+ @kind == MESSAGE || @kind == GROUP
125
+ end
126
+
127
+ # @return [Boolean] whether a singular value equals the type's zero
128
+ # value, so that a field without presence is left out on encode.
129
+ # Negative zero is not a default, as in protoc.
130
+ def zero?(value)
131
+ case @kind
132
+ when DOUBLE, FLOAT then value == 0 && (1.0 / value) > 0
133
+ when STRING, BYTES then value.empty?
134
+ when BOOL then value == false
135
+ when ENUM then (value.is_a?(Symbol) ? @enum_numbers[value] : value) == 0
136
+ else value == 0
137
+ end
138
+ end
139
+
140
+ def inspect
141
+ "#<#{self.class.name} #{@descriptor.full_name} slot=#{@index}>"
142
+ end
143
+ end
144
+ end
145
+ end
@@ -0,0 +1,149 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Protostar
4
+ class Message
5
+ # Reading and writing a message class's fields by descriptor, name or
6
+ # number rather than through the accessors, for code that walks messages
7
+ # it does not know in advance: serializers, builders, form mappers.
8
+ # Every message class has one, made when the class is defined, frozen and
9
+ # shareable:
10
+ #
11
+ # r = Acme::Person.reflection
12
+ # r.fields.map(&:name) # => ["name", "id", "emails", "address"]
13
+ # r.get(person, :name) # => "Ada"
14
+ # r.set(person, "id", 7)
15
+ # r.set?(person, :address) # => false
16
+ # r.message_class(:address) # => Acme::Address
17
+ # r.each(person) { |field, value| ... } # fields that are set, in declaration order
18
+ #
19
+ # It lives on the class (`Klass.reflection`), where no field accessor can
20
+ # take its name. Values go through the same coercion and checks as the
21
+ # accessors: `set(m, f, v)` is `m.f = v`, `get(m, f)` is `m.f`.
22
+ class Reflection
23
+ # @return [Class] the message class it reflects
24
+ attr_reader :klass
25
+ # @return [Schema::Message]
26
+ attr_reader :descriptor
27
+
28
+ # @api private
29
+ def initialize(klass, descriptor)
30
+ @klass = klass
31
+ @descriptor = descriptor
32
+ @by_number = klass.__by_number
33
+ @by_name = klass.__by_name
34
+ end
35
+
36
+ # @return [Array<Schema::Field>] in declaration order
37
+ def fields
38
+ @descriptor.fields
39
+ end
40
+
41
+ # @return [Array<Schema::Oneof>] real oneofs; a proto3 `optional` field's
42
+ # synthetic oneof is left out, as it is no choice
43
+ def oneofs
44
+ @descriptor.real_oneofs
45
+ end
46
+
47
+ # @param key [Schema::Field, String, Symbol, Integer] a field, its name or its number
48
+ # @return [Schema::Field, nil]
49
+ def field(key)
50
+ info(key)&.descriptor
51
+ end
52
+
53
+ # @param message [Message] an instance of the class
54
+ # @param key [Schema::Field, String, Symbol, Integer]
55
+ # @return [Object] what the field's reader returns
56
+ # @raise [ArgumentError] when there is no such field
57
+ def get(message, key)
58
+ message.__get(info!(key))
59
+ end
60
+
61
+ # @param message [Message]
62
+ # @param key [Schema::Field, String, Symbol, Integer]
63
+ # @param value [Object] nil clears the field
64
+ # @raise [ArgumentError] when there is no such field
65
+ # @raise [Protostar::TypeError] for a value the field cannot hold
66
+ def set(message, key, value)
67
+ message.__set(info!(key).index, value)
68
+ message
69
+ end
70
+
71
+ # @param message [Message]
72
+ # @param key [Schema::Field, String, Symbol, Integer]
73
+ # @return [Boolean] set, for a field with presence; not empty, for a
74
+ # repeated or map field; not its zero value, for any other
75
+ def set?(message, key)
76
+ info = info!(key)
77
+ v = message.__values[info.index]
78
+ return false if v.nil?
79
+ return !v.empty? if info.repeated || info.map
80
+ info.presence || !info.zero?(v)
81
+ end
82
+
83
+ # @param message [Message]
84
+ # @param key [Schema::Field, String, Symbol, Integer]
85
+ def clear(message, key)
86
+ message.__set(info!(key).index, nil)
87
+ message
88
+ end
89
+
90
+ # @param message [Message]
91
+ # @param oneof [Schema::Oneof, String, Symbol]
92
+ # @return [Schema::Field, nil] the member that is set
93
+ def which(message, oneof)
94
+ oneof = @descriptor.oneofs.find { |o| o.name == oneof.to_s } unless oneof.is_a?(Schema::Oneof)
95
+ raise ArgumentError, "#{@descriptor.full_name} has no oneof #{oneof.inspect}" unless oneof
96
+ oneof.fields.find { |f| !message.__values[@by_number.fetch(f.number).index].nil? }
97
+ end
98
+
99
+ # @param key [Schema::Field, String, Symbol, Integer] a message or group field,
100
+ # or a map field whose values are messages
101
+ # @return [Class, nil] the class its values are instances of
102
+ def message_class(key)
103
+ info = info!(key)
104
+ info.map ? info.value.message_class : info.message_class
105
+ end
106
+
107
+ # @param key [Schema::Field, String, Symbol, Integer] an enum field, or a map field of enum values
108
+ # @return [Module, nil] the enum's module
109
+ def enum_module(key)
110
+ info = info!(key)
111
+ info.map ? info.value.enum_module : info.enum_module
112
+ end
113
+
114
+ # Yields each field that is {#set?}, in declaration order
115
+ # @param message [Message]
116
+ # @yieldparam field [Schema::Field]
117
+ # @yieldparam value [Object] what the reader returns
118
+ # @return [Enumerator] without a block
119
+ def each(message)
120
+ return enum_for(:each, message) unless block_given?
121
+ @klass.__fields.each do |info|
122
+ next unless set?(message, info.descriptor)
123
+ yield info.descriptor, message.__get(info)
124
+ end
125
+ nil
126
+ end
127
+
128
+ def inspect
129
+ "#<#{self.class.name} #{@descriptor.full_name}>"
130
+ end
131
+
132
+ private
133
+
134
+ def info(key)
135
+ case key
136
+ when Integer then @by_number[key]
137
+ when Schema::Field
138
+ found = @by_number[key.number]
139
+ found if found&.descriptor.equal?(key)
140
+ else @by_name[key]
141
+ end
142
+ end
143
+
144
+ def info!(key)
145
+ info(key) || raise(ArgumentError, "#{@descriptor.full_name} has no field #{key.inspect}")
146
+ end
147
+ end
148
+ end
149
+ end