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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +60 -0
- data/LICENSE.txt +21 -0
- data/README.md +647 -0
- data/THIRD_PARTY_NOTICES.md +61 -0
- data/exe/protoc-gen-protostar +7 -0
- data/exe/protostar +7 -0
- data/lib/protostar/builder/generator.rb +71 -0
- data/lib/protostar/builder/sink.rb +35 -0
- data/lib/protostar/builder.rb +965 -0
- data/lib/protostar/cli.rb +267 -0
- data/lib/protostar/codec/decode_generator.rb +199 -0
- data/lib/protostar/codec/decoder.rb +296 -0
- data/lib/protostar/codec/encode_generator.rb +224 -0
- data/lib/protostar/codec/encoder.rb +121 -0
- data/lib/protostar/codec/sizer.rb +91 -0
- data/lib/protostar/codec.rb +15 -0
- data/lib/protostar/compiler/ast.rb +193 -0
- data/lib/protostar/compiler/emitters/descriptor_set.rb +57 -0
- data/lib/protostar/compiler/emitters/google_ruby.rb +103 -0
- data/lib/protostar/compiler/emitters/grpc.rb +175 -0
- data/lib/protostar/compiler/emitters/protostar_rbs.rb +252 -0
- data/lib/protostar/compiler/emitters/rbs.rb +394 -0
- data/lib/protostar/compiler/emitters/ruby.rb +503 -0
- data/lib/protostar/compiler/emitters.rb +268 -0
- data/lib/protostar/compiler/include/LICENSE +32 -0
- data/lib/protostar/compiler/include/google/protobuf/any.proto +106 -0
- data/lib/protostar/compiler/include/google/protobuf/api.proto +229 -0
- data/lib/protostar/compiler/include/google/protobuf/compiler/plugin.proto +180 -0
- data/lib/protostar/compiler/include/google/protobuf/cpp_features.proto +87 -0
- data/lib/protostar/compiler/include/google/protobuf/descriptor.proto +1532 -0
- data/lib/protostar/compiler/include/google/protobuf/duration.proto +115 -0
- data/lib/protostar/compiler/include/google/protobuf/empty.proto +51 -0
- data/lib/protostar/compiler/include/google/protobuf/field_mask.proto +243 -0
- data/lib/protostar/compiler/include/google/protobuf/java_features.proto +132 -0
- data/lib/protostar/compiler/include/google/protobuf/source_context.proto +48 -0
- data/lib/protostar/compiler/include/google/protobuf/struct.proto +111 -0
- data/lib/protostar/compiler/include/google/protobuf/timestamp.proto +145 -0
- data/lib/protostar/compiler/include/google/protobuf/type.proto +217 -0
- data/lib/protostar/compiler/include/google/protobuf/wrappers.proto +157 -0
- data/lib/protostar/compiler/lexer.rb +659 -0
- data/lib/protostar/compiler/linker.rb +894 -0
- data/lib/protostar/compiler/option_interpreter.rb +363 -0
- data/lib/protostar/compiler/parser.rb +1696 -0
- data/lib/protostar/compiler/retention.rb +104 -0
- data/lib/protostar/compiler/run.rb +184 -0
- data/lib/protostar/compiler/source_info.rb +161 -0
- data/lib/protostar/compiler/symbol_table.rb +223 -0
- data/lib/protostar/compiler/text_format.rb +340 -0
- data/lib/protostar/compiler/validator.rb +944 -0
- data/lib/protostar/compiler.rb +304 -0
- data/lib/protostar/diagnostics/codes.rb +1307 -0
- data/lib/protostar/diagnostics/formats.rb +64 -0
- data/lib/protostar/diagnostics/renderer.rb +240 -0
- data/lib/protostar/diagnostics/source.rb +153 -0
- data/lib/protostar/diagnostics.rb +117 -0
- data/lib/protostar/dsl.rb +367 -0
- data/lib/protostar/enum.rb +70 -0
- data/lib/protostar/errors.rb +23 -0
- data/lib/protostar/google/protobuf/any_pb.rb +90 -0
- data/lib/protostar/google/protobuf/api_pb.rb +199 -0
- data/lib/protostar/google/protobuf/compiler/plugin_pb.rb +168 -0
- data/lib/protostar/google/protobuf/descriptor_pb.rb +1239 -0
- data/lib/protostar/google/protobuf/duration_pb.rb +99 -0
- data/lib/protostar/google/protobuf/empty_pb.rb +36 -0
- data/lib/protostar/google/protobuf/field_mask_pb.rb +228 -0
- data/lib/protostar/google/protobuf/source_context_pb.rb +33 -0
- data/lib/protostar/google/protobuf/struct_pb.rb +91 -0
- data/lib/protostar/google/protobuf/timestamp_pb.rb +129 -0
- data/lib/protostar/google/protobuf/type_pb.rb +202 -0
- data/lib/protostar/google/protobuf/wrappers_pb.rb +125 -0
- data/lib/protostar/google_protobuf_shim.rb +24 -0
- data/lib/protostar/json/encoder.rb +340 -0
- data/lib/protostar/json/errors.rb +34 -0
- data/lib/protostar/json/parser.rb +437 -0
- data/lib/protostar/json/path.rb +39 -0
- data/lib/protostar/json.rb +95 -0
- data/lib/protostar/lint/command.rb +197 -0
- data/lib/protostar/lint/config.rb +98 -0
- data/lib/protostar/lint/context.rb +126 -0
- data/lib/protostar/lint/directives.rb +56 -0
- data/lib/protostar/lint/fixer.rb +165 -0
- data/lib/protostar/lint/naming.rb +54 -0
- data/lib/protostar/lint/rule.rb +120 -0
- data/lib/protostar/lint/rules/comment_enum.rb +31 -0
- data/lib/protostar/lint/rules/comment_enum_value.rb +32 -0
- data/lib/protostar/lint/rules/comment_field.rb +33 -0
- data/lib/protostar/lint/rules/comment_message.rb +31 -0
- data/lib/protostar/lint/rules/comment_rpc.rb +31 -0
- data/lib/protostar/lint/rules/comment_service.rb +31 -0
- data/lib/protostar/lint/rules/edition_recommended.rb +31 -0
- data/lib/protostar/lint/rules/enum_first_value_zero.rb +34 -0
- data/lib/protostar/lint/rules/enum_pascal_case.rb +25 -0
- data/lib/protostar/lint/rules/enum_value_prefix.rb +38 -0
- data/lib/protostar/lint/rules/enum_value_upper_snake_case.rb +28 -0
- data/lib/protostar/lint/rules/enum_zero_value_suffix.rb +41 -0
- data/lib/protostar/lint/rules/field_lower_snake_case.rb +34 -0
- data/lib/protostar/lint/rules/field_not_required.rb +39 -0
- data/lib/protostar/lint/rules/field_number_reuse_risk.rb +45 -0
- data/lib/protostar/lint/rules/field_numbers_hot_range.rb +44 -0
- data/lib/protostar/lint/rules/file_lower_snake_case.rb +27 -0
- data/lib/protostar/lint/rules/import_no_public.rb +29 -0
- data/lib/protostar/lint/rules/import_no_weak.rb +28 -0
- data/lib/protostar/lint/rules/import_used.rb +33 -0
- data/lib/protostar/lint/rules/message_pascal_case.rb +27 -0
- data/lib/protostar/lint/rules/no_deprecated_features.rb +50 -0
- data/lib/protostar/lint/rules/no_groups.rb +34 -0
- data/lib/protostar/lint/rules/oneof_lower_snake_case.rb +27 -0
- data/lib/protostar/lint/rules/package_defined.rb +28 -0
- data/lib/protostar/lint/rules/package_directory_match.rb +33 -0
- data/lib/protostar/lint/rules/package_lower_snake_case.rb +28 -0
- data/lib/protostar/lint/rules/package_same_directory.rb +39 -0
- data/lib/protostar/lint/rules/package_version_suffix.rb +31 -0
- data/lib/protostar/lint/rules/reserved_names_with_numbers.rb +44 -0
- data/lib/protostar/lint/rules/rpc_pascal_case.rb +25 -0
- data/lib/protostar/lint/rules/rpc_request_response_unique.rb +40 -0
- data/lib/protostar/lint/rules/rpc_request_standard_name.rb +32 -0
- data/lib/protostar/lint/rules/rpc_response_standard_name.rb +31 -0
- data/lib/protostar/lint/rules/service_pascal_case.rb +25 -0
- data/lib/protostar/lint/rules/service_suffix.rb +28 -0
- data/lib/protostar/lint/rules/syntax_specified.rb +35 -0
- data/lib/protostar/lint/runner.rb +135 -0
- data/lib/protostar/lint.rb +122 -0
- data/lib/protostar/message/accessors.rb +86 -0
- data/lib/protostar/message/coercion.rb +171 -0
- data/lib/protostar/message/field_info.rb +145 -0
- data/lib/protostar/message/reflection.rb +149 -0
- data/lib/protostar/message.rb +572 -0
- data/lib/protostar/plugin.rb +94 -0
- data/lib/protostar/schema/default_value.rb +113 -0
- data/lib/protostar/schema/descriptor.rb +41 -0
- data/lib/protostar/schema/draft/copy.rb +88 -0
- data/lib/protostar/schema/draft/resolution.rb +177 -0
- data/lib/protostar/schema/draft.rb +779 -0
- data/lib/protostar/schema/enum.rb +106 -0
- data/lib/protostar/schema/extension_range.rb +37 -0
- data/lib/protostar/schema/features.rb +153 -0
- data/lib/protostar/schema/field.rb +201 -0
- data/lib/protostar/schema/file.rb +217 -0
- data/lib/protostar/schema/freezer.rb +61 -0
- data/lib/protostar/schema/message.rb +104 -0
- data/lib/protostar/schema/oneof.rb +38 -0
- data/lib/protostar/schema/options.rb +367 -0
- data/lib/protostar/schema/pool.rb +179 -0
- data/lib/protostar/schema/proto.rb +576 -0
- data/lib/protostar/schema/resolver.rb +118 -0
- data/lib/protostar/schema/service.rb +89 -0
- data/lib/protostar/schema/source_info.rb +53 -0
- data/lib/protostar/schema.rb +65 -0
- data/lib/protostar/short_names/any.rb +7 -0
- data/lib/protostar/short_names/duration.rb +7 -0
- data/lib/protostar/short_names/empty.rb +7 -0
- data/lib/protostar/short_names/field_mask.rb +7 -0
- data/lib/protostar/short_names/struct.rb +9 -0
- data/lib/protostar/short_names/timestamp.rb +7 -0
- data/lib/protostar/short_names/wrappers.rb +15 -0
- data/lib/protostar/text/extensions.rb +114 -0
- data/lib/protostar/text/parser.rb +439 -0
- data/lib/protostar/text/printer.rb +304 -0
- data/lib/protostar/text/tokenizer.rb +116 -0
- data/lib/protostar/text.rb +67 -0
- data/lib/protostar/types.rb +152 -0
- data/lib/protostar/unknown_field.rb +58 -0
- data/lib/protostar/version.rb +5 -0
- data/lib/protostar/view/generator.rb +298 -0
- data/lib/protostar/view/map.rb +194 -0
- data/lib/protostar/view/repeated.rb +143 -0
- data/lib/protostar/view/scan.rb +183 -0
- data/lib/protostar/view.rb +283 -0
- data/lib/protostar/well_known/any.rb +52 -0
- data/lib/protostar/well_known/duration.rb +53 -0
- data/lib/protostar/well_known/list_value.rb +63 -0
- data/lib/protostar/well_known/struct.rb +55 -0
- data/lib/protostar/well_known/timestamp.rb +64 -0
- data/lib/protostar/well_known/value.rb +60 -0
- data/lib/protostar/well_known.rb +38 -0
- data/lib/protostar/wire/io_source.rb +40 -0
- data/lib/protostar/wire/reader.rb +254 -0
- data/lib/protostar/wire/writer.rb +201 -0
- data/lib/protostar/wire.rb +96 -0
- data/lib/protostar.rb +95 -0
- data/shims/google-protobuf/lib/google/protobuf/any_pb.rb +17 -0
- data/shims/google-protobuf/lib/google/protobuf/api_pb.rb +22 -0
- data/shims/google-protobuf/lib/google/protobuf/compiler/plugin_pb.rb +25 -0
- data/shims/google-protobuf/lib/google/protobuf/descriptor_pb.rb +72 -0
- data/shims/google-protobuf/lib/google/protobuf/descriptor_pool.rb +164 -0
- data/shims/google-protobuf/lib/google/protobuf/descriptors.rb +553 -0
- data/shims/google-protobuf/lib/google/protobuf/duration_pb.rb +17 -0
- data/shims/google-protobuf/lib/google/protobuf/empty_pb.rb +17 -0
- data/shims/google-protobuf/lib/google/protobuf/field_mask_pb.rb +17 -0
- data/shims/google-protobuf/lib/google/protobuf/internal/convert.rb +180 -0
- data/shims/google-protobuf/lib/google/protobuf/internal/extensions.rb +154 -0
- data/shims/google-protobuf/lib/google/protobuf/internal/json.rb +104 -0
- data/shims/google-protobuf/lib/google/protobuf/internal/well_known.rb +140 -0
- data/shims/google-protobuf/lib/google/protobuf/map.rb +216 -0
- data/shims/google-protobuf/lib/google/protobuf/message.rb +544 -0
- data/shims/google-protobuf/lib/google/protobuf/message_exts.rb +41 -0
- data/shims/google-protobuf/lib/google/protobuf/plugin_pb.rb +4 -0
- data/shims/google-protobuf/lib/google/protobuf/repeated_field.rb +366 -0
- data/shims/google-protobuf/lib/google/protobuf/source_context_pb.rb +17 -0
- data/shims/google-protobuf/lib/google/protobuf/struct_pb.rb +20 -0
- data/shims/google-protobuf/lib/google/protobuf/timestamp_pb.rb +17 -0
- data/shims/google-protobuf/lib/google/protobuf/type_pb.rb +27 -0
- data/shims/google-protobuf/lib/google/protobuf/well_known_types.rb +37 -0
- data/shims/google-protobuf/lib/google/protobuf/wrappers_pb.rb +25 -0
- data/shims/google-protobuf/lib/google/protobuf.rb +107 -0
- data/shims/google-protobuf/lib/google/protobuf_ffi.rb +5 -0
- data/shims/google-protobuf/lib/google/protobuf_native.rb +5 -0
- data/sig/protostar/google/protobuf/any_pb.rbs +77 -0
- data/sig/protostar/google/protobuf/api_pb.rbs +242 -0
- data/sig/protostar/google/protobuf/compiler/plugin_pb.rbs +264 -0
- data/sig/protostar/google/protobuf/descriptor_pb.rbs +2220 -0
- data/sig/protostar/google/protobuf/duration_pb.rbs +82 -0
- data/sig/protostar/google/protobuf/empty_pb.rbs +18 -0
- data/sig/protostar/google/protobuf/field_mask_pb.rbs +170 -0
- data/sig/protostar/google/protobuf/source_context_pb.rbs +24 -0
- data/sig/protostar/google/protobuf/struct_pb.rbs +135 -0
- data/sig/protostar/google/protobuf/timestamp_pb.rbs +102 -0
- data/sig/protostar/google/protobuf/type_pb.rbs +304 -0
- data/sig/protostar/google/protobuf/wrappers_pb.rbs +169 -0
- data/sig/protostar/lint.rbs +216 -0
- data/sig/protostar.rbs +326 -0
- metadata +366 -0
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Protostar
|
|
4
|
+
module Schema
|
|
5
|
+
# An enum type
|
|
6
|
+
class Enum < Descriptor
|
|
7
|
+
# @return [File]
|
|
8
|
+
attr_reader :file
|
|
9
|
+
# @return [Message, nil]
|
|
10
|
+
attr_reader :containing_message
|
|
11
|
+
# @return [Array<EnumValue>] declaration order
|
|
12
|
+
attr_reader :values
|
|
13
|
+
# @return [Hash{Integer => EnumValue}] the first declared value wins for aliases
|
|
14
|
+
attr_reader :values_by_number
|
|
15
|
+
# @return [Hash{String => EnumValue}]
|
|
16
|
+
attr_reader :values_by_name
|
|
17
|
+
# @return [Array<Range>] inclusive
|
|
18
|
+
attr_reader :reserved_ranges
|
|
19
|
+
# @return [Array<String>]
|
|
20
|
+
attr_reader :reserved_names
|
|
21
|
+
# @return [Symbol, nil] declared `visibility`: :local or :export (edition 2024), nil when not declared
|
|
22
|
+
attr_reader :visibility
|
|
23
|
+
|
|
24
|
+
# @api private
|
|
25
|
+
def initialize(name:, full_name:, file:, containing_message:, index:)
|
|
26
|
+
@name = name
|
|
27
|
+
@full_name = full_name
|
|
28
|
+
@file = file
|
|
29
|
+
@containing_message = containing_message
|
|
30
|
+
@index = index
|
|
31
|
+
@reserved_ranges = Freezer::EMPTY_ARRAY
|
|
32
|
+
@reserved_names = Freezer::EMPTY_ARRAY
|
|
33
|
+
@visibility = nil
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# @api private
|
|
37
|
+
def __values(values)
|
|
38
|
+
@values = values
|
|
39
|
+
@values_by_number = {}
|
|
40
|
+
@values_by_name = {}
|
|
41
|
+
values.each do |v|
|
|
42
|
+
@values_by_number[v.number] ||= v
|
|
43
|
+
@values_by_name[v.name] ||= v
|
|
44
|
+
end
|
|
45
|
+
@values_by_number.freeze
|
|
46
|
+
@values_by_name.freeze
|
|
47
|
+
self
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# @param key [Integer, String, Symbol] a value number or name
|
|
51
|
+
# @return [EnumValue, nil]
|
|
52
|
+
def value(key)
|
|
53
|
+
key.is_a?(Integer) ? @values_by_number[key] : @values_by_name[key.to_s]
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# @return [Boolean]
|
|
57
|
+
def allow_alias?
|
|
58
|
+
options.allow_alias?
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# @return [Boolean] unknown numbers go to unknown fields (proto2, editions
|
|
62
|
+
# `enum_type = CLOSED`) instead of being kept in the field (proto3, `OPEN`)
|
|
63
|
+
def closed?
|
|
64
|
+
@features.enum_type == :CLOSED
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# @return [Boolean]
|
|
68
|
+
def open?
|
|
69
|
+
!closed?
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# @return [Protostar::Google::Protobuf::EnumDescriptorProto]
|
|
73
|
+
def to_proto
|
|
74
|
+
Proto::Writer.enum(self)
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# A value of an enum. Its {#full_name} lives in the enum's enclosing scope,
|
|
79
|
+
# as in protoc: value `FOO` of `pkg.Color` is `pkg.FOO`.
|
|
80
|
+
class EnumValue < Descriptor
|
|
81
|
+
# @return [Integer]
|
|
82
|
+
attr_reader :number
|
|
83
|
+
# @return [Enum]
|
|
84
|
+
attr_reader :enum
|
|
85
|
+
|
|
86
|
+
# @api private
|
|
87
|
+
def initialize(name:, full_name:, number:, enum:, index:)
|
|
88
|
+
@name = name
|
|
89
|
+
@full_name = full_name
|
|
90
|
+
@number = number
|
|
91
|
+
@enum = enum
|
|
92
|
+
@index = index
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# @return [File]
|
|
96
|
+
def file
|
|
97
|
+
@enum.file
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# @return [Protostar::Google::Protobuf::EnumValueDescriptorProto]
|
|
101
|
+
def to_proto
|
|
102
|
+
Proto::Writer.enum_value(self)
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Protostar
|
|
4
|
+
module Schema
|
|
5
|
+
# One `extensions` declaration of a message, with its options and features
|
|
6
|
+
class ExtensionRange < Descriptor
|
|
7
|
+
# @return [Message]
|
|
8
|
+
attr_reader :containing_message
|
|
9
|
+
# @return [Range] inclusive
|
|
10
|
+
attr_reader :range
|
|
11
|
+
|
|
12
|
+
# @api private
|
|
13
|
+
def initialize(containing_message:, index:, range:)
|
|
14
|
+
@containing_message = containing_message
|
|
15
|
+
@index = index
|
|
16
|
+
@range = range
|
|
17
|
+
@name = "#{range.begin}..#{range.end}"
|
|
18
|
+
@full_name = "#{containing_message.full_name}.extensions(#{@name})"
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# @return [File]
|
|
22
|
+
def file
|
|
23
|
+
@containing_message.file
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# @return [Integer] first extension number, inclusive
|
|
27
|
+
def start
|
|
28
|
+
@range.begin
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# @return [Integer] last extension number, inclusive
|
|
32
|
+
def end
|
|
33
|
+
@range.end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Protostar
|
|
4
|
+
module Schema
|
|
5
|
+
# Resolved editions features of a descriptor. proto2 and proto3 files are
|
|
6
|
+
# resolved as the editions EDITION_PROTO2 and EDITION_PROTO3, the way protoc
|
|
7
|
+
# does internally, so every descriptor has a complete set.
|
|
8
|
+
#
|
|
9
|
+
# Custom (extension) features such as `pb.cpp` are carried in {#extensions}
|
|
10
|
+
# as merged explicit values; their defaults are not known to this model.
|
|
11
|
+
class Features
|
|
12
|
+
# The Edition enum from descriptor.proto (lines 45-82)
|
|
13
|
+
EDITIONS = {
|
|
14
|
+
EDITION_UNKNOWN: 0,
|
|
15
|
+
EDITION_LEGACY: 900,
|
|
16
|
+
EDITION_PROTO2: 998,
|
|
17
|
+
EDITION_PROTO3: 999,
|
|
18
|
+
EDITION_2023: 1000,
|
|
19
|
+
EDITION_2024: 1001,
|
|
20
|
+
EDITION_2026: 1002,
|
|
21
|
+
EDITION_UNSTABLE: 9999,
|
|
22
|
+
EDITION_1_TEST_ONLY: 1,
|
|
23
|
+
EDITION_2_TEST_ONLY: 2,
|
|
24
|
+
EDITION_99997_TEST_ONLY: 99997,
|
|
25
|
+
EDITION_99998_TEST_ONLY: 99998,
|
|
26
|
+
EDITION_99999_TEST_ONLY: 99999,
|
|
27
|
+
EDITION_MAX: 0x7FFFFFFF
|
|
28
|
+
}.freeze
|
|
29
|
+
|
|
30
|
+
# Edition numbers to their enum names
|
|
31
|
+
EDITION_NAMES = EDITIONS.invert.freeze
|
|
32
|
+
|
|
33
|
+
# The `edition_defaults` annotations on FeatureSet in descriptor.proto,
|
|
34
|
+
# as [edition, value] pairs in ascending edition order. A feature takes the
|
|
35
|
+
# value of the last pair whose edition is at or before the file's edition.
|
|
36
|
+
DEFAULTS = {
|
|
37
|
+
# descriptor.proto lines 1074-1076
|
|
38
|
+
field_presence: [[:EDITION_LEGACY, :EXPLICIT], [:EDITION_PROTO3, :IMPLICIT], [:EDITION_2023, :EXPLICIT]],
|
|
39
|
+
# lines 1091-1092
|
|
40
|
+
enum_type: [[:EDITION_LEGACY, :CLOSED], [:EDITION_PROTO3, :OPEN]],
|
|
41
|
+
# lines 1107-1108
|
|
42
|
+
repeated_field_encoding: [[:EDITION_LEGACY, :EXPANDED], [:EDITION_PROTO3, :PACKED]],
|
|
43
|
+
# lines 1124-1125
|
|
44
|
+
utf8_validation: [[:EDITION_LEGACY, :NONE], [:EDITION_PROTO3, :VERIFY]],
|
|
45
|
+
# line 1140
|
|
46
|
+
message_encoding: [[:EDITION_LEGACY, :LENGTH_PREFIXED]],
|
|
47
|
+
# lines 1156-1157
|
|
48
|
+
json_format: [[:EDITION_LEGACY, :LEGACY_BEST_EFFORT], [:EDITION_PROTO3, :ALLOW]],
|
|
49
|
+
# lines 1180-1182
|
|
50
|
+
enforce_naming_style: [[:EDITION_LEGACY, :STYLE_LEGACY], [:EDITION_2024, :STYLE2024], [:EDITION_2026, :STYLE2026]],
|
|
51
|
+
# lines 1212-1214
|
|
52
|
+
default_symbol_visibility: [[:EDITION_LEGACY, :EXPORT_ALL], [:EDITION_2024, :EXPORT_TOP_LEVEL], [:EDITION_2026, :STRICT]],
|
|
53
|
+
# lines 1241-1245
|
|
54
|
+
enforce_proto_limits: [[:EDITION_LEGACY, :LEGACY_NO_EXPLICIT_LIMITS], [:EDITION_2026, :PROTO_LIMITS2026]]
|
|
55
|
+
}.transform_values { |pairs| pairs.map(&:freeze).freeze }.freeze
|
|
56
|
+
|
|
57
|
+
# Names of the core features, in FeatureSet field number order
|
|
58
|
+
NAMES = DEFAULTS.keys.freeze
|
|
59
|
+
|
|
60
|
+
# @param edition [Symbol, Integer] an Edition enum name or number
|
|
61
|
+
# @return [Integer]
|
|
62
|
+
def self.edition_number(edition)
|
|
63
|
+
return edition if edition.is_a?(Integer)
|
|
64
|
+
EDITIONS.fetch(edition) { raise Error, "unknown edition #{edition.inspect}" }
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# The defaults for an edition, as protoc computes them from descriptor.proto
|
|
68
|
+
# @param edition [Symbol, Integer]
|
|
69
|
+
# @return [Features]
|
|
70
|
+
def self.defaults(edition)
|
|
71
|
+
number = edition_number(edition)
|
|
72
|
+
values = DEFAULTS.transform_values do |pairs|
|
|
73
|
+
pick = pairs.reverse_each.find { |(ed, _)| EDITIONS.fetch(ed) <= number }
|
|
74
|
+
raise Error, "no feature defaults for edition #{edition.inspect}" unless pick
|
|
75
|
+
pick.last
|
|
76
|
+
end
|
|
77
|
+
new(values, Freezer::EMPTY_HASH)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# @return [Hash{Field => MessageValue}] merged explicit custom features by extension
|
|
81
|
+
attr_reader :extensions
|
|
82
|
+
|
|
83
|
+
# @api private
|
|
84
|
+
def initialize(values, extensions)
|
|
85
|
+
@values = values.freeze
|
|
86
|
+
@extensions = extensions
|
|
87
|
+
NAMES.each { |name| instance_variable_set(:"@#{name}", values.fetch(name)) }
|
|
88
|
+
@hash = [@values, @extensions].hash
|
|
89
|
+
freeze
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# @!attribute [r] field_presence
|
|
93
|
+
# @return [Symbol] :EXPLICIT, :IMPLICIT or :LEGACY_REQUIRED
|
|
94
|
+
# @!attribute [r] enum_type
|
|
95
|
+
# @return [Symbol] :OPEN or :CLOSED
|
|
96
|
+
# @!attribute [r] repeated_field_encoding
|
|
97
|
+
# @return [Symbol] :PACKED or :EXPANDED
|
|
98
|
+
# @!attribute [r] utf8_validation
|
|
99
|
+
# @return [Symbol] :VERIFY or :NONE
|
|
100
|
+
# @!attribute [r] message_encoding
|
|
101
|
+
# @return [Symbol] :LENGTH_PREFIXED or :DELIMITED
|
|
102
|
+
# @!attribute [r] json_format
|
|
103
|
+
# @return [Symbol] :ALLOW or :LEGACY_BEST_EFFORT
|
|
104
|
+
# @!attribute [r] enforce_naming_style
|
|
105
|
+
# @return [Symbol]
|
|
106
|
+
# @!attribute [r] default_symbol_visibility
|
|
107
|
+
# @return [Symbol]
|
|
108
|
+
# @!attribute [r] enforce_proto_limits
|
|
109
|
+
# @return [Symbol]
|
|
110
|
+
attr_reader :field_presence, :enum_type, :repeated_field_encoding, :utf8_validation, :message_encoding,
|
|
111
|
+
:json_format, :enforce_naming_style, :default_symbol_visibility, :enforce_proto_limits
|
|
112
|
+
|
|
113
|
+
# Overlays a declared `features` option (a FeatureSet) on these features
|
|
114
|
+
# @param declared [MessageValue, nil]
|
|
115
|
+
# @return [Features] self when the overlay changes nothing
|
|
116
|
+
def merge(declared)
|
|
117
|
+
return self if declared.nil? || declared.empty?
|
|
118
|
+
values = @values
|
|
119
|
+
declared.fields.each do |key, value|
|
|
120
|
+
next unless NAMES.include?(key) && value.is_a?(Symbol)
|
|
121
|
+
values = values.merge(key => value) unless values[key] == value
|
|
122
|
+
end
|
|
123
|
+
extensions = MessageValue.merge_values(@extensions, declared.extensions)
|
|
124
|
+
return self if values.equal?(@values) && extensions.equal?(@extensions)
|
|
125
|
+
Features.new(values, extensions)
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# @param values [Hash{Symbol => Symbol}] core features to override
|
|
129
|
+
# @return [Features] self when nothing changes
|
|
130
|
+
def with(**values)
|
|
131
|
+
return self if values.all? { |k, v| @values[k] == v }
|
|
132
|
+
Features.new(@values.merge(values), @extensions)
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
# @return [Hash{Symbol => Symbol}] the core features by name
|
|
136
|
+
def to_h
|
|
137
|
+
@values
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def ==(other)
|
|
141
|
+
other.is_a?(Features) && other.to_h == @values && other.extensions == @extensions
|
|
142
|
+
end
|
|
143
|
+
alias_method :eql?, :==
|
|
144
|
+
|
|
145
|
+
attr_reader :hash
|
|
146
|
+
|
|
147
|
+
def inspect
|
|
148
|
+
custom = @extensions.map { |f, v| " (#{f.full_name}): #{v.inspect}" }.join
|
|
149
|
+
"#<#{self.class.name} #{@values.inspect}#{custom}>"
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
end
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Protostar
|
|
4
|
+
module Schema
|
|
5
|
+
# A field of a message, or an extension
|
|
6
|
+
class Field < Descriptor
|
|
7
|
+
# FieldDescriptorProto.Type names to the short type symbols
|
|
8
|
+
TYPES = {
|
|
9
|
+
TYPE_DOUBLE: :double, TYPE_FLOAT: :float, TYPE_INT64: :int64, TYPE_UINT64: :uint64,
|
|
10
|
+
TYPE_INT32: :int32, TYPE_FIXED64: :fixed64, TYPE_FIXED32: :fixed32, TYPE_BOOL: :bool,
|
|
11
|
+
TYPE_STRING: :string, TYPE_GROUP: :group, TYPE_MESSAGE: :message, TYPE_BYTES: :bytes,
|
|
12
|
+
TYPE_UINT32: :uint32, TYPE_ENUM: :enum, TYPE_SFIXED32: :sfixed32, TYPE_SFIXED64: :sfixed64,
|
|
13
|
+
TYPE_SINT32: :sint32, TYPE_SINT64: :sint64
|
|
14
|
+
}.freeze
|
|
15
|
+
|
|
16
|
+
# FieldDescriptorProto.Label names to the short label symbols
|
|
17
|
+
LABELS = {LABEL_OPTIONAL: :optional, LABEL_REQUIRED: :required, LABEL_REPEATED: :repeated}.freeze
|
|
18
|
+
|
|
19
|
+
# @api private
|
|
20
|
+
PROTO_TYPES = TYPES.invert.freeze
|
|
21
|
+
# @api private
|
|
22
|
+
PROTO_LABELS = LABELS.invert.freeze
|
|
23
|
+
|
|
24
|
+
# Wire type of a single, unpacked value of each type
|
|
25
|
+
WIRE_TYPES = {
|
|
26
|
+
double: 1, float: 5, int64: 0, uint64: 0, int32: 0, fixed64: 1, fixed32: 5, bool: 0,
|
|
27
|
+
string: 2, group: 3, message: 2, bytes: 2, uint32: 0, enum: 0, sfixed32: 5, sfixed64: 1,
|
|
28
|
+
sint32: 0, sint64: 0
|
|
29
|
+
}.freeze
|
|
30
|
+
|
|
31
|
+
# The implicit default of each scalar type
|
|
32
|
+
ZERO = {
|
|
33
|
+
double: 0.0, float: 0.0, int64: 0, uint64: 0, int32: 0, fixed64: 0, fixed32: 0, bool: false,
|
|
34
|
+
string: "".encode(Encoding::UTF_8).freeze, bytes: "".b.freeze, uint32: 0, sfixed32: 0,
|
|
35
|
+
sfixed64: 0, sint32: 0, sint64: 0
|
|
36
|
+
}.freeze
|
|
37
|
+
|
|
38
|
+
UNPACKABLE = %i[string bytes message group].freeze
|
|
39
|
+
|
|
40
|
+
# @return [Integer]
|
|
41
|
+
attr_reader :number
|
|
42
|
+
# @return [Symbol] :optional, :required or :repeated, with editions
|
|
43
|
+
# `LEGACY_REQUIRED` presence reported as :required
|
|
44
|
+
attr_reader :label
|
|
45
|
+
# @return [Symbol] :int32, :string, :message, ... with editions
|
|
46
|
+
# `DELIMITED` message fields reported as :group, as protoc does
|
|
47
|
+
attr_reader :type
|
|
48
|
+
# @return [String, nil] full name of the message or enum type, no leading dot
|
|
49
|
+
attr_reader :type_name
|
|
50
|
+
# @return [Message, nil]
|
|
51
|
+
attr_reader :message_type
|
|
52
|
+
# @return [Enum, nil]
|
|
53
|
+
attr_reader :enum_type
|
|
54
|
+
# @return [Object, nil] the declared default parsed to a Ruby value
|
|
55
|
+
# (Integer, Float, true/false, String, binary String, or Symbol for enums)
|
|
56
|
+
attr_reader :default_value
|
|
57
|
+
# @return [Object, nil] {#default_value}, or the type's implicit default:
|
|
58
|
+
# zero, false, an empty String, the first value's name for an enum, nil for messages.
|
|
59
|
+
# For repeated fields this is the default of a single element.
|
|
60
|
+
attr_reader :default
|
|
61
|
+
# @return [String]
|
|
62
|
+
attr_reader :json_name
|
|
63
|
+
# @return [Oneof, nil] the containing oneof, synthetic ones included
|
|
64
|
+
attr_reader :oneof
|
|
65
|
+
# @return [Message, nil] for an extension, the extended message
|
|
66
|
+
attr_reader :extendee
|
|
67
|
+
# @return [Message, nil] the message holding the field; for an extension the
|
|
68
|
+
# message it was declared in, or nil when declared at file level
|
|
69
|
+
attr_reader :containing_message
|
|
70
|
+
# @return [File]
|
|
71
|
+
attr_reader :file
|
|
72
|
+
|
|
73
|
+
# @api private
|
|
74
|
+
def initialize(name:, full_name:, number:, label:, type:, type_name:, extendee_name:, raw_default:, json_name:,
|
|
75
|
+
proto3_optional:, extension:, containing_message:, file:, index:)
|
|
76
|
+
@name = name
|
|
77
|
+
@full_name = full_name
|
|
78
|
+
@number = number
|
|
79
|
+
@declared_label = label
|
|
80
|
+
@declared_type = type
|
|
81
|
+
@label = label
|
|
82
|
+
@type = type
|
|
83
|
+
@type_name = type_name
|
|
84
|
+
@extendee_name = extendee_name
|
|
85
|
+
@raw_default = raw_default
|
|
86
|
+
@json_name = json_name
|
|
87
|
+
@proto3_optional = proto3_optional
|
|
88
|
+
@extension = extension
|
|
89
|
+
@containing_message = containing_message
|
|
90
|
+
@file = file
|
|
91
|
+
@index = index
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# @api private
|
|
95
|
+
# @return [String, nil] the default as protoc stores it in `default_value`
|
|
96
|
+
attr_reader :raw_default
|
|
97
|
+
# @api private
|
|
98
|
+
# @return [String, nil] the extendee as written, until it is resolved
|
|
99
|
+
attr_reader :extendee_name
|
|
100
|
+
# @api private
|
|
101
|
+
# @return [Symbol, nil] the label as declared: :repeated, :optional or :required,
|
|
102
|
+
# before editions features turn `LEGACY_REQUIRED` into :required
|
|
103
|
+
attr_reader :declared_label
|
|
104
|
+
# @api private
|
|
105
|
+
# @return [Symbol, nil] the type as declared, before editions features turn
|
|
106
|
+
# `DELIMITED` message fields into :group; nil while a type name is unresolved
|
|
107
|
+
attr_reader :declared_type
|
|
108
|
+
|
|
109
|
+
# @return [Boolean]
|
|
110
|
+
def proto3_optional?
|
|
111
|
+
@proto3_optional
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
# @return [Boolean]
|
|
115
|
+
def extension?
|
|
116
|
+
@extension
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# @return [Oneof, nil] the containing oneof unless it is synthetic
|
|
120
|
+
def real_oneof
|
|
121
|
+
@oneof unless @oneof.nil? || @oneof.synthetic?
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# @return [Boolean]
|
|
125
|
+
def repeated?
|
|
126
|
+
@label == :repeated
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
# @return [Boolean]
|
|
130
|
+
def required?
|
|
131
|
+
@label == :required
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# @return [Boolean]
|
|
135
|
+
def optional?
|
|
136
|
+
@label == :optional
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
# @return [Boolean] a `map<K, V>` field: repeated, of a map entry message type
|
|
140
|
+
def map?
|
|
141
|
+
@label == :repeated && !@message_type.nil? && @message_type.map_entry?
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
# @return [Field, nil] the key field of a map field's entry
|
|
145
|
+
def map_key
|
|
146
|
+
@message_type.fields_by_number[1] if map?
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
# @return [Field, nil] the value field of a map field's entry
|
|
150
|
+
def map_value
|
|
151
|
+
@message_type.fields_by_number[2] if map?
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
# @return [Boolean] not a message or group; enums count as scalars
|
|
155
|
+
def scalar?
|
|
156
|
+
@type != :message && @type != :group
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
# @return [Boolean] repeated and of a type that can be packed
|
|
160
|
+
def packable?
|
|
161
|
+
@label == :repeated && !UNPACKABLE.include?(@type)
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
# @return [Boolean] whether repeated values are written packed. Resolved
|
|
165
|
+
# through features: proto2 defaults to expanded, proto3 to packed, editions
|
|
166
|
+
# follow `repeated_field_encoding`, and a legacy `packed` option wins.
|
|
167
|
+
def packed?
|
|
168
|
+
packable? && @features.repeated_field_encoding == :PACKED
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
# @return [Boolean] explicit presence (has-bits): singular fields that are
|
|
172
|
+
# messages, extensions, oneof members, or not `IMPLICIT` by features
|
|
173
|
+
def presence?
|
|
174
|
+
return false if @label == :repeated
|
|
175
|
+
@type == :message || @type == :group || @extension || !@oneof.nil? ||
|
|
176
|
+
@features.field_presence != :IMPLICIT
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
# @return [Boolean] group, or editions `message_encoding = DELIMITED`
|
|
180
|
+
def delimited?
|
|
181
|
+
@type == :group
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
# @return [Integer] the wire type of one unpacked value
|
|
185
|
+
def wire_type
|
|
186
|
+
WIRE_TYPES.fetch(@type)
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
# @return [Boolean] whether string values must be valid UTF-8 when parsed
|
|
190
|
+
def utf8_validation?
|
|
191
|
+
@type == :string && @features.utf8_validation == :VERIFY
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
# @param default_json_names [Boolean] see {File#to_proto}
|
|
195
|
+
# @return [Protostar::Google::Protobuf::FieldDescriptorProto]
|
|
196
|
+
def to_proto(default_json_names: true)
|
|
197
|
+
Proto::Writer.field(self, default_json_names)
|
|
198
|
+
end
|
|
199
|
+
end
|
|
200
|
+
end
|
|
201
|
+
end
|