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,367 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Protostar
4
+ # The runtime of generated `_pb.rb` files, also meant to be written by hand.
5
+ # A block describes one `.proto` file through {Schema::File.draft}; the
6
+ # file is resolved and frozen into {Protostar.generated_pool}, and its
7
+ # message classes and enum modules are defined.
8
+ #
9
+ # Protostar::DSL.file("acme/person.proto", package: "acme", syntax: :proto3) do |f|
10
+ # f.message "Person" do |m|
11
+ # m.field :name, 1, :string
12
+ # m.field :friends, 2, :message, ".acme.Person", label: :repeated
13
+ # m.oneof :contact do |o|
14
+ # o.field :email, 3, :string
15
+ # end
16
+ # m.map :attrs, 4, :string, :string
17
+ # end
18
+ # end
19
+ # module Acme
20
+ # Person = Protostar::DSL.message("acme.Person")
21
+ # end
22
+ #
23
+ # Every descriptor-level call takes the options of its descriptor as extra
24
+ # keywords: `deprecated: true`, `packed: false`, `features: {...}`, with
25
+ # custom options by extension full name under `extensions:` and fields
26
+ # nobody could interpret as wire bytes under `unknown_fields:`. An
27
+ # `options:` Hash is taken as the options message verbatim instead, in the
28
+ # same spelling, and is how an empty options message is written. Option
29
+ # values that are messages are Hashes in that spelling too; a field of
30
+ # such a message that is itself named `extensions` or `unknown_fields` is
31
+ # given with a String key.
32
+ #
33
+ # The earlier spellings, `__extensions:`, `__unknown_fields:` (as
34
+ # `[number, wire_type, bytes]` triples) and `visibility: :VISIBILITY_EXPORT`,
35
+ # are still read until 0.2.0, with a deprecation warning.
36
+ module DSL
37
+ # Raised for a call the DSL cannot turn into a descriptor
38
+ class Error < Protostar::Error; end
39
+
40
+ SYNTAXES = {proto2: :proto2, proto3: :proto3, editions: :editions}.freeze
41
+ LABELS = %i[optional required repeated].freeze
42
+ OLD_VISIBILITIES = {VISIBILITY_LOCAL: :local, VISIBILITY_EXPORT: :export}.freeze
43
+
44
+ class << self
45
+ # Describes, builds and defines one `.proto` file. Loading a file the pool
46
+ # already has is a no-op that returns the file there.
47
+ #
48
+ # @param name [String] the file name as imported, e.g. "acme/person.proto"
49
+ # @param package [String, nil]
50
+ # @param syntax [Symbol, String, nil] :proto2, :proto3 or :editions; omitted for proto2 as protoc does
51
+ # @param edition [Symbol, Integer, nil] e.g. :EDITION_2023 or 2023; implies `syntax: :editions`
52
+ # @param dependencies [Array<String>] imported file names, which must be loaded already
53
+ # @param public_dependencies [Array<String, Integer>] names (or indexes) of `import public` files
54
+ # @param weak_dependencies [Array<String, Integer>]
55
+ # @param option_dependencies [Array<String>] `import option` file names
56
+ # @param options [Hash, nil] the FileOptions verbatim
57
+ # @param pool [Schema::Pool] where the file is built and added
58
+ # @param registry [Types::Registry, nil] where classes are defined; nil builds the file only
59
+ # @param file_options [Hash] FileOptions fields as keywords, custom ones under `extensions:`
60
+ # @yieldparam f [FileBuilder]
61
+ # @return [Schema::File]
62
+ def file(name, package: nil, syntax: nil, edition: nil, dependencies: nil, public_dependencies: nil,
63
+ weak_dependencies: nil, option_dependencies: nil, options: nil, pool: Protostar.generated_pool,
64
+ registry: Types.registry, **file_options, &block)
65
+ existing = pool.file(name)
66
+ return existing if existing
67
+ draft = begin
68
+ Schema::File.draft(name, package: package, syntax: syntax(name, syntax), edition: edition(edition),
69
+ dependencies: Array(dependencies), public_dependencies: Array(public_dependencies),
70
+ weak_dependencies: Array(weak_dependencies), option_dependencies: Array(option_dependencies),
71
+ options: DSL.options(options, file_options))
72
+ rescue Schema::Error => e
73
+ raise Error, e.message
74
+ end
75
+ block&.call(FileBuilder.new(draft))
76
+ built = draft.resolve(pool).freeze!
77
+ pool.add(built)
78
+ registry&.define(built)
79
+ built
80
+ end
81
+
82
+ # @param full_name [String] e.g. "acme.Person"
83
+ # @return [Class] the message class defined for it
84
+ # @raise [Error] when no file defined it
85
+ def message(full_name, registry: Types.registry)
86
+ found = registry.find(full_name)
87
+ raise Error, "no message #{full_name} has been defined" unless found.is_a?(Class)
88
+ found
89
+ end
90
+
91
+ # @param full_name [String]
92
+ # @return [Module] the enum module defined for it
93
+ def enum(full_name, registry: Types.registry)
94
+ found = registry.find(full_name)
95
+ raise Error, "no enum #{full_name} has been defined" unless found.is_a?(Module) && !found.is_a?(Class)
96
+ found
97
+ end
98
+
99
+ # A Module standing for a service, which gRPC stubs reopen to add
100
+ # `Service` and `Stub`
101
+ # @param full_name [String]
102
+ # @return [Module] answering `descriptor` with the {Schema::Service}
103
+ def service(full_name, pool: Protostar.generated_pool)
104
+ descriptor = pool.find_service(full_name) || raise(Error, "no service #{full_name} has been defined")
105
+ mod = Module.new
106
+ mod.instance_variable_set(:@descriptor, descriptor)
107
+ mod.extend(ServiceModule)
108
+ mod
109
+ end
110
+
111
+ # Options given as keywords merged into a verbatim options Hash
112
+ # @api private
113
+ def options(verbatim, keywords)
114
+ return verbatim if keywords.empty?
115
+ out = verbatim ? verbatim.dup : {}
116
+ keywords.each do |key, value|
117
+ if key == :extensions
118
+ out[:extensions] = (out[:extensions] || {}).merge(value)
119
+ else
120
+ out[key] = value
121
+ end
122
+ end
123
+ out
124
+ end
125
+
126
+ # :local or :export; the deprecated protoc spellings are read with a warning
127
+ # @api private
128
+ def visibility(value)
129
+ replacement = OLD_VISIBILITIES[value]
130
+ return value unless replacement
131
+ Protostar.deprecated("visibility: #{value.inspect}", "visibility: #{replacement.inspect}")
132
+ replacement
133
+ end
134
+
135
+ # protoc's name for the entry message of a map field
136
+ # @param field_name [String]
137
+ # @return [String]
138
+ def map_entry_name(field_name)
139
+ Schema::Draft.map_entry_name(field_name)
140
+ end
141
+
142
+ # A field type as the draft spells it: a short type Symbol, or a type name
143
+ # @api private
144
+ def type(type)
145
+ return type if type.is_a?(String)
146
+ type = type.to_sym
147
+ type = Schema::Field::TYPES.fetch(type, type)
148
+ raise Error, "unknown field type #{type.inspect}" unless Schema::Field::TYPES.value?(type)
149
+ type
150
+ end
151
+
152
+ # @api private
153
+ def label(label)
154
+ return :optional if label.nil?
155
+ label = label.to_sym
156
+ label = Schema::Field::LABELS.fetch(label, label)
157
+ raise Error, "unknown label #{label.inspect}" unless LABELS.include?(label)
158
+ label
159
+ end
160
+
161
+ private
162
+
163
+ def syntax(name, syntax)
164
+ return nil if syntax.nil?
165
+ SYNTAXES.fetch(syntax.to_sym) { raise Error, "#{name}: unknown syntax #{syntax.inspect}" }
166
+ end
167
+
168
+ def edition(edition)
169
+ return edition unless edition.is_a?(Integer)
170
+ Schema::Features::EDITION_NAMES.fetch(edition) { :"EDITION_#{edition}" }
171
+ end
172
+ end
173
+
174
+ # Extended by the Modules {DSL.service} returns
175
+ module ServiceModule
176
+ # @return [Schema::Service]
177
+ attr_reader :descriptor
178
+ end
179
+
180
+ # Common to every scope that holds messages, enums and extensions
181
+ # @api private
182
+ class Scope
183
+ def initialize(draft)
184
+ @draft = draft
185
+ end
186
+
187
+ # A nested (or top-level) message
188
+ # @param name [String]
189
+ # @param visibility [Symbol, nil] :local or :export (edition 2024)
190
+ # @param options [Hash, nil] MessageOptions verbatim
191
+ # @yieldparam m [MessageBuilder]
192
+ def message(name, visibility: nil, options: nil, **message_options, &block)
193
+ visibility = DSL.visibility(visibility)
194
+ @draft.message(name, visibility: visibility, options: DSL.options(options, message_options)) do |m|
195
+ block&.call(MessageBuilder.new(m))
196
+ end
197
+ end
198
+
199
+ # An enum
200
+ # @yieldparam e [EnumBuilder]
201
+ def enum(name, visibility: nil, options: nil, **enum_options, &block)
202
+ visibility = DSL.visibility(visibility)
203
+ @draft.enum(name, visibility: visibility, options: DSL.options(options, enum_options)) do |e|
204
+ block&.call(EnumBuilder.new(e))
205
+ end
206
+ end
207
+
208
+ # Extensions of another message declared in this scope
209
+ # @param extendee [String] the extended message, e.g. ".acme.Base"
210
+ # @yieldparam e [ExtendBuilder]
211
+ def extend(extendee, &block)
212
+ block.call(ExtendBuilder.new(@draft, extendee.to_s))
213
+ self
214
+ end
215
+ end
216
+
217
+ # The block argument of {DSL.file}
218
+ class FileBuilder < Scope
219
+ # @param name [String]
220
+ # @yieldparam s [ServiceBuilder]
221
+ def service(name, options: nil, **service_options, &block)
222
+ @draft.service(name, options: DSL.options(options, service_options)) do |s|
223
+ block&.call(ServiceBuilder.new(s))
224
+ end
225
+ end
226
+ end
227
+
228
+ # The block argument of {Scope#message}
229
+ class MessageBuilder < Scope
230
+ # A field
231
+ # @param name [Symbol, String]
232
+ # @param number [Integer]
233
+ # @param type [Symbol, String] :int32, :string, :message, :enum, :group, ...; a String is taken as
234
+ # the type name of a message or enum, its kind looked up when the file is built
235
+ # @param type_name [String, nil] the message or enum type, e.g. ".acme.Person"
236
+ # @param label [Symbol, nil] :optional (the default), :required or :repeated
237
+ # @param default [Object, nil] the default as protoc stores it: text, C-escaped for bytes
238
+ # @param json_name [String, nil] when not the one derived from the name
239
+ # @param proto3_optional [Boolean] a proto3 `optional` field; its synthetic oneof is made for it
240
+ # @param oneof [Symbol, String, nil] the oneof the field belongs to
241
+ # @param options [Hash, nil] FieldOptions verbatim
242
+ def field(name, number, type, type_name = nil, label: nil, default: nil, json_name: nil, proto3_optional: nil,
243
+ oneof: nil, options: nil, **field_options)
244
+ @draft.field(name, number, DSL.type(type), type_name, label: DSL.label(label), default: default,
245
+ json_name: json_name, optional: proto3_optional ? true : false, oneof: oneof,
246
+ options: DSL.options(options, field_options))
247
+ end
248
+
249
+ # A `map<K, V>` field and its synthesized entry message
250
+ # @param key_type [Symbol]
251
+ # @param value_type [Symbol, String] a scalar type, :message or :enum (then give `value_type_name`),
252
+ # or the value's type name
253
+ def map(name, number, key_type, value_type, value_type_name = nil, json_name: nil, options: nil, **field_options)
254
+ value = value_type.is_a?(String) ? value_type : DSL.type(value_type)
255
+ @draft.map(name, number, key: DSL.type(key_type), value: value, value_type_name: value_type_name,
256
+ json_name: json_name, options: DSL.options(options, field_options))
257
+ end
258
+
259
+ # A proto2 group: a field of type group and its nested message, named as
260
+ # in `group Name = number { ... }`
261
+ # @yieldparam g [MessageBuilder]
262
+ def group(name, number, label: nil, json_name: nil, oneof: nil, options: nil, message_options: nil,
263
+ **field_options, &block)
264
+ @draft.group(name, number, label: DSL.label(label), json_name: json_name, oneof: oneof,
265
+ options: DSL.options(options, field_options), message_options: message_options) do |g|
266
+ block&.call(MessageBuilder.new(g))
267
+ end
268
+ end
269
+
270
+ # A oneof. Fields given in the block belong to it; fields elsewhere may
271
+ # name it with `oneof:`.
272
+ # @yieldparam o [OneofBuilder]
273
+ def oneof(name, options: nil, **oneof_options, &block)
274
+ @draft.oneof(name.to_s, options: DSL.options(options, oneof_options))
275
+ block&.call(OneofBuilder.new(self, name))
276
+ end
277
+
278
+ # Extension ranges, inclusive
279
+ # @param ranges [Array<Range, Integer>]
280
+ def extensions(*ranges, options: nil, **range_options)
281
+ @draft.extensions(*ranges, options: DSL.options(options, range_options))
282
+ self
283
+ end
284
+
285
+ # Reserved numbers (Integers or inclusive Ranges) and names (Strings)
286
+ def reserved(*items)
287
+ @draft.reserved(*items)
288
+ self
289
+ end
290
+ end
291
+
292
+ # The block argument of {MessageBuilder#oneof}
293
+ class OneofBuilder
294
+ # @api private
295
+ def initialize(message, name)
296
+ @message = message
297
+ @name = name
298
+ end
299
+
300
+ # A member field; same arguments as {MessageBuilder#field}
301
+ def field(name, number, type, type_name = nil, **kwargs)
302
+ @message.field(name, number, type, type_name, oneof: @name, **kwargs)
303
+ end
304
+
305
+ # A member group; same arguments as {MessageBuilder#group}
306
+ def group(name, number, **kwargs, &block)
307
+ @message.group(name, number, oneof: @name, **kwargs, &block)
308
+ end
309
+ end
310
+
311
+ # The block argument of {Scope#extend}
312
+ class ExtendBuilder
313
+ # @api private
314
+ def initialize(draft, extendee)
315
+ @draft = draft
316
+ @extendee = extendee
317
+ end
318
+
319
+ # An extension field; same arguments as {MessageBuilder#field}
320
+ def field(name, number, type, type_name = nil, label: nil, default: nil, json_name: nil, proto3_optional: nil,
321
+ options: nil, **field_options)
322
+ @draft.extension(name, number, DSL.type(type), type_name, extendee: @extendee, label: DSL.label(label),
323
+ default: default, json_name: json_name, optional: proto3_optional ? true : false,
324
+ options: DSL.options(options, field_options))
325
+ end
326
+ end
327
+
328
+ # The block argument of {Scope#enum}
329
+ class EnumBuilder
330
+ # @api private
331
+ def initialize(draft)
332
+ @draft = draft
333
+ end
334
+
335
+ # @param name [Symbol, String]
336
+ # @param number [Integer]
337
+ def value(name, number, options: nil, **value_options)
338
+ @draft.value(name, number, options: DSL.options(options, value_options))
339
+ self
340
+ end
341
+
342
+ # Reserved numbers (Integers or inclusive Ranges) and names (Strings)
343
+ def reserved(*items)
344
+ @draft.reserved(*items)
345
+ self
346
+ end
347
+ end
348
+
349
+ # The block argument of {FileBuilder#service}
350
+ class ServiceBuilder
351
+ # @api private
352
+ def initialize(draft)
353
+ @draft = draft
354
+ end
355
+
356
+ # @param name [Symbol, String]
357
+ # @param input_type [String] e.g. ".acme.Request"
358
+ # @param output_type [String]
359
+ def rpc(name, input_type, output_type, client_streaming: false, server_streaming: false, options: nil,
360
+ **method_options)
361
+ @draft.rpc(name, input_type, output_type, client_streaming: client_streaming,
362
+ server_streaming: server_streaming, options: DSL.options(options, method_options))
363
+ self
364
+ end
365
+ end
366
+ end
367
+ end
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Protostar
4
+ # Extended by every enum Module that {Types.define} makes. Such a Module has
5
+ # one constant per value (aliases included) holding its number, and is frozen.
6
+ #
7
+ # Color::RED # => 1
8
+ # Color.lookup(1) # => :RED
9
+ # Color.resolve(:RED) # => 1
10
+ module Enum
11
+ # @return [Schema::Enum]
12
+ attr_reader :descriptor
13
+
14
+ # @param number [Integer]
15
+ # @return [Symbol, nil] the first name declared for the number
16
+ def lookup(number)
17
+ @__names[number]
18
+ end
19
+
20
+ # @param name [Symbol, String]
21
+ # @return [Integer, nil]
22
+ def resolve(name)
23
+ @__numbers[name.is_a?(String) ? name.to_sym : name]
24
+ end
25
+
26
+ # @api private
27
+ def __names
28
+ @__names
29
+ end
30
+
31
+ # @api private
32
+ def __numbers
33
+ @__numbers
34
+ end
35
+
36
+ def inspect
37
+ name || "#<Module #{@descriptor.full_name}>"
38
+ end
39
+
40
+ # Builds the enum Module for a descriptor
41
+ # @param descriptor [Schema::Enum]
42
+ # @return [Module] frozen
43
+ # @api private
44
+ def self.build(descriptor)
45
+ mod = Module.new
46
+ mod.extend(self)
47
+ names = {}
48
+ numbers = {}
49
+ descriptor.values.each do |v|
50
+ sym = v.name.to_sym
51
+ names[v.number] ||= sym
52
+ numbers[sym] = v.number
53
+ const = constant_name(v.name)
54
+ mod.const_set(const, v.number) if const && !mod.const_defined?(const, false)
55
+ end
56
+ mod.instance_variable_set(:@descriptor, descriptor)
57
+ mod.instance_variable_set(:@__names, Ractor.make_shareable(names))
58
+ mod.instance_variable_set(:@__numbers, Ractor.make_shareable(numbers))
59
+ mod
60
+ end
61
+
62
+ # @return [String, nil] the value name as a Ruby constant name: first
63
+ # letter upper-cased, nil when that is still not a constant name
64
+ # @api private
65
+ def self.constant_name(name)
66
+ const = name.sub(/\A[a-z]/, &:upcase)
67
+ const if /\A[A-Z]\w*\z/.match?(const)
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Protostar
4
+ # Raised for malformed wire input. {#offset} is the byte position in the
5
+ # decoded buffer where the problem was found.
6
+ class DecodeError < Error
7
+ # @return [Integer, nil]
8
+ attr_reader :offset
9
+
10
+ def initialize(message, offset: nil)
11
+ @offset = offset
12
+ super(offset ? "#{message} at byte #{offset}" : message)
13
+ end
14
+ end
15
+
16
+ # Raised when encoding a message whose stored values cannot be written
17
+ class EncodeError < Error; end
18
+
19
+ # Raised when a value of the wrong type, out of range or with invalid
20
+ # contents is assigned to a field. A subclass of Ruby's TypeError so that
21
+ # callers used to google-protobuf's errors can rescue it the same way.
22
+ class TypeError < ::TypeError; end
23
+ end
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Generated by protostar from google/protobuf/any.proto. Do not edit.
4
+
5
+ require "protostar"
6
+
7
+ Protostar::DSL.file(
8
+ "google/protobuf/any.proto",
9
+ package: "google.protobuf",
10
+ syntax: :proto3,
11
+ go_package: "google.golang.org/protobuf/types/known/anypb",
12
+ java_package: "com.google.protobuf",
13
+ java_outer_classname: "AnyProto",
14
+ java_multiple_files: true,
15
+ objc_class_prefix: "GPB",
16
+ csharp_namespace: "Google.Protobuf.WellKnownTypes"
17
+ ) do |f|
18
+ # `Any` contains an arbitrary serialized protocol buffer message along with a
19
+ # URL that describes the type of the serialized message.
20
+ #
21
+ # In its binary encoding, an `Any` is an ordinary message; but in other wire
22
+ # forms like JSON, it has a special encoding. The format of the type URL is
23
+ # described on the `type_url` field.
24
+ #
25
+ # Protobuf APIs provide utilities to interact with `Any` values:
26
+ #
27
+ # - A 'pack' operation accepts a message and constructs a generic `Any` wrapper
28
+ # around it.
29
+ # - An 'unpack' operation reads the content of an `Any` message, either into an
30
+ # existing message or a new one. Unpack operations must check the type of the
31
+ # value they unpack against the declared `type_url`.
32
+ # - An 'is' operation decides whether an `Any` contains a message of the given
33
+ # type, i.e. whether it can 'unpack' that type.
34
+ #
35
+ # The JSON format representation of an `Any` follows one of these cases:
36
+ #
37
+ # - For types without special-cased JSON encodings, the JSON format
38
+ # representation of the `Any` is the same as that of the message, with an
39
+ # additional `@type` field which contains the type URL.
40
+ # - For types with special-cased JSON encodings (typically called 'well-known'
41
+ # types, listed in https://protobuf.dev/programming-guides/json/#any), the
42
+ # JSON format representation has a key `@type` which contains the type URL
43
+ # and a key `value` which contains the JSON-serialized value.
44
+ #
45
+ # The text format representation of an `Any` is like a message with one field
46
+ # whose name is the type URL in brackets. For example, an `Any` containing a
47
+ # `foo.Bar` message may be written `[type.googleapis.com/foo.Bar] { a: 2 }`.
48
+ f.message "Any" do |m|
49
+ # Identifies the type of the serialized Protobuf message with a URI reference
50
+ # consisting of a prefix ending in a slash and the fully-qualified type name.
51
+ #
52
+ # Example: type.googleapis.com/google.protobuf.StringValue
53
+ #
54
+ # This string must contain at least one `/` character, and the content after
55
+ # the last `/` must be the fully-qualified name of the type in canonical
56
+ # form, without a leading dot. Do not write a scheme on these URI references
57
+ # so that clients do not attempt to contact them.
58
+ #
59
+ # The prefix is arbitrary and Protobuf implementations are expected to
60
+ # simply strip off everything up to and including the last `/` to identify
61
+ # the type. `type.googleapis.com/` is a common default prefix that some
62
+ # legacy implementations require. This prefix does not indicate the origin of
63
+ # the type, and URIs containing it are not expected to respond to any
64
+ # requests.
65
+ #
66
+ # All type URL strings must be legal URI references with the additional
67
+ # restriction (for the text format) that the content of the reference
68
+ # must consist only of alphanumeric characters, percent-encoded escapes, and
69
+ # characters in the following set (not including the outer backticks):
70
+ # `/-.~_!$&()*+,;=`. Despite our allowing percent encodings, implementations
71
+ # should not unescape them to prevent confusion with existing parsers. For
72
+ # example, `type.googleapis.com%2FFoo` should be rejected.
73
+ #
74
+ # In the original design of `Any`, the possibility of launching a type
75
+ # resolution service at these type URLs was considered but Protobuf never
76
+ # implemented one and considers contacting these URLs to be problematic and
77
+ # a potential security issue. Do not attempt to contact type URLs.
78
+ m.field :type_url, 1, :string
79
+ # Holds a Protobuf serialization of the type described by type_url.
80
+ m.field :value, 2, :bytes
81
+ end
82
+ end
83
+
84
+ module Protostar
85
+ module Google
86
+ module Protobuf
87
+ Any = Protostar::DSL.message("google.protobuf.Any")
88
+ end
89
+ end
90
+ end