Merge branch 'main' into main

pull/14867/head
Marcel Hlopko 2023-12-15 15:47:56 +01:00 committed by GitHub
commit 971562ba47
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
313 changed files with 11962 additions and 8619 deletions

View File

@ -30,6 +30,9 @@ jobs:
- targets: //pkg/... //src/... @com_google_protobuf_examples//... //third_party/utf8_range/...
# Override cases with custom images
- config: { name: "Bazel7" }
image: "us-docker.pkg.dev/protobuf-build/containers/common/linux/bazel:7.0.0-a04396cc76704d4b7c722789e9c08df18f47df53"
targets: "//src/... //third_party/utf8_range/..."
- config: { name: "TCMalloc" }
image: "us-docker.pkg.dev/protobuf-build/containers/test/linux/tcmalloc@sha256:bd39119d74b8a3fad4ae335d4cf5294e70384676331b7e19949459fc7a8d8328"
targets: "//src/... //third_party/utf8_range/..."
@ -313,21 +316,32 @@ jobs:
fail-fast: false # Don't cancel all jobs if one fails.
matrix:
include:
- name: MacOS
- name: MacOS Bazel
os: macos-12
cache_key: macos-12
bazel: test //src/... //third_party/utf8_range/...
- name: MacOS Apple Silicon (build only)
# TODO Enable these once mac setup is working for Bazel 7
#- name: MacOS Bazel 7
# os: macos-12
# cache_key: macos-12-bazel7
# bazel: test //src/... //third_party/utf8_range/...
# bazel_version: '7.0.0'
- name: MacOS Apple Silicon (build only) Bazel
os: macos-12
cache_key: macos-12-arm
# Current github runners are all Intel based, so just build/compile
# for Apple Silicon to detect issues there.
bazel: build --cpu=darwin_arm64 //src/... //third_party/utf8_range/...
- name: Windows
- name: Windows Bazel
os: windows-2022
cache_key: windows-2022
bazel: test //src/... @com_google_protobuf_examples//... --test_tag_filters=-conformance --build_tag_filters=-conformance
name: ${{ matrix.name }} Bazel
- name: Windows Bazel 7
os: windows-2022
cache_key: windows-2022-bazel7
bazel: test //src/... @com_google_protobuf_examples//... --test_tag_filters=-conformance --build_tag_filters=-conformance
bazel_version: '7.0.0'
name: ${{ matrix.name }}
runs-on: ${{ matrix.os }}
steps:
- name: Checkout pending changes
@ -340,6 +354,7 @@ jobs:
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
bazel: ${{ matrix.bazel }}
bazel-cache: cpp_${{ matrix.cache_key }}
version: ${{ matrix.bazel_version || '6.3.0' }}
non-linux-cmake:
strategy:

View File

@ -17,6 +17,7 @@ jobs:
fail-fast: false # Don't cancel all jobs if one fails.
matrix:
config:
- { name: "Bazel 7", bazel_version: "7.0.0" }
- { name: "Fastbuild" }
- { name: "Optimized", flags: "-c opt" }
- { name: "FastTable", flags: "--//upb:fasttable_enabled=true" }
@ -37,7 +38,7 @@ jobs:
- name: Run tests
uses: protocolbuffers/protobuf-ci/bazel-docker@v2
with:
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/sanitize@sha256:04cd765285bc52cbbf51d66c8c66d8603579cf0f19cc42df26b09d2c270541fb
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/sanitize:${{ matrix.config.bazel_version || '6.3.0' }}-d07b7d649401d147e71e7182d2832cc8344f1f35
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
bazel-cache: upb-bazel
bazel: test --cxxopt=-std=c++17 --host_cxxopt=-std=c++17 //bazel/... //benchmarks/... //lua/... //protos/... //protos_generator/... //python/... //upb/... //upb_generator/... ${{ matrix.config.flags }}
@ -81,6 +82,7 @@ jobs:
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
bazel-cache: "upb-bazel-windows"
bazel: test --cxxopt=/std:c++17 --host_cxxopt=/std:c++17 //upb/... //upb_generator/... //python/... //protos/... //protos_generator/...
version: 6.3.0
exclude-targets: -//python:conformance_test -//upb/reflection:def_builder_test
macos:
@ -107,6 +109,7 @@ jobs:
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
bazel-cache: "upb-bazel-macos"
bazel: ${{ matrix.config.bazel-command }} --cxxopt=-std=c++17 --host_cxxopt=-std=c++17 ${{ matrix.config.flags }} //bazel/... //benchmarks/... //lua/... //protos/... //protos_generator/... //python/... //upb/... //upb_generator/...
version: 6.3.0
no-python:
strategy:

View File

@ -7,6 +7,7 @@
load("@rules_python//python:defs.bzl", "py_binary")
load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
load("@bazel_skylib//lib:selects.bzl", "selects")
# begin:google_only
# package(default_applicable_licenses = ["//upb:license"])
@ -14,6 +15,16 @@ load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
licenses(["notice"])
# begin:google_only
# selects.config_setting_group(
# name = "android_opt",
# match_all = [
# "//tools/cc_target_os:android",
# "//tools/compilation_mode:opt",
# ],
# )
# end:google_only
py_binary(
name = "amalgamate",
srcs = ["amalgamate.py"],

View File

@ -30,12 +30,20 @@ _DEFAULT_COPTS.extend([
UPB_DEFAULT_CPPOPTS = select({
"//upb:windows": [],
# begin:google_only
# # Override default -Oz for release builds on Android.
# "//bazel:android_opt": _DEFAULT_CPPOPTS + ["-O2"],
# end:google_only
"//conditions:default": _DEFAULT_CPPOPTS,
})
UPB_DEFAULT_COPTS = select({
"//upb:windows": [],
"//upb:fasttable_enabled_setting": ["-std=gnu99", "-DUPB_ENABLE_FASTTABLE"],
# begin:google_only
# # Override default -Oz for release builds on Android.
# "//bazel:android_opt": _DEFAULT_COPTS + ["-O2"],
# end:google_only
"//conditions:default": _DEFAULT_COPTS,
})

View File

@ -35,7 +35,6 @@ build:ubsan --copt=-fno-sanitize=function --copt=-fno-sanitize=vptr
build --incompatible_check_sharding_support
build --incompatible_default_to_explicit_init_py
build --incompatible_disable_native_android_rules
build --incompatible_disable_runtimes_filegroups
build --incompatible_disable_target_provider_fields
build --incompatible_disallow_empty_glob
build --incompatible_dont_use_javasourceinfoprovider
@ -66,3 +65,7 @@ build --incompatible_use_host_features
# --incompatible_disable_objc_library_transition
# --incompatible_fail_on_unknown_attributes
# --incompatible_merge_fixed_and_default_shell_env
# TODO: migrate all dependencies from WORKSPACE to MODULE.bazel
# https://github.com/protocolbuffers/protobuf/issues/14313
common --noenable_bzlmod

View File

@ -78,7 +78,10 @@ foreach(_header ${protobuf_HEADERS})
elseif (_find_nosrc GREATER -1)
set(_from_dir "${protobuf_SOURCE_DIR}")
endif()
string(REPLACE "${_from_dir}" "" _header ${_header})
# On some platforms `_form_dir` ends up being just "protobuf", which can
# easily match multiple times in our paths. We force it to only replace
# prefixes to avoid this case.
string(REGEX REPLACE "^${_from_dir}" "" _header ${_header})
get_filename_component(_extract_from "${_from_dir}/${_header}" ABSOLUTE)
get_filename_component(_extract_name ${_header} NAME)
get_filename_component(_extract_to "${CMAKE_INSTALL_INCLUDEDIR}/${_header}" DIRECTORY)

View File

@ -144,7 +144,6 @@ cc_library(
includes = ["."],
deps = [
":conformance_cc_proto",
"//src/google/protobuf:descriptor_legacy",
"//src/google/protobuf/util:differencer",
"//src/google/protobuf/util:json_util",
"//src/google/protobuf/util:type_resolver_util",
@ -329,6 +328,8 @@ objc_library(
":conformance_objc_proto",
"//:test_messages_proto2_objc_proto",
"//:test_messages_proto3_objc_proto",
"//src/google/protobuf/editions:test_messages_proto2_editions_objc_proto",
"//src/google/protobuf/editions:test_messages_proto3_editions_objc_proto",
],
)

View File

@ -10,6 +10,8 @@
#import "Conformance.pbobjc.h"
#import "google/protobuf/TestMessagesProto2.pbobjc.h"
#import "google/protobuf/TestMessagesProto3.pbobjc.h"
#import "google/protobuf/editions/golden/TestMessagesProto2Editions.pbobjc.h"
#import "google/protobuf/editions/golden/TestMessagesProto3Editions.pbobjc.h"
static void Die(NSString *format, ...) __dead2;
@ -49,22 +51,25 @@ static ConformanceResponse *DoTest(ConformanceRequest *request) {
break;
case ConformanceRequest_Payload_OneOfCase_ProtobufPayload: {
Class msgClass = nil;
if ([request.messageType isEqual:@"protobuf_test_messages.proto3.TestAllTypesProto3"]) {
msgClass = [Proto3TestAllTypesProto3 class];
} else if ([request.messageType
isEqual:@"protobuf_test_messages.proto2.TestAllTypesProto2"]) {
msgClass = [Proto2TestAllTypesProto2 class];
NSDictionary *mappings = @{
@"protobuf_test_messages.proto2.TestAllTypesProto2" : [Proto2TestAllTypesProto2 class],
@"protobuf_test_messages.proto3.TestAllTypesProto3" : [Proto3TestAllTypesProto3 class],
@"protobuf_test_messages.editions.proto2.TestAllTypesProto2" :
[EditionsProto2TestAllTypesProto2 class],
@"protobuf_test_messages.editions.proto3.TestAllTypesProto3" :
[EditionsProto3TestAllTypesProto3 class],
};
Class msgClass = mappings[request.messageType];
if (msgClass) {
NSError *error = nil;
testMessage = [msgClass parseFromData:request.protobufPayload error:&error];
if (!testMessage) {
response.parseError = [NSString stringWithFormat:@"Parse error: %@", error];
}
} else {
response.runtimeError =
[NSString stringWithFormat:@"Protobuf request had an unknown message_type: %@",
request.messageType];
break;
}
NSError *error = nil;
testMessage = [msgClass parseFromData:request.protobufPayload error:&error];
if (!testMessage) {
response.parseError = [NSString stringWithFormat:@"Parse error: %@", error];
}
break;
}

View File

@ -24,7 +24,6 @@
#include "absl/strings/string_view.h"
#include "conformance/conformance.pb.h"
#include "conformance/conformance.pb.h"
#include "google/protobuf/descriptor_legacy.h"
#include "google/protobuf/message.h"
#include "google/protobuf/text_format.h"
@ -143,13 +142,12 @@ ConformanceTestSuite::ConformanceRequestSetting::NewTestMessage() const {
std::string
ConformanceTestSuite::ConformanceRequestSetting::GetSyntaxIdentifier() const {
switch (FileDescriptorLegacy(prototype_message_.GetDescriptor()->file())
.syntax()) {
case FileDescriptorLegacy::Syntax::SYNTAX_PROTO3:
switch (prototype_message_.GetDescriptor()->file()->edition()) {
case Edition::EDITION_PROTO3:
return "Proto3";
case FileDescriptorLegacy::Syntax::SYNTAX_PROTO2:
case Edition::EDITION_PROTO2:
return "Proto2";
case FileDescriptorLegacy::Syntax::SYNTAX_EDITIONS: {
default: {
std::string id = "Editions";
if (prototype_message_.GetDescriptor()->name() == "TestAllTypesProto2") {
absl::StrAppend(&id, "_Proto2");
@ -159,8 +157,6 @@ ConformanceTestSuite::ConformanceRequestSetting::GetSyntaxIdentifier() const {
}
return id;
}
default:
return "Unknown";
}
}

View File

@ -1,4 +1,4 @@
#region Copyright notice and license
#region Copyright notice and license
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
//
@ -471,11 +471,11 @@ namespace Google.Protobuf
// Assume that anything non-bounds-related is covered in the Int32 case
[Test]
[TestCase("9223372036854775808")]
// Theoretical bound would be -9223372036854775809, but when that is parsed to a double
// we end up with the exact value of long.MinValue due to lack of precision. The value here
// is the "next double down".
[TestCase("-9223372036854780000")]
// Runtime implementation differences produce different results for values just outside
// (long.MinValue, long.MaxValue) which cannot be exactly represented as a double. Use the
// next values exactly representable as doubles to ensure consistency.
[TestCase("9223372036854777856")]
[TestCase("-9223372036854777856")]
public void NumberToInt64_Invalid(string jsonValue)
{
string json = "{ \"singleInt64\": " + jsonValue + "}";
@ -498,7 +498,10 @@ namespace Google.Protobuf
// Assume that anything non-bounds-related is covered in the Int32 case
[Test]
[TestCase("-1")]
[TestCase("18446744073709551616")]
// Runtime implementation differences produce different results for values just beyond
// ulong.MaxValue which cannot be exactly represented as a double. Use the next value
// exactly representable as a double to ensure consistency.
[TestCase("18446744073709555712")]
public void NumberToUInt64_Invalid(string jsonValue)
{
string json = "{ \"singleUint64\": " + jsonValue + "}";

View File

@ -33,24 +33,25 @@ namespace Google.Protobuf.Compiler {
"LnByb3RvYnVmLkZpbGVEZXNjcmlwdG9yUHJvdG8SRQoXc291cmNlX2ZpbGVf",
"ZGVzY3JpcHRvcnMYESADKAsyJC5nb29nbGUucHJvdG9idWYuRmlsZURlc2Ny",
"aXB0b3JQcm90bxI7ChBjb21waWxlcl92ZXJzaW9uGAMgASgLMiEuZ29vZ2xl",
"LnByb3RvYnVmLmNvbXBpbGVyLlZlcnNpb24i4AIKFUNvZGVHZW5lcmF0b3JS",
"LnByb3RvYnVmLmNvbXBpbGVyLlZlcnNpb24ikgMKFUNvZGVHZW5lcmF0b3JS",
"ZXNwb25zZRINCgVlcnJvchgBIAEoCRIaChJzdXBwb3J0ZWRfZmVhdHVyZXMY",
"AiABKAQSQgoEZmlsZRgPIAMoCzI0Lmdvb2dsZS5wcm90b2J1Zi5jb21waWxl",
"ci5Db2RlR2VuZXJhdG9yUmVzcG9uc2UuRmlsZRp/CgRGaWxlEgwKBG5hbWUY",
"ASABKAkSFwoPaW5zZXJ0aW9uX3BvaW50GAIgASgJEg8KB2NvbnRlbnQYDyAB",
"KAkSPwoTZ2VuZXJhdGVkX2NvZGVfaW5mbxgQIAEoCzIiLmdvb2dsZS5wcm90",
"b2J1Zi5HZW5lcmF0ZWRDb2RlSW5mbyJXCgdGZWF0dXJlEhAKDEZFQVRVUkVf",
"Tk9ORRAAEhsKF0ZFQVRVUkVfUFJPVE8zX09QVElPTkFMEAESHQoZRkVBVFVS",
"RV9TVVBQT1JUU19FRElUSU9OUxACQnIKHGNvbS5nb29nbGUucHJvdG9idWYu",
"Y29tcGlsZXJCDFBsdWdpblByb3Rvc1opZ29vZ2xlLmdvbGFuZy5vcmcvcHJv",
"dG9idWYvdHlwZXMvcGx1Z2lucGKqAhhHb29nbGUuUHJvdG9idWYuQ29tcGls",
"ZXI="));
"AiABKAQSFwoPbWluaW11bV9lZGl0aW9uGAMgASgFEhcKD21heGltdW1fZWRp",
"dGlvbhgEIAEoBRJCCgRmaWxlGA8gAygLMjQuZ29vZ2xlLnByb3RvYnVmLmNv",
"bXBpbGVyLkNvZGVHZW5lcmF0b3JSZXNwb25zZS5GaWxlGn8KBEZpbGUSDAoE",
"bmFtZRgBIAEoCRIXCg9pbnNlcnRpb25fcG9pbnQYAiABKAkSDwoHY29udGVu",
"dBgPIAEoCRI/ChNnZW5lcmF0ZWRfY29kZV9pbmZvGBAgASgLMiIuZ29vZ2xl",
"LnByb3RvYnVmLkdlbmVyYXRlZENvZGVJbmZvIlcKB0ZlYXR1cmUSEAoMRkVB",
"VFVSRV9OT05FEAASGwoXRkVBVFVSRV9QUk9UTzNfT1BUSU9OQUwQARIdChlG",
"RUFUVVJFX1NVUFBPUlRTX0VESVRJT05TEAJCcgocY29tLmdvb2dsZS5wcm90",
"b2J1Zi5jb21waWxlckIMUGx1Z2luUHJvdG9zWilnb29nbGUuZ29sYW5nLm9y",
"Zy9wcm90b2J1Zi90eXBlcy9wbHVnaW5wYqoCGEdvb2dsZS5Qcm90b2J1Zi5D",
"b21waWxlcg=="));
descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
new pbr::FileDescriptor[] { global::Google.Protobuf.Reflection.DescriptorReflection.Descriptor, },
new pbr::GeneratedClrTypeInfo(null, null, new pbr::GeneratedClrTypeInfo[] {
new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Compiler.Version), global::Google.Protobuf.Compiler.Version.Parser, new[]{ "Major", "Minor", "Patch", "Suffix" }, null, null, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Compiler.CodeGeneratorRequest), global::Google.Protobuf.Compiler.CodeGeneratorRequest.Parser, new[]{ "FileToGenerate", "Parameter", "ProtoFile", "SourceFileDescriptors", "CompilerVersion" }, null, null, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Compiler.CodeGeneratorResponse), global::Google.Protobuf.Compiler.CodeGeneratorResponse.Parser, new[]{ "Error", "SupportedFeatures", "File" }, null, new[]{ typeof(global::Google.Protobuf.Compiler.CodeGeneratorResponse.Types.Feature) }, null, new pbr::GeneratedClrTypeInfo[] { new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Compiler.CodeGeneratorResponse.Types.File), global::Google.Protobuf.Compiler.CodeGeneratorResponse.Types.File.Parser, new[]{ "Name", "InsertionPoint", "Content", "GeneratedCodeInfo" }, null, null, null, null)})
new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Compiler.CodeGeneratorResponse), global::Google.Protobuf.Compiler.CodeGeneratorResponse.Parser, new[]{ "Error", "SupportedFeatures", "MinimumEdition", "MaximumEdition", "File" }, null, new[]{ typeof(global::Google.Protobuf.Compiler.CodeGeneratorResponse.Types.Feature) }, null, new pbr::GeneratedClrTypeInfo[] { new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Compiler.CodeGeneratorResponse.Types.File), global::Google.Protobuf.Compiler.CodeGeneratorResponse.Types.File.Parser, new[]{ "Name", "InsertionPoint", "Content", "GeneratedCodeInfo" }, null, null, null, null)})
}));
}
#endregion
@ -836,6 +837,8 @@ namespace Google.Protobuf.Compiler {
_hasBits0 = other._hasBits0;
error_ = other.error_;
supportedFeatures_ = other.supportedFeatures_;
minimumEdition_ = other.minimumEdition_;
maximumEdition_ = other.maximumEdition_;
file_ = other.file_.Clone();
_unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
}
@ -913,6 +916,72 @@ namespace Google.Protobuf.Compiler {
_hasBits0 &= ~1;
}
/// <summary>Field number for the "minimum_edition" field.</summary>
public const int MinimumEditionFieldNumber = 3;
private readonly static int MinimumEditionDefaultValue = 0;
private int minimumEdition_;
/// <summary>
/// The minimum edition this plugin supports. This will be treated as an
/// Edition enum, but we want to allow unknown values. It should be specified
/// according the edition enum value, *not* the edition number. Only takes
/// effect for plugins that have FEATURE_SUPPORTS_EDITIONS set.
/// </summary>
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public int MinimumEdition {
get { if ((_hasBits0 & 2) != 0) { return minimumEdition_; } else { return MinimumEditionDefaultValue; } }
set {
_hasBits0 |= 2;
minimumEdition_ = value;
}
}
/// <summary>Gets whether the "minimum_edition" field is set</summary>
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public bool HasMinimumEdition {
get { return (_hasBits0 & 2) != 0; }
}
/// <summary>Clears the value of the "minimum_edition" field</summary>
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public void ClearMinimumEdition() {
_hasBits0 &= ~2;
}
/// <summary>Field number for the "maximum_edition" field.</summary>
public const int MaximumEditionFieldNumber = 4;
private readonly static int MaximumEditionDefaultValue = 0;
private int maximumEdition_;
/// <summary>
/// The maximum edition this plugin supports. This will be treated as an
/// Edition enum, but we want to allow unknown values. It should be specified
/// according the edition enum value, *not* the edition number. Only takes
/// effect for plugins that have FEATURE_SUPPORTS_EDITIONS set.
/// </summary>
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public int MaximumEdition {
get { if ((_hasBits0 & 4) != 0) { return maximumEdition_; } else { return MaximumEditionDefaultValue; } }
set {
_hasBits0 |= 4;
maximumEdition_ = value;
}
}
/// <summary>Gets whether the "maximum_edition" field is set</summary>
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public bool HasMaximumEdition {
get { return (_hasBits0 & 4) != 0; }
}
/// <summary>Clears the value of the "maximum_edition" field</summary>
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public void ClearMaximumEdition() {
_hasBits0 &= ~4;
}
/// <summary>Field number for the "file" field.</summary>
public const int FileFieldNumber = 15;
private static readonly pb::FieldCodec<global::Google.Protobuf.Compiler.CodeGeneratorResponse.Types.File> _repeated_file_codec
@ -941,6 +1010,8 @@ namespace Google.Protobuf.Compiler {
}
if (Error != other.Error) return false;
if (SupportedFeatures != other.SupportedFeatures) return false;
if (MinimumEdition != other.MinimumEdition) return false;
if (MaximumEdition != other.MaximumEdition) return false;
if(!file_.Equals(other.file_)) return false;
return Equals(_unknownFields, other._unknownFields);
}
@ -951,6 +1022,8 @@ namespace Google.Protobuf.Compiler {
int hash = 1;
if (HasError) hash ^= Error.GetHashCode();
if (HasSupportedFeatures) hash ^= SupportedFeatures.GetHashCode();
if (HasMinimumEdition) hash ^= MinimumEdition.GetHashCode();
if (HasMaximumEdition) hash ^= MaximumEdition.GetHashCode();
hash ^= file_.GetHashCode();
if (_unknownFields != null) {
hash ^= _unknownFields.GetHashCode();
@ -978,6 +1051,14 @@ namespace Google.Protobuf.Compiler {
output.WriteRawTag(16);
output.WriteUInt64(SupportedFeatures);
}
if (HasMinimumEdition) {
output.WriteRawTag(24);
output.WriteInt32(MinimumEdition);
}
if (HasMaximumEdition) {
output.WriteRawTag(32);
output.WriteInt32(MaximumEdition);
}
file_.WriteTo(output, _repeated_file_codec);
if (_unknownFields != null) {
_unknownFields.WriteTo(output);
@ -997,6 +1078,14 @@ namespace Google.Protobuf.Compiler {
output.WriteRawTag(16);
output.WriteUInt64(SupportedFeatures);
}
if (HasMinimumEdition) {
output.WriteRawTag(24);
output.WriteInt32(MinimumEdition);
}
if (HasMaximumEdition) {
output.WriteRawTag(32);
output.WriteInt32(MaximumEdition);
}
file_.WriteTo(ref output, _repeated_file_codec);
if (_unknownFields != null) {
_unknownFields.WriteTo(ref output);
@ -1014,6 +1103,12 @@ namespace Google.Protobuf.Compiler {
if (HasSupportedFeatures) {
size += 1 + pb::CodedOutputStream.ComputeUInt64Size(SupportedFeatures);
}
if (HasMinimumEdition) {
size += 1 + pb::CodedOutputStream.ComputeInt32Size(MinimumEdition);
}
if (HasMaximumEdition) {
size += 1 + pb::CodedOutputStream.ComputeInt32Size(MaximumEdition);
}
size += file_.CalculateSize(_repeated_file_codec);
if (_unknownFields != null) {
size += _unknownFields.CalculateSize();
@ -1033,6 +1128,12 @@ namespace Google.Protobuf.Compiler {
if (other.HasSupportedFeatures) {
SupportedFeatures = other.SupportedFeatures;
}
if (other.HasMinimumEdition) {
MinimumEdition = other.MinimumEdition;
}
if (other.HasMaximumEdition) {
MaximumEdition = other.MaximumEdition;
}
file_.Add(other.file_);
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
}
@ -1057,6 +1158,14 @@ namespace Google.Protobuf.Compiler {
SupportedFeatures = input.ReadUInt64();
break;
}
case 24: {
MinimumEdition = input.ReadInt32();
break;
}
case 32: {
MaximumEdition = input.ReadInt32();
break;
}
case 122: {
file_.AddEntriesFrom(input, _repeated_file_codec);
break;
@ -1084,6 +1193,14 @@ namespace Google.Protobuf.Compiler {
SupportedFeatures = input.ReadUInt64();
break;
}
case 24: {
MinimumEdition = input.ReadInt32();
break;
}
case 32: {
MaximumEdition = input.ReadInt32();
break;
}
case 122: {
file_.AddEntriesFrom(ref input, _repeated_file_codec);
break;

View File

@ -53,190 +53,190 @@ namespace Google.Protobuf.Reflection {
"X25hbWUYCiADKAkaZQoORXh0ZW5zaW9uUmFuZ2USDQoFc3RhcnQYASABKAUS",
"CwoDZW5kGAIgASgFEjcKB29wdGlvbnMYAyABKAsyJi5nb29nbGUucHJvdG9i",
"dWYuRXh0ZW5zaW9uUmFuZ2VPcHRpb25zGisKDVJlc2VydmVkUmFuZ2USDQoF",
"c3RhcnQYASABKAUSCwoDZW5kGAIgASgFIuADChVFeHRlbnNpb25SYW5nZU9w",
"c3RhcnQYASABKAUSCwoDZW5kGAIgASgFIuUDChVFeHRlbnNpb25SYW5nZU9w",
"dGlvbnMSQwoUdW5pbnRlcnByZXRlZF9vcHRpb24Y5wcgAygLMiQuZ29vZ2xl",
"LnByb3RvYnVmLlVuaW50ZXJwcmV0ZWRPcHRpb24STAoLZGVjbGFyYXRpb24Y",
"AiADKAsyMi5nb29nbGUucHJvdG9idWYuRXh0ZW5zaW9uUmFuZ2VPcHRpb25z",
"LkRlY2xhcmF0aW9uQgOIAQISLQoIZmVhdHVyZXMYMiABKAsyGy5nb29nbGUu",
"cHJvdG9idWYuRmVhdHVyZVNldBJaCgx2ZXJpZmljYXRpb24YAyABKA4yOC5n",
"cHJvdG9idWYuRmVhdHVyZVNldBJfCgx2ZXJpZmljYXRpb24YAyABKA4yOC5n",
"b29nbGUucHJvdG9idWYuRXh0ZW5zaW9uUmFuZ2VPcHRpb25zLlZlcmlmaWNh",
"dGlvblN0YXRlOgpVTlZFUklGSUVEGmgKC0RlY2xhcmF0aW9uEg4KBm51bWJl",
"chgBIAEoBRIRCglmdWxsX25hbWUYAiABKAkSDAoEdHlwZRgDIAEoCRIQCghy",
"ZXNlcnZlZBgFIAEoCBIQCghyZXBlYXRlZBgGIAEoCEoECAQQBSI0ChFWZXJp",
"ZmljYXRpb25TdGF0ZRIPCgtERUNMQVJBVElPThAAEg4KClVOVkVSSUZJRUQQ",
"ASoJCOgHEICAgIACItUFChRGaWVsZERlc2NyaXB0b3JQcm90bxIMCgRuYW1l",
"GAEgASgJEg4KBm51bWJlchgDIAEoBRI6CgVsYWJlbBgEIAEoDjIrLmdvb2ds",
"ZS5wcm90b2J1Zi5GaWVsZERlc2NyaXB0b3JQcm90by5MYWJlbBI4CgR0eXBl",
"GAUgASgOMiouZ29vZ2xlLnByb3RvYnVmLkZpZWxkRGVzY3JpcHRvclByb3Rv",
"LlR5cGUSEQoJdHlwZV9uYW1lGAYgASgJEhAKCGV4dGVuZGVlGAIgASgJEhUK",
"DWRlZmF1bHRfdmFsdWUYByABKAkSEwoLb25lb2ZfaW5kZXgYCSABKAUSEQoJ",
"anNvbl9uYW1lGAogASgJEi4KB29wdGlvbnMYCCABKAsyHS5nb29nbGUucHJv",
"dG9idWYuRmllbGRPcHRpb25zEhcKD3Byb3RvM19vcHRpb25hbBgRIAEoCCK2",
"AgoEVHlwZRIPCgtUWVBFX0RPVUJMRRABEg4KClRZUEVfRkxPQVQQAhIOCgpU",
"WVBFX0lOVDY0EAMSDwoLVFlQRV9VSU5UNjQQBBIOCgpUWVBFX0lOVDMyEAUS",
"EAoMVFlQRV9GSVhFRDY0EAYSEAoMVFlQRV9GSVhFRDMyEAcSDQoJVFlQRV9C",
"T09MEAgSDwoLVFlQRV9TVFJJTkcQCRIOCgpUWVBFX0dST1VQEAoSEAoMVFlQ",
"RV9NRVNTQUdFEAsSDgoKVFlQRV9CWVRFUxAMEg8KC1RZUEVfVUlOVDMyEA0S",
"DQoJVFlQRV9FTlVNEA4SEQoNVFlQRV9TRklYRUQzMhAPEhEKDVRZUEVfU0ZJ",
"WEVENjQQEBIPCgtUWVBFX1NJTlQzMhAREg8KC1RZUEVfU0lOVDY0EBIiQwoF",
"TGFiZWwSEgoOTEFCRUxfT1BUSU9OQUwQARISCg5MQUJFTF9SRVBFQVRFRBAD",
"EhIKDkxBQkVMX1JFUVVJUkVEEAIiVAoUT25lb2ZEZXNjcmlwdG9yUHJvdG8S",
"DAoEbmFtZRgBIAEoCRIuCgdvcHRpb25zGAIgASgLMh0uZ29vZ2xlLnByb3Rv",
"YnVmLk9uZW9mT3B0aW9ucyKkAgoTRW51bURlc2NyaXB0b3JQcm90bxIMCgRu",
"YW1lGAEgASgJEjgKBXZhbHVlGAIgAygLMikuZ29vZ2xlLnByb3RvYnVmLkVu",
"dW1WYWx1ZURlc2NyaXB0b3JQcm90bxItCgdvcHRpb25zGAMgASgLMhwuZ29v",
"Z2xlLnByb3RvYnVmLkVudW1PcHRpb25zEk4KDnJlc2VydmVkX3JhbmdlGAQg",
"AygLMjYuZ29vZ2xlLnByb3RvYnVmLkVudW1EZXNjcmlwdG9yUHJvdG8uRW51",
"bVJlc2VydmVkUmFuZ2USFQoNcmVzZXJ2ZWRfbmFtZRgFIAMoCRovChFFbnVt",
"UmVzZXJ2ZWRSYW5nZRINCgVzdGFydBgBIAEoBRILCgNlbmQYAiABKAUibAoY",
"RW51bVZhbHVlRGVzY3JpcHRvclByb3RvEgwKBG5hbWUYASABKAkSDgoGbnVt",
"YmVyGAIgASgFEjIKB29wdGlvbnMYAyABKAsyIS5nb29nbGUucHJvdG9idWYu",
"RW51bVZhbHVlT3B0aW9ucyKQAQoWU2VydmljZURlc2NyaXB0b3JQcm90bxIM",
"CgRuYW1lGAEgASgJEjYKBm1ldGhvZBgCIAMoCzImLmdvb2dsZS5wcm90b2J1",
"Zi5NZXRob2REZXNjcmlwdG9yUHJvdG8SMAoHb3B0aW9ucxgDIAEoCzIfLmdv",
"b2dsZS5wcm90b2J1Zi5TZXJ2aWNlT3B0aW9ucyLBAQoVTWV0aG9kRGVzY3Jp",
"cHRvclByb3RvEgwKBG5hbWUYASABKAkSEgoKaW5wdXRfdHlwZRgCIAEoCRIT",
"CgtvdXRwdXRfdHlwZRgDIAEoCRIvCgdvcHRpb25zGAQgASgLMh4uZ29vZ2xl",
"LnByb3RvYnVmLk1ldGhvZE9wdGlvbnMSHwoQY2xpZW50X3N0cmVhbWluZxgF",
"IAEoCDoFZmFsc2USHwoQc2VydmVyX3N0cmVhbWluZxgGIAEoCDoFZmFsc2Ui",
"1AYKC0ZpbGVPcHRpb25zEhQKDGphdmFfcGFja2FnZRgBIAEoCRIcChRqYXZh",
"X291dGVyX2NsYXNzbmFtZRgIIAEoCRIiChNqYXZhX211bHRpcGxlX2ZpbGVz",
"GAogASgIOgVmYWxzZRIpCh1qYXZhX2dlbmVyYXRlX2VxdWFsc19hbmRfaGFz",
"aBgUIAEoCEICGAESJQoWamF2YV9zdHJpbmdfY2hlY2tfdXRmOBgbIAEoCDoF",
"ZmFsc2USRgoMb3B0aW1pemVfZm9yGAkgASgOMikuZ29vZ2xlLnByb3RvYnVm",
"LkZpbGVPcHRpb25zLk9wdGltaXplTW9kZToFU1BFRUQSEgoKZ29fcGFja2Fn",
"ZRgLIAEoCRIiChNjY19nZW5lcmljX3NlcnZpY2VzGBAgASgIOgVmYWxzZRIk",
"ChVqYXZhX2dlbmVyaWNfc2VydmljZXMYESABKAg6BWZhbHNlEiIKE3B5X2dl",
"bmVyaWNfc2VydmljZXMYEiABKAg6BWZhbHNlEiMKFHBocF9nZW5lcmljX3Nl",
"cnZpY2VzGCogASgIOgVmYWxzZRIZCgpkZXByZWNhdGVkGBcgASgIOgVmYWxz",
"ZRIeChBjY19lbmFibGVfYXJlbmFzGB8gASgIOgR0cnVlEhkKEW9iamNfY2xh",
"c3NfcHJlZml4GCQgASgJEhgKEGNzaGFycF9uYW1lc3BhY2UYJSABKAkSFAoM",
"c3dpZnRfcHJlZml4GCcgASgJEhgKEHBocF9jbGFzc19wcmVmaXgYKCABKAkS",
"FQoNcGhwX25hbWVzcGFjZRgpIAEoCRIeChZwaHBfbWV0YWRhdGFfbmFtZXNw",
"YWNlGCwgASgJEhQKDHJ1YnlfcGFja2FnZRgtIAEoCRItCghmZWF0dXJlcxgy",
"IAEoCzIbLmdvb2dsZS5wcm90b2J1Zi5GZWF0dXJlU2V0EkMKFHVuaW50ZXJw",
"cmV0ZWRfb3B0aW9uGOcHIAMoCzIkLmdvb2dsZS5wcm90b2J1Zi5VbmludGVy",
"cHJldGVkT3B0aW9uIjoKDE9wdGltaXplTW9kZRIJCgVTUEVFRBABEg0KCUNP",
"REVfU0laRRACEhAKDExJVEVfUlVOVElNRRADKgkI6AcQgICAgAJKBAgmECci",
"5wIKDk1lc3NhZ2VPcHRpb25zEiYKF21lc3NhZ2Vfc2V0X3dpcmVfZm9ybWF0",
"GAEgASgIOgVmYWxzZRIuCh9ub19zdGFuZGFyZF9kZXNjcmlwdG9yX2FjY2Vz",
"c29yGAIgASgIOgVmYWxzZRIZCgpkZXByZWNhdGVkGAMgASgIOgVmYWxzZRIR",
"CgltYXBfZW50cnkYByABKAgSMgomZGVwcmVjYXRlZF9sZWdhY3lfanNvbl9m",
"aWVsZF9jb25mbGljdHMYCyABKAhCAhgBEi0KCGZlYXR1cmVzGAwgASgLMhsu",
"Z29vZ2xlLnByb3RvYnVmLkZlYXR1cmVTZXQSQwoUdW5pbnRlcnByZXRlZF9v",
"dGlvblN0YXRlOgpVTlZFUklGSUVEQgOIAQIaaAoLRGVjbGFyYXRpb24SDgoG",
"bnVtYmVyGAEgASgFEhEKCWZ1bGxfbmFtZRgCIAEoCRIMCgR0eXBlGAMgASgJ",
"EhAKCHJlc2VydmVkGAUgASgIEhAKCHJlcGVhdGVkGAYgASgISgQIBBAFIjQK",
"EVZlcmlmaWNhdGlvblN0YXRlEg8KC0RFQ0xBUkFUSU9OEAASDgoKVU5WRVJJ",
"RklFRBABKgkI6AcQgICAgAIi1QUKFEZpZWxkRGVzY3JpcHRvclByb3RvEgwK",
"BG5hbWUYASABKAkSDgoGbnVtYmVyGAMgASgFEjoKBWxhYmVsGAQgASgOMisu",
"Z29vZ2xlLnByb3RvYnVmLkZpZWxkRGVzY3JpcHRvclByb3RvLkxhYmVsEjgK",
"BHR5cGUYBSABKA4yKi5nb29nbGUucHJvdG9idWYuRmllbGREZXNjcmlwdG9y",
"UHJvdG8uVHlwZRIRCgl0eXBlX25hbWUYBiABKAkSEAoIZXh0ZW5kZWUYAiAB",
"KAkSFQoNZGVmYXVsdF92YWx1ZRgHIAEoCRITCgtvbmVvZl9pbmRleBgJIAEo",
"BRIRCglqc29uX25hbWUYCiABKAkSLgoHb3B0aW9ucxgIIAEoCzIdLmdvb2ds",
"ZS5wcm90b2J1Zi5GaWVsZE9wdGlvbnMSFwoPcHJvdG8zX29wdGlvbmFsGBEg",
"ASgIIrYCCgRUeXBlEg8KC1RZUEVfRE9VQkxFEAESDgoKVFlQRV9GTE9BVBAC",
"Eg4KClRZUEVfSU5UNjQQAxIPCgtUWVBFX1VJTlQ2NBAEEg4KClRZUEVfSU5U",
"MzIQBRIQCgxUWVBFX0ZJWEVENjQQBhIQCgxUWVBFX0ZJWEVEMzIQBxINCglU",
"WVBFX0JPT0wQCBIPCgtUWVBFX1NUUklORxAJEg4KClRZUEVfR1JPVVAQChIQ",
"CgxUWVBFX01FU1NBR0UQCxIOCgpUWVBFX0JZVEVTEAwSDwoLVFlQRV9VSU5U",
"MzIQDRINCglUWVBFX0VOVU0QDhIRCg1UWVBFX1NGSVhFRDMyEA8SEQoNVFlQ",
"RV9TRklYRUQ2NBAQEg8KC1RZUEVfU0lOVDMyEBESDwoLVFlQRV9TSU5UNjQQ",
"EiJDCgVMYWJlbBISCg5MQUJFTF9PUFRJT05BTBABEhIKDkxBQkVMX1JFUEVB",
"VEVEEAMSEgoOTEFCRUxfUkVRVUlSRUQQAiJUChRPbmVvZkRlc2NyaXB0b3JQ",
"cm90bxIMCgRuYW1lGAEgASgJEi4KB29wdGlvbnMYAiABKAsyHS5nb29nbGUu",
"cHJvdG9idWYuT25lb2ZPcHRpb25zIqQCChNFbnVtRGVzY3JpcHRvclByb3Rv",
"EgwKBG5hbWUYASABKAkSOAoFdmFsdWUYAiADKAsyKS5nb29nbGUucHJvdG9i",
"dWYuRW51bVZhbHVlRGVzY3JpcHRvclByb3RvEi0KB29wdGlvbnMYAyABKAsy",
"HC5nb29nbGUucHJvdG9idWYuRW51bU9wdGlvbnMSTgoOcmVzZXJ2ZWRfcmFu",
"Z2UYBCADKAsyNi5nb29nbGUucHJvdG9idWYuRW51bURlc2NyaXB0b3JQcm90",
"by5FbnVtUmVzZXJ2ZWRSYW5nZRIVCg1yZXNlcnZlZF9uYW1lGAUgAygJGi8K",
"EUVudW1SZXNlcnZlZFJhbmdlEg0KBXN0YXJ0GAEgASgFEgsKA2VuZBgCIAEo",
"BSJsChhFbnVtVmFsdWVEZXNjcmlwdG9yUHJvdG8SDAoEbmFtZRgBIAEoCRIO",
"CgZudW1iZXIYAiABKAUSMgoHb3B0aW9ucxgDIAEoCzIhLmdvb2dsZS5wcm90",
"b2J1Zi5FbnVtVmFsdWVPcHRpb25zIpABChZTZXJ2aWNlRGVzY3JpcHRvclBy",
"b3RvEgwKBG5hbWUYASABKAkSNgoGbWV0aG9kGAIgAygLMiYuZ29vZ2xlLnBy",
"b3RvYnVmLk1ldGhvZERlc2NyaXB0b3JQcm90bxIwCgdvcHRpb25zGAMgASgL",
"Mh8uZ29vZ2xlLnByb3RvYnVmLlNlcnZpY2VPcHRpb25zIsEBChVNZXRob2RE",
"ZXNjcmlwdG9yUHJvdG8SDAoEbmFtZRgBIAEoCRISCgppbnB1dF90eXBlGAIg",
"ASgJEhMKC291dHB1dF90eXBlGAMgASgJEi8KB29wdGlvbnMYBCABKAsyHi5n",
"b29nbGUucHJvdG9idWYuTWV0aG9kT3B0aW9ucxIfChBjbGllbnRfc3RyZWFt",
"aW5nGAUgASgIOgVmYWxzZRIfChBzZXJ2ZXJfc3RyZWFtaW5nGAYgASgIOgVm",
"YWxzZSLUBgoLRmlsZU9wdGlvbnMSFAoMamF2YV9wYWNrYWdlGAEgASgJEhwK",
"FGphdmFfb3V0ZXJfY2xhc3NuYW1lGAggASgJEiIKE2phdmFfbXVsdGlwbGVf",
"ZmlsZXMYCiABKAg6BWZhbHNlEikKHWphdmFfZ2VuZXJhdGVfZXF1YWxzX2Fu",
"ZF9oYXNoGBQgASgIQgIYARIlChZqYXZhX3N0cmluZ19jaGVja191dGY4GBsg",
"ASgIOgVmYWxzZRJGCgxvcHRpbWl6ZV9mb3IYCSABKA4yKS5nb29nbGUucHJv",
"dG9idWYuRmlsZU9wdGlvbnMuT3B0aW1pemVNb2RlOgVTUEVFRBISCgpnb19w",
"YWNrYWdlGAsgASgJEiIKE2NjX2dlbmVyaWNfc2VydmljZXMYECABKAg6BWZh",
"bHNlEiQKFWphdmFfZ2VuZXJpY19zZXJ2aWNlcxgRIAEoCDoFZmFsc2USIgoT",
"cHlfZ2VuZXJpY19zZXJ2aWNlcxgSIAEoCDoFZmFsc2USIwoUcGhwX2dlbmVy",
"aWNfc2VydmljZXMYKiABKAg6BWZhbHNlEhkKCmRlcHJlY2F0ZWQYFyABKAg6",
"BWZhbHNlEh4KEGNjX2VuYWJsZV9hcmVuYXMYHyABKAg6BHRydWUSGQoRb2Jq",
"Y19jbGFzc19wcmVmaXgYJCABKAkSGAoQY3NoYXJwX25hbWVzcGFjZRglIAEo",
"CRIUCgxzd2lmdF9wcmVmaXgYJyABKAkSGAoQcGhwX2NsYXNzX3ByZWZpeBgo",
"IAEoCRIVCg1waHBfbmFtZXNwYWNlGCkgASgJEh4KFnBocF9tZXRhZGF0YV9u",
"YW1lc3BhY2UYLCABKAkSFAoMcnVieV9wYWNrYWdlGC0gASgJEi0KCGZlYXR1",
"cmVzGDIgASgLMhsuZ29vZ2xlLnByb3RvYnVmLkZlYXR1cmVTZXQSQwoUdW5p",
"bnRlcnByZXRlZF9vcHRpb24Y5wcgAygLMiQuZ29vZ2xlLnByb3RvYnVmLlVu",
"aW50ZXJwcmV0ZWRPcHRpb24iOgoMT3B0aW1pemVNb2RlEgkKBVNQRUVEEAES",
"DQoJQ09ERV9TSVpFEAISEAoMTElURV9SVU5USU1FEAMqCQjoBxCAgICAAkoE",
"CCYQJyLnAgoOTWVzc2FnZU9wdGlvbnMSJgoXbWVzc2FnZV9zZXRfd2lyZV9m",
"b3JtYXQYASABKAg6BWZhbHNlEi4KH25vX3N0YW5kYXJkX2Rlc2NyaXB0b3Jf",
"YWNjZXNzb3IYAiABKAg6BWZhbHNlEhkKCmRlcHJlY2F0ZWQYAyABKAg6BWZh",
"bHNlEhEKCW1hcF9lbnRyeRgHIAEoCBIyCiZkZXByZWNhdGVkX2xlZ2FjeV9q",
"c29uX2ZpZWxkX2NvbmZsaWN0cxgLIAEoCEICGAESLQoIZmVhdHVyZXMYDCAB",
"KAsyGy5nb29nbGUucHJvdG9idWYuRmVhdHVyZVNldBJDChR1bmludGVycHJl",
"dGVkX29wdGlvbhjnByADKAsyJC5nb29nbGUucHJvdG9idWYuVW5pbnRlcnBy",
"ZXRlZE9wdGlvbioJCOgHEICAgIACSgQIBBAFSgQIBRAGSgQIBhAHSgQICBAJ",
"SgQICRAKIo0JCgxGaWVsZE9wdGlvbnMSOgoFY3R5cGUYASABKA4yIy5nb29n",
"bGUucHJvdG9idWYuRmllbGRPcHRpb25zLkNUeXBlOgZTVFJJTkcSDgoGcGFj",
"a2VkGAIgASgIEj8KBmpzdHlwZRgGIAEoDjIkLmdvb2dsZS5wcm90b2J1Zi5G",
"aWVsZE9wdGlvbnMuSlNUeXBlOglKU19OT1JNQUwSEwoEbGF6eRgFIAEoCDoF",
"ZmFsc2USHgoPdW52ZXJpZmllZF9sYXp5GA8gASgIOgVmYWxzZRIZCgpkZXBy",
"ZWNhdGVkGAMgASgIOgVmYWxzZRITCgR3ZWFrGAogASgIOgVmYWxzZRIbCgxk",
"ZWJ1Z19yZWRhY3QYECABKAg6BWZhbHNlEkAKCXJldGVudGlvbhgRIAEoDjIt",
"Lmdvb2dsZS5wcm90b2J1Zi5GaWVsZE9wdGlvbnMuT3B0aW9uUmV0ZW50aW9u",
"Ej8KB3RhcmdldHMYEyADKA4yLi5nb29nbGUucHJvdG9idWYuRmllbGRPcHRp",
"b25zLk9wdGlvblRhcmdldFR5cGUSRgoQZWRpdGlvbl9kZWZhdWx0cxgUIAMo",
"CzIsLmdvb2dsZS5wcm90b2J1Zi5GaWVsZE9wdGlvbnMuRWRpdGlvbkRlZmF1",
"bHQSLQoIZmVhdHVyZXMYFSABKAsyGy5nb29nbGUucHJvdG9idWYuRmVhdHVy",
"ZVNldBJDChR1bmludGVycHJldGVkX29wdGlvbhjnByADKAsyJC5nb29nbGUu",
"cHJvdG9idWYuVW5pbnRlcnByZXRlZE9wdGlvbhpKCg5FZGl0aW9uRGVmYXVs",
"dBIpCgdlZGl0aW9uGAMgASgOMhguZ29vZ2xlLnByb3RvYnVmLkVkaXRpb24S",
"DQoFdmFsdWUYAiABKAkiLwoFQ1R5cGUSCgoGU1RSSU5HEAASCAoEQ09SRBAB",
"EhAKDFNUUklOR19QSUVDRRACIjUKBkpTVHlwZRINCglKU19OT1JNQUwQABIN",
"CglKU19TVFJJTkcQARINCglKU19OVU1CRVIQAiJVCg9PcHRpb25SZXRlbnRp",
"b24SFQoRUkVURU5USU9OX1VOS05PV04QABIVChFSRVRFTlRJT05fUlVOVElN",
"RRABEhQKEFJFVEVOVElPTl9TT1VSQ0UQAiKMAgoQT3B0aW9uVGFyZ2V0VHlw",
"ZRIXChNUQVJHRVRfVFlQRV9VTktOT1dOEAASFAoQVEFSR0VUX1RZUEVfRklM",
"RRABEh8KG1RBUkdFVF9UWVBFX0VYVEVOU0lPTl9SQU5HRRACEhcKE1RBUkdF",
"VF9UWVBFX01FU1NBR0UQAxIVChFUQVJHRVRfVFlQRV9GSUVMRBAEEhUKEVRB",
"UkdFVF9UWVBFX09ORU9GEAUSFAoQVEFSR0VUX1RZUEVfRU5VTRAGEhoKFlRB",
"UkdFVF9UWVBFX0VOVU1fRU5UUlkQBxIXChNUQVJHRVRfVFlQRV9TRVJWSUNF",
"EAgSFgoSVEFSR0VUX1RZUEVfTUVUSE9EEAkqCQjoBxCAgICAAkoECAQQBUoE",
"CBIQEyKNAQoMT25lb2ZPcHRpb25zEi0KCGZlYXR1cmVzGAEgASgLMhsuZ29v",
"Z2xlLnByb3RvYnVmLkZlYXR1cmVTZXQSQwoUdW5pbnRlcnByZXRlZF9vcHRp",
"b24Y5wcgAygLMiQuZ29vZ2xlLnByb3RvYnVmLlVuaW50ZXJwcmV0ZWRPcHRp",
"b24qCQjoBxCAgICAAiL2AQoLRW51bU9wdGlvbnMSEwoLYWxsb3dfYWxpYXMY",
"AiABKAgSGQoKZGVwcmVjYXRlZBgDIAEoCDoFZmFsc2USMgomZGVwcmVjYXRl",
"ZF9sZWdhY3lfanNvbl9maWVsZF9jb25mbGljdHMYBiABKAhCAhgBEi0KCGZl",
"YXR1cmVzGAcgASgLMhsuZ29vZ2xlLnByb3RvYnVmLkZlYXR1cmVTZXQSQwoU",
"dW5pbnRlcnByZXRlZF9vcHRpb24Y5wcgAygLMiQuZ29vZ2xlLnByb3RvYnVm",
"LlVuaW50ZXJwcmV0ZWRPcHRpb24qCQjoBxCAgICAAkoECAUQBiLJAQoQRW51",
"bVZhbHVlT3B0aW9ucxIZCgpkZXByZWNhdGVkGAEgASgIOgVmYWxzZRItCghm",
"ZWF0dXJlcxgCIAEoCzIbLmdvb2dsZS5wcm90b2J1Zi5GZWF0dXJlU2V0EhsK",
"DGRlYnVnX3JlZGFjdBgDIAEoCDoFZmFsc2USQwoUdW5pbnRlcnByZXRlZF9v",
"cHRpb24Y5wcgAygLMiQuZ29vZ2xlLnByb3RvYnVmLlVuaW50ZXJwcmV0ZWRP",
"cHRpb24qCQjoBxCAgICAAkoECAQQBUoECAUQBkoECAYQB0oECAgQCUoECAkQ",
"CiKNCQoMRmllbGRPcHRpb25zEjoKBWN0eXBlGAEgASgOMiMuZ29vZ2xlLnBy",
"b3RvYnVmLkZpZWxkT3B0aW9ucy5DVHlwZToGU1RSSU5HEg4KBnBhY2tlZBgC",
"IAEoCBI/CgZqc3R5cGUYBiABKA4yJC5nb29nbGUucHJvdG9idWYuRmllbGRP",
"cHRpb25zLkpTVHlwZToJSlNfTk9STUFMEhMKBGxhenkYBSABKAg6BWZhbHNl",
"Eh4KD3VudmVyaWZpZWRfbGF6eRgPIAEoCDoFZmFsc2USGQoKZGVwcmVjYXRl",
"ZBgDIAEoCDoFZmFsc2USEwoEd2VhaxgKIAEoCDoFZmFsc2USGwoMZGVidWdf",
"cmVkYWN0GBAgASgIOgVmYWxzZRJACglyZXRlbnRpb24YESABKA4yLS5nb29n",
"bGUucHJvdG9idWYuRmllbGRPcHRpb25zLk9wdGlvblJldGVudGlvbhI/Cgd0",
"YXJnZXRzGBMgAygOMi4uZ29vZ2xlLnByb3RvYnVmLkZpZWxkT3B0aW9ucy5P",
"cHRpb25UYXJnZXRUeXBlEkYKEGVkaXRpb25fZGVmYXVsdHMYFCADKAsyLC5n",
"b29nbGUucHJvdG9idWYuRmllbGRPcHRpb25zLkVkaXRpb25EZWZhdWx0Ei0K",
"CGZlYXR1cmVzGBUgASgLMhsuZ29vZ2xlLnByb3RvYnVmLkZlYXR1cmVTZXQS",
"QwoUdW5pbnRlcnByZXRlZF9vcHRpb24Y5wcgAygLMiQuZ29vZ2xlLnByb3Rv",
"YnVmLlVuaW50ZXJwcmV0ZWRPcHRpb24aSgoORWRpdGlvbkRlZmF1bHQSKQoH",
"ZWRpdGlvbhgDIAEoDjIYLmdvb2dsZS5wcm90b2J1Zi5FZGl0aW9uEg0KBXZh",
"bHVlGAIgASgJIi8KBUNUeXBlEgoKBlNUUklORxAAEggKBENPUkQQARIQCgxT",
"VFJJTkdfUElFQ0UQAiI1CgZKU1R5cGUSDQoJSlNfTk9STUFMEAASDQoJSlNf",
"U1RSSU5HEAESDQoJSlNfTlVNQkVSEAIiVQoPT3B0aW9uUmV0ZW50aW9uEhUK",
"EVJFVEVOVElPTl9VTktOT1dOEAASFQoRUkVURU5USU9OX1JVTlRJTUUQARIU",
"ChBSRVRFTlRJT05fU09VUkNFEAIijAIKEE9wdGlvblRhcmdldFR5cGUSFwoT",
"VEFSR0VUX1RZUEVfVU5LTk9XThAAEhQKEFRBUkdFVF9UWVBFX0ZJTEUQARIf",
"ChtUQVJHRVRfVFlQRV9FWFRFTlNJT05fUkFOR0UQAhIXChNUQVJHRVRfVFlQ",
"RV9NRVNTQUdFEAMSFQoRVEFSR0VUX1RZUEVfRklFTEQQBBIVChFUQVJHRVRf",
"VFlQRV9PTkVPRhAFEhQKEFRBUkdFVF9UWVBFX0VOVU0QBhIaChZUQVJHRVRf",
"VFlQRV9FTlVNX0VOVFJZEAcSFwoTVEFSR0VUX1RZUEVfU0VSVklDRRAIEhYK",
"ElRBUkdFVF9UWVBFX01FVEhPRBAJKgkI6AcQgICAgAJKBAgEEAVKBAgSEBMi",
"jQEKDE9uZW9mT3B0aW9ucxItCghmZWF0dXJlcxgBIAEoCzIbLmdvb2dsZS5w",
"cHRpb24qCQjoBxCAgICAAiKqAQoOU2VydmljZU9wdGlvbnMSLQoIZmVhdHVy",
"ZXMYIiABKAsyGy5nb29nbGUucHJvdG9idWYuRmVhdHVyZVNldBIZCgpkZXBy",
"ZWNhdGVkGCEgASgIOgVmYWxzZRJDChR1bmludGVycHJldGVkX29wdGlvbhjn",
"ByADKAsyJC5nb29nbGUucHJvdG9idWYuVW5pbnRlcnByZXRlZE9wdGlvbioJ",
"COgHEICAgIACItwCCg1NZXRob2RPcHRpb25zEhkKCmRlcHJlY2F0ZWQYISAB",
"KAg6BWZhbHNlEl8KEWlkZW1wb3RlbmN5X2xldmVsGCIgASgOMi8uZ29vZ2xl",
"LnByb3RvYnVmLk1ldGhvZE9wdGlvbnMuSWRlbXBvdGVuY3lMZXZlbDoTSURF",
"TVBPVEVOQ1lfVU5LTk9XThItCghmZWF0dXJlcxgjIAEoCzIbLmdvb2dsZS5w",
"cm90b2J1Zi5GZWF0dXJlU2V0EkMKFHVuaW50ZXJwcmV0ZWRfb3B0aW9uGOcH",
"IAMoCzIkLmdvb2dsZS5wcm90b2J1Zi5VbmludGVycHJldGVkT3B0aW9uKgkI",
"6AcQgICAgAIi9gEKC0VudW1PcHRpb25zEhMKC2FsbG93X2FsaWFzGAIgASgI",
"EhkKCmRlcHJlY2F0ZWQYAyABKAg6BWZhbHNlEjIKJmRlcHJlY2F0ZWRfbGVn",
"YWN5X2pzb25fZmllbGRfY29uZmxpY3RzGAYgASgIQgIYARItCghmZWF0dXJl",
"cxgHIAEoCzIbLmdvb2dsZS5wcm90b2J1Zi5GZWF0dXJlU2V0EkMKFHVuaW50",
"ZXJwcmV0ZWRfb3B0aW9uGOcHIAMoCzIkLmdvb2dsZS5wcm90b2J1Zi5Vbmlu",
"dGVycHJldGVkT3B0aW9uKgkI6AcQgICAgAJKBAgFEAYiyQEKEEVudW1WYWx1",
"ZU9wdGlvbnMSGQoKZGVwcmVjYXRlZBgBIAEoCDoFZmFsc2USLQoIZmVhdHVy",
"ZXMYAiABKAsyGy5nb29nbGUucHJvdG9idWYuRmVhdHVyZVNldBIbCgxkZWJ1",
"Z19yZWRhY3QYAyABKAg6BWZhbHNlEkMKFHVuaW50ZXJwcmV0ZWRfb3B0aW9u",
"GOcHIAMoCzIkLmdvb2dsZS5wcm90b2J1Zi5VbmludGVycHJldGVkT3B0aW9u",
"KgkI6AcQgICAgAIiqgEKDlNlcnZpY2VPcHRpb25zEi0KCGZlYXR1cmVzGCIg",
"ASgLMhsuZ29vZ2xlLnByb3RvYnVmLkZlYXR1cmVTZXQSGQoKZGVwcmVjYXRl",
"ZBghIAEoCDoFZmFsc2USQwoUdW5pbnRlcnByZXRlZF9vcHRpb24Y5wcgAygL",
"MiQuZ29vZ2xlLnByb3RvYnVmLlVuaW50ZXJwcmV0ZWRPcHRpb24qCQjoBxCA",
"gICAAiLcAgoNTWV0aG9kT3B0aW9ucxIZCgpkZXByZWNhdGVkGCEgASgIOgVm",
"YWxzZRJfChFpZGVtcG90ZW5jeV9sZXZlbBgiIAEoDjIvLmdvb2dsZS5wcm90",
"b2J1Zi5NZXRob2RPcHRpb25zLklkZW1wb3RlbmN5TGV2ZWw6E0lERU1QT1RF",
"TkNZX1VOS05PV04SLQoIZmVhdHVyZXMYIyABKAsyGy5nb29nbGUucHJvdG9i",
"dWYuRmVhdHVyZVNldBJDChR1bmludGVycHJldGVkX29wdGlvbhjnByADKAsy",
"JC5nb29nbGUucHJvdG9idWYuVW5pbnRlcnByZXRlZE9wdGlvbiJQChBJZGVt",
"cG90ZW5jeUxldmVsEhcKE0lERU1QT1RFTkNZX1VOS05PV04QABITCg9OT19T",
"SURFX0VGRkVDVFMQARIOCgpJREVNUE9URU5UEAIqCQjoBxCAgICAAiKeAgoT",
"VW5pbnRlcnByZXRlZE9wdGlvbhI7CgRuYW1lGAIgAygLMi0uZ29vZ2xlLnBy",
"b3RvYnVmLlVuaW50ZXJwcmV0ZWRPcHRpb24uTmFtZVBhcnQSGAoQaWRlbnRp",
"Zmllcl92YWx1ZRgDIAEoCRIaChJwb3NpdGl2ZV9pbnRfdmFsdWUYBCABKAQS",
"GgoSbmVnYXRpdmVfaW50X3ZhbHVlGAUgASgDEhQKDGRvdWJsZV92YWx1ZRgG",
"IAEoARIUCgxzdHJpbmdfdmFsdWUYByABKAwSFwoPYWdncmVnYXRlX3ZhbHVl",
"GAggASgJGjMKCE5hbWVQYXJ0EhEKCW5hbWVfcGFydBgBIAIoCRIUCgxpc19l",
"eHRlbnNpb24YAiACKAginQkKCkZlYXR1cmVTZXQSfAoOZmllbGRfcHJlc2Vu",
"Y2UYASABKA4yKS5nb29nbGUucHJvdG9idWYuRmVhdHVyZVNldC5GaWVsZFBy",
"ZXNlbmNlQjmIAQGYAQSYAQGiAQ0SCEVYUExJQ0lUGOYHogENEghJTVBMSUNJ",
"VBjnB6IBDRIIRVhQTElDSVQY6AcSXAoJZW51bV90eXBlGAIgASgOMiQuZ29v",
"Z2xlLnByb3RvYnVmLkZlYXR1cmVTZXQuRW51bVR5cGVCI4gBAZgBBpgBAaIB",
"CxIGQ0xPU0VEGOYHogEJEgRPUEVOGOcHEnsKF3JlcGVhdGVkX2ZpZWxkX2Vu",
"Y29kaW5nGAMgASgOMjEuZ29vZ2xlLnByb3RvYnVmLkZlYXR1cmVTZXQuUmVw",
"ZWF0ZWRGaWVsZEVuY29kaW5nQieIAQGYAQSYAQGiAQ0SCEVYUEFOREVEGOYH",
"ogELEgZQQUNLRUQY5wcSaAoPdXRmOF92YWxpZGF0aW9uGAQgASgOMiouZ29v",
"Z2xlLnByb3RvYnVmLkZlYXR1cmVTZXQuVXRmOFZhbGlkYXRpb25CI4gBAZgB",
"BJgBAaIBCRIETk9ORRjmB6IBCxIGVkVSSUZZGOcHEmcKEG1lc3NhZ2VfZW5j",
"b2RpbmcYBSABKA4yKy5nb29nbGUucHJvdG9idWYuRmVhdHVyZVNldC5NZXNz",
"YWdlRW5jb2RpbmdCIIgBAZgBBJgBAaIBFBIPTEVOR1RIX1BSRUZJWEVEGOYH",
"EnAKC2pzb25fZm9ybWF0GAYgASgOMiYuZ29vZ2xlLnByb3RvYnVmLkZlYXR1",
"cmVTZXQuSnNvbkZvcm1hdEIziAEBmAEDmAEGmAEBogEXEhJMRUdBQ1lfQkVT",
"VF9FRkZPUlQY5geiAQoSBUFMTE9XGOcHIlwKDUZpZWxkUHJlc2VuY2USGgoW",
"RklFTERfUFJFU0VOQ0VfVU5LTk9XThAAEgwKCEVYUExJQ0lUEAESDAoISU1Q",
"TElDSVQQAhITCg9MRUdBQ1lfUkVRVUlSRUQQAyI3CghFbnVtVHlwZRIVChFF",
"TlVNX1RZUEVfVU5LTk9XThAAEggKBE9QRU4QARIKCgZDTE9TRUQQAiJWChVS",
"ZXBlYXRlZEZpZWxkRW5jb2RpbmcSIwofUkVQRUFURURfRklFTERfRU5DT0RJ",
"TkdfVU5LTk9XThAAEgoKBlBBQ0tFRBABEgwKCEVYUEFOREVEEAIiQwoOVXRm",
"OFZhbGlkYXRpb24SGwoXVVRGOF9WQUxJREFUSU9OX1VOS05PV04QABIICgRO",
"T05FEAESCgoGVkVSSUZZEAIiUwoPTWVzc2FnZUVuY29kaW5nEhwKGE1FU1NB",
"R0VfRU5DT0RJTkdfVU5LTk9XThAAEhMKD0xFTkdUSF9QUkVGSVhFRBABEg0K",
"CURFTElNSVRFRBACIkgKCkpzb25Gb3JtYXQSFwoTSlNPTl9GT1JNQVRfVU5L",
"Tk9XThAAEgkKBUFMTE9XEAESFgoSTEVHQUNZX0JFU1RfRUZGT1JUEAIqBgjo",
"BxDpByoGCOkHEOoHKgYIi04QkE5KBgjnBxDoByLAAgoSRmVhdHVyZVNldERl",
"ZmF1bHRzEk4KCGRlZmF1bHRzGAEgAygLMjwuZ29vZ2xlLnByb3RvYnVmLkZl",
"YXR1cmVTZXREZWZhdWx0cy5GZWF0dXJlU2V0RWRpdGlvbkRlZmF1bHQSMQoP",
"bWluaW11bV9lZGl0aW9uGAQgASgOMhguZ29vZ2xlLnByb3RvYnVmLkVkaXRp",
"b24SMQoPbWF4aW11bV9lZGl0aW9uGAUgASgOMhguZ29vZ2xlLnByb3RvYnVm",
"LkVkaXRpb24adAoYRmVhdHVyZVNldEVkaXRpb25EZWZhdWx0EikKB2VkaXRp",
"b24YAyABKA4yGC5nb29nbGUucHJvdG9idWYuRWRpdGlvbhItCghmZWF0dXJl",
"cxgCIAEoCzIbLmdvb2dsZS5wcm90b2J1Zi5GZWF0dXJlU2V0ItUBCg5Tb3Vy",
"Y2VDb2RlSW5mbxI6Cghsb2NhdGlvbhgBIAMoCzIoLmdvb2dsZS5wcm90b2J1",
"Zi5Tb3VyY2VDb2RlSW5mby5Mb2NhdGlvbhqGAQoITG9jYXRpb24SEAoEcGF0",
"aBgBIAMoBUICEAESEAoEc3BhbhgCIAMoBUICEAESGAoQbGVhZGluZ19jb21t",
"ZW50cxgDIAEoCRIZChF0cmFpbGluZ19jb21tZW50cxgEIAEoCRIhChlsZWFk",
"aW5nX2RldGFjaGVkX2NvbW1lbnRzGAYgAygJIpwCChFHZW5lcmF0ZWRDb2Rl",
"SW5mbxJBCgphbm5vdGF0aW9uGAEgAygLMi0uZ29vZ2xlLnByb3RvYnVmLkdl",
"bmVyYXRlZENvZGVJbmZvLkFubm90YXRpb24awwEKCkFubm90YXRpb24SEAoE",
"cGF0aBgBIAMoBUICEAESEwoLc291cmNlX2ZpbGUYAiABKAkSDQoFYmVnaW4Y",
"AyABKAUSCwoDZW5kGAQgASgFEkgKCHNlbWFudGljGAUgASgOMjYuZ29vZ2xl",
"LnByb3RvYnVmLkdlbmVyYXRlZENvZGVJbmZvLkFubm90YXRpb24uU2VtYW50",
"aWMiKAoIU2VtYW50aWMSCAoETk9ORRAAEgcKA1NFVBABEgkKBUFMSUFTEAIq",
"6gEKB0VkaXRpb24SEwoPRURJVElPTl9VTktOT1dOEAASEwoORURJVElPTl9Q",
"Uk9UTzIQ5gcSEwoORURJVElPTl9QUk9UTzMQ5wcSEQoMRURJVElPTl8yMDIz",
"EOgHEhcKE0VESVRJT05fMV9URVNUX09OTFkQARIXChNFRElUSU9OXzJfVEVT",
"VF9PTkxZEAISHQoXRURJVElPTl85OTk5N19URVNUX09OTFkQnY0GEh0KF0VE",
"SVRJT05fOTk5OThfVEVTVF9PTkxZEJ6NBhIdChdFRElUSU9OXzk5OTk5X1RF",
"U1RfT05MWRCfjQZCfgoTY29tLmdvb2dsZS5wcm90b2J1ZkIQRGVzY3JpcHRv",
"clByb3Rvc0gBWi1nb29nbGUuZ29sYW5nLm9yZy9wcm90b2J1Zi90eXBlcy9k",
"ZXNjcmlwdG9ycGL4AQGiAgNHUEKqAhpHb29nbGUuUHJvdG9idWYuUmVmbGVj",
"dGlvbg=="));
"IAMoCzIkLmdvb2dsZS5wcm90b2J1Zi5VbmludGVycHJldGVkT3B0aW9uIlAK",
"EElkZW1wb3RlbmN5TGV2ZWwSFwoTSURFTVBPVEVOQ1lfVU5LTk9XThAAEhMK",
"D05PX1NJREVfRUZGRUNUUxABEg4KCklERU1QT1RFTlQQAioJCOgHEICAgIAC",
"Ip4CChNVbmludGVycHJldGVkT3B0aW9uEjsKBG5hbWUYAiADKAsyLS5nb29n",
"bGUucHJvdG9idWYuVW5pbnRlcnByZXRlZE9wdGlvbi5OYW1lUGFydBIYChBp",
"ZGVudGlmaWVyX3ZhbHVlGAMgASgJEhoKEnBvc2l0aXZlX2ludF92YWx1ZRgE",
"IAEoBBIaChJuZWdhdGl2ZV9pbnRfdmFsdWUYBSABKAMSFAoMZG91YmxlX3Zh",
"bHVlGAYgASgBEhQKDHN0cmluZ192YWx1ZRgHIAEoDBIXCg9hZ2dyZWdhdGVf",
"dmFsdWUYCCABKAkaMwoITmFtZVBhcnQSEQoJbmFtZV9wYXJ0GAEgAigJEhQK",
"DGlzX2V4dGVuc2lvbhgCIAIoCCKdCQoKRmVhdHVyZVNldBJ8Cg5maWVsZF9w",
"cmVzZW5jZRgBIAEoDjIpLmdvb2dsZS5wcm90b2J1Zi5GZWF0dXJlU2V0LkZp",
"ZWxkUHJlc2VuY2VCOYgBAZgBBJgBAaIBDRIIRVhQTElDSVQY5geiAQ0SCElN",
"UExJQ0lUGOcHogENEghFWFBMSUNJVBjoBxJcCgllbnVtX3R5cGUYAiABKA4y",
"JC5nb29nbGUucHJvdG9idWYuRmVhdHVyZVNldC5FbnVtVHlwZUIjiAEBmAEG",
"mAEBogELEgZDTE9TRUQY5geiAQkSBE9QRU4Y5wcSewoXcmVwZWF0ZWRfZmll",
"bGRfZW5jb2RpbmcYAyABKA4yMS5nb29nbGUucHJvdG9idWYuRmVhdHVyZVNl",
"dC5SZXBlYXRlZEZpZWxkRW5jb2RpbmdCJ4gBAZgBBJgBAaIBDRIIRVhQQU5E",
"RUQY5geiAQsSBlBBQ0tFRBjnBxJoCg91dGY4X3ZhbGlkYXRpb24YBCABKA4y",
"Ki5nb29nbGUucHJvdG9idWYuRmVhdHVyZVNldC5VdGY4VmFsaWRhdGlvbkIj",
"iAEBmAEEmAEBogEJEgROT05FGOYHogELEgZWRVJJRlkY5wcSZwoQbWVzc2Fn",
"ZV9lbmNvZGluZxgFIAEoDjIrLmdvb2dsZS5wcm90b2J1Zi5GZWF0dXJlU2V0",
"Lk1lc3NhZ2VFbmNvZGluZ0IgiAEBmAEEmAEBogEUEg9MRU5HVEhfUFJFRklY",
"RUQY5gcScAoLanNvbl9mb3JtYXQYBiABKA4yJi5nb29nbGUucHJvdG9idWYu",
"RmVhdHVyZVNldC5Kc29uRm9ybWF0QjOIAQGYAQOYAQaYAQGiARcSEkxFR0FD",
"WV9CRVNUX0VGRk9SVBjmB6IBChIFQUxMT1cY5wciXAoNRmllbGRQcmVzZW5j",
"ZRIaChZGSUVMRF9QUkVTRU5DRV9VTktOT1dOEAASDAoIRVhQTElDSVQQARIM",
"CghJTVBMSUNJVBACEhMKD0xFR0FDWV9SRVFVSVJFRBADIjcKCEVudW1UeXBl",
"EhUKEUVOVU1fVFlQRV9VTktOT1dOEAASCAoET1BFThABEgoKBkNMT1NFRBAC",
"IlYKFVJlcGVhdGVkRmllbGRFbmNvZGluZxIjCh9SRVBFQVRFRF9GSUVMRF9F",
"TkNPRElOR19VTktOT1dOEAASCgoGUEFDS0VEEAESDAoIRVhQQU5ERUQQAiJD",
"Cg5VdGY4VmFsaWRhdGlvbhIbChdVVEY4X1ZBTElEQVRJT05fVU5LTk9XThAA",
"EgoKBlZFUklGWRACEggKBE5PTkUQAyJTCg9NZXNzYWdlRW5jb2RpbmcSHAoY",
"TUVTU0FHRV9FTkNPRElOR19VTktOT1dOEAASEwoPTEVOR1RIX1BSRUZJWEVE",
"EAESDQoJREVMSU1JVEVEEAIiSAoKSnNvbkZvcm1hdBIXChNKU09OX0ZPUk1B",
"VF9VTktOT1dOEAASCQoFQUxMT1cQARIWChJMRUdBQ1lfQkVTVF9FRkZPUlQQ",
"AioGCOgHEOkHKgYI6QcQ6gcqBgiLThCQTkoGCOcHEOgHIsACChJGZWF0dXJl",
"U2V0RGVmYXVsdHMSTgoIZGVmYXVsdHMYASADKAsyPC5nb29nbGUucHJvdG9i",
"dWYuRmVhdHVyZVNldERlZmF1bHRzLkZlYXR1cmVTZXRFZGl0aW9uRGVmYXVs",
"dBIxCg9taW5pbXVtX2VkaXRpb24YBCABKA4yGC5nb29nbGUucHJvdG9idWYu",
"RWRpdGlvbhIxCg9tYXhpbXVtX2VkaXRpb24YBSABKA4yGC5nb29nbGUucHJv",
"dG9idWYuRWRpdGlvbhp0ChhGZWF0dXJlU2V0RWRpdGlvbkRlZmF1bHQSKQoH",
"ZWRpdGlvbhgDIAEoDjIYLmdvb2dsZS5wcm90b2J1Zi5FZGl0aW9uEi0KCGZl",
"YXR1cmVzGAIgASgLMhsuZ29vZ2xlLnByb3RvYnVmLkZlYXR1cmVTZXQi1QEK",
"DlNvdXJjZUNvZGVJbmZvEjoKCGxvY2F0aW9uGAEgAygLMiguZ29vZ2xlLnBy",
"b3RvYnVmLlNvdXJjZUNvZGVJbmZvLkxvY2F0aW9uGoYBCghMb2NhdGlvbhIQ",
"CgRwYXRoGAEgAygFQgIQARIQCgRzcGFuGAIgAygFQgIQARIYChBsZWFkaW5n",
"X2NvbW1lbnRzGAMgASgJEhkKEXRyYWlsaW5nX2NvbW1lbnRzGAQgASgJEiEK",
"GWxlYWRpbmdfZGV0YWNoZWRfY29tbWVudHMYBiADKAkinAIKEUdlbmVyYXRl",
"ZENvZGVJbmZvEkEKCmFubm90YXRpb24YASADKAsyLS5nb29nbGUucHJvdG9i",
"dWYuR2VuZXJhdGVkQ29kZUluZm8uQW5ub3RhdGlvbhrDAQoKQW5ub3RhdGlv",
"bhIQCgRwYXRoGAEgAygFQgIQARITCgtzb3VyY2VfZmlsZRgCIAEoCRINCgVi",
"ZWdpbhgDIAEoBRILCgNlbmQYBCABKAUSSAoIc2VtYW50aWMYBSABKA4yNi5n",
"b29nbGUucHJvdG9idWYuR2VuZXJhdGVkQ29kZUluZm8uQW5ub3RhdGlvbi5T",
"ZW1hbnRpYyIoCghTZW1hbnRpYxIICgROT05FEAASBwoDU0VUEAESCQoFQUxJ",
"QVMQAir/AQoHRWRpdGlvbhITCg9FRElUSU9OX1VOS05PV04QABITCg5FRElU",
"SU9OX1BST1RPMhDmBxITCg5FRElUSU9OX1BST1RPMxDnBxIRCgxFRElUSU9O",
"XzIwMjMQ6AcSFwoTRURJVElPTl8xX1RFU1RfT05MWRABEhcKE0VESVRJT05f",
"Ml9URVNUX09OTFkQAhIdChdFRElUSU9OXzk5OTk3X1RFU1RfT05MWRCdjQYS",
"HQoXRURJVElPTl85OTk5OF9URVNUX09OTFkQno0GEh0KF0VESVRJT05fOTk5",
"OTlfVEVTVF9PTkxZEJ+NBhITCgtFRElUSU9OX01BWBD/////B0J+ChNjb20u",
"Z29vZ2xlLnByb3RvYnVmQhBEZXNjcmlwdG9yUHJvdG9zSAFaLWdvb2dsZS5n",
"b2xhbmcub3JnL3Byb3RvYnVmL3R5cGVzL2Rlc2NyaXB0b3JwYvgBAaICA0dQ",
"QqoCGkdvb2dsZS5Qcm90b2J1Zi5SZWZsZWN0aW9u"));
descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
new pbr::FileDescriptor[] { },
new pbr::GeneratedClrTypeInfo(new[] {typeof(global::Google.Protobuf.Reflection.Edition), }, null, new pbr::GeneratedClrTypeInfo[] {
@ -301,6 +301,12 @@ namespace Google.Protobuf.Reflection {
[pbr::OriginalName("EDITION_99997_TEST_ONLY")] _99997TestOnly = 99997,
[pbr::OriginalName("EDITION_99998_TEST_ONLY")] _99998TestOnly = 99998,
[pbr::OriginalName("EDITION_99999_TEST_ONLY")] _99999TestOnly = 99999,
/// <summary>
/// Placeholder for specifying unbounded edition support. This should only
/// ever be used by plugins that can expect to never require any changes to
/// support a new edition.
/// </summary>
[pbr::OriginalName("EDITION_MAX")] Max = 2147483647,
}
#endregion
@ -7420,10 +7426,6 @@ namespace Google.Protobuf.Reflection {
private bool mapEntry_;
/// <summary>
/// NOTE: Do not set the option in .proto files. Always use the maps syntax
/// instead. The option should only be implicitly set by the proto compiler
/// parser.
///
/// Whether the message is an automatically generated map entry type for the
/// maps field.
///
@ -7441,6 +7443,10 @@ namespace Google.Protobuf.Reflection {
/// use a native map in the target language to hold the keys and values.
/// The reflection APIs in such implementations still need to work as
/// if the field is a repeated message field.
///
/// NOTE: Do not set the option in .proto files. Always use the maps syntax
/// instead. The option should only be implicitly set by the proto compiler
/// parser.
/// </summary>
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
@ -12256,8 +12262,8 @@ namespace Google.Protobuf.Reflection {
public enum Utf8Validation {
[pbr::OriginalName("UTF8_VALIDATION_UNKNOWN")] Unknown = 0,
[pbr::OriginalName("NONE")] None = 1,
[pbr::OriginalName("VERIFY")] Verify = 2,
[pbr::OriginalName("NONE")] None = 3,
}
public enum MessageEncoding {
@ -13133,7 +13139,7 @@ namespace Google.Protobuf.Reflection {
/// location.
///
/// Each element is a field number or an index. They form a path from
/// the root FileDescriptorProto to the place where the definition occurs.
/// the root FileDescriptorProto to the place where the definition appears.
/// For example, this path:
/// [ 4, 3, 2, 7, 1 ]
/// refers to:

View File

@ -538,44 +538,4 @@ public abstract class AbstractMessage
return (BuilderType) super.mergeFrom(input, extensionRegistry);
}
}
/**
* @deprecated from v3.0.0-beta-3+, for compatibility with v2.5.0 and v2.6.1
* generated code.
*/
@Deprecated
protected static int hashLong(long n) {
return (int) (n ^ (n >>> 32));
}
/**
* @deprecated from v3.0.0-beta-3+, for compatibility with v2.5.0 and v2.6.1
* generated code.
*/
@Deprecated
protected static int hashBoolean(boolean b) {
return b ? 1231 : 1237;
}
/**
* @deprecated from v3.0.0-beta-3+, for compatibility with v2.5.0 and v2.6.1
* generated code.
*/
@Deprecated
protected static int hashEnum(EnumLite e) {
return e.getNumber();
}
/**
* @deprecated from v3.0.0-beta-3+, for compatibility with v2.5.0 and v2.6.1
* generated code.
*/
@Deprecated
protected static int hashEnumList(List<? extends EnumLite> list) {
int hash = 1;
for (EnumLite e : list) {
hash = 31 * hash + hashEnum(e);
}
return hash;
}
}

View File

@ -40,7 +40,9 @@ public abstract class CodedOutputStream extends ByteOutput {
/** Used to adapt to the experimental {@link Writer} interface. */
CodedOutputStreamWriter wrapper;
/** @deprecated Use {@link #computeFixed32SizeNoTag(int)} instead. */
/**
* @deprecated Use {@link #computeFixed32SizeNoTag(int)} instead.
*/
@Deprecated public static final int LITTLE_ENDIAN_32_SIZE = FIXED32_SIZE;
/** The buffer size used in {@link #newInstance(OutputStream)}. */
@ -669,9 +671,8 @@ public abstract class CodedOutputStream extends ByteOutput {
}
/**
* Compute the number of bytes that would be needed to encode a lazily parsed MessageSet
* extension field to the stream. For historical reasons, the wire format differs from normal
* fields.
* Compute the number of bytes that would be needed to encode a lazily parsed MessageSet extension
* field to the stream. For historical reasons, the wire format differs from normal fields.
*/
public static int computeLazyFieldMessageSetExtensionSize(
final int fieldNumber, final LazyFieldLite value) {
@ -692,29 +693,52 @@ public abstract class CodedOutputStream extends ByteOutput {
* tag.
*/
public static int computeInt32SizeNoTag(final int value) {
if (value >= 0) {
return computeUInt32SizeNoTag(value);
} else {
// Must sign-extend.
return MAX_VARINT_SIZE;
}
return computeUInt64SizeNoTag((long) value);
}
/** Compute the number of bytes that would be needed to encode a {@code uint32} field. */
public static int computeUInt32SizeNoTag(final int value) {
if ((value & (~0 << 7)) == 0) {
return 1;
}
if ((value & (~0 << 14)) == 0) {
return 2;
}
if ((value & (~0 << 21)) == 0) {
return 3;
}
if ((value & (~0 << 28)) == 0) {
return 4;
}
return 5;
/*
This code is ported from the C++ varint implementation.
Implementation notes:
To calcuate varint size, we want to count the number of 7 bit chunks required. Rather than using
division by 7 to accomplish this, we use multiplication by 9/64. This has a number of important
properties:
* It's roughly 1/7.111111. This makes the 0 bits set case have the same value as the 7 bits set
case, so offsetting by 1 gives us the correct value we want for integers up to 448 bits.
* Multiplying by 9 is special. x * 9 = x << 3 + x, and so this multiplication can be done by a
single shifted add on arm (add w0, w0, w0, lsl #3), or a single lea instruction
(leal (%rax,%rax,8), %eax)) on x86.
* Dividing by 64 is a 6 bit right shift.
An explicit non-sign-extended right shift is used instead of the more obvious '/ 64' because
that actually produces worse code on android arm64 at time of authoring because of sign
extension. Rather than
lsr w0, w0, #6
It would emit:
add w16, w0, #0x3f (63)
cmp w0, #0x0 (0)
csel w0, w16, w0, lt
asr w0, w0, #6
Summarized:
floor(((Integer.SIZE - clz) / 7.1111) + 1
((Integer.SIZE - clz) * 9) / 64 + 1
(((Integer.SIZE - clz) * 9) >>> 6) + 1
((Integer.SIZE - clz) * 9 + (1 << 6)) >>> 6
(Integer.SIZE * 9 + (1 << 6) - clz * 9) >>> 6
(352 - clz * 9) >>> 6
on arm:
(352 - clz - (clz << 3)) >>> 6
on x86:
(352 - lea(clz, clz, 8)) >>> 6
If you make changes here, please validate their compiled output on different architectures and
runtimes.
*/
int clz = Integer.numberOfLeadingZeros(value);
return ((Integer.SIZE * 9 + (1 << 6)) - (clz * 9)) >>> 6;
}
/** Compute the number of bytes that would be needed to encode an {@code sint32} field. */
@ -745,27 +769,9 @@ public abstract class CodedOutputStream extends ByteOutput {
* tag.
*/
public static int computeUInt64SizeNoTag(long value) {
// handle two popular special cases up front ...
if ((value & (~0L << 7)) == 0L) {
return 1;
}
if (value < 0L) {
return 10;
}
// ... leaving us with 8 remaining, which we can divide and conquer
int n = 2;
if ((value & (~0L << 35)) != 0L) {
n += 4;
value >>>= 28;
}
if ((value & (~0L << 21)) != 0L) {
n += 2;
value >>>= 14;
}
if ((value & (~0L << 14)) != 0L) {
n += 1;
}
return n;
int clz = Long.numberOfLeadingZeros(value);
// See computeUInt32SizeNoTag for explanation
return ((Long.SIZE * 9 + (1 << 6)) - (clz * 9)) >>> 6;
}
/** Compute the number of bytes that would be needed to encode an {@code sint64} field. */
@ -1326,7 +1332,7 @@ public abstract class CodedOutputStream extends ByteOutput {
buffer[position++] = (byte) value;
return;
} else {
buffer[position++] = (byte) ((value & 0x7F) | 0x80);
buffer[position++] = (byte) ((value | 0x80) & 0xFF);
value >>>= 7;
}
}
@ -1357,7 +1363,7 @@ public abstract class CodedOutputStream extends ByteOutput {
UnsafeUtil.putByte(buffer, position++, (byte) value);
return;
} else {
UnsafeUtil.putByte(buffer, position++, (byte) (((int) value & 0x7F) | 0x80));
UnsafeUtil.putByte(buffer, position++, (byte) (((int) value | 0x80) & 0xFF));
value >>>= 7;
}
}
@ -1368,7 +1374,7 @@ public abstract class CodedOutputStream extends ByteOutput {
buffer[position++] = (byte) value;
return;
} else {
buffer[position++] = (byte) (((int) value & 0x7F) | 0x80);
buffer[position++] = (byte) (((int) value | 0x80) & 0xFF);
value >>>= 7;
}
}
@ -1684,7 +1690,7 @@ public abstract class CodedOutputStream extends ByteOutput {
buffer.put((byte) value);
return;
} else {
buffer.put((byte) ((value & 0x7F) | 0x80));
buffer.put((byte) ((value | 0x80) & 0xFF));
value >>>= 7;
}
}
@ -1710,7 +1716,7 @@ public abstract class CodedOutputStream extends ByteOutput {
buffer.put((byte) value);
return;
} else {
buffer.put((byte) (((int) value & 0x7F) | 0x80));
buffer.put((byte) (((int) value | 0x80) & 0xFF));
value >>>= 7;
}
}
@ -2015,7 +2021,7 @@ public abstract class CodedOutputStream extends ByteOutput {
UnsafeUtil.putByte(position++, (byte) value);
return;
} else {
UnsafeUtil.putByte(position++, (byte) ((value & 0x7F) | 0x80));
UnsafeUtil.putByte(position++, (byte) ((value | 0x80) & 0xFF));
value >>>= 7;
}
}
@ -2025,7 +2031,7 @@ public abstract class CodedOutputStream extends ByteOutput {
UnsafeUtil.putByte(position++, (byte) value);
return;
} else {
UnsafeUtil.putByte(position++, (byte) ((value & 0x7F) | 0x80));
UnsafeUtil.putByte(position++, (byte) ((value | 0x80) & 0xFF));
value >>>= 7;
}
}
@ -2049,7 +2055,7 @@ public abstract class CodedOutputStream extends ByteOutput {
UnsafeUtil.putByte(position++, (byte) value);
return;
} else {
UnsafeUtil.putByte(position++, (byte) (((int) value & 0x7F) | 0x80));
UnsafeUtil.putByte(position++, (byte) (((int) value | 0x80) & 0xFF));
value >>>= 7;
}
}
@ -2059,7 +2065,7 @@ public abstract class CodedOutputStream extends ByteOutput {
UnsafeUtil.putByte(position++, (byte) value);
return;
} else {
UnsafeUtil.putByte(position++, (byte) (((int) value & 0x7F) | 0x80));
UnsafeUtil.putByte(position++, (byte) (((int) value | 0x80) & 0xFF));
value >>>= 7;
}
}
@ -2259,7 +2265,7 @@ public abstract class CodedOutputStream extends ByteOutput {
UnsafeUtil.putByte(buffer, position++, (byte) value);
break;
} else {
UnsafeUtil.putByte(buffer, position++, (byte) ((value & 0x7F) | 0x80));
UnsafeUtil.putByte(buffer, position++, (byte) ((value | 0x80) & 0xFF));
value >>>= 7;
}
}
@ -2272,7 +2278,7 @@ public abstract class CodedOutputStream extends ByteOutput {
totalBytesWritten++;
return;
} else {
buffer[position++] = (byte) ((value & 0x7F) | 0x80);
buffer[position++] = (byte) ((value | 0x80) & 0xFF);
totalBytesWritten++;
value >>>= 7;
}
@ -2292,7 +2298,7 @@ public abstract class CodedOutputStream extends ByteOutput {
UnsafeUtil.putByte(buffer, position++, (byte) value);
break;
} else {
UnsafeUtil.putByte(buffer, position++, (byte) (((int) value & 0x7F) | 0x80));
UnsafeUtil.putByte(buffer, position++, (byte) (((int) value | 0x80) & 0xFF));
value >>>= 7;
}
}
@ -2305,7 +2311,7 @@ public abstract class CodedOutputStream extends ByteOutput {
totalBytesWritten++;
return;
} else {
buffer[position++] = (byte) (((int) value & 0x7F) | 0x80);
buffer[position++] = (byte) (((int) value | 0x80) & 0xFF);
totalBytesWritten++;
value >>>= 7;
}

View File

@ -140,8 +140,6 @@ public final class Descriptors {
}
/** The syntax of the .proto file. */
@Deprecated
public
enum Syntax {
UNKNOWN("unknown"),
PROTO2("proto2"),
@ -156,8 +154,6 @@ public final class Descriptors {
}
/** Get the syntax of the .proto file. */
@Deprecated
public
Syntax getSyntax() {
if (Syntax.PROTO3.name.equals(proto.getSyntax())) {
return Syntax.PROTO3;
@ -1273,8 +1269,6 @@ public final class Descriptors {
* Returns true if this field was syntactically written with "optional" in the .proto file.
* Excludes singular proto3 fields that do not have a label.
*/
@Deprecated
public
boolean hasOptionalKeyword() {
return isProto3Optional
|| (file.getSyntax() == Syntax.PROTO2 && isOptional() && getContainingOneof() == null);
@ -2843,8 +2837,6 @@ public final class Descriptors {
return proto;
}
@Deprecated
public
boolean isSynthetic() {
return fields.length == 1 && fields[0].isProto3Optional;
}

View File

@ -1440,7 +1440,7 @@ public abstract class GeneratedMessageLite<
} catch (ClassNotFoundException e) {
throw new RuntimeException("Unable to find proto buffer class: " + messageClassName, e);
} catch (NoSuchFieldException e) {
return readResolveFallback();
throw new RuntimeException("Unable to find DEFAULT_INSTANCE in " + messageClassName, e);
} catch (SecurityException e) {
throw new RuntimeException("Unable to call DEFAULT_INSTANCE in " + messageClassName, e);
} catch (IllegalAccessException e) {
@ -1450,33 +1450,6 @@ public abstract class GeneratedMessageLite<
}
}
/**
* @deprecated from v3.0.0-beta-3+, for compatibility with v2.5.0 and v2.6.1 generated code.
*/
@Deprecated
private Object readResolveFallback() throws ObjectStreamException {
try {
Class<?> messageClass = resolveMessageClass();
java.lang.reflect.Field defaultInstanceField =
messageClass.getDeclaredField("defaultInstance");
defaultInstanceField.setAccessible(true);
MessageLite defaultInstance = (MessageLite) defaultInstanceField.get(null);
return defaultInstance.newBuilderForType()
.mergeFrom(asBytes)
.buildPartial();
} catch (ClassNotFoundException e) {
throw new RuntimeException("Unable to find proto buffer class: " + messageClassName, e);
} catch (NoSuchFieldException e) {
throw new RuntimeException("Unable to find defaultInstance in " + messageClassName, e);
} catch (SecurityException e) {
throw new RuntimeException("Unable to call defaultInstance in " + messageClassName, e);
} catch (IllegalAccessException e) {
throw new RuntimeException("Unable to call parsePartialFrom", e);
} catch (InvalidProtocolBufferException e) {
throw new RuntimeException("Unable to understand proto buffer", e);
}
}
private Class<?> resolveMessageClass() throws ClassNotFoundException {
return messageClass != null ? messageClass : Class.forName(messageClassName);
}

View File

@ -2459,11 +2459,7 @@ public abstract class GeneratedMessageV3 extends AbstractMessage implements Seri
final String containingOneofCamelCaseName) {
isOneofField =
descriptor.getRealContainingOneof() != null;
hasHasMethod =
descriptor.getFile().getSyntax() == FileDescriptor.Syntax.EDITIONS && descriptor.hasPresence()
|| descriptor.getFile().getSyntax() == FileDescriptor.Syntax.PROTO2
|| descriptor.hasOptionalKeyword()
|| (!isOneofField && descriptor.getJavaType() == FieldDescriptor.JavaType.MESSAGE);
hasHasMethod = descriptor.hasPresence();
ReflectionInvoker reflectionInvoker =
new ReflectionInvoker(
descriptor,

View File

@ -7,6 +7,8 @@
package com.google.protobuf;
import java.util.logging.Logger;
/**
* Provides the version of this Protobuf Java runtime, and methods for Protobuf Java gencode to
* validate that versions are compatible. Fields and methods in this class should be only accessed
@ -29,6 +31,31 @@ public final class RuntimeVersion {
public static final String SUFFIX = "-dev";
private static final String VERSION_STRING = versionString(MAJOR, MINOR, PATCH, SUFFIX);
/**
* Validates that the gencode is in the same domain as the runtime.
*
* <p>This method will be directly called by the google-internal gencode to verify no cross-domain
* usages.
*
* @param gencodeDomain the domain where Protobuf Java code was generated.
* @throws ProtobufRuntimeVersionException if gencodeDomain is not the same as DOMAIN.
*/
public static void validateProtobufGencodeDomain(RuntimeDomain gencodeDomain) {
// Check the environmental variable, and temporarily disable validation if it's set to true.
String disableFlag = java.lang.System.getenv("TEMORARILY_DISABLE_PROTOBUF_VERSION_CHECK");
if ((disableFlag != null && disableFlag.equals("true"))) {
return;
}
if (gencodeDomain != DOMAIN) {
throw new ProtobufRuntimeVersionException(
String.format(
"Mismatched Protobuf Gencode/Runtime domains: gencode %s, runtime %s. Cross-domain"
+ " usage of Protobuf is not supported.",
gencodeDomain, DOMAIN));
}
}
/**
* Validates that the gencode version is compatible with this runtime version according to
* https://protobuf.dev/support/cross-version-runtime-guarantee/.
@ -37,7 +64,7 @@ public final class RuntimeVersion {
*
* <p>This method is only for Protobuf Java gencode; do not call it elsewhere.
*
* @param domain the domain where Protobuf Java code was generated. Currently ignored.
* @param domain the domain where Protobuf Java code was generated.
* @param major the major version of Protobuf Java gencode.
* @param minor the minor version of Protobuf Java gencode.
* @param patch the micro/patch version of Protobuf Java gencode.
@ -47,18 +74,14 @@ public final class RuntimeVersion {
public static void validateProtobufGencodeVersion(
RuntimeDomain domain, int major, int minor, int patch, String suffix) {
// Check the environmental variable, and temporarily disable poison pills if it's set to true.
String disableFlag = java.lang.System.getenv("TEMORARILY_DISABLE_PROTOBUF_VERSION_CHECK");
if (disableFlag != null && disableFlag.equals("true")) {
return;
}
// Check that version numbers are valid.
if (major < 0 || minor < 0 || patch < 0) {
throw new ProtobufRuntimeVersionException(
"Invalid gencode version: " + versionString(major, minor, patch, suffix));
}
validateProtobufGencodeDomain(domain);
String gencodeVersionString = versionString(major, minor, patch, suffix);
// Check that runtime major version is the same as the gencode major version.
if (major != MAJOR) {

View File

@ -38,58 +38,6 @@ public final class TextFormat {
private static final String DEBUG_STRING_SILENT_MARKER = "\t ";
/**
* Outputs a textual representation of the Protocol Message supplied into the parameter output.
* (This representation is the new version of the classic "ProtocolPrinter" output from the
* original Protocol Buffer system)
*
* @deprecated Use {@code printer().print(MessageOrBuilder, Appendable)}
*/
@Deprecated
@InlineMe(
replacement = "TextFormat.printer().print(message, output)",
imports = "com.google.protobuf.TextFormat")
public static void print(final MessageOrBuilder message, final Appendable output)
throws IOException {
printer().print(message, output);
}
/**
* Outputs a textual representation of {@code fields} to {@code output}.
*
* @deprecated Use {@code printer().print(UnknownFieldSet, Appendable)}
*/
@Deprecated
public static void print(final UnknownFieldSet fields, final Appendable output)
throws IOException {
printer().print(fields, output);
}
/**
* Same as {@code print()}, except that non-ASCII characters are not escaped.
*
* @deprecated Use {@code printer().escapingNonAscii(false).print(MessageOrBuilder, Appendable)}
*/
@Deprecated
@InlineMe(
replacement = "TextFormat.printer().escapingNonAscii(false).print(message, output)",
imports = "com.google.protobuf.TextFormat")
public static void printUnicode(final MessageOrBuilder message, final Appendable output)
throws IOException {
printer().escapingNonAscii(false).print(message, output);
}
/**
* Same as {@code print()}, except that non-ASCII characters are not escaped.
*
* @deprecated Use {@code printer().escapingNonAscii(false).print(UnknownFieldSet, Appendable)}
*/
@Deprecated
public static void printUnicode(final UnknownFieldSet fields, final Appendable output)
throws IOException {
printer().escapingNonAscii(false).print(fields, output);
}
/**
* Generates a human readable form of this message, useful for debugging and other purposes, with
* no newline characters. This is just a trivial wrapper around {@link
@ -99,130 +47,6 @@ public final class TextFormat {
return printer().shortDebugString(message);
}
/**
* Generates a human readable form of the field, useful for debugging and other purposes, with
* no newline characters.
*
* @deprecated Use {@code printer().shortDebugString(FieldDescriptor, Object)}
*/
@Deprecated
public static String shortDebugString(final FieldDescriptor field, final Object value) {
return printer().shortDebugString(field, value);
}
/**
* Generates a human readable form of the unknown fields, useful for debugging and other
* purposes, with no newline characters.
*
* @deprecated Use {@code printer().shortDebugString(UnknownFieldSet)}
*/
@Deprecated
public static String shortDebugString(final UnknownFieldSet fields) {
return printer().shortDebugString(fields);
}
/**
* Like {@code print()}, but writes directly to a {@code String} and returns it.
*
* @deprecated Use {@code message.toString()}
*/
@Deprecated
@InlineMe(
replacement = "TextFormat.printer().printToString(message)",
imports = "com.google.protobuf.TextFormat")
public static String printToString(final MessageOrBuilder message) {
return printer().printToString(message);
}
/**
* Like {@code print()}, but writes directly to a {@code String} and returns it.
*
* @deprecated Use {@link UnknownFieldSet#toString()}
*/
@Deprecated
public static String printToString(final UnknownFieldSet fields) {
return printer().printToString(fields);
}
/**
* Same as {@code printToString()}, except that non-ASCII characters in string type fields are not
* escaped in backslash+octals.
*
* @deprecated Use {@code printer().escapingNonAscii(false).printToString(MessageOrBuilder)}
*/
@Deprecated
@InlineMe(
replacement = "TextFormat.printer().escapingNonAscii(false).printToString(message)",
imports = "com.google.protobuf.TextFormat")
public static String printToUnicodeString(final MessageOrBuilder message) {
return printer().escapingNonAscii(false).printToString(message);
}
/**
* Same as {@code printToString()}, except that non-ASCII characters in string type fields are
* not escaped in backslash+octals.
*
* @deprecated Use {@code printer().escapingNonAscii(false).printToString(UnknownFieldSet)}
*/
@Deprecated
public static String printToUnicodeString(final UnknownFieldSet fields) {
return printer().escapingNonAscii(false).printToString(fields);
}
/** @deprecated Use {@code printer().printField(FieldDescriptor, Object, Appendable)} */
@Deprecated
public static void printField(
final FieldDescriptor field, final Object value, final Appendable output)
throws IOException {
printer().printField(field, value, output);
}
/** @deprecated Use {@code printer().printFieldToString(FieldDescriptor, Object)} */
@Deprecated
public static String printFieldToString(final FieldDescriptor field, final Object value) {
return printer().printFieldToString(field, value);
}
/**
* Outputs a unicode textual representation of the value of given field value.
*
* <p>Same as {@code printFieldValue()}, except that non-ASCII characters in string type fields
* are not escaped in backslash+octals.
*
* @deprecated Use {@code printer().escapingNonAscii(false).printFieldValue(FieldDescriptor,
* Object, Appendable)}
* @param field the descriptor of the field
* @param value the value of the field
* @param output the output to which to append the formatted value
* @throws ClassCastException if the value is not appropriate for the given field descriptor
* @throws IOException if there is an exception writing to the output
*/
@Deprecated
public static void printUnicodeFieldValue(
final FieldDescriptor field, final Object value, final Appendable output)
throws IOException {
printer().escapingNonAscii(false).printFieldValue(field, value, output);
}
/**
* Outputs a textual representation of the value of given field value.
*
* @deprecated Use {@code printer().printFieldValue(FieldDescriptor, Object, Appendable)}
* @param field the descriptor of the field
* @param value the value of the field
* @param output the output to which to append the formatted value
* @throws ClassCastException if the value is not appropriate for the given field descriptor
* @throws IOException if there is an exception writing to the output
*/
@Deprecated
@InlineMe(
replacement = "TextFormat.printer().printFieldValue(field, value, output)",
imports = "com.google.protobuf.TextFormat")
public static void printFieldValue(
final FieldDescriptor field, final Object value, final Appendable output) throws IOException {
printer().printFieldValue(field, value, output);
}
/**
* Outputs a textual representation of the value of an unknown field.
*
@ -283,16 +107,23 @@ public final class TextFormat {
public static final class Printer {
// Printer instance which escapes non-ASCII characters.
private static final Printer DEFAULT = new Printer(true, TypeRegistry.getEmptyTypeRegistry());
private static final Printer DEFAULT =
new Printer(
true, TypeRegistry.getEmptyTypeRegistry(), ExtensionRegistryLite.getEmptyRegistry());
/** Whether to escape non ASCII characters with backslash and octal. */
private final boolean escapeNonAscii;
private final TypeRegistry typeRegistry;
private final ExtensionRegistryLite extensionRegistry;
private Printer(boolean escapeNonAscii, TypeRegistry typeRegistry) {
private Printer(
boolean escapeNonAscii,
TypeRegistry typeRegistry,
ExtensionRegistryLite extensionRegistry) {
this.escapeNonAscii = escapeNonAscii;
this.typeRegistry = typeRegistry;
this.extensionRegistry = extensionRegistry;
}
/**
@ -305,7 +136,7 @@ public final class TextFormat {
* with the escape mode set to the given parameter.
*/
public Printer escapingNonAscii(boolean escapeNonAscii) {
return new Printer(escapeNonAscii, typeRegistry);
return new Printer(escapeNonAscii, typeRegistry, extensionRegistry);
}
/**
@ -318,7 +149,20 @@ public final class TextFormat {
if (this.typeRegistry != TypeRegistry.getEmptyTypeRegistry()) {
throw new IllegalArgumentException("Only one typeRegistry is allowed.");
}
return new Printer(escapeNonAscii, typeRegistry);
return new Printer(escapeNonAscii, typeRegistry, extensionRegistry);
}
/**
* Creates a new {@link Printer} using the given extensionRegistry. The new Printer clones all
* other configurations from the current {@link Printer}.
*
* @throws IllegalArgumentException if a registry is already set.
*/
public Printer usingExtensionRegistry(ExtensionRegistryLite extensionRegistry) {
if (this.extensionRegistry != ExtensionRegistryLite.getEmptyRegistry()) {
throw new IllegalArgumentException("Only one extensionRegistry is allowed.");
}
return new Printer(escapeNonAscii, typeRegistry, extensionRegistry);
}
/**
@ -377,7 +221,7 @@ public final class TextFormat {
return false;
}
contentBuilder = DynamicMessage.getDefaultInstance(contentType).newBuilderForType();
contentBuilder.mergeFrom((ByteString) value);
contentBuilder.mergeFrom((ByteString) value, extensionRegistry);
} catch (InvalidProtocolBufferException e) {
// The value of Any is malformed. We cannot print it out nicely, so fallback to printing out
// the type_url and value as bytes. Note that we fail open here to be consistent with

View File

@ -214,24 +214,24 @@ final class Utf8 {
* @throws IllegalArgumentException if {@code sequence} contains ill-formed UTF-16 (unpaired
* surrogates)
*/
static int encodedLength(CharSequence sequence) {
static int encodedLength(String string) {
// Warning to maintainers: this implementation is highly optimized.
int utf16Length = sequence.length();
int utf16Length = string.length();
int utf8Length = utf16Length;
int i = 0;
// This loop optimizes for pure ASCII.
while (i < utf16Length && sequence.charAt(i) < 0x80) {
while (i < utf16Length && string.charAt(i) < 0x80) {
i++;
}
// This loop optimizes for chars less than 0x800.
for (; i < utf16Length; i++) {
char c = sequence.charAt(i);
char c = string.charAt(i);
if (c < 0x800) {
utf8Length += ((0x7f - c) >>> 31); // branch free!
} else {
utf8Length += encodedLengthGeneral(sequence, i);
utf8Length += encodedLengthGeneral(string, i);
break;
}
}
@ -244,11 +244,11 @@ final class Utf8 {
return utf8Length;
}
private static int encodedLengthGeneral(CharSequence sequence, int start) {
int utf16Length = sequence.length();
private static int encodedLengthGeneral(String string, int start) {
int utf16Length = string.length();
int utf8Length = 0;
for (int i = start; i < utf16Length; i++) {
char c = sequence.charAt(i);
char c = string.charAt(i);
if (c < 0x800) {
utf8Length += (0x7f - c) >>> 31; // branch free!
} else {
@ -256,7 +256,7 @@ final class Utf8 {
// jdk7+: if (Character.isSurrogate(c)) {
if (Character.MIN_SURROGATE <= c && c <= Character.MAX_SURROGATE) {
// Check that we have a well-formed surrogate pair.
int cp = Character.codePointAt(sequence, i);
int cp = Character.codePointAt(string, i);
if (cp < MIN_SUPPLEMENTARY_CODE_POINT) {
throw new UnpairedSurrogateException(i, utf16Length);
}
@ -267,7 +267,7 @@ final class Utf8 {
return utf8Length;
}
static int encode(CharSequence in, byte[] out, int offset, int length) {
static int encode(String in, byte[] out, int offset, int length) {
return processor.encodeUtf8(in, out, offset, length);
}
// End Guava UTF-8 methods.
@ -326,9 +326,9 @@ final class Utf8 {
*
* @param in the source string to be encoded
* @param out the target buffer to receive the encoded string.
* @see Utf8#encode(CharSequence, byte[], int, int)
* @see Utf8#encode(String, byte[], int, int)
*/
static void encodeUtf8(CharSequence in, ByteBuffer out) {
static void encodeUtf8(String in, ByteBuffer out) {
processor.encodeUtf8(in, out);
}
@ -724,7 +724,7 @@ final class Utf8 {
* {@code bytes.length - offset}
* @return the new offset, equivalent to {@code offset + Utf8.encodedLength(sequence)}
*/
abstract int encodeUtf8(CharSequence in, byte[] out, int offset, int length);
abstract int encodeUtf8(String in, byte[] out, int offset, int length);
/**
* Encodes an input character sequence ({@code in}) to UTF-8 in the target buffer ({@code out}).
@ -743,7 +743,7 @@ final class Utf8 {
* @throws ArrayIndexOutOfBoundsException if {@code in} encoded in UTF-8 is longer than {@code
* out.remaining()}
*/
final void encodeUtf8(CharSequence in, ByteBuffer out) {
final void encodeUtf8(String in, ByteBuffer out) {
if (out.hasArray()) {
final int offset = out.arrayOffset();
int endIndex = Utf8.encode(in, out.array(), offset + out.position(), out.remaining());
@ -756,13 +756,13 @@ final class Utf8 {
}
/** Encodes the input character sequence to a direct {@link ByteBuffer} instance. */
abstract void encodeUtf8Direct(CharSequence in, ByteBuffer out);
abstract void encodeUtf8Direct(String in, ByteBuffer out);
/**
* Encodes the input character sequence to a {@link ByteBuffer} instance using the {@link
* ByteBuffer} API, rather than potentially faster approaches.
*/
final void encodeUtf8Default(CharSequence in, ByteBuffer out) {
final void encodeUtf8Default(String in, ByteBuffer out) {
final int inLength = in.length();
int outIx = out.position();
int inIx = 0;
@ -1013,7 +1013,7 @@ final class Utf8 {
}
@Override
int encodeUtf8(CharSequence in, byte[] out, int offset, int length) {
int encodeUtf8(String in, byte[] out, int offset, int length) {
int utf16Length = in.length();
int j = offset;
int i = 0;
@ -1065,7 +1065,7 @@ final class Utf8 {
}
@Override
void encodeUtf8Direct(CharSequence in, ByteBuffer out) {
void encodeUtf8Direct(String in, ByteBuffer out) {
// For safe processing, we have to use the ByteBuffer API.
encodeUtf8Default(in, out);
}
@ -1442,7 +1442,7 @@ final class Utf8 {
}
@Override
int encodeUtf8(final CharSequence in, final byte[] out, final int offset, final int length) {
int encodeUtf8(final String in, final byte[] out, final int offset, final int length) {
long outIx = offset;
final long outLimit = outIx + length;
final int inLimit = in.length();
@ -1503,7 +1503,7 @@ final class Utf8 {
}
@Override
void encodeUtf8Direct(CharSequence in, ByteBuffer out) {
void encodeUtf8Direct(String in, ByteBuffer out) {
final long address = addressOffset(out);
long outIx = address + out.position();
final long outLimit = address + out.limit();

View File

@ -327,6 +327,81 @@ public class CodedOutputStreamTest {
.isEqualTo(-75123905439571256L);
}
@Test
public void computeIntSize() {
assertThat(CodedOutputStream.computeUInt32SizeNoTag(0)).isEqualTo(1);
assertThat(CodedOutputStream.computeUInt64SizeNoTag(0)).isEqualTo(1);
int i;
for (i = 0; i < 7; i++) {
assertThat(CodedOutputStream.computeInt32SizeNoTag(1 << i)).isEqualTo(1);
assertThat(CodedOutputStream.computeUInt32SizeNoTag(1 << i)).isEqualTo(1);
assertThat(CodedOutputStream.computeUInt64SizeNoTag(1L << i)).isEqualTo(1);
}
for (; i < 14; i++) {
assertThat(CodedOutputStream.computeInt32SizeNoTag(1 << i)).isEqualTo(2);
assertThat(CodedOutputStream.computeUInt32SizeNoTag(1 << i)).isEqualTo(2);
assertThat(CodedOutputStream.computeUInt64SizeNoTag(1L << i)).isEqualTo(2);
}
for (; i < 21; i++) {
assertThat(CodedOutputStream.computeInt32SizeNoTag(1 << i)).isEqualTo(3);
assertThat(CodedOutputStream.computeUInt32SizeNoTag(1 << i)).isEqualTo(3);
assertThat(CodedOutputStream.computeUInt64SizeNoTag(1L << i)).isEqualTo(3);
}
for (; i < 28; i++) {
assertThat(CodedOutputStream.computeInt32SizeNoTag(1 << i)).isEqualTo(4);
assertThat(CodedOutputStream.computeUInt32SizeNoTag(1 << i)).isEqualTo(4);
assertThat(CodedOutputStream.computeUInt64SizeNoTag(1L << i)).isEqualTo(4);
}
for (; i < 31; i++) {
assertThat(CodedOutputStream.computeInt32SizeNoTag(1 << i)).isEqualTo(5);
assertThat(CodedOutputStream.computeUInt32SizeNoTag(1 << i)).isEqualTo(5);
assertThat(CodedOutputStream.computeUInt64SizeNoTag(1L << i)).isEqualTo(5);
}
for (; i < 32; i++) {
assertThat(CodedOutputStream.computeInt32SizeNoTag(1 << i)).isEqualTo(10);
assertThat(CodedOutputStream.computeUInt32SizeNoTag(1 << i)).isEqualTo(5);
assertThat(CodedOutputStream.computeUInt64SizeNoTag(1L << i)).isEqualTo(5);
}
for (; i < 35; i++) {
assertThat(CodedOutputStream.computeUInt64SizeNoTag(1L << i)).isEqualTo(5);
}
for (; i < 42; i++) {
assertThat(CodedOutputStream.computeUInt64SizeNoTag(1L << i)).isEqualTo(6);
}
for (; i < 49; i++) {
assertThat(CodedOutputStream.computeUInt64SizeNoTag(1L << i)).isEqualTo(7);
}
for (; i < 56; i++) {
assertThat(CodedOutputStream.computeUInt64SizeNoTag(1L << i)).isEqualTo(8);
}
for (; i < 63; i++) {
assertThat(CodedOutputStream.computeUInt64SizeNoTag(1L << i)).isEqualTo(9);
}
}
@Test
public void computeTagSize() {
assertThat(CodedOutputStream.computeTagSize(0)).isEqualTo(1);
int i;
for (i = 0; i < 4; i++) {
assertThat(CodedOutputStream.computeTagSize(1 << i)).isEqualTo(1);
}
for (; i < 11; i++) {
assertThat(CodedOutputStream.computeTagSize(1 << i)).isEqualTo(2);
}
for (; i < 18; i++) {
assertThat(CodedOutputStream.computeTagSize(1 << i)).isEqualTo(3);
}
for (; i < 25; i++) {
assertThat(CodedOutputStream.computeTagSize(1 << i)).isEqualTo(4);
}
for (; i < 29; i++) {
assertThat(CodedOutputStream.computeTagSize(1 << i)).isEqualTo(5);
}
// Invalid tags
assertThat(CodedOutputStream.computeTagSize((1 << 30) + 1)).isEqualTo(1);
}
/** Tests writing a whole message with every field type. */
@Test
public void testWriteWholeMessage() throws Exception {

View File

@ -24,12 +24,26 @@ public final class RuntimeVersionTest {
RuntimeVersion.ProtobufRuntimeVersionException.class,
() ->
RuntimeVersion.validateProtobufGencodeVersion(
RuntimeVersion.DOMAIN,
-1,
RuntimeVersion.MINOR,
RuntimeVersion.PATCH,
RuntimeVersion.SUFFIX));
assertThat(thrown).hasMessageThat().contains("Invalid gencode version: -1");
RuntimeVersion.DOMAIN, 1, -2, -3, ""));
assertThat(thrown).hasMessageThat().contains("Invalid gencode version: 1.-2.-3");
}
@Test
public void versionValidation_crossDomainDisallowed() {
RuntimeVersion.RuntimeDomain gencodeDomain = RuntimeVersion.RuntimeDomain.GOOGLE_INTERNAL;
RuntimeVersion.ProtobufRuntimeVersionException thrown =
assertThrows(
RuntimeVersion.ProtobufRuntimeVersionException.class,
() -> RuntimeVersion.validateProtobufGencodeDomain(gencodeDomain));
assertThat(thrown).hasMessageThat().contains("Mismatched Protobuf Gencode/Runtime domains");
}
@Test
public void versionValidation_sameDomainAllowed() {
RuntimeVersion.RuntimeDomain gencodeDomain = RuntimeVersion.RuntimeDomain.PUBLIC;
RuntimeVersion.validateProtobufGencodeDomain(gencodeDomain);
}
@Test

View File

@ -11,6 +11,7 @@ import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
import static com.google.protobuf.TestUtil.TEST_REQUIRED_INITIALIZED;
import static com.google.protobuf.TestUtil.TEST_REQUIRED_UNINITIALIZED;
import static protobuf_unittest.UnittestProto.optionalInt32Extension;
import static org.junit.Assert.assertThrows;
import com.google.protobuf.DescriptorProtos.DescriptorProto;
@ -623,6 +624,83 @@ public class TextFormatTest {
assertThat(actual).isEqualTo(expected);
}
@Test
public void testPrintAny_anyWithDynamicMessageContainingExtensionTreatedAsUnknown()
throws Exception {
Descriptor descriptor =
createDescriptorForAny(
FieldDescriptorProto.newBuilder()
.setName("type_url")
.setNumber(1)
.setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
.setType(FieldDescriptorProto.Type.TYPE_STRING)
.build(),
FieldDescriptorProto.newBuilder()
.setName("value")
.setNumber(2)
.setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
.setType(FieldDescriptorProto.Type.TYPE_BYTES)
.build());
DynamicMessage testAny =
DynamicMessage.newBuilder(descriptor)
.setField(
descriptor.findFieldByNumber(1),
"type.googleapis.com/" + TestAllExtensions.getDescriptor().getFullName())
.setField(
descriptor.findFieldByNumber(2),
TestAllExtensions.newBuilder()
.setExtension(optionalInt32Extension, 12345)
.build()
.toByteString())
.build();
String actual =
TextFormat.printer()
.usingTypeRegistry(TypeRegistry.newBuilder().add(TestAllTypes.getDescriptor()).build())
.printToString(testAny);
String expected = "[type.googleapis.com/protobuf_unittest.TestAllExtensions] {\n 1: 12345\n}\n";
assertThat(actual).isEqualTo(expected);
}
@Test
public void testPrintAny_anyWithDynamicMessageContainingExtensionWithRegistry() throws Exception {
Descriptor descriptor =
createDescriptorForAny(
FieldDescriptorProto.newBuilder()
.setName("type_url")
.setNumber(1)
.setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
.setType(FieldDescriptorProto.Type.TYPE_STRING)
.build(),
FieldDescriptorProto.newBuilder()
.setName("value")
.setNumber(2)
.setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
.setType(FieldDescriptorProto.Type.TYPE_BYTES)
.build());
DynamicMessage testAny =
DynamicMessage.newBuilder(descriptor)
.setField(
descriptor.findFieldByNumber(1),
"type.googleapis.com/" + TestAllExtensions.getDescriptor().getFullName())
.setField(
descriptor.findFieldByNumber(2),
TestAllExtensions.newBuilder()
.setExtension(optionalInt32Extension, 12345)
.build()
.toByteString())
.build();
String actual =
TextFormat.printer()
.usingTypeRegistry(TypeRegistry.newBuilder().add(TestAllTypes.getDescriptor()).build())
.usingExtensionRegistry(TestUtil.getFullExtensionRegistry())
.printToString(testAny);
String expected =
"[type.googleapis.com/protobuf_unittest.TestAllExtensions] {\n"
+ " [protobuf_unittest.optional_int32_extension]: 12345\n"
+ "}\n";
assertThat(actual).isEqualTo(expected);
}
@Test
public void testPrintAny_anyFromWithNoValueField() throws Exception {
Descriptor descriptor =

View File

@ -194,7 +194,7 @@ public class Utf8Test {
private static byte[] encodeToByteArray(String message, int length, Utf8.Processor processor) {
byte[] output = new byte[length];
processor.encodeUtf8(message, output, 0, output.length);
int unused = processor.encodeUtf8(message, output, 0, output.length);
return output;
}

View File

@ -426,13 +426,13 @@ public final class Durations {
* Add two durations.
*
* <!-- MOE:begin_intracomment_strip -->
* <p>Do not use this method for new code. Instead, convert to {@link java.time.Duration} using
* {@link com.google.protobuf.util.JavaTimeConversions#toJavaDuration}, do the arithmetic there,
* and convert back using {@link com.google.protobuf.util.JavaTimeConversions#toProtoDuration}.
*
* <p>This method will be deprecated once most uses have been eliminated.
* @deprecated Do not use this method for new code. Instead, convert to {@link java.time.Duration}
* using {@link com.google.protobuf.util.JavaTimeConversions#toJavaDuration}, do the
* arithmetic there, and convert back using {@link
* com.google.protobuf.util.JavaTimeConversions#toProtoDuration}.
* <!-- MOE:end_intracomment_strip -->
*/
@Deprecated // MOE:strip_line
public static Duration add(Duration d1, Duration d2) {
checkValid(d1);
checkValid(d2);
@ -444,13 +444,13 @@ public final class Durations {
* Subtract a duration from another.
*
* <!-- MOE:begin_intracomment_strip -->
* <p>Do not use this method for new code. Instead, convert to {@link java.time.Duration} using
* {@link com.google.protobuf.util.JavaTimeConversions#toJavaDuration}, do the arithmetic there,
* and convert back using {@link com.google.protobuf.util.JavaTimeConversions#toProtoDuration}.
*
* <p>This method will be deprecated once most uses have been eliminated.
* @deprecated Do not use this method for new code. Instead, convert to {@link java.time.Duration}
* using {@link com.google.protobuf.util.JavaTimeConversions#toJavaDuration}, do the
* arithmetic there, and convert back using {@link
* com.google.protobuf.util.JavaTimeConversions#toProtoDuration}.
* <!-- MOE:end_intracomment_strip -->
*/
@Deprecated // MOE:strip_line
public static Duration subtract(Duration d1, Duration d2) {
checkValid(d1);
checkValid(d2);

View File

@ -431,13 +431,13 @@ public final class Timestamps {
* Calculate the difference between two timestamps.
*
* <!-- MOE:begin_intracomment_strip -->
* <p>Do not use this method for new code. Instead, convert to {@link java.time.Instant} using
* {@link com.google.protobuf.util.JavaTimeConversions#toJavaInstant}, do the arithmetic there,
* and convert back using {@link com.google.protobuf.util.JavaTimeConversions#toProtoDuration}.
*
* <p>This method will be deprecated once most uses have been eliminated.
* @deprecated Do not use this method for new code. Instead, convert to {@link java.time.Instant}
* using {@link com.google.protobuf.util.JavaTimeConversions#toJavaInstant}, do the arithmetic
* there, and convert back using {@link
* com.google.protobuf.util.JavaTimeConversions#toProtoDuration}.
* <!-- MOE:end_intracomment_strip -->
*/
@Deprecated // MOE:strip_line
public static Duration between(Timestamp from, Timestamp to) {
checkValid(from);
checkValid(to);
@ -450,15 +450,14 @@ public final class Timestamps {
* Add a duration to a timestamp.
*
* <!-- MOE:begin_intracomment_strip -->
* <p>Do not use this method for new code. Instead, convert to {@link java.time.Instant} and
* {@link java.time.Duration} using {@link
* com.google.protobuf.util.JavaTimeConversions#toJavaInstant} and {@link
* com.google.protobuf.util.JavaTimeConversions#toJavaDuration}, do the arithmetic there, and
* convert back using {@link com.google.protobuf.util.JavaTimeConversions#toProtoTimestamp}.
*
* <p>This method will be deprecated once most uses have been eliminated.
* @deprecated Do not use this method for new code. Instead, convert to {@link java.time.Instant}
* and {@link java.time.Duration} using {@link
* com.google.protobuf.util.JavaTimeConversions#toJavaInstant} and {@link
* com.google.protobuf.util.JavaTimeConversions#toJavaDuration}, do the arithmetic there, and
* convert back using {@link com.google.protobuf.util.JavaTimeConversions#toProtoTimestamp}.
* <!-- MOE:end_intracomment_strip -->
*/
@Deprecated // MOE:strip_line
public static Timestamp add(Timestamp start, Duration length) {
checkValid(start);
Durations.checkValid(length);
@ -471,15 +470,14 @@ public final class Timestamps {
* Subtract a duration from a timestamp.
*
* <!-- MOE:begin_intracomment_strip -->
* <p>Do not use this method for new code. Instead, convert to {@link java.time.Instant} and
* {@link java.time.Duration} using {@link
* com.google.protobuf.util.JavaTimeConversions#toJavaInstant} and {@link
* com.google.protobuf.util.JavaTimeConversions#toJavaDuration}, do the arithmetic there, and
* convert back using {@link com.google.protobuf.util.JavaTimeConversions#toProtoTimestamp}.
*
* <p>This method will be deprecated once most uses have been eliminated.
* @deprecated Do not use this method for new code. Instead, convert to {@link java.time.Instant}
* and {@link java.time.Duration} using {@link
* com.google.protobuf.util.JavaTimeConversions#toJavaInstant} and {@link
* com.google.protobuf.util.JavaTimeConversions#toJavaDuration}, do the arithmetic there, and
* convert back using {@link com.google.protobuf.util.JavaTimeConversions#toProtoTimestamp}.
* <!-- MOE:end_intracomment_strip -->
*/
@Deprecated // MOE:strip_line
public static Timestamp subtract(Timestamp start, Duration length) {
checkValid(start);
Durations.checkValid(length);

View File

@ -160,6 +160,7 @@ objc_library(
conformance_test(
name = "conformance_test",
failure_list = "//conformance:failure_list_objc.txt",
maximum_edition = "2023",
target_compatible_with = ["@platforms//os:macos"],
testee = "//conformance:conformance_objc",
)

View File

@ -168,6 +168,9 @@ GPB_FINAL @interface GPBAny : GPBMessage
/** Must be a valid serialized protocol buffer of the above specified type. */
@property(nonatomic, readwrite, copy, null_resettable) NSData *value;
// NOTE: There are some Objective-C specific methods/properties in
// GPBWellKnownTypes.h that will likey be useful.
@end
NS_ASSUME_NONNULL_END

View File

@ -3,6 +3,7 @@
// source: google/protobuf/any.proto
#import "GPBProtocolBuffers_RuntimeSupport.h"
#import "GPBWellKnownTypes.h"
#import "GPBAny.pbobjc.h"
#if GOOGLE_PROTOBUF_OBJC_VERSION < 30007
@ -39,6 +40,13 @@ static GPBFileDescription GPBAnyRoot_FileDescription = {
.syntax = GPBFileSyntaxProto3
};
// This is to help make sure that the GPBWellKnownTypes.* categories get linked and
// developers do not have to use the `-ObjC` linker flag. More information
// here: https://medium.com/ios-os-x-development/categories-in-static-libraries-78e41f8ddb96
__attribute__((used)) static NSString* any_importCategories () {
return GPBWellKnownTypesErrorDomain;
}
#pragma mark - GPBAny
@implementation GPBAny

View File

@ -123,6 +123,9 @@ GPB_FINAL @interface GPBDuration : GPBMessage
**/
@property(nonatomic, readwrite) int32_t nanos;
// NOTE: There are some Objective-C specific methods/properties in
// GPBWellKnownTypes.h that will likey be useful.
@end
NS_ASSUME_NONNULL_END

View File

@ -3,6 +3,7 @@
// source: google/protobuf/duration.proto
#import "GPBProtocolBuffers_RuntimeSupport.h"
#import "GPBWellKnownTypes.h"
#import "GPBDuration.pbobjc.h"
#if GOOGLE_PROTOBUF_OBJC_VERSION < 30007
@ -39,6 +40,13 @@ static GPBFileDescription GPBDurationRoot_FileDescription = {
.syntax = GPBFileSyntaxProto3
};
// This is to help make sure that the GPBWellKnownTypes.* categories get linked and
// developers do not have to use the `-ObjC` linker flag. More information
// here: https://medium.com/ios-os-x-development/categories-in-static-libraries-78e41f8ddb96
__attribute__((used)) static NSString* duration_importCategories () {
return GPBWellKnownTypesErrorDomain;
}
#pragma mark - GPBDuration
@implementation GPBDuration

View File

@ -152,6 +152,9 @@ GPB_FINAL @interface GPBTimestamp : GPBMessage
**/
@property(nonatomic, readwrite) int32_t nanos;
// NOTE: There are some Objective-C specific methods/properties in
// GPBWellKnownTypes.h that will likey be useful.
@end
NS_ASSUME_NONNULL_END

View File

@ -3,6 +3,7 @@
// source: google/protobuf/timestamp.proto
#import "GPBProtocolBuffers_RuntimeSupport.h"
#import "GPBWellKnownTypes.h"
#import "GPBTimestamp.pbobjc.h"
#if GOOGLE_PROTOBUF_OBJC_VERSION < 30007
@ -39,6 +40,13 @@ static GPBFileDescription GPBTimestampRoot_FileDescription = {
.syntax = GPBFileSyntaxProto3
};
// This is to help make sure that the GPBWellKnownTypes.* categories get linked and
// developers do not have to use the `-ObjC` linker flag. More information
// here: https://medium.com/ios-os-x-development/categories-in-static-libraries-78e41f8ddb96
__attribute__((used)) static NSString* timestamp_importCategories () {
return GPBWellKnownTypesErrorDomain;
}
#pragma mark - GPBTimestamp
@implementation GPBTimestamp

View File

@ -201,6 +201,24 @@ typedef NS_ENUM(NSInteger, GPBWellKnownTypesErrorCode) {
*/
- (nullable GPBMessage *)unpackMessageClass:(Class)messageClass error:(NSError **)errorPtr;
/**
* Unpacks the serialized message as if it was an instance of the given class.
*
* @note When checking type_url, the base URL is not checked, only the fully
* qualified name.
*
* @param messageClass The class to use to deserialize the contained message.
* @param extensionRegistry The extension registry to use to look up extensions.
* @param errorPtr Pointer to an error that will be populated if something
* goes wrong.
*
* @return An instance of the given class populated with the contained data, or
* nil on failure.
*/
- (nullable GPBMessage *)unpackMessageClass:(Class)messageClass
extensionRegistry:(nullable id<GPBExtensionRegistry>)extensionRegistry
error:(NSError **)errorPtr;
@end
NS_ASSUME_NONNULL_END

View File

@ -195,6 +195,12 @@ static NSString *ParseTypeFromURL(NSString *typeURLString) {
}
- (GPBMessage *)unpackMessageClass:(Class)messageClass error:(NSError **)errorPtr {
return [self unpackMessageClass:messageClass extensionRegistry:nil error:errorPtr];
}
- (nullable GPBMessage *)unpackMessageClass:(Class)messageClass
extensionRegistry:(nullable id<GPBExtensionRegistry>)extensionRegistry
error:(NSError **)errorPtr {
NSString *fullName = [messageClass descriptor].fullName;
if (fullName.length == 0) {
if (errorPtr) {
@ -215,10 +221,7 @@ static NSString *ParseTypeFromURL(NSString *typeURLString) {
return nil;
}
// Any is proto3, which means no extensions, so this assumes anything put
// within an any also won't need extensions. A second helper could be added
// if needed.
return [messageClass parseFromData:self.value error:errorPtr];
return [messageClass parseFromData:self.value extensionRegistry:extensionRegistry error:errorPtr];
}
@end

View File

@ -4,7 +4,7 @@ if test "$PHP_PROTOBUF" != "no"; then
PHP_NEW_EXTENSION(
protobuf,
arena.c array.c convert.c def.c map.c message.c names.c php-upb.c protobuf.c third_party/utf8_range/naive.c third_party/utf8_range/range2-neon.c third_party/utf8_range/range2-sse.c,
arena.c array.c convert.c def.c map.c message.c names.c php-upb.c protobuf.c third_party/utf8_range/utf8_range.c,
$ext_shared, , -std=gnu99 -I@ext_srcdir@/third_party/utf8_range)
PHP_ADD_BUILD_DIR($ext_builddir/third_party/utf8_range)

View File

@ -400,11 +400,8 @@ static zval* Message_get_property_ptr_ptr(zend_object* object,
static zend_object* Message_clone_obj(zend_object* object) {
Message* intern = (Message*)object;
const upb_MiniTable* t = upb_MessageDef_MiniTable(intern->desc->msgdef);
upb_Message* clone = upb_Message_New(t, Arena_Get(&intern->arena));
// TODO: copy unknown fields?
// TODO: use official upb msg copy function
memcpy(clone, intern->msg, t->size);
upb_Message* clone =
upb_Message_ShallowClone(intern->msg, t, Arena_Get(&intern->arena));
zval ret;
Message_GetPhpWrapper(&ret, intern->desc, clone, &intern->arena);
return Z_OBJ_P(&ret);

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -220,6 +220,7 @@ cc_dist_library(
"//src/google/protobuf:lite_test_util",
"//src/google/protobuf:test_util",
"//src/google/protobuf:test_util2",
"//src/google/protobuf:unredacted_debug_format_for_test",
"//src/google/protobuf/compiler:annotation_test_util",
"//src/google/protobuf/compiler/cpp:unittest_lib",
"//src/google/protobuf/io:test_zero_copy_stream",

View File

@ -80,6 +80,7 @@ def _proto_gen_impl(ctx):
srcs = ctx.files.srcs
langs = ctx.attr.langs or []
out_type = ctx.attr.out_type
enable_editions = ctx.attr.enable_editions
deps = depset(direct = ctx.files.srcs)
source_dir = _SourceDir(ctx)
gen_dir = _GenDir(ctx).rstrip("/")
@ -130,6 +131,8 @@ def _proto_gen_impl(ctx):
generated_files = []
for src in srcs:
args = []
if enable_editions:
args.append("--experimental_editions")
in_gen_dir = src.root.path == gen_dir
if in_gen_dir:
@ -247,6 +250,7 @@ _proto_gen = rule(
attrs = {
"srcs": attr.label_list(allow_files = True),
"deps": attr.label_list(providers = [ProtoGenInfo]),
"enable_editions": attr.bool(),
"includes": attr.string_list(),
"protoc": attr.label(
cfg = "exec",
@ -406,11 +410,11 @@ def internal_objc_proto_library(
includes = ["."],
default_runtime = Label("//:protobuf_objc"),
protoc = Label("//:protoc"),
enable_editions = False,
testonly = None,
visibility = ["//visibility:public"],
**kwargs):
"""Bazel rule to create a Objective-C protobuf library from proto source
files
"""Bazel rule to create a Objective-C protobuf library from proto sources
NOTE: the rule is only an internal workaround to generate protos. The
interface may change and the rule may be removed when bazel has introduced
@ -423,9 +427,10 @@ def internal_objc_proto_library(
outs: a list of expected output files.
proto_deps: a list of proto file dependencies that don't have a
objc_proto_library rule.
include: a string indicating the include path of the .proto files.
includes: a string indicating the include path of the .proto files.
default_runtime: the Objective-C Protobuf runtime
protoc: the label of the protocol compiler to generate the sources.
enable_editions: if editions should be enabled while invoking the compiler.
testonly: common rule attribute (see:
https://bazel.build/reference/be/common-definitions#common-attributes)
visibility: the visibility of the generated files.
@ -440,6 +445,7 @@ def internal_objc_proto_library(
testonly = testonly,
srcs = proto_deps,
protoc = protoc,
enable_editions = enable_editions,
includes = includes,
)
full_deps.append(":%s_deps_genproto" % name)
@ -454,6 +460,7 @@ def internal_objc_proto_library(
out_type = "hdrs",
includes = includes,
protoc = protoc,
enable_editions = enable_editions,
testonly = testonly,
visibility = visibility,
tags = ["manual"],
@ -467,6 +474,7 @@ def internal_objc_proto_library(
out_type = "srcs",
includes = includes,
protoc = protoc,
enable_editions = enable_editions,
testonly = testonly,
visibility = visibility,
tags = ["manual"],

View File

@ -72,8 +72,8 @@ def protobuf_deps():
_github_archive(
name = "rules_cc",
repo = "https://github.com/bazelbuild/rules_cc",
commit = "818289e5613731ae410efb54218a4077fb9dbb03",
sha256 = "0adbd6f567291ad526e82c765e15aed33cea5e256eeba129f1501142c2c56610",
commit = "c8c38f8c710cbbf834283e4777916b68261b359c", # 0.0.9
sha256 = "5f862a44bbd032e1b48ed53c9c211ba2a1da60e10c5baa01c97369c249299ecb",
)
if not native.existing_rule("rules_java"):
@ -122,8 +122,8 @@ def protobuf_deps():
if not native.existing_rule("build_bazel_rules_apple"):
http_archive(
name = "build_bazel_rules_apple",
sha256 = "f94e6dddf74739ef5cb30f000e13a2a613f6ebfa5e63588305a71fce8a8a9911",
url = "https://github.com/bazelbuild/rules_apple/releases/download/1.1.3/rules_apple.1.1.3.tar.gz",
sha256 = "34c41bfb59cdaea29ac2df5a2fa79e5add609c71bb303b2ebb10985f93fa20e7",
url = "https://github.com/bazelbuild/rules_apple/releases/download/3.1.1/rules_apple.3.1.1.tar.gz",
)
if not native.existing_rule("io_bazel_rules_kotlin"):

View File

@ -115,7 +115,7 @@ bool HasExtensionOrUnknown(const upb_Message* msg,
const upb_MiniTableExtension* eid) {
MessageLock msg_lock(msg);
return _upb_Message_Getext(msg, eid) != nullptr ||
upb_MiniTable_FindUnknown(msg, upb_MiniTableExtension_Number(eid), 0)
upb_Message_FindUnknown(msg, upb_MiniTableExtension_Number(eid), 0)
.status == kUpb_FindUnknown_Ok;
}

View File

@ -121,7 +121,6 @@ def build_targets(name):
deps = [
":proto_api",
"//:protobuf",
"//src/google/protobuf:descriptor_legacy",
] + select({
"//conditions:default": [],
":use_fast_cpp_protos": ["//external:python_headers"],

View File

@ -241,7 +241,7 @@ bool PyUpb_PyToUpb(PyObject* obj, const upb_FieldDef* f, upb_MessageValue* val,
// Use the object's bytes if they are valid UTF-8.
char* ptr;
if (PyBytes_AsStringAndSize(obj, &ptr, &size) < 0) return false;
if (utf8_range2((const unsigned char*)ptr, size) != 0) {
if (!utf8_range_IsValid(ptr, size)) {
// Invalid UTF-8. Try to convert the message to a Python Unicode
// object, even though we know this will fail, just to get the
// idiomatic Python error message.

View File

@ -648,18 +648,6 @@ static PyObject* PyUpb_Descriptor_GetOneofsByName(PyObject* _self,
return PyUpb_ByNameMap_New(&funcs, self->def, self->pool);
}
static PyObject* PyUpb_Descriptor_GetSyntax(PyObject* self, void* closure) {
PyErr_WarnEx(NULL,
"descriptor.syntax is deprecated. It will be removed soon. "
"Most usages are checking field descriptors. Consider to use "
"has_presence, is_packed on field descriptors.",
1);
const upb_MessageDef* msgdef = PyUpb_Descriptor_GetDef(self);
const char* syntax =
upb_MessageDef_Syntax(msgdef) == kUpb_Syntax_Proto2 ? "proto2" : "proto3";
return PyUnicode_InternFromString(syntax);
}
static PyGetSetDef PyUpb_Descriptor_Getters[] = {
{"name", PyUpb_Descriptor_GetName, NULL, "Last name"},
{"full_name", PyUpb_Descriptor_GetFullName, NULL, "Full name"},
@ -694,13 +682,6 @@ static PyGetSetDef PyUpb_Descriptor_Getters[] = {
"Containing type"},
{"is_extendable", PyUpb_Descriptor_GetIsExtendable, NULL},
{"has_options", PyUpb_Descriptor_GetHasOptions, NULL, "Has Options"},
// begin:github_only
{"syntax", &PyUpb_Descriptor_GetSyntax, NULL, "Syntax"},
// end:github_only
// begin:google_only
// // TODO Use this to open-source syntax deprecation.
// {"deprecated_syntax", &PyUpb_Descriptor_GetSyntax, NULL, "Syntax"},
// end:google_only
{NULL}};
static PyMethodDef PyUpb_Descriptor_Methods[] = {
@ -1248,26 +1229,34 @@ static const void* PyUpb_FileDescriptor_NestedLookup(
static const void* PyUpb_FileDescriptor_LookupMessage(
const upb_FileDef* filedef, const char* name) {
return PyUpb_FileDescriptor_NestedLookup(
const upb_MessageDef* m = PyUpb_FileDescriptor_NestedLookup(
filedef, name, (void*)&upb_DefPool_FindMessageByName);
if (!m) return NULL;
return upb_MessageDef_File(m) == filedef ? m : NULL;
}
static const void* PyUpb_FileDescriptor_LookupEnum(const upb_FileDef* filedef,
const char* name) {
return PyUpb_FileDescriptor_NestedLookup(filedef, name,
(void*)&upb_DefPool_FindEnumByName);
const upb_EnumDef* e = PyUpb_FileDescriptor_NestedLookup(
filedef, name, (void*)&upb_DefPool_FindEnumByName);
if (!e) return NULL;
return upb_EnumDef_File(e) == filedef ? e : NULL;
}
static const void* PyUpb_FileDescriptor_LookupExtension(
const upb_FileDef* filedef, const char* name) {
return PyUpb_FileDescriptor_NestedLookup(
const upb_FieldDef* f = PyUpb_FileDescriptor_NestedLookup(
filedef, name, (void*)&upb_DefPool_FindExtensionByName);
if (!f) return NULL;
return upb_FieldDef_File(f) == filedef ? f : NULL;
}
static const void* PyUpb_FileDescriptor_LookupService(
const upb_FileDef* filedef, const char* name) {
return PyUpb_FileDescriptor_NestedLookup(
const upb_ServiceDef* s = PyUpb_FileDescriptor_NestedLookup(
filedef, name, (void*)&upb_DefPool_FindServiceByName);
if (!s) return NULL;
return upb_ServiceDef_File(s) == filedef ? s : NULL;
}
static PyObject* PyUpb_FileDescriptor_GetName(PyUpb_DescriptorBase* self,
@ -1376,17 +1365,10 @@ static PyObject* PyUpb_FileDescriptor_GetPublicDependencies(PyObject* _self,
return PyUpb_GenericSequence_New(&funcs, self->def, self->pool);
}
static PyObject* PyUpb_FileDescriptor_GetSyntax(PyObject* _self,
void* closure) {
PyErr_WarnEx(NULL,
"descriptor.syntax is deprecated. It will be removed soon. "
"Most usages are checking field descriptors. Consider to use "
"has_presence, is_packed on field descriptors.",
1);
static PyObject* PyUpb_FileDescriptor_GetEdition(PyObject* _self,
void* closure) {
PyUpb_DescriptorBase* self = (void*)_self;
const char* syntax =
upb_FileDef_Syntax(self->def) == kUpb_Syntax_Proto2 ? "proto2" : "proto3";
return PyUnicode_FromString(syntax);
return PyLong_FromLong(upb_FileDef_Edition(self->def));
}
static PyObject* PyUpb_FileDescriptor_GetHasOptions(PyObject* _self,
@ -1437,14 +1419,7 @@ static PyGetSetDef PyUpb_FileDescriptor_Getters[] = {
{"public_dependencies", PyUpb_FileDescriptor_GetPublicDependencies, NULL,
"Dependencies"},
{"has_options", PyUpb_FileDescriptor_GetHasOptions, NULL, "Has Options"},
// begin:github_only
{"syntax", PyUpb_FileDescriptor_GetSyntax, (setter)NULL, "Syntax"},
// end:github_only
// begin:google_only
// // TODO Use this to open-source syntax deprecation.
// {"deprecated_syntax", PyUpb_FileDescriptor_GetSyntax, (setter)NULL,
// "Syntax"},
// end:google_only
{"edition", PyUpb_FileDescriptor_GetEdition, (setter)NULL, "Edition"},
{NULL},
};

View File

@ -1179,24 +1179,23 @@ class FileDescriptor(DescriptorBase):
Attributes:
name (str): Name of file, relative to root of source tree.
package (str): Name of the package
syntax (str): string indicating syntax of the file (can be "proto2" or
"proto3")
edition (Edition): Enum value indicating edition of the file
serialized_pb (bytes): Byte string of serialized
:class:`descriptor_pb2.FileDescriptorProto`.
dependencies (list[FileDescriptor]): List of other :class:`FileDescriptor`
objects this :class:`FileDescriptor` depends on.
public_dependencies (list[FileDescriptor]): A subset of
:attr:`dependencies`, which were declared as "public".
message_types_by_name (dict(str, Descriptor)): Mapping from message names
to their :class:`Descriptor`.
message_types_by_name (dict(str, Descriptor)): Mapping from message names to
their :class:`Descriptor`.
enum_types_by_name (dict(str, EnumDescriptor)): Mapping from enum names to
their :class:`EnumDescriptor`.
extensions_by_name (dict(str, FieldDescriptor)): Mapping from extension
names declared at file scope to their :class:`FieldDescriptor`.
services_by_name (dict(str, ServiceDescriptor)): Mapping from services'
names to their :class:`ServiceDescriptor`.
pool (DescriptorPool): The pool this descriptor belongs to. When not
passed to the constructor, the global default pool is used.
pool (DescriptorPool): The pool this descriptor belongs to. When not passed
to the constructor, the global default pool is used.
"""
if _USE_C_DESCRIPTORS:
@ -1260,7 +1259,6 @@ class FileDescriptor(DescriptorBase):
self.message_types_by_name = {}
self.name = name
self.package = package
self._deprecated_syntax = syntax or "proto2"
self.serialized_pb = serialized_pb
self.enum_types_by_name = {}
@ -1269,15 +1267,6 @@ class FileDescriptor(DescriptorBase):
self.dependencies = (dependencies or [])
self.public_dependencies = (public_dependencies or [])
@property
def syntax(self):
warnings.warn(
'descriptor.syntax is deprecated. It will be removed'
' soon. Most usages are checking field descriptors. Consider to use'
' has_presence, is_packed on field descriptors.'
)
return self._deprecated_syntax
def CopyToProto(self, proto):
"""Copies this to a descriptor_pb2.FileDescriptorProto.
@ -1290,6 +1279,13 @@ class FileDescriptor(DescriptorBase):
def _parent(self):
return None
@property
def edition(self):
# pylint: disable=g-import-not-at-top
from google.protobuf import descriptor_pb2
return descriptor_pb2.Edition.Value(self._edition)
def _ParseOptions(message, string):
"""Parses serialized options.

View File

@ -132,6 +132,51 @@ class DescriptorPoolTestBase(object):
self.assertRaises(KeyError, self.pool.FindFileContainingSymbol,
'google.protobuf.python.internal.Factory1Message.none_field')
def testCrossFileMessageTypesByName(self):
self.assertIs(
descriptor_pool_test1_pb2.DescriptorPoolTest1.DESCRIPTOR,
descriptor_pool_test1_pb2.DESCRIPTOR.message_types_by_name[
'DescriptorPoolTest1'
],
)
with self.assertRaises(KeyError):
descriptor_pool_test2_pb2.DESCRIPTOR.message_types_by_name[
'DescriptorPoolTest1'
]
def testCrossFileEnumTypesByName(self):
self.assertIs(
descriptor_pool_test1_pb2.TopLevelEnumTest1.DESCRIPTOR,
descriptor_pool_test1_pb2.DESCRIPTOR.enum_types_by_name[
'TopLevelEnumTest1'
],
)
with self.assertRaises(KeyError):
descriptor_pool_test2_pb2.DESCRIPTOR.enum_types_by_name[
'TopLevelEnumTest1'
]
def testCrossFileExtensionsByName(self):
self.assertIs(
descriptor_pool_test1_pb2.top_level_extension_test1,
descriptor_pool_test1_pb2.DESCRIPTOR.extensions_by_name[
'top_level_extension_test1'
],
)
with self.assertRaises(KeyError):
descriptor_pool_test2_pb2.DESCRIPTOR.extensions_by_name[
'top_level_extension_test1'
]
def testCrossFileServicesByName(self):
descriptor_pool_test1_pb2.DESCRIPTOR.services_by_name[
'DescriporPoolTestService'
],
with self.assertRaises(KeyError):
descriptor_pool_test2_pb2.DESCRIPTOR.services_by_name[
'DescriporPoolTestService'
]
def testFindFileContainingSymbolFailure(self):
with self.assertRaises(KeyError):
self.pool.FindFileContainingSymbol('Does not exist')

View File

@ -9,6 +9,17 @@ syntax = "proto2";
package google.protobuf.python.internal;
enum TopLevelEnumTest1 {
TOP_LEVEL_ENUM_TEST_1_NONE = 0;
TOP_LEVEL_ENUM_TEST_1_ONE = 1;
}
extend DescriptorPoolTest1 {
optional TopLevelEnumTest1 top_level_extension_test1 = 1000;
}
service DescriporPoolTestService {}
message DescriptorPoolTest1 {
extensions 1000 to max;
@ -63,7 +74,7 @@ message DescriptorPoolTest2 {
LAMBDA = 11;
MU = 12;
reserved -1;
reserved - 1;
reserved 536870913; // 0x20000001
}
optional NestedEnum nested_enum = 1 [default = MU];

View File

@ -539,7 +539,9 @@ class DescriptorTest(unittest.TestCase):
self.assertEqual(self.my_file.package, 'protobuf_unittest')
self.assertEqual(self.my_file.pool, self.pool)
self.assertFalse(self.my_file.has_options)
self.assertEqual(self.my_file.syntax, 'proto2')
self.assertEqual(
self.my_file.edition, descriptor_pb2.Edition.EDITION_PROTO2
)
file_proto = descriptor_pb2.FileDescriptorProto()
self.my_file.CopyToProto(file_proto)
self.assertEqual(self.my_file.serialized_pb,

View File

@ -1340,6 +1340,17 @@ class Proto2Test(unittest.TestCase):
self.assertEqual(False, message.optional_bool)
self.assertEqual(0, message.optional_nested_message.bb)
def testDel(self):
msg = unittest_pb2.TestAllTypes()
# Fields cannot be deleted.
with self.assertRaises(AttributeError):
del msg.optional_int32
with self.assertRaises(AttributeError):
del msg.optional_bool
with self.assertRaises(AttributeError):
del msg.repeated_nested_message
def testAssignInvalidEnum(self):
"""Assigning an invalid enum number is not allowed in proto2."""
m = unittest_pb2.TestAllTypes()

View File

@ -1385,15 +1385,9 @@ def _Clear(self):
def _UnknownFields(self):
warnings.warn(
'message.UnknownFields() is deprecated. Please use the add one '
'feature unknown_fields.UnknownFieldSet(message) in '
'unknown_fields.py instead.'
)
if self._unknown_field_set is None: # pylint: disable=protected-access
# pylint: disable=protected-access
self._unknown_field_set = containers.UnknownFieldSet()
return self._unknown_field_set # pylint: disable=protected-access
raise NotImplementedError('Please use the add-on feaure '
'unknown_fields.UnknownFieldSet(message) in '
'unknown_fields.py instead.')
def _DiscardUnknownFields(self):

View File

@ -22,7 +22,6 @@
#include "absl/log/absl_check.h"
#include "absl/strings/string_view.h"
#include "google/protobuf/descriptor.h"
#include "google/protobuf/descriptor_legacy.h"
#include "google/protobuf/dynamic_message.h"
#include "google/protobuf/io/coded_stream.h"
#include "google/protobuf/pyext/descriptor_containers.h"
@ -696,17 +695,6 @@ static PyObject* EnumValueName(PyBaseDescriptor *self, PyObject *args) {
return PyString_FromCppString(enum_value->name());
}
static PyObject* GetSyntax(PyBaseDescriptor *self, void *closure) {
PyErr_WarnEx(nullptr,
"descriptor.syntax is deprecated. It will be removed soon. "
"Most usages are checking field descriptors. Consider to use "
"has_presence, is_packed on field descriptors.",
1);
std::string syntax(FileDescriptorLegacy::SyntaxName(
FileDescriptorLegacy(_GetDescriptor(self)->file()).syntax()));
return PyUnicode_InternFromString(syntax.c_str());
}
static PyGetSetDef Getters[] = {
{"name", (getter)GetName, nullptr, "Last name"},
{"full_name", (getter)GetFullName, nullptr, "Full name"},
@ -743,7 +731,6 @@ static PyGetSetDef Getters[] = {
{"_options", (getter) nullptr, (setter)SetOptions, "Options"},
{"_serialized_options", (getter) nullptr, (setter)SetSerializedOptions,
"Serialized Options"},
{"syntax", (getter)GetSyntax, (setter) nullptr, "Syntax"},
{nullptr},
};
@ -1542,15 +1529,8 @@ static int SetSerializedOptions(PyFileDescriptor *self, PyObject *value,
return CheckCalledFromGeneratedFile("_serialized_options");
}
static PyObject* GetSyntax(PyFileDescriptor *self, void *closure) {
PyErr_WarnEx(nullptr,
"descriptor.syntax is deprecated. It will be removed soon. "
"Most usages are checking field descriptors. Consider to use "
"has_presence, is_packed on field descriptors.",
1);
std::string syntax(FileDescriptorLegacy::SyntaxName(
FileDescriptorLegacy(_GetDescriptor(self)).syntax()));
return PyUnicode_InternFromString(syntax.c_str());
static PyObject* GetEdition(PyFileDescriptor* self, void* closure) {
return PyLong_FromLong(_GetDescriptor(self)->edition());
}
static PyObject* CopyToProto(PyFileDescriptor *self, PyObject *target) {
@ -1579,7 +1559,7 @@ static PyGetSetDef Getters[] = {
{"_options", (getter) nullptr, (setter)SetOptions, "Options"},
{"_serialized_options", (getter) nullptr, (setter)SetSerializedOptions,
"Serialized Options"},
{"syntax", (getter)GetSyntax, (setter) nullptr, "Syntax"},
{"edition", (getter)GetEdition, (setter) nullptr, "Edition"},
{nullptr},
};

View File

@ -2346,16 +2346,11 @@ static PyObject* GetExtensionDict(CMessage* self, void *closure) {
}
static PyObject* GetUnknownFields(CMessage* self) {
PyErr_Warn(nullptr,
"message.UnknownFields() is deprecated. Please use the "
"add one feature unknown_fields.UnknownFieldSet(message) in "
"unknown_fields.py instead.");
if (self->unknown_field_set == nullptr) {
self->unknown_field_set = unknown_fields::NewPyUnknownFields(self);
} else {
Py_INCREF(self->unknown_field_set);
}
return self->unknown_field_set;
PyErr_Format(PyExc_NotImplementedError,
"Please use the add-on feature "
"unknown_fields.UnknownFieldSet(message) in "
"unknown_fields.py instead.");
return nullptr;
}
static PyGetSetDef Getters[] = {

View File

@ -1005,6 +1005,12 @@ __attribute__((flatten)) static PyObject* PyUpb_Message_GetAttr(
static int PyUpb_Message_SetAttr(PyObject* _self, PyObject* attr,
PyObject* value) {
PyUpb_Message* self = (void*)_self;
if (value == NULL) {
PyErr_SetString(PyExc_AttributeError, "Cannot delete field attribute");
return -1;
}
const upb_FieldDef* field;
if (!PyUpb_Message_LookupName(self, attr, &field, NULL,
PyExc_AttributeError)) {

4
ruby/.gitignore vendored
View File

@ -8,8 +8,6 @@ pkg/
tmp/
tests/google/
ext/google/protobuf_c/third_party/utf8_range/utf8_range.h
ext/google/protobuf_c/third_party/utf8_range/range2-sse.c
ext/google/protobuf_c/third_party/utf8_range/range2-neon.c
ext/google/protobuf_c/third_party/utf8_range/naive.c
ext/google/protobuf_c/third_party/utf8_range/utf8_range.c
ext/google/protobuf_c/third_party/utf8_range/LICENSE
lib/google/protobuf/*_pb.rb

View File

@ -115,7 +115,7 @@ $ bazel test //ruby/tests/...
To run tests against the FFI implementation:
```
$ bazel test //ruby/tests/... //ruby:ffi=enabled --test_env=PROTOCOL_BUFFERS_RUBY_IMPLEMENTATION=FFI
$ bazel test //ruby/tests/... //ruby:ffi_enabled --test_env=PROTOCOL_BUFFERS_RUBY_IMPLEMENTATION=FFI
```
Version Number Scheme

View File

@ -75,7 +75,7 @@ task :copy_third_party do
# We need utf8_range in-tree.
utf8_root = '../third_party/utf8_range'
%w[
utf8_range.h naive.c range2-neon.c range2-neon.c range2-sse.c LICENSE
utf8_range.h utf8_range.c LICENSE
].each do |file|
FileUtils.cp File.join(utf8_root, file),
"ext/google/protobuf_c/third_party/utf8_range"

View File

@ -141,7 +141,7 @@ upb_MessageValue Convert_RubyToUpb(VALUE value, const char* name,
VALUE utf8 = rb_enc_from_encoding(rb_utf8_encoding());
if (rb_obj_class(value) == rb_cSymbol) {
value = rb_funcall(value, rb_intern("to_s"), 0);
} else if (rb_obj_class(value) != rb_cString) {
} else if (!rb_obj_is_kind_of(value, rb_cString)) {
rb_raise(cTypeError,
"Invalid argument for string field '%s' (given %s).", name,
rb_class2name(CLASS_OF(value)));

View File

@ -22,7 +22,7 @@ $INCFLAGS += " -I$(srcdir)/third_party/utf8_range"
$srcs = ["protobuf.c", "convert.c", "defs.c", "message.c",
"repeated_field.c", "map.c", "ruby-upb.c", "wrap_memcpy.c",
"naive.c", "range2-neon.c", "range2-sse.c", "shared_convert.c",
"utf8_range.c", "shared_convert.c",
"shared_message.c"]
create_makefile(ext_name)

View File

@ -660,11 +660,8 @@ static VALUE Message_dup(VALUE _self) {
Message* self = ruby_to_Message(_self);
VALUE new_msg = rb_class_new_instance(0, NULL, CLASS_OF(_self));
Message* new_msg_self = ruby_to_Message(new_msg);
size_t size = upb_MessageDef_MiniTable(self->msgdef)->size;
// TODO
// TODO
memcpy((upb_Message*)new_msg_self->msg, self->msg, size);
const upb_MiniTable* m = upb_MessageDef_MiniTable(self->msgdef);
upb_Message_ShallowCopy((upb_Message*)new_msg_self->msg, self->msg, m);
Arena_fuse(self->arena, Arena_get(new_msg_self->arena));
return new_msg;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -74,9 +74,7 @@ begin
FFI::Compiler::CompileTask.new 'protobuf_c_ffi' do |c|
configure_common_compile_task c
# Ruby UPB was already compiled with different flags.
c.exclude << "/range2-neon.c"
c.exclude << "/range2-sse.c"
c.exclude << "/naive.c"
c.exclude << "/utf8_range.c"
c.exclude << "/ruby-upb.c"
end

View File

@ -42,6 +42,7 @@ import com.google.protobuf.Descriptors.OneofDescriptor;
import com.google.protobuf.DynamicMessage;
import com.google.protobuf.InvalidProtocolBufferException;
import com.google.protobuf.LegacyDescriptorsUtil.LegacyFileDescriptor;
import com.google.protobuf.LegacyDescriptorsUtil.LegacyOneofDescriptor;
import com.google.protobuf.Message;
import com.google.protobuf.UnknownFieldSet;
import com.google.protobuf.util.JsonFormat;
@ -1340,7 +1341,7 @@ public class RubyMessage extends RubyObject {
// Keep track of what Oneofs are set
if (value.isNil()) {
oneofCases.remove(oneofDescriptor);
if (!oneofDescriptor.isSynthetic()) {
if (!LegacyOneofDescriptor.isSynthetic(oneofDescriptor)) {
addValue = false;
}
} else {

View File

@ -787,4 +787,15 @@ module BasicTest
assert_respond_to msg, :has_d?
refute msg.has_d?
end
def test_string_subclass
str = "hello"
myString = Class.new(String)
m = proto_module::TestMessage.new(
optional_string: myString.new(str),
)
assert_equal str, m.optional_string
end
end

View File

@ -7,11 +7,14 @@
// Rust Protobuf runtime using the C++ kernel.
use crate::__internal::{Private, RawArena, RawMap, RawMessage, RawRepeatedField};
use crate::ProtoStr;
use crate::__internal::{Private, PtrAndLen, RawArena, RawMap, RawMessage, RawRepeatedField};
use crate::{Mut, ProxiedInRepeated, Repeated, View};
use core::fmt::Debug;
use paste::paste;
use std::alloc::Layout;
use std::cell::UnsafeCell;
use std::convert::identity;
use std::fmt;
use std::marker::PhantomData;
use std::mem::MaybeUninit;
@ -139,7 +142,7 @@ impl fmt::Debug for SerializedData {
pub type BytesPresentMutData<'msg> = crate::vtable::RawVTableOptionalMutatorData<'msg, [u8]>;
pub type BytesAbsentMutData<'msg> = crate::vtable::RawVTableOptionalMutatorData<'msg, [u8]>;
pub type InnerBytesMut<'msg> = crate::vtable::RawVTableMutator<'msg, [u8]>;
pub type InnerPrimitiveMut<'a, T> = crate::vtable::RawVTableMutator<'a, T>;
pub type InnerPrimitiveMut<'msg, T> = crate::vtable::RawVTableMutator<'msg, T>;
/// The raw contents of every generated message.
#[derive(Debug)]
@ -185,140 +188,104 @@ impl<'msg> MutatorMessageRef<'msg> {
}
}
pub fn copy_bytes_in_arena_if_needed_by_runtime<'a>(
_msg_ref: MutatorMessageRef<'a>,
val: &'a [u8],
) -> &'a [u8] {
pub fn copy_bytes_in_arena_if_needed_by_runtime<'msg>(
_msg_ref: MutatorMessageRef<'msg>,
val: &'msg [u8],
) -> &'msg [u8] {
// Nothing to do, the message manages its own string memory for C++.
val
}
/// RepeatedField impls delegate out to `extern "C"` functions exposed by
/// `cpp_api.h` and store either a RepeatedField* or a RepeatedPtrField*
/// depending on the type.
/// The raw type-erased pointer version of `RepeatedMut`.
///
/// Note: even though this type is `Copy`, it should only be copied by
/// protobuf internals that can maintain mutation invariants:
///
/// - No concurrent mutation for any two fields in a message: this means
/// mutators cannot be `Send` but are `Sync`.
/// - If there are multiple accessible `Mut` to a single message at a time, they
/// must be different fields, and not be in the same oneof. As such, a `Mut`
/// cannot be `Clone` but *can* reborrow itself with `.as_mut()`, which
/// converts `&'b mut Mut<'a, T>` to `Mut<'b, T>`.
#[derive(Debug)]
pub struct RepeatedField<'msg, T: ?Sized> {
inner: RepeatedFieldInner<'msg>,
_phantom: PhantomData<&'msg mut T>,
}
/// CPP runtime-specific arguments for initializing a RepeatedField.
/// See RepeatedField comment about mutation invariants for when this type can
/// be copied.
/// Contains a `proto2::RepeatedField*` or `proto2::RepeatedPtrField*`.
#[derive(Clone, Copy, Debug)]
pub struct RepeatedFieldInner<'msg> {
pub raw: RawRepeatedField,
pub _phantom: PhantomData<&'msg ()>,
pub struct InnerRepeatedMut<'msg> {
pub(crate) raw: RawRepeatedField,
_phantom: PhantomData<&'msg ()>,
}
impl<'msg, T: ?Sized> RepeatedField<'msg, T> {
pub fn from_inner(_private: Private, inner: RepeatedFieldInner<'msg>) -> Self {
RepeatedField { inner, _phantom: PhantomData }
impl<'msg> InnerRepeatedMut<'msg> {
#[doc(hidden)]
pub fn new(_private: Private, raw: RawRepeatedField) -> Self {
InnerRepeatedMut { raw, _phantom: PhantomData }
}
}
// These use manual impls instead of derives to avoid unnecessary bounds on `T`.
// This problem is referred to as "perfect derive".
// https://smallcultfollowing.com/babysteps/blog/2022/04/12/implied-bounds-and-perfect-derive/
impl<'msg, T: ?Sized> Copy for RepeatedField<'msg, T> {}
impl<'msg, T: ?Sized> Clone for RepeatedField<'msg, T> {
fn clone(&self) -> RepeatedField<'msg, T> {
*self
}
}
pub trait RepeatedScalarOps {
fn new_repeated_field() -> RawRepeatedField;
fn push(f: RawRepeatedField, v: Self);
fn len(f: RawRepeatedField) -> usize;
fn get(f: RawRepeatedField, i: usize) -> Self;
fn set(f: RawRepeatedField, i: usize, v: Self);
fn copy_from(src: RawRepeatedField, dst: RawRepeatedField);
}
macro_rules! impl_repeated_scalar_ops {
($($t: ty),*) => {
paste! { $(
macro_rules! impl_repeated_primitives {
(@impl $($t:ty => [
$new_thunk:ident,
$free_thunk:ident,
$add_thunk:ident,
$size_thunk:ident,
$get_thunk:ident,
$set_thunk:ident,
$clear_thunk:ident,
$copy_from_thunk:ident $(,)?
]),* $(,)?) => {
$(
extern "C" {
fn [< __pb_rust_RepeatedField_ $t _new >]() -> RawRepeatedField;
fn [< __pb_rust_RepeatedField_ $t _add >](f: RawRepeatedField, v: $t);
fn [< __pb_rust_RepeatedField_ $t _size >](f: RawRepeatedField) -> usize;
fn [< __pb_rust_RepeatedField_ $t _get >](f: RawRepeatedField, i: usize) -> $t;
fn [< __pb_rust_RepeatedField_ $t _set >](f: RawRepeatedField, i: usize, v: $t);
fn [< __pb_rust_RepeatedField_ $t _copy_from >](src: RawRepeatedField, dst: RawRepeatedField);
fn $new_thunk() -> RawRepeatedField;
fn $free_thunk(f: RawRepeatedField);
fn $add_thunk(f: RawRepeatedField, v: $t);
fn $size_thunk(f: RawRepeatedField) -> usize;
fn $get_thunk(f: RawRepeatedField, i: usize) -> $t;
fn $set_thunk(f: RawRepeatedField, i: usize, v: $t);
fn $clear_thunk(f: RawRepeatedField);
fn $copy_from_thunk(src: RawRepeatedField, dst: RawRepeatedField);
}
impl RepeatedScalarOps for $t {
fn new_repeated_field() -> RawRepeatedField {
unsafe { [< __pb_rust_RepeatedField_ $t _new >]() }
unsafe impl ProxiedInRepeated for $t {
#[allow(dead_code)]
fn repeated_new(_: Private) -> Repeated<$t> {
unsafe {
Repeated::from_inner(InnerRepeatedMut::new(Private, $new_thunk()))
}
}
fn push(f: RawRepeatedField, v: Self) {
unsafe { [< __pb_rust_RepeatedField_ $t _add >](f, v) }
#[allow(dead_code)]
unsafe fn repeated_free(_: Private, f: &mut Repeated<$t>) {
unsafe { $free_thunk(f.as_mut().as_raw(Private)) }
}
fn len(f: RawRepeatedField) -> usize {
unsafe { [< __pb_rust_RepeatedField_ $t _size >](f) }
fn repeated_len(f: View<Repeated<$t>>) -> usize {
unsafe { $size_thunk(f.as_raw(Private)) }
}
fn get(f: RawRepeatedField, i: usize) -> Self {
unsafe { [< __pb_rust_RepeatedField_ $t _get >](f, i) }
fn repeated_push(mut f: Mut<Repeated<$t>>, v: View<$t>) {
unsafe { $add_thunk(f.as_raw(Private), v) }
}
fn set(f: RawRepeatedField, i: usize, v: Self) {
unsafe { [< __pb_rust_RepeatedField_ $t _set >](f, i, v) }
fn repeated_clear(mut f: Mut<Repeated<$t>>) {
unsafe { $clear_thunk(f.as_raw(Private)) }
}
fn copy_from(src: RawRepeatedField, dst: RawRepeatedField) {
unsafe { [< __pb_rust_RepeatedField_ $t _copy_from >](src, dst) }
unsafe fn repeated_get_unchecked(f: View<Repeated<$t>>, i: usize) -> View<$t> {
unsafe { $get_thunk(f.as_raw(Private), i) }
}
unsafe fn repeated_set_unchecked(mut f: Mut<Repeated<$t>>, i: usize, v: View<$t>) {
unsafe { $set_thunk(f.as_raw(Private), i, v) }
}
fn repeated_copy_from(src: View<Repeated<$t>>, mut dest: Mut<Repeated<$t>>) {
unsafe { $copy_from_thunk(src.as_raw(Private), dest.as_raw(Private)) }
}
}
)* }
)*
};
($($t:ty),* $(,)?) => {
paste!{
impl_repeated_primitives!(@impl $(
$t => [
[< __pb_rust_RepeatedField_ $t _new >],
[< __pb_rust_RepeatedField_ $t _free >],
[< __pb_rust_RepeatedField_ $t _add >],
[< __pb_rust_RepeatedField_ $t _size >],
[< __pb_rust_RepeatedField_ $t _get >],
[< __pb_rust_RepeatedField_ $t _set >],
[< __pb_rust_RepeatedField_ $t _clear >],
[< __pb_rust_RepeatedField_ $t _copy_from >],
],
)*);
}
};
}
impl_repeated_scalar_ops!(i32, u32, i64, u64, f32, f64, bool);
impl<'msg, T: RepeatedScalarOps> RepeatedField<'msg, T> {
#[allow(clippy::new_without_default, dead_code)]
/// new() is not currently used in our normal pathways, it is only used
/// for testing. Existing `RepeatedField<>`s are owned by, and retrieved
/// from, the containing `Message`.
pub fn new() -> Self {
Self::from_inner(
Private,
RepeatedFieldInner::<'msg> { raw: T::new_repeated_field(), _phantom: PhantomData },
)
}
pub fn push(&mut self, val: T) {
T::push(self.inner.raw, val)
}
pub fn len(&self) -> usize {
T::len(self.inner.raw)
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn get(&self, index: usize) -> Option<T> {
if index >= self.len() {
return None;
}
Some(T::get(self.inner.raw, index))
}
pub fn set(&mut self, index: usize, val: T) {
if index >= self.len() {
return;
}
T::set(self.inner.raw, index, val)
}
pub fn copy_from(&mut self, src: &RepeatedField<'_, T>) {
T::copy_from(src.inner.raw, self.inner.raw)
}
}
impl_repeated_primitives!(i32, u32, i64, u64, f32, f64, bool);
#[derive(Debug)]
pub struct MapInner<'msg, K: ?Sized, V: ?Sized> {
@ -327,9 +294,6 @@ pub struct MapInner<'msg, K: ?Sized, V: ?Sized> {
pub _phantom_value: PhantomData<&'msg mut V>,
}
// These use manual impls instead of derives to avoid unnecessary bounds on `K`
// and `V`. This problem is referred to as "perfect derive".
// https://smallcultfollowing.com/babysteps/blog/2022/04/12/implied-bounds-and-perfect-derive/
impl<'msg, K: ?Sized, V: ?Sized> Copy for MapInner<'msg, K, V> {}
impl<'msg, K: ?Sized, V: ?Sized> Clone for MapInner<'msg, K, V> {
fn clone(&self) -> MapInner<'msg, K, V> {
@ -337,78 +301,22 @@ impl<'msg, K: ?Sized, V: ?Sized> Clone for MapInner<'msg, K, V> {
}
}
macro_rules! impl_scalar_map_values {
($kt:ty, $trait:ident for $($t:ty),*) => {
paste! { $(
extern "C" {
fn [< __pb_rust_Map_ $kt _ $t _new >]() -> RawMap;
fn [< __pb_rust_Map_ $kt _ $t _clear >](m: RawMap);
fn [< __pb_rust_Map_ $kt _ $t _size >](m: RawMap) -> usize;
fn [< __pb_rust_Map_ $kt _ $t _insert >](m: RawMap, key: $kt, value: $t);
fn [< __pb_rust_Map_ $kt _ $t _get >](m: RawMap, key: $kt, value: *mut $t) -> bool;
fn [< __pb_rust_Map_ $kt _ $t _remove >](m: RawMap, key: $kt, value: *mut $t) -> bool;
}
impl $trait for $t {
fn new_map() -> RawMap {
unsafe { [< __pb_rust_Map_ $kt _ $t _new >]() }
}
macro_rules! generate_map_with_key_ops_traits {
($($t:ty, $sized_t:ty;)*) => {
paste! {
$(
pub trait [< MapWith $t:camel KeyOps >] {
type Value<'msg>: Sized;
fn clear(m: RawMap) {
unsafe { [< __pb_rust_Map_ $kt _ $t _clear >](m) }
}
fn size(m: RawMap) -> usize {
unsafe { [< __pb_rust_Map_ $kt _ $t _size >](m) }
}
fn insert(m: RawMap, key: $kt, value: $t) {
unsafe { [< __pb_rust_Map_ $kt _ $t _insert >](m, key, value) }
}
fn get(m: RawMap, key: $kt) -> Option<$t> {
let mut val: $t = Default::default();
let found = unsafe { [< __pb_rust_Map_ $kt _ $t _get >](m, key, &mut val) };
if !found {
return None;
}
Some(val)
}
fn remove(m: RawMap, key: $kt) -> Option<$t> {
let mut val: $t = Default::default();
let removed =
unsafe { [< __pb_rust_Map_ $kt _ $t _remove >](m, key, &mut val) };
if !removed {
return None;
}
Some(val)
}
}
)* }
}
}
macro_rules! impl_scalar_maps {
($($t:ty),*) => {
paste! { $(
pub trait [< MapWith $t:camel KeyOps >] : Sync + Send + Copy + Clone + Debug {
fn new_map() -> RawMap;
fn clear(m: RawMap);
fn size(m: RawMap) -> usize;
fn insert(m: RawMap, key: $t, value: Self);
fn get(m: RawMap, key: $t) -> Option<Self>
where
Self: Sized;
fn remove(m: RawMap, key: $t) -> Option<Self>
where
Self: Sized;
fn insert(m: RawMap, key: $sized_t, value: Self::Value<'_>) -> bool;
fn get<'msg>(m: RawMap, key: $sized_t) -> Option<Self::Value<'msg>>;
fn remove(m: RawMap, key: $sized_t) -> bool;
}
impl_scalar_map_values!(
$t, [< MapWith $t:camel KeyOps >] for i32, u32, f32, f64, bool, u64, i64
);
impl<'msg, V: [< MapWith $t:camel KeyOps >]> Default for MapInner<'msg, $t, V> {
impl<'msg, V: [< MapWith $t:camel KeyOps >] + ?Sized> Default for MapInner<'msg, $t, V> {
fn default() -> Self {
MapInner {
raw: V::new_map(),
@ -418,7 +326,7 @@ macro_rules! impl_scalar_maps {
}
}
impl<'msg, V: [< MapWith $t:camel KeyOps >]> MapInner<'msg, $t, V> {
impl<'msg, V: [< MapWith $t:camel KeyOps >] + ?Sized> MapInner<'msg, $t, V> {
pub fn size(&self) -> usize {
V::size(self.raw)
}
@ -427,27 +335,129 @@ macro_rules! impl_scalar_maps {
V::clear(self.raw)
}
pub fn get(&self, key: $t) -> Option<V> {
pub fn get<'a>(&self, key: $sized_t) -> Option<V::Value<'a>> {
V::get(self.raw, key)
}
pub fn remove(&mut self, key: $t) -> Option<V> {
pub fn remove(&mut self, key: $sized_t) -> bool {
V::remove(self.raw, key)
}
pub fn insert(&mut self, key: $t, value: V) -> bool {
pub fn insert(&mut self, key: $sized_t, value: V::Value<'_>) -> bool {
V::insert(self.raw, key, value);
true
}
}
)* }
)*
}
}
}
impl_scalar_maps!(i32, u32, bool, u64, i64);
generate_map_with_key_ops_traits!(
i32, i32;
u32, u32;
i64, i64;
u64, u64;
bool, bool;
ProtoStr, &ProtoStr;
);
macro_rules! impl_scalar_map_with_key_op_for_scalar_values {
($key_t:ty, $sized_key_t:ty, $ffi_key_t:ty, $to_ffi_key:expr, $trait:ident for $($t:ty, $sized_t:ty, $ffi_t:ty, $to_ffi_value:expr, $from_ffi_value:expr, $zero_val:literal;)*) => {
paste! { $(
extern "C" {
fn [< __pb_rust_Map_ $key_t _ $t _new >]() -> RawMap;
fn [< __pb_rust_Map_ $key_t _ $t _clear >](m: RawMap);
fn [< __pb_rust_Map_ $key_t _ $t _size >](m: RawMap) -> usize;
fn [< __pb_rust_Map_ $key_t _ $t _insert >](m: RawMap, key: $ffi_key_t, value: $ffi_t);
fn [< __pb_rust_Map_ $key_t _ $t _get >](m: RawMap, key: $ffi_key_t, value: *mut $ffi_t) -> bool;
fn [< __pb_rust_Map_ $key_t _ $t _remove >](m: RawMap, key: $ffi_key_t, value: *mut $ffi_t) -> bool;
}
impl $trait for $t {
type Value<'msg> = $sized_t;
fn new_map() -> RawMap {
unsafe { [< __pb_rust_Map_ $key_t _ $t _new >]() }
}
fn clear(m: RawMap) {
unsafe { [< __pb_rust_Map_ $key_t _ $t _clear >](m) }
}
fn size(m: RawMap) -> usize {
unsafe { [< __pb_rust_Map_ $key_t _ $t _size >](m) }
}
fn insert(m: RawMap, key: $sized_key_t, value: Self::Value<'_>) -> bool {
let ffi_key = $to_ffi_key(key);
let ffi_value = $to_ffi_value(value);
unsafe { [< __pb_rust_Map_ $key_t _ $t _insert >](m, ffi_key, ffi_value) }
true
}
fn get<'msg>(m: RawMap, key: $sized_key_t) -> Option<Self::Value<'msg>> {
let ffi_key = $to_ffi_key(key);
let mut ffi_value = $to_ffi_value($zero_val);
let found = unsafe { [< __pb_rust_Map_ $key_t _ $t _get >](m, ffi_key, &mut ffi_value) };
if !found {
return None;
}
Some($from_ffi_value(ffi_value))
}
fn remove(m: RawMap, key: $sized_key_t) -> bool {
let ffi_key = $to_ffi_key(key);
let mut ffi_value = $to_ffi_value($zero_val);
unsafe { [< __pb_rust_Map_ $key_t _ $t _remove >](m, ffi_key, &mut ffi_value) }
}
}
)* }
}
}
fn str_to_ptrlen<'msg>(val: impl Into<&'msg ProtoStr>) -> PtrAndLen {
val.into().as_bytes().into()
}
fn ptrlen_to_str<'msg>(val: PtrAndLen) -> &'msg ProtoStr {
unsafe { ProtoStr::from_utf8_unchecked(val.as_ref()) }
}
macro_rules! impl_map_with_key_ops_for_scalar_values {
($($t:ty, $t_sized:ty, $ffi_t:ty, $to_ffi_key:expr;)*) => {
paste! {
$(
impl_scalar_map_with_key_op_for_scalar_values!($t, $t_sized, $ffi_t, $to_ffi_key, [< MapWith $t:camel KeyOps >] for
f32, f32, f32, identity, identity, 0f32;
f64, f64, f64, identity, identity, 0f64;
i32, i32, i32, identity, identity, 0i32;
u32, u32, u32, identity, identity, 0u32;
i64, i64, i64, identity, identity, 0i64;
u64, u64, u64, identity, identity, 0u64;
bool, bool, bool, identity, identity, false;
ProtoStr, &'msg ProtoStr, PtrAndLen, str_to_ptrlen, ptrlen_to_str, "";
);
)*
}
}
}
impl_map_with_key_ops_for_scalar_values!(
i32, i32, i32, identity;
u32, u32, u32, identity;
i64, i64, i64, identity;
u64, u64, u64, identity;
bool, bool, bool, identity;
ProtoStr, &ProtoStr, PtrAndLen, str_to_ptrlen;
);
#[cfg(test)]
pub(crate) fn new_map_inner() -> MapInner<'static, i32, i64> {
pub(crate) fn new_map_i32_i64() -> MapInner<'static, i32, i64> {
Default::default()
}
#[cfg(test)]
pub(crate) fn new_map_str_str() -> MapInner<'static, ProtoStr, ProtoStr> {
Default::default()
}
@ -472,29 +482,6 @@ mod tests {
assert_that!(&*serialized_data, eq(b"Hello world"));
}
#[test]
fn repeated_field() {
let mut r = RepeatedField::<i32>::new();
assert_that!(r.len(), eq(0));
r.push(32);
assert_that!(r.get(0), eq(Some(32)));
let mut r = RepeatedField::<u32>::new();
assert_that!(r.len(), eq(0));
r.push(32);
assert_that!(r.get(0), eq(Some(32)));
let mut r = RepeatedField::<f64>::new();
assert_that!(r.len(), eq(0));
r.push(0.1234f64);
assert_that!(r.get(0), eq(Some(0.1234)));
let mut r = RepeatedField::<bool>::new();
assert_that!(r.len(), eq(0));
r.push(true);
assert_that!(r.get(0), eq(Some(true)));
}
#[test]
fn i32_i32_map() {
let mut map: MapInner<'_, i32, i32> = Default::default();
@ -505,9 +492,9 @@ mod tests {
assert_that!(map.get(3), eq(None));
assert_that!(map.size(), eq(1));
assert_that!(map.remove(1), eq(Some(2)));
assert_that!(map.remove(1), eq(true));
assert_that!(map.size(), eq(0));
assert_that!(map.remove(1), eq(None));
assert_that!(map.remove(1), eq(false));
assert_that!(map.insert(4, 5), eq(true));
assert_that!(map.insert(6, 7), eq(true));
@ -525,13 +512,61 @@ mod tests {
assert_that!(map.get(3), eq(None));
assert_that!(map.size(), eq(1));
assert_that!(map.remove(1), eq(Some(2.5)));
assert_that!(map.remove(1), eq(true));
assert_that!(map.size(), eq(0));
assert_that!(map.remove(1), eq(None));
assert_that!(map.remove(1), eq(false));
assert_that!(map.insert(4, 5.1), eq(true));
assert_that!(map.insert(6, 7.2), eq(true));
map.clear();
assert_that!(map.size(), eq(0));
}
#[test]
fn str_str_map() {
let mut map = MapInner::<'_, ProtoStr, ProtoStr>::default();
assert_that!(map.size(), eq(0));
map.insert("fizz".into(), "buzz".into());
assert_that!(map.size(), eq(1));
assert_that!(map.remove("fizz".into()), eq(true));
map.clear();
assert_that!(map.size(), eq(0));
}
#[test]
fn u64_str_map() {
let mut map = MapInner::<'_, u64, ProtoStr>::default();
assert_that!(map.size(), eq(0));
map.insert(1, "fizz".into());
map.insert(2, "buzz".into());
assert_that!(map.size(), eq(2));
assert_that!(map.remove(1), eq(true));
assert_that!(map.get(1), eq(None));
map.clear();
assert_that!(map.size(), eq(0));
}
#[test]
fn test_all_maps_can_be_constructed() {
macro_rules! gen_proto_values {
($key_t:ty, $($value_t:ty),*) => {
$(
let map = MapInner::<'_, $key_t, $value_t>::default();
assert_that!(map.size(), eq(0));
)*
}
}
macro_rules! gen_proto_keys {
($($key_t:ty),*) => {
$(
gen_proto_values!($key_t, f32, f64, i32, u32, i64, bool, ProtoStr);
)*
}
}
gen_proto_keys!(i32, u32, i64, u64, bool, ProtoStr);
}
}

View File

@ -12,6 +12,7 @@ cc_library(
],
deps = [
":rust_alloc_for_cpp_api", # buildcleaner: keep
"@com_google_absl//absl/strings:string_view",
"//:protobuf_nowkt",
],
)

View File

@ -1,3 +1,8 @@
#include "rust/cpp_kernel/cpp_api.h"
#include <cstdint>
#include <string>
#include "google/protobuf/map.h"
#include "google/protobuf/repeated_field.h"
@ -7,6 +12,10 @@ extern "C" {
google::protobuf::RepeatedField<ty>* __pb_rust_RepeatedField_##rust_ty##_new() { \
return new google::protobuf::RepeatedField<ty>(); \
} \
void __pb_rust_RepeatedField_##rust_ty##_free( \
google::protobuf::RepeatedField<ty>* r) { \
delete r; \
} \
void __pb_rust_RepeatedField_##rust_ty##_add(google::protobuf::RepeatedField<ty>* r, \
ty val) { \
r->Add(val); \
@ -26,6 +35,10 @@ extern "C" {
void __pb_rust_RepeatedField_##rust_ty##_copy_from( \
google::protobuf::RepeatedField<ty> const& src, google::protobuf::RepeatedField<ty>& dst) { \
dst.CopyFrom(src); \
} \
void __pb_rust_RepeatedField_##rust_ty##_clear( \
google::protobuf::RepeatedField<ty>* r) { \
r->Clear(); \
}
expose_repeated_field_methods(int32_t, i32);
@ -38,59 +51,74 @@ expose_repeated_field_methods(int64_t, i64);
#undef expose_repeated_field_methods
#define expose_scalar_map_methods(key_ty, rust_key_ty, value_ty, \
rust_value_ty) \
google::protobuf::Map<key_ty, value_ty>* \
__pb_rust_Map_##rust_key_ty##_##rust_value_ty##_new() { \
return new google::protobuf::Map<key_ty, value_ty>(); \
} \
void __pb_rust_Map_##rust_key_ty##_##rust_value_ty##_clear( \
google::protobuf::Map<key_ty, value_ty>* m) { \
m->clear(); \
} \
size_t __pb_rust_Map_##rust_key_ty##_##rust_value_ty##_size( \
google::protobuf::Map<key_ty, value_ty>* m) { \
return m->size(); \
} \
void __pb_rust_Map_##rust_key_ty##_##rust_value_ty##_insert( \
google::protobuf::Map<key_ty, value_ty>* m, key_ty key, value_ty val) { \
(*m)[key] = val; \
} \
bool __pb_rust_Map_##rust_key_ty##_##rust_value_ty##_get( \
google::protobuf::Map<key_ty, value_ty>* m, key_ty key, value_ty* value) { \
auto it = m->find(key); \
if (it == m->end()) { \
return false; \
} \
*value = it->second; \
return true; \
} \
bool __pb_rust_Map_##rust_key_ty##_##rust_value_ty##_remove( \
google::protobuf::Map<key_ty, value_ty>* m, key_ty key, value_ty* value) { \
auto it = m->find(key); \
if (it == m->end()) { \
return false; \
} else { \
*value = it->second; \
m->erase(it); \
return true; \
} \
#define expose_scalar_map_methods(key_ty, rust_key_ty, ffi_key_ty, to_cpp_key, \
value_ty, rust_value_ty, ffi_value_ty, \
to_cpp_value, to_ffi_value) \
google::protobuf::Map<key_ty, value_ty>* \
__pb_rust_Map_##rust_key_ty##_##rust_value_ty##_new() { \
return new google::protobuf::Map<key_ty, value_ty>(); \
} \
void __pb_rust_Map_##rust_key_ty##_##rust_value_ty##_clear( \
google::protobuf::Map<key_ty, value_ty>* m) { \
m->clear(); \
} \
size_t __pb_rust_Map_##rust_key_ty##_##rust_value_ty##_size( \
google::protobuf::Map<key_ty, value_ty>* m) { \
return m->size(); \
} \
void __pb_rust_Map_##rust_key_ty##_##rust_value_ty##_insert( \
google::protobuf::Map<key_ty, value_ty>* m, ffi_key_ty key, ffi_value_ty value) { \
auto cpp_key = to_cpp_key; \
auto cpp_value = to_cpp_value; \
(*m)[cpp_key] = cpp_value; \
} \
bool __pb_rust_Map_##rust_key_ty##_##rust_value_ty##_get( \
google::protobuf::Map<key_ty, value_ty>* m, ffi_key_ty key, ffi_value_ty* value) { \
auto cpp_key = to_cpp_key; \
auto it = m->find(cpp_key); \
if (it == m->end()) { \
return false; \
} \
auto& cpp_value = it->second; \
*value = to_ffi_value; \
return true; \
} \
bool __pb_rust_Map_##rust_key_ty##_##rust_value_ty##_remove( \
google::protobuf::Map<key_ty, value_ty>* m, ffi_key_ty key, ffi_value_ty* value) { \
auto cpp_key = to_cpp_key; \
auto num_removed = m->erase(cpp_key); \
return num_removed > 0; \
}
#define expose_scalar_map_methods_for_key_type(key_ty, rust_key_ty) \
expose_scalar_map_methods(key_ty, rust_key_ty, int32_t, i32); \
expose_scalar_map_methods(key_ty, rust_key_ty, uint32_t, u32); \
expose_scalar_map_methods(key_ty, rust_key_ty, float, f32); \
expose_scalar_map_methods(key_ty, rust_key_ty, double, f64); \
expose_scalar_map_methods(key_ty, rust_key_ty, bool, bool); \
expose_scalar_map_methods(key_ty, rust_key_ty, uint64_t, u64); \
expose_scalar_map_methods(key_ty, rust_key_ty, int64_t, i64);
#define expose_scalar_map_methods_for_key_type(key_ty, rust_key_ty, \
ffi_key_ty, to_cpp_key) \
expose_scalar_map_methods(key_ty, rust_key_ty, ffi_key_ty, to_cpp_key, \
int32_t, i32, int32_t, value, cpp_value); \
expose_scalar_map_methods(key_ty, rust_key_ty, ffi_key_ty, to_cpp_key, \
uint32_t, u32, uint32_t, value, cpp_value); \
expose_scalar_map_methods(key_ty, rust_key_ty, ffi_key_ty, to_cpp_key, \
float, f32, float, value, cpp_value); \
expose_scalar_map_methods(key_ty, rust_key_ty, ffi_key_ty, to_cpp_key, \
double, f64, double, value, cpp_value); \
expose_scalar_map_methods(key_ty, rust_key_ty, ffi_key_ty, to_cpp_key, bool, \
bool, bool, value, cpp_value); \
expose_scalar_map_methods(key_ty, rust_key_ty, ffi_key_ty, to_cpp_key, \
uint64_t, u64, uint64_t, value, cpp_value); \
expose_scalar_map_methods(key_ty, rust_key_ty, ffi_key_ty, to_cpp_key, \
int64_t, i64, int64_t, value, cpp_value); \
expose_scalar_map_methods( \
key_ty, rust_key_ty, ffi_key_ty, to_cpp_key, std::string, ProtoStr, \
google::protobuf::rust_internal::PtrAndLen, std::string(value.ptr, value.len), \
google::protobuf::rust_internal::PtrAndLen(cpp_value.data(), cpp_value.size()));
expose_scalar_map_methods_for_key_type(int32_t, i32);
expose_scalar_map_methods_for_key_type(uint32_t, u32);
expose_scalar_map_methods_for_key_type(bool, bool);
expose_scalar_map_methods_for_key_type(uint64_t, u64);
expose_scalar_map_methods_for_key_type(int64_t, i64);
expose_scalar_map_methods_for_key_type(int32_t, i32, int32_t, key);
expose_scalar_map_methods_for_key_type(uint32_t, u32, uint32_t, key);
expose_scalar_map_methods_for_key_type(bool, bool, bool, key);
expose_scalar_map_methods_for_key_type(uint64_t, u64, uint64_t, key);
expose_scalar_map_methods_for_key_type(int64_t, i64, int64_t, key);
expose_scalar_map_methods_for_key_type(std::string, ProtoStr,
google::protobuf::rust_internal::PtrAndLen,
std::string(key.ptr, key.len));
#undef expose_scalar_map_methods
#undef expose_map_methods

View File

@ -11,7 +11,7 @@
pub use crate::vtable::{
new_vtable_field_entry, BytesMutVTable, BytesOptionalMutVTable, PrimitiveOptionalMutVTable,
PrimitiveVTable, RawVTableMutator,
PrimitiveVTable, PrimitiveWithRawVTable, RawVTableMutator,
};
use std::ptr::NonNull;
use std::slice;

View File

@ -6,32 +6,38 @@
// https://developers.google.com/open-source/licenses/bsd
use crate::{
Mut, MutProxy, Proxied, SettableValue, View, ViewProxy,
Mut, MutProxy, ProtoStr, Proxied, SettableValue, View, ViewProxy,
__internal::Private,
__runtime::{
MapInner, MapWithBoolKeyOps, MapWithI32KeyOps, MapWithI64KeyOps, MapWithU32KeyOps,
MapWithU64KeyOps,
MapInner, MapWithBoolKeyOps, MapWithI32KeyOps, MapWithI64KeyOps, MapWithProtoStrKeyOps,
MapWithU32KeyOps, MapWithU64KeyOps,
},
};
use paste::paste;
use std::marker::PhantomData;
#[derive(Clone, Copy)]
#[repr(transparent)]
pub struct MapView<'a, K: ?Sized, V: ?Sized> {
inner: MapInner<'a, K, V>,
pub struct MapView<'msg, K: ?Sized, V: ?Sized> {
inner: MapInner<'msg, K, V>,
}
impl<'a, K: ?Sized, V: ?Sized> MapView<'a, K, V> {
pub fn from_inner(_private: Private, inner: MapInner<'a, K, V>) -> Self {
impl<'msg, K: ?Sized, V: ?Sized> MapView<'msg, K, V> {
pub fn from_inner(_private: Private, inner: MapInner<'msg, K, V>) -> Self {
Self { inner }
}
}
unsafe impl<'a, K: ?Sized, V: ?Sized> Sync for MapView<'a, K, V> {}
unsafe impl<'a, K: ?Sized, V: ?Sized> Send for MapView<'a, K, V> {}
impl<'msg, K: ?Sized, V: ?Sized> Copy for MapView<'msg, K, V> {}
impl<'msg, K: ?Sized, V: ?Sized> Clone for MapView<'msg, K, V> {
fn clone(&self) -> Self {
*self
}
}
impl<'a, K: ?Sized, V: ?Sized> std::fmt::Debug for MapView<'a, K, V> {
unsafe impl<'msg, K: ?Sized, V: ?Sized> Sync for MapView<'msg, K, V> {}
unsafe impl<'msg, K: ?Sized, V: ?Sized> Send for MapView<'msg, K, V> {}
impl<'msg, K: ?Sized, V: ?Sized> std::fmt::Debug for MapView<'msg, K, V> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("MapView")
.field(&std::any::type_name::<K>())
@ -40,28 +46,36 @@ impl<'a, K: ?Sized, V: ?Sized> std::fmt::Debug for MapView<'a, K, V> {
}
}
#[derive(Debug)]
#[repr(transparent)]
pub struct MapMut<'a, K: ?Sized, V: ?Sized> {
inner: MapInner<'a, K, V>,
pub struct MapMut<'msg, K: ?Sized, V: ?Sized> {
inner: MapInner<'msg, K, V>,
}
impl<'a, K: ?Sized, V: ?Sized> MapMut<'a, K, V> {
pub fn from_inner(_private: Private, inner: MapInner<'a, K, V>) -> Self {
impl<'msg, K: ?Sized, V: ?Sized> MapMut<'msg, K, V> {
pub fn from_inner(_private: Private, inner: MapInner<'msg, K, V>) -> Self {
Self { inner }
}
}
unsafe impl<'a, K: ?Sized, V: ?Sized> Sync for MapMut<'a, K, V> {}
unsafe impl<'msg, K: ?Sized, V: ?Sized> Sync for MapMut<'msg, K, V> {}
impl<'a, K: ?Sized, V: ?Sized> std::ops::Deref for MapMut<'a, K, V> {
type Target = MapView<'a, K, V>;
impl<'msg, K: ?Sized, V: ?Sized> std::fmt::Debug for MapMut<'msg, K, V> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("MapMut")
.field(&std::any::type_name::<K>())
.field(&std::any::type_name::<V>())
.finish()
}
}
impl<'msg, K: ?Sized, V: ?Sized> std::ops::Deref for MapMut<'msg, K, V> {
type Target = MapView<'msg, K, V>;
fn deref(&self) -> &Self::Target {
// SAFETY:
// - `Map{View,Mut}<'a, T>` are both `#[repr(transparent)]` over `MapInner<'a,
// T>`.
// - `Map{View,Mut}<'msg, T>` are both `#[repr(transparent)]` over
// `MapInner<'msg, T>`.
// - `MapInner` is a type alias for `NonNull`.
unsafe { &*(self as *const Self as *const MapView<'a, K, V>) }
unsafe { &*(self as *const Self as *const MapView<'msg, K, V>) }
}
}
@ -69,64 +83,79 @@ impl<'a, K: ?Sized, V: ?Sized> std::ops::Deref for MapMut<'a, K, V> {
// `MapView` (`View<'_, Map>>) and `MapMut` (Mut<'_, Map>).
pub struct Map<K: ?Sized, V: ?Sized>(PhantomData<K>, PhantomData<V>);
macro_rules! impl_proxied_for_map_keys {
($(key_type $t:ty;)*) => {
paste! { $(
impl<V: [< MapWith $t:camel KeyOps >] + Proxied + ?Sized> Proxied for Map<$t, V>{
type View<'msg> = MapView<'msg, $t, V> where V: 'msg;
type Mut<'msg> = MapMut<'msg, $t, V> where V: 'msg;
}
impl<'msg, V: [< MapWith $t:camel KeyOps >] + Proxied + ?Sized + 'msg> SettableValue<Map<$t, V>> for MapView<'msg, $t, V> {
fn set_on<'b>(self, _private: Private, mut mutator: Mut<'b, Map<$t, V>>)
where
Map<$t, V>: 'b {
mutator.copy_from(self);
}
}
impl<'msg, V: [< MapWith $t:camel KeyOps >] + Proxied + ?Sized + 'msg> ViewProxy<'msg> for MapView<'msg, $t, V> {
type Proxied = Map<$t, V>;
fn as_view(&self) -> View<'_, Self::Proxied> {
*self
}
fn into_view<'shorter>(self) -> View<'shorter, Self::Proxied>
where 'msg: 'shorter,
{
MapView { inner: self.inner }
}
}
impl<'msg, V: [< MapWith $t:camel KeyOps >] + Proxied + ?Sized + 'msg> ViewProxy<'msg> for MapMut<'msg, $t, V> {
type Proxied = Map<$t, V>;
fn as_view(&self) -> View<'_, Self::Proxied> {
**self
}
fn into_view<'shorter>(self) -> View<'shorter, Self::Proxied>
where 'msg: 'shorter,
{
*self.into_mut::<'shorter>()
}
}
impl<'msg, V: [< MapWith $t:camel KeyOps >] + Proxied + ?Sized + 'msg> MutProxy<'msg> for MapMut<'msg, $t, V> {
fn as_mut(&mut self) -> Mut<'_, Self::Proxied> {
MapMut { inner: self.inner }
}
fn into_mut<'shorter>(self) -> Mut<'shorter, Self::Proxied>
where 'msg: 'shorter,
{
MapMut { inner: self.inner }
}
}
)* }
}
}
impl_proxied_for_map_keys!(
key_type i32;
key_type u32;
key_type i64;
key_type u64;
key_type bool;
key_type ProtoStr;
);
macro_rules! impl_scalar_map_keys {
($(key_type $t:ty;)*) => {
paste! { $(
impl<V: [< MapWith $t:camel KeyOps >]> Proxied for Map<$t, V>{
type View<'a> = MapView<'a, $t, V> where V: 'a;
type Mut<'a> = MapMut<'a, $t, V> where V: 'a;
}
impl<'a, V: [< MapWith $t:camel KeyOps >]> SettableValue<Map<$t, V>> for MapView<'a, $t, V> {
fn set_on<'b>(self, _private: Private, mut mutator: Mut<'b, Map<$t, V>>)
where
Map<$t, V>: 'b {
mutator.copy_from(self);
}
}
impl<'a, V: [< MapWith $t:camel KeyOps >]> ViewProxy<'a> for MapView<'a, $t, V> {
type Proxied = Map<$t, V>;
fn as_view(&self) -> View<'_, Self::Proxied> {
*self
}
fn into_view<'shorter>(self) -> View<'shorter, Self::Proxied>
where 'a: 'shorter,
{
MapView { inner: self.inner }
}
}
impl<'a, V: [< MapWith $t:camel KeyOps >]> ViewProxy<'a> for MapMut<'a, $t, V> {
type Proxied = Map<$t, V>;
fn as_view(&self) -> View<'_, Self::Proxied> {
**self
}
fn into_view<'shorter>(self) -> View<'shorter, Self::Proxied>
where 'a: 'shorter,
{
*self.into_mut::<'shorter>()
}
}
impl<'a, V: [< MapWith $t:camel KeyOps >]> MutProxy<'a> for MapMut<'a, $t, V> {
fn as_mut(&mut self) -> Mut<'_, Self::Proxied> {
MapMut { inner: self.inner }
}
fn into_mut<'shorter>(self) -> Mut<'shorter, Self::Proxied>
where 'a: 'shorter,
{
MapMut { inner: self.inner }
}
}
impl<'a, V: [< MapWith $t:camel KeyOps >]> MapView<'a, $t, V> {
pub fn get(&self, key: $t) -> Option<V> {
impl<'msg, V: [< MapWith $t:camel KeyOps >] + Proxied + ?Sized + 'msg> MapView<'msg, $t, V> {
pub fn get<'b>(&self, key: $t) -> Option<V::Value<'b>> {
self.inner.get(key)
}
@ -139,12 +168,12 @@ macro_rules! impl_scalar_map_keys {
}
}
impl<'a, V: [< MapWith $t:camel KeyOps >]> MapMut<'a, $t, V> {
pub fn insert(&mut self, key: $t, value: V) -> bool {
impl<'msg, V: [< MapWith $t:camel KeyOps >] + Proxied + ?Sized + 'msg> MapMut<'msg, $t, V> {
pub fn insert(&mut self, key: $t, value: V::Value<'_>) -> bool {
self.inner.insert(key, value)
}
pub fn remove(&mut self, key: $t) -> Option<V> {
pub fn remove<'b>(&mut self, key: $t) -> bool {
self.inner.remove(key)
}
@ -168,15 +197,47 @@ impl_scalar_map_keys!(
key_type bool;
);
impl<'msg, V: MapWithProtoStrKeyOps + Proxied + ?Sized + 'msg> MapView<'msg, ProtoStr, V> {
pub fn get(&self, key: impl Into<&'msg ProtoStr>) -> Option<V::Value<'_>> {
self.inner.get(key.into())
}
pub fn len(&self) -> usize {
self.inner.size()
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
}
impl<'msg, V: MapWithProtoStrKeyOps + Proxied + ?Sized + 'msg> MapMut<'msg, ProtoStr, V> {
pub fn insert(&mut self, key: impl Into<&'msg ProtoStr>, value: V::Value<'_>) -> bool {
self.inner.insert(key.into(), value)
}
pub fn remove(&mut self, key: impl Into<&'msg ProtoStr>) -> bool {
self.inner.remove(key.into())
}
pub fn clear(&mut self) {
self.inner.clear()
}
pub fn copy_from(&mut self, _src: MapView<'_, ProtoStr, V>) {
todo!("implement b/28530933");
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::__runtime::new_map_inner;
use crate::__runtime::{new_map_i32_i64, new_map_str_str};
use googletest::prelude::*;
#[test]
fn test_proxied() {
let mut map_mut = MapMut::from_inner(Private, new_map_inner());
fn test_proxied_scalar() {
let mut map_mut = MapMut::from_inner(Private, new_map_i32_i64());
map_mut.insert(1, 2);
let map_view_1 = map_mut.as_view();
assert_that!(map_view_1.len(), eq(1));
@ -197,9 +258,33 @@ mod tests {
assert_that!(map_view_4.is_empty(), eq(false));
}
#[test]
fn test_proxied_str() {
let mut map_mut = MapMut::from_inner(Private, new_map_str_str());
map_mut.insert("a", "b".into());
let map_view_1 = map_mut.as_view();
assert_that!(map_view_1.len(), eq(1));
assert_that!(map_view_1.get("a").unwrap(), eq("b"));
map_mut.insert("c", "d".into());
let map_view_2 = map_mut.into_view();
assert_that!(map_view_2.len(), eq(2));
assert_that!(map_view_2.get("c").unwrap(), eq("d"));
{
let map_view_3 = map_view_2.as_view();
assert_that!(map_view_3.is_empty(), eq(false));
}
let map_view_4 = map_view_2.into_view();
assert_that!(map_view_4.is_empty(), eq(false));
}
#[test]
fn test_dbg() {
let mut map_view = MapView::from_inner(Private, new_map_inner());
let map_view = MapView::from_inner(Private, new_map_i32_i64());
assert_that!(format!("{:?}", map_view), eq("MapView(\"i32\", \"i64\")"));
}
}

View File

@ -83,7 +83,7 @@ impl<T> From<Optional<T>> for Option<T> {
/// A mutable view into the value of an optional field, which may be set or
/// unset.
pub type FieldEntry<'a, T> = Optional<PresentField<'a, T>, AbsentField<'a, T>>;
pub type FieldEntry<'msg, T> = Optional<PresentField<'msg, T>, AbsentField<'msg, T>>;
/// Methods for `_mut()` accessors of optional types.
///
@ -285,11 +285,11 @@ where
/// A field mutator capable of setting that is statically known to point to a
/// non-set field.
pub struct AbsentField<'a, T>
pub struct AbsentField<'msg, T>
where
T: ProxiedWithPresence + ?Sized + 'a,
T: ProxiedWithPresence + ?Sized + 'msg,
{
pub(crate) inner: T::AbsentMutData<'a>,
pub(crate) inner: T::AbsentMutData<'msg>,
}
impl<'msg, T: ProxiedWithPresence + ?Sized + 'msg> Debug for AbsentField<'msg, T> {
@ -432,10 +432,10 @@ mod tests {
}
}
fn make_field_entry<'a>(
msg: &'a mut MyMessage,
vtable: &'a ProxyVtable,
) -> FieldEntry<'a, VtableProxied> {
fn make_field_entry<'msg>(
msg: &'msg mut MyMessage,
vtable: &'msg ProxyVtable,
) -> FieldEntry<'msg, VtableProxied> {
if (vtable.has)(&*msg) {
Optional::Set(PresentField::from_inner(Private, VtableProxiedMut { msg, vtable }))
} else {
@ -494,8 +494,8 @@ mod tests {
struct VtableProxied;
impl Proxied for VtableProxied {
type View<'a> = VtableProxiedView;
type Mut<'a> = VtableProxiedMut<'a>;
type View<'msg> = VtableProxiedView;
type Mut<'msg> = VtableProxiedMut<'msg>;
}
impl ProxiedWithPresence for VtableProxied {
@ -503,19 +503,19 @@ mod tests {
// `Mut` in layout. Other types/runtimes could require otherwise, e.g. `Mut`
// could be defined to only have get/set functions in its vtable, and not
// has/clear.
type PresentMutData<'a> = VtableProxiedMut<'a>;
type AbsentMutData<'a> = VtableProxiedMut<'a>;
type PresentMutData<'msg> = VtableProxiedMut<'msg>;
type AbsentMutData<'msg> = VtableProxiedMut<'msg>;
fn clear_present_field<'a>(
present_mutator: Self::PresentMutData<'a>,
) -> Self::AbsentMutData<'a> {
fn clear_present_field<'msg>(
present_mutator: Self::PresentMutData<'msg>,
) -> Self::AbsentMutData<'msg> {
(present_mutator.vtable.clear)(&mut *present_mutator.msg);
present_mutator
}
fn set_absent_to_default<'a>(
absent_mutator: Self::AbsentMutData<'a>,
) -> Self::PresentMutData<'a> {
fn set_absent_to_default<'msg>(
absent_mutator: Self::AbsentMutData<'msg>,
) -> Self::PresentMutData<'msg> {
SettableValue::<VtableProxied>::set_on_absent(
absent_mutator.as_view().val(),
Private,
@ -539,28 +539,28 @@ mod tests {
}
}
impl<'a> ViewProxy<'a> for VtableProxiedView {
impl<'msg> ViewProxy<'msg> for VtableProxiedView {
type Proxied = VtableProxied;
fn as_view(&self) -> View<'a, VtableProxied> {
fn as_view(&self) -> View<'msg, VtableProxied> {
*self
}
fn into_view<'shorter>(self) -> View<'shorter, VtableProxied>
where
'a: 'shorter,
'msg: 'shorter,
{
self
}
}
#[derive(Debug)]
struct VtableProxiedMut<'a> {
msg: &'a mut MyMessage,
vtable: &'a ProxyVtable,
struct VtableProxiedMut<'msg> {
msg: &'msg mut MyMessage,
vtable: &'msg ProxyVtable,
}
impl<'a> ViewProxy<'a> for VtableProxiedMut<'a> {
impl<'msg> ViewProxy<'msg> for VtableProxiedMut<'msg> {
type Proxied = VtableProxied;
fn as_view(&self) -> View<'_, VtableProxied> {
@ -569,55 +569,55 @@ mod tests {
fn into_view<'shorter>(self) -> View<'shorter, VtableProxied>
where
'a: 'shorter,
'msg: 'shorter,
{
VtableProxiedView::read(self.msg, self.vtable)
}
}
impl<'a> MutProxy<'a> for VtableProxiedMut<'a> {
impl<'msg> MutProxy<'msg> for VtableProxiedMut<'msg> {
fn as_mut(&mut self) -> Mut<'_, VtableProxied> {
VtableProxiedMut { msg: self.msg, vtable: self.vtable }
}
fn into_mut<'shorter>(self) -> Mut<'shorter, VtableProxied>
where
'a: 'shorter,
'msg: 'shorter,
{
self
}
}
impl SettableValue<VtableProxied> for View<'_, VtableProxied> {
fn set_on<'a>(self, _private: Private, mutator: Mut<'a, VtableProxied>)
fn set_on<'msg>(self, _private: Private, mutator: Mut<'msg, VtableProxied>)
where
VtableProxied: 'a,
VtableProxied: 'msg,
{
SettableValue::<VtableProxied>::set_on(self.val(), Private, mutator)
}
fn set_on_absent<'a>(
fn set_on_absent<'msg>(
self,
_private: Private,
absent_mutator: <VtableProxied as ProxiedWithPresence>::AbsentMutData<'a>,
) -> <VtableProxied as ProxiedWithPresence>::PresentMutData<'a> {
absent_mutator: <VtableProxied as ProxiedWithPresence>::AbsentMutData<'msg>,
) -> <VtableProxied as ProxiedWithPresence>::PresentMutData<'msg> {
SettableValue::<VtableProxied>::set_on_absent(self.val(), Private, absent_mutator)
}
}
impl SettableValue<VtableProxied> for i32 {
fn set_on<'a>(self, _private: Private, mutator: Mut<'a, VtableProxied>)
fn set_on<'msg>(self, _private: Private, mutator: Mut<'msg, VtableProxied>)
where
VtableProxied: 'a,
VtableProxied: 'msg,
{
(mutator.vtable.set)(mutator.msg, self)
}
fn set_on_absent<'a>(
fn set_on_absent<'msg>(
self,
_private: Private,
absent_mutator: <VtableProxied as ProxiedWithPresence>::AbsentMutData<'a>,
) -> <VtableProxied as ProxiedWithPresence>::PresentMutData<'a> {
absent_mutator: <VtableProxied as ProxiedWithPresence>::AbsentMutData<'msg>,
) -> <VtableProxied as ProxiedWithPresence>::PresentMutData<'msg> {
(absent_mutator.vtable.set)(absent_mutator.msg, self);
absent_mutator
}

View File

@ -5,156 +5,116 @@
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd
use std::fmt::Debug;
use crate::__internal::Private;
use crate::__runtime::InnerPrimitiveMut;
use crate::repeated::RepeatedMut;
use crate::vtable::{
PrimitiveOptionalMutVTable, PrimitiveVTable, ProxiedWithRawOptionalVTable,
ProxiedWithRawVTable, RawVTableOptionalMutatorData,
};
use crate::vtable::{PrimitiveWithRawVTable, ProxiedWithRawVTable, RawVTableOptionalMutatorData};
use crate::{Mut, MutProxy, Proxied, ProxiedWithPresence, SettableValue, View, ViewProxy};
#[derive(Debug)]
pub struct SingularPrimitiveMut<'a, T: ProxiedWithRawVTable> {
inner: InnerPrimitiveMut<'a, T>,
/// A mutator for a primitive (numeric or enum) value of `T`.
///
/// This type is `protobuf::Mut<'msg, T>`.
pub struct PrimitiveMut<'msg, T> {
inner: InnerPrimitiveMut<'msg, T>,
}
#[derive(Debug)]
pub enum PrimitiveMut<'a, T: ProxiedWithRawVTable> {
Singular(SingularPrimitiveMut<'a, T>),
Repeated(RepeatedMut<'a, T>, usize),
}
impl<'a, T: ProxiedWithRawVTable> PrimitiveMut<'a, T> {
#[doc(hidden)]
pub fn from_singular(_private: Private, inner: InnerPrimitiveMut<'a, T>) -> Self {
PrimitiveMut::Singular(SingularPrimitiveMut::from_inner(_private, inner))
impl<'msg, T> Debug for PrimitiveMut<'msg, T>
where
T: PrimitiveWithRawVTable,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("PrimitiveMut").field("inner", &self.inner).finish()
}
}
impl<'a, T: ProxiedWithRawVTable> SingularPrimitiveMut<'a, T> {
impl<'msg, T> PrimitiveMut<'msg, T> {
/// # Safety
/// `inner` must be valid and non-aliased for `T` for `'msg`
#[doc(hidden)]
pub fn from_inner(_private: Private, inner: InnerPrimitiveMut<'a, T>) -> Self {
pub unsafe fn from_inner(_private: Private, inner: InnerPrimitiveMut<'msg, T>) -> Self {
Self { inner }
}
}
unsafe impl<'a, T: ProxiedWithRawVTable> Sync for SingularPrimitiveMut<'a, T> {}
// SAFETY: all `T` that can perform mutations don't mutate through a shared
// reference.
unsafe impl<'msg, T> Sync for PrimitiveMut<'msg, T> {}
impl<'msg, T> PrimitiveMut<'msg, T>
where
T: PrimitiveWithRawVTable,
{
pub fn get(&self) -> View<'_, T> {
T::make_view(Private, self.inner)
}
pub fn set(&mut self, val: impl SettableValue<T>) {
MutProxy::set(self, val)
}
}
impl<'msg, T> ViewProxy<'msg> for PrimitiveMut<'msg, T>
where
T: PrimitiveWithRawVTable,
{
type Proxied = T;
fn as_view(&self) -> View<'_, Self::Proxied> {
self.get()
}
fn into_view<'shorter>(self) -> View<'shorter, Self::Proxied> {
self.get()
}
}
impl<'msg, T> MutProxy<'msg> for PrimitiveMut<'msg, T>
where
T: PrimitiveWithRawVTable,
{
fn as_mut(&mut self) -> Mut<'_, Self::Proxied> {
PrimitiveMut { inner: self.inner }
}
fn into_mut<'shorter>(self) -> Mut<'shorter, Self::Proxied>
where
'msg: 'shorter,
{
self
}
}
macro_rules! impl_singular_primitives {
($($t:ty),*) => {
$(
impl Proxied for $t {
type View<'a> = $t;
type Mut<'a> = PrimitiveMut<'a, $t>;
}
impl Proxied for $t {
type View<'msg> = $t;
type Mut<'msg> = PrimitiveMut<'msg, $t>;
}
impl<'a> ViewProxy<'a> for $t {
type Proxied = $t;
impl<'msg> ViewProxy<'msg> for $t {
type Proxied = $t;
fn as_view(&self) -> View<'_, Self::Proxied> {
*self
}
fn into_view<'shorter>(self) -> View<'shorter, Self::Proxied> {
self
}
}
impl<'a> PrimitiveMut<'a, $t> {
pub fn get(&self) -> View<'_, $t> {
match self {
PrimitiveMut::Singular(s) => {
s.get()
}
PrimitiveMut::Repeated(r, i) => {
r.get().get(*i).unwrap()
}
}
}
pub fn set(&mut self, val: impl SettableValue<$t>) {
val.set_on(Private, self.as_mut());
}
pub fn clear(&mut self) {
// The default value for a boolean field is false and 0 for numerical types. It
// matches the Rust default values for corresponding types. Let's use this fact.
SettableValue::<$t>::set_on(<$t>::default(), Private, MutProxy::as_mut(self));
}
}
impl<'a> ViewProxy<'a> for PrimitiveMut<'a, $t> {
type Proxied = $t;
fn as_view(&self) -> View<'_, Self::Proxied> {
self.get()
}
fn into_view<'shorter>(self) -> View<'shorter, Self::Proxied> {
self.get()
}
}
impl<'a> MutProxy<'a> for PrimitiveMut<'a, $t> {
fn as_mut(&mut self) -> Mut<'_, Self::Proxied> {
match self {
PrimitiveMut::Singular(s) => {
PrimitiveMut::Singular(s.as_mut())
}
PrimitiveMut::Repeated(r, i) => {
PrimitiveMut::Repeated(r.as_mut(), *i)
}
}
}
fn into_mut<'shorter>(self) -> Mut<'shorter, Self::Proxied>
where 'a: 'shorter,
{
self
}
}
impl SettableValue<$t> for $t {
fn set_on<'a>(self, _private: Private, mutator: Mut<'a, $t>) where $t: 'a {
match mutator {
PrimitiveMut::Singular(s) => {
unsafe { (s.inner).set(self) };
}
PrimitiveMut::Repeated(mut r, i) => {
r.set(i, self);
}
}
}
}
impl<'a> SingularPrimitiveMut<'a, $t> {
pub fn get(&self) -> $t {
self.inner.get()
}
pub fn as_mut(&mut self) -> SingularPrimitiveMut<'_, $t> {
SingularPrimitiveMut::from_inner(Private, self.inner)
}
}
impl ProxiedWithRawVTable for $t {
type VTable = PrimitiveVTable<$t>;
fn make_view(
_private: Private,
mut_inner: InnerPrimitiveMut<'_, Self>
) -> View<'_, Self> {
mut_inner.get()
fn as_view(&self) -> View<'_, Self::Proxied> {
*self
}
fn make_mut(_private: Private, inner: InnerPrimitiveMut<'_, Self>) -> Mut<'_, Self> {
PrimitiveMut::Singular(SingularPrimitiveMut::from_inner(Private, inner))
fn into_view<'shorter>(self) -> View<'shorter, Self::Proxied> {
self
}
}
}
impl ProxiedWithPresence for $t {
type PresentMutData<'a> = RawVTableOptionalMutatorData<'a, $t>;
type AbsentMutData<'a> = RawVTableOptionalMutatorData<'a, $t>;
impl SettableValue<$t> for $t {
fn set_on<'msg>(self, _private: Private, mutator: Mut<'msg, $t>) where $t: 'msg {
// SAFETY: the raw mutator is valid for `'msg` as enforced by `Mut`
unsafe { mutator.inner.set(self) }
}
}
impl ProxiedWithPresence for $t {
type PresentMutData<'msg> = RawVTableOptionalMutatorData<'msg, $t>;
type AbsentMutData<'msg> = RawVTableOptionalMutatorData<'msg, $t>;
fn clear_present_field(
present_mutator: Self::PresentMutData<'_>,
@ -167,18 +127,11 @@ macro_rules! impl_singular_primitives {
) -> Self::PresentMutData<'_> {
absent_mutator.set_absent_to_default()
}
}
}
impl ProxiedWithRawOptionalVTable for $t {
type OptionalVTable = PrimitiveOptionalMutVTable<$t>;
impl PrimitiveWithRawVTable for $t {}
fn upcast_vtable(
_private: Private,
optional_vtable: &'static Self::OptionalVTable,
) -> &'static Self::VTable {
&optional_vtable.base
}
}
// ProxiedInRepeated is implemented in {cpp,upb}.rs
)*
}
}

View File

@ -44,7 +44,9 @@
//! implemented the concept of "proxy" types. Proxy types are a reference-like
//! indirection between the user and the internal memory representation.
use crate::RepeatedMut;
use crate::__internal::Private;
use crate::repeated::ProxiedInRepeated;
use std::fmt::Debug;
use std::marker::{Send, Sync};
@ -55,47 +57,47 @@ use std::marker::{Send, Sync};
///
/// All Protobuf field types implement `Proxied`.
pub trait Proxied {
/// The proxy type that provides shared access to a `T`, like a `&'a T`.
/// The proxy type that provides shared access to a `T`, like a `&'msg T`.
///
/// Most code should use the type alias [`View`].
type View<'a>: ViewProxy<'a, Proxied = Self> + Copy + Send + SettableValue<Self>
type View<'msg>: ViewProxy<'msg, Proxied = Self> + Copy + Send + SettableValue<Self>
where
Self: 'a;
Self: 'msg;
/// The proxy type that provides exclusive mutable access to a `T`, like a
/// `&'a mut T`.
/// `&'msg mut T`.
///
/// Most code should use the type alias [`Mut`].
type Mut<'a>: MutProxy<'a, Proxied = Self>
type Mut<'msg>: MutProxy<'msg, Proxied = Self>
where
Self: 'a;
Self: 'msg;
}
/// A proxy type that provides shared access to a `T`, like a `&'a T`.
/// A proxy type that provides shared access to a `T`, like a `&'msg T`.
///
/// This is more concise than fully spelling the associated type.
#[allow(dead_code)]
pub type View<'a, T> = <T as Proxied>::View<'a>;
pub type View<'msg, T> = <T as Proxied>::View<'msg>;
/// A proxy type that provides exclusive mutable access to a `T`, like a
/// `&'a mut T`.
/// `&'msg mut T`.
///
/// This is more concise than fully spelling the associated type.
#[allow(dead_code)]
pub type Mut<'a, T> = <T as Proxied>::Mut<'a>;
pub type Mut<'msg, T> = <T as Proxied>::Mut<'msg>;
/// Declares conversion operations common to all views.
///
/// This trait is intentionally made non-object-safe to prevent a potential
/// future incompatible change.
pub trait ViewProxy<'a>: 'a + Sized + Sync + Unpin + Sized + Debug {
type Proxied: 'a + Proxied + ?Sized;
pub trait ViewProxy<'msg>: 'msg + Sized + Sync + Unpin + Sized + Debug {
type Proxied: 'msg + Proxied + ?Sized;
/// Converts a borrow into a `View` with the lifetime of that borrow.
///
/// In non-generic code we don't need to use `as_view` because the proxy
/// types are covariant over `'a`. However, generic code conservatively
/// treats `'a` as [invariant], therefore we need to call
/// types are covariant over `'msg`. However, generic code conservatively
/// treats `'msg` as [invariant], therefore we need to call
/// `as_view` to explicitly perform the operation that in concrete code
/// coercion would perform implicitly.
///
@ -115,8 +117,8 @@ pub trait ViewProxy<'a>: 'a + Sized + Sync + Unpin + Sized + Debug {
/// Converts into a `View` with a potentially shorter lifetime.
///
/// In non-generic code we don't need to use `into_view` because the proxy
/// types are covariant over `'a`. However, generic code conservatively
/// treats `'a` as [invariant], therefore we need to call
/// types are covariant over `'msg`. However, generic code conservatively
/// treats `'msg` as [invariant], therefore we need to call
/// `into_view` to explicitly perform the operation that in concrete
/// code coercion would perform implicitly.
///
@ -139,14 +141,14 @@ pub trait ViewProxy<'a>: 'a + Sized + Sync + Unpin + Sized + Debug {
/// [invariant]: https://doc.rust-lang.org/nomicon/subtyping.html#variance
fn into_view<'shorter>(self) -> View<'shorter, Self::Proxied>
where
'a: 'shorter;
'msg: 'shorter;
}
/// Declares operations common to all mutators.
///
/// This trait is intentionally made non-object-safe to prevent a potential
/// future incompatible change.
pub trait MutProxy<'a>: ViewProxy<'a> {
pub trait MutProxy<'msg>: ViewProxy<'msg> {
/// Gets an immutable view of this field. This is shorthand for `as_view`.
///
/// This provides a shorter lifetime than `into_view` but can also be called
@ -181,8 +183,8 @@ pub trait MutProxy<'a>: ViewProxy<'a> {
/// Converts into a `Mut` with a potentially shorter lifetime.
///
/// In non-generic code we don't need to use `into_mut` because the proxy
/// types are covariant over `'a`. However, generic code conservatively
/// treats `'a` as [invariant], therefore we need to call
/// types are covariant over `'msg`. However, generic code conservatively
/// treats `'msg` as [invariant], therefore we need to call
/// `into_mut` to explicitly perform the operation that in concrete code
/// coercion would perform implicitly.
///
@ -202,34 +204,31 @@ pub trait MutProxy<'a>: ViewProxy<'a> {
/// [invariant]: https://doc.rust-lang.org/nomicon/subtyping.html#variance
fn into_mut<'shorter>(self) -> Mut<'shorter, Self::Proxied>
where
'a: 'shorter;
'msg: 'shorter;
}
// TODO: move this to `optional.rs` as it's only used for optionals
/// `Proxied` types that can be optionally set or unset.
///
/// All scalar and message types implement `ProxiedWithPresence`, while repeated
/// types don't.
pub trait ProxiedWithPresence: Proxied {
/// The data necessary to store a present field mutator proxying `Self`.
/// This is the contents of `PresentField<'a, Self>`.
type PresentMutData<'a>: MutProxy<'a, Proxied = Self>;
/// This is the contents of `PresentField<'msg, Self>`.
type PresentMutData<'msg>: MutProxy<'msg, Proxied = Self>;
/// The data necessary to store an absent field mutator proxying `Self`.
/// This is the contents of `AbsentField<'a, Self>`.
type AbsentMutData<'a>: ViewProxy<'a, Proxied = Self>;
/// This is the contents of `AbsentField<'msg, Self>`.
type AbsentMutData<'msg>: ViewProxy<'msg, Proxied = Self>;
/// Clears a present field.
fn clear_present_field<'a>(
present_mutator: Self::PresentMutData<'a>,
) -> Self::AbsentMutData<'a>;
fn clear_present_field(present_mutator: Self::PresentMutData<'_>) -> Self::AbsentMutData<'_>;
/// Sets an absent field to its default value.
///
/// This can be more efficient than setting with a default value, e.g.
/// a default submessage could share resources with the parent message.
fn set_absent_to_default<'a>(
absent_mutator: Self::AbsentMutData<'a>,
) -> Self::PresentMutData<'a>;
fn set_absent_to_default(absent_mutator: Self::AbsentMutData<'_>) -> Self::PresentMutData<'_>;
}
/// Values that can be used to set a field of `T`.
@ -237,20 +236,20 @@ pub trait SettableValue<T>: Sized
where
T: Proxied + ?Sized,
{
/// Consumes `self` to set the given mutator to its value.
/// Consumes `self` to set the given mutator to the value of `self`.
#[doc(hidden)]
fn set_on<'a>(self, _private: Private, mutator: Mut<'a, T>)
fn set_on<'msg>(self, _private: Private, mutator: Mut<'msg, T>)
where
T: 'a;
T: 'msg;
/// Consumes `self` and `absent_mutator` to set the given empty field to
/// a value.
/// the value of `self`.
#[doc(hidden)]
fn set_on_absent<'a>(
fn set_on_absent(
self,
_private: Private,
absent_mutator: T::AbsentMutData<'a>,
) -> T::PresentMutData<'a>
absent_mutator: T::AbsentMutData<'_>,
) -> T::PresentMutData<'_>
where
T: ProxiedWithPresence,
{
@ -260,7 +259,7 @@ where
}
/// Consumes `self` and `present_mutator` to set the given present field
/// to a value.
/// to the value of `self`.
#[doc(hidden)]
fn set_on_present(self, _private: Private, mut present_mutator: T::PresentMutData<'_>)
where
@ -268,6 +267,23 @@ where
{
self.set_on(Private, present_mutator.as_mut())
}
/// Consumes `self` and `repeated_mutator` to set the value at the
/// given index to the value of `self`.
///
/// # Safety
/// `index` must be less than `repeated_mutator.len()`
#[doc(hidden)]
unsafe fn set_on_repeated_unchecked(
self,
_private: Private,
mut _repeated_mutator: RepeatedMut<T>,
_index: usize,
) where
T: ProxiedInRepeated,
{
unimplemented!()
}
}
#[cfg(test)]
@ -291,13 +307,13 @@ mod tests {
}
impl Proxied for MyProxied {
type View<'a> = MyProxiedView<'a>;
type Mut<'a> = MyProxiedMut<'a>;
type View<'msg> = MyProxiedView<'msg>;
type Mut<'msg> = MyProxiedMut<'msg>;
}
#[derive(Debug, Clone, Copy)]
struct MyProxiedView<'a> {
my_proxied_ref: &'a MyProxied,
struct MyProxiedView<'msg> {
my_proxied_ref: &'msg MyProxied,
}
impl MyProxiedView<'_> {
@ -306,27 +322,27 @@ mod tests {
}
}
impl<'a> ViewProxy<'a> for MyProxiedView<'a> {
impl<'msg> ViewProxy<'msg> for MyProxiedView<'msg> {
type Proxied = MyProxied;
fn as_view(&self) -> View<'a, MyProxied> {
fn as_view(&self) -> View<'msg, MyProxied> {
*self
}
fn into_view<'shorter>(self) -> View<'shorter, MyProxied>
where
'a: 'shorter,
'msg: 'shorter,
{
self
}
}
#[derive(Debug)]
struct MyProxiedMut<'a> {
my_proxied_ref: &'a mut MyProxied,
struct MyProxiedMut<'msg> {
my_proxied_ref: &'msg mut MyProxied,
}
impl<'a> ViewProxy<'a> for MyProxiedMut<'a> {
impl<'msg> ViewProxy<'msg> for MyProxiedMut<'msg> {
type Proxied = MyProxied;
fn as_view(&self) -> View<'_, MyProxied> {
@ -334,56 +350,56 @@ mod tests {
}
fn into_view<'shorter>(self) -> View<'shorter, MyProxied>
where
'a: 'shorter,
'msg: 'shorter,
{
MyProxiedView { my_proxied_ref: self.my_proxied_ref }
}
}
impl<'a> MutProxy<'a> for MyProxiedMut<'a> {
impl<'msg> MutProxy<'msg> for MyProxiedMut<'msg> {
fn as_mut(&mut self) -> Mut<'_, MyProxied> {
MyProxiedMut { my_proxied_ref: self.my_proxied_ref }
}
fn into_mut<'shorter>(self) -> Mut<'shorter, MyProxied>
where
'a: 'shorter,
'msg: 'shorter,
{
self
}
}
impl SettableValue<MyProxied> for MyProxiedView<'_> {
fn set_on<'a>(self, _private: Private, mutator: Mut<'a, MyProxied>)
fn set_on<'msg>(self, _private: Private, mutator: Mut<'msg, MyProxied>)
where
MyProxied: 'a,
MyProxied: 'msg,
{
mutator.my_proxied_ref.val = self.my_proxied_ref.val.clone();
}
}
impl SettableValue<MyProxied> for String {
fn set_on<'a>(self, _private: Private, mutator: Mut<'a, MyProxied>)
fn set_on<'msg>(self, _private: Private, mutator: Mut<'msg, MyProxied>)
where
MyProxied: 'a,
MyProxied: 'msg,
{
mutator.my_proxied_ref.val = self;
}
}
impl SettableValue<MyProxied> for &'_ str {
fn set_on<'a>(self, _private: Private, mutator: Mut<'a, MyProxied>)
fn set_on<'msg>(self, _private: Private, mutator: Mut<'msg, MyProxied>)
where
MyProxied: 'a,
MyProxied: 'msg,
{
mutator.my_proxied_ref.val.replace_range(.., self);
}
}
impl SettableValue<MyProxied> for Cow<'_, str> {
fn set_on<'a>(self, _private: Private, mutator: Mut<'a, MyProxied>)
fn set_on<'msg>(self, _private: Private, mutator: Mut<'msg, MyProxied>)
where
MyProxied: 'a,
MyProxied: 'msg,
{
match self {
Cow::Owned(x) => <String as SettableValue<MyProxied>>::set_on(x, Private, mutator),
@ -413,7 +429,7 @@ mod tests {
assert_eq!(my_proxied.val, "Hello indeed");
}
fn reborrow_mut_into_view<'a>(x: Mut<'a, MyProxied>) -> View<'a, MyProxied> {
fn reborrow_mut_into_view<'msg>(x: Mut<'msg, MyProxied>) -> View<'msg, MyProxied> {
// x.as_view() fails to compile with:
// `ERROR: attempt to return function-local borrowed content`
x.into_view() // OK: we return the same lifetime as we got in.
@ -425,7 +441,7 @@ mod tests {
reborrow_mut_into_view(my_proxied.as_mut());
}
fn require_unified_lifetimes<'a>(_x: Mut<'a, MyProxied>, _y: View<'a, MyProxied>) {}
fn require_unified_lifetimes<'msg>(_x: Mut<'msg, MyProxied>, _y: View<'msg, MyProxied>) {}
#[test]
fn test_require_unified_lifetimes() {

View File

@ -5,231 +5,424 @@
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd
use std::fmt::{self, Debug};
use std::iter;
/// Repeated scalar fields are implemented around the runtime-specific
/// `RepeatedField` struct. `RepeatedField` stores an opaque pointer to the
/// runtime-specific representation of a repeated scalar (`upb_Array*` on upb,
/// and `RepeatedField<T>*` on cpp).
use std::marker::PhantomData;
use std::ops::Deref;
use crate::{
Mut, MutProxy, Proxied, SettableValue, View, ViewProxy,
__internal::{Private, RawRepeatedField},
__runtime::{RepeatedField, RepeatedFieldInner},
primitive::PrimitiveMut,
vtable::ProxiedWithRawVTable,
__runtime::InnerRepeatedMut,
};
#[derive(Clone, Copy)]
pub struct RepeatedFieldRef<'a> {
pub repeated_field: RawRepeatedField,
pub _phantom: PhantomData<&'a mut ()>,
}
unsafe impl<'a> Send for RepeatedFieldRef<'a> {}
unsafe impl<'a> Sync for RepeatedFieldRef<'a> {}
#[derive(Clone, Copy)]
/// Views the elements in a `repeated` field of `T`.
#[repr(transparent)]
pub struct RepeatedView<'a, T: ?Sized> {
inner: RepeatedField<'a, T>,
pub struct RepeatedView<'msg, T: ?Sized> {
// This does not need to carry an arena in upb, so it can be just the raw repeated field
raw: RawRepeatedField,
_phantom: PhantomData<&'msg T>,
}
unsafe impl<'a, T: ProxiedWithRawVTable> Sync for RepeatedView<'a, T> {}
unsafe impl<'a, T: ProxiedWithRawVTable> Send for RepeatedView<'a, T> {}
impl<'msg, T: ?Sized> RepeatedView<'msg, T> {
pub fn from_inner(_private: Private, inner: RepeatedFieldInner<'msg>) -> Self {
Self { inner: RepeatedField::<'msg>::from_inner(_private, inner) }
impl<'msg, T: ?Sized> Copy for RepeatedView<'msg, T> {}
impl<'msg, T: ?Sized> Clone for RepeatedView<'msg, T> {
fn clone(&self) -> Self {
*self
}
}
pub struct RepeatedFieldIter<'a, T> {
inner: RepeatedField<'a, T>,
current_index: usize,
}
unsafe impl<'msg, T: ?Sized> Sync for RepeatedView<'msg, T> {}
unsafe impl<'msg, T: ?Sized> Send for RepeatedView<'msg, T> {}
impl<'a, T> std::fmt::Debug for RepeatedView<'a, T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("RepeatedView").finish()
impl<'msg, T: ?Sized> Debug for RepeatedView<'msg, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("RepeatedView").field("raw", &self.raw).finish()
}
}
/// Mutates the elements in a `repeated` field of `T`.
#[repr(transparent)]
#[derive(Debug)]
pub struct RepeatedMut<'a, T: ?Sized> {
inner: RepeatedField<'a, T>,
pub struct RepeatedMut<'msg, T: ?Sized> {
pub(crate) inner: InnerRepeatedMut<'msg>,
_phantom: PhantomData<&'msg mut T>,
}
unsafe impl<'a, T: ProxiedWithRawVTable> Sync for RepeatedMut<'a, T> {}
unsafe impl<'msg, T: ?Sized> Sync for RepeatedMut<'msg, T> {}
impl<'msg, T: ?Sized> RepeatedMut<'msg, T> {
pub fn from_inner(_private: Private, inner: RepeatedFieldInner<'msg>) -> Self {
Self { inner: RepeatedField::from_inner(_private, inner) }
}
pub fn as_mut(&self) -> RepeatedMut<'_, T> {
Self { inner: self.inner }
}
}
impl<'a, T> std::ops::Deref for RepeatedMut<'a, T> {
type Target = RepeatedView<'a, T>;
impl<'msg, T: ?Sized> Deref for RepeatedMut<'msg, T> {
type Target = RepeatedView<'msg, T>;
fn deref(&self) -> &Self::Target {
// SAFETY:
// - `Repeated{View,Mut}<'a, T>` are both `#[repr(transparent)]` over
// `RepeatedField<'a, T>`.
// - `Repeated{View,Mut}<'msg, T>` are both `#[repr(transparent)]` over
// `RepeatedField<'msg, T>`.
// - `Repeated{View,Mut}<'msg, T>` are both `#[repr(transparent)]` over
// `RepeatedField<'msg, T>`.
// - `RepeatedField` is a type alias for `NonNull`.
unsafe { &*(self as *const Self as *const RepeatedView<'a, T>) }
unsafe { &*(self as *const Self as *const RepeatedView<'msg, T>) }
}
}
pub struct RepeatedFieldIterMut<'a, T> {
inner: RepeatedMut<'a, T>,
impl<'msg, T: ?Sized> Debug for RepeatedMut<'msg, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("RepeatedMut").field("raw", &self.raw).finish()
}
}
impl<'msg, T> RepeatedView<'msg, T>
where
T: ProxiedInRepeated + ?Sized + 'msg,
{
#[doc(hidden)]
pub fn as_raw(&self, _private: Private) -> RawRepeatedField {
self.raw
}
/// # Safety
/// - `inner` must be valid to read from for `'msg`
#[doc(hidden)]
pub unsafe fn from_raw(_private: Private, raw: RawRepeatedField) -> Self {
Self { raw, _phantom: PhantomData }
}
pub fn len(&self) -> usize {
T::repeated_len(*self)
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn get(self, index: usize) -> Option<View<'msg, T>> {
if index >= self.len() {
return None;
}
// SAFETY: `index` has been checked to be in-bounds
Some(unsafe { T::repeated_get_unchecked(self, index) })
}
pub fn iter(self) -> RepeatedIter<'msg, T> {
self.into_iter()
}
}
impl<'msg, T> RepeatedMut<'msg, T>
where
T: ProxiedInRepeated + ?Sized + 'msg,
{
/// # Safety
/// - `inner` must be valid to read and write from for `'msg`
/// - There must be no aliasing references or mutations on the same
/// underlying object.
#[doc(hidden)]
pub unsafe fn from_inner(_private: Private, inner: InnerRepeatedMut<'msg>) -> Self {
Self { inner, _phantom: PhantomData }
}
#[doc(hidden)]
pub fn as_raw(&mut self, _private: Private) -> RawRepeatedField {
self.inner.raw
}
/// Appends `val` to the end of the repeated field.
pub fn push(&mut self, val: View<T>) {
T::repeated_push(self.as_mut(), val);
}
/// Sets the value at `index` to the value `val`.
///
/// # Panics
/// Panics if `index >= len`
pub fn set(&mut self, index: usize, val: View<T>) {
let len = self.len();
if index >= len {
panic!("index {index} >= repeated len {len}");
}
// SAFETY: `index` has been checked to be in-bounds.
unsafe { T::repeated_set_unchecked(self.as_mut(), index, val) }
}
/// Returns the value at `index`.
// This is defined as an inherent function to prevent `MutProxy::get` from being
// preferred over `RepeatedView::get`. The former gets priority as it does
// not require a deref.
pub fn get(&self, index: usize) -> Option<View<T>> {
self.as_view().get(index)
}
/// Copies from the `src` repeated field into this one.
///
/// Also provided by [`MutProxy::set`].
pub fn copy_from(&mut self, src: RepeatedView<'_, T>) {
T::repeated_copy_from(src, self.as_mut())
}
/// Clears the repeated field.
pub fn clear(&mut self) {
T::repeated_clear(self.as_mut())
}
}
/// Types that can appear in a `Repeated<T>`.
///
/// This trait is implemented by generated code to communicate how the proxied
/// type can be manipulated for a repeated field.
///
/// Scalars and messages implement `ProxiedInRepeated`.
///
/// # Safety
/// - It must be sound to call `*_unchecked*(x)` with an `index` less than
/// `repeated_len(x)`.
pub unsafe trait ProxiedInRepeated: Proxied {
/// Constructs a new owned `Repeated` field.
#[doc(hidden)]
fn repeated_new(_private: Private) -> Repeated<Self> {
unimplemented!("not required")
}
/// Frees the repeated field in-place, for use in `Drop`.
///
/// # Safety
/// - After `repeated_free`, no other methods on the input are safe to call.
#[doc(hidden)]
unsafe fn repeated_free(_private: Private, _repeated: &mut Repeated<Self>) {
unimplemented!("not required")
}
/// Gets the length of the repeated field.
fn repeated_len(repeated: View<Repeated<Self>>) -> usize;
/// Appends a new element to the end of the repeated field.
fn repeated_push(repeated: Mut<Repeated<Self>>, val: View<Self>);
/// Clears the repeated field of elements.
fn repeated_clear(repeated: Mut<Repeated<Self>>);
/// # Safety
/// `index` must be less than `Self::repeated_len(repeated)`
unsafe fn repeated_get_unchecked(repeated: View<Repeated<Self>>, index: usize) -> View<Self>;
/// # Safety
/// `index` must be less than `Self::repeated_len(repeated)`
unsafe fn repeated_set_unchecked(repeated: Mut<Repeated<Self>>, index: usize, val: View<Self>);
/// Copies the values in the `src` repeated field into `dest`.
fn repeated_copy_from(src: View<Repeated<Self>>, dest: Mut<Repeated<Self>>);
}
/// An iterator over the values inside of a [`View<Repeated<T>>`](RepeatedView).
pub struct RepeatedIter<'msg, T: ?Sized> {
view: RepeatedView<'msg, T>,
current_index: usize,
}
pub struct Repeated<T>(PhantomData<T>);
macro_rules! impl_repeated_primitives {
($($t:ty),*) => {
$(
impl Proxied for Repeated<$t> {
type View<'a> = RepeatedView<'a, $t>;
type Mut<'a> = RepeatedMut<'a, $t>;
}
impl<'a> ViewProxy<'a> for RepeatedView<'a, $t> {
type Proxied = Repeated<$t>;
fn as_view(&self) -> View<'_, Self::Proxied> {
*self
}
fn into_view<'shorter>(self) -> View<'shorter, Self::Proxied>
where 'a: 'shorter,
{
RepeatedView { inner: self.inner }
}
}
impl<'a> ViewProxy<'a> for RepeatedMut<'a, $t> {
type Proxied = Repeated<$t>;
fn as_view(&self) -> View<'_, Self::Proxied> {
**self
}
fn into_view<'shorter>(self) -> View<'shorter, Self::Proxied>
where 'a: 'shorter,
{
*self.into_mut::<'shorter>()
}
}
impl<'a> MutProxy<'a> for RepeatedMut<'a, $t> {
fn as_mut(&mut self) -> Mut<'_, Self::Proxied> {
RepeatedMut { inner: self.inner }
}
fn into_mut<'shorter>(self) -> Mut<'shorter, Self::Proxied>
where 'a: 'shorter,
{
RepeatedMut { inner: self.inner }
}
}
impl <'a> SettableValue<Repeated<$t>> for RepeatedView<'a, $t> {
fn set_on<'b> (self, _private: Private, mut mutator: Mut<'b, Repeated<$t>>)
where
Repeated<$t>: 'b {
mutator.copy_from(self);
}
}
impl<'a> RepeatedView<'a, $t> {
pub fn len(&self) -> usize {
self.inner.len()
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn get(&self, index: usize) -> Option<$t> {
self.inner.get(index)
}
pub fn iter(&self) -> RepeatedFieldIter<'_, $t> {
(*self).into_iter()
}
}
impl<'a> RepeatedMut<'a, $t> {
pub fn push(&mut self, val: $t) {
self.inner.push(val)
}
pub fn set(&mut self, index: usize, val: $t) {
self.inner.set(index, val)
}
pub fn get_mut(&mut self, index: usize) -> Option<Mut<'_, $t>> {
if index >= self.len() {
return None;
}
Some(PrimitiveMut::Repeated(self.as_mut(), index))
}
pub fn iter(&self) -> RepeatedFieldIter<'_, $t> {
self.as_view().into_iter()
}
pub fn iter_mut(&mut self) -> RepeatedFieldIterMut<'_, $t> {
self.as_mut().into_iter()
}
pub fn copy_from(&mut self, src: RepeatedView<'_, $t>) {
self.inner.copy_from(&src.inner);
}
}
impl<'a> std::iter::Iterator for RepeatedFieldIter<'a, $t> {
type Item = $t;
fn next(&mut self) -> Option<Self::Item> {
let val = self.inner.get(self.current_index);
if val.is_some() {
self.current_index += 1;
}
val
}
}
impl<'a> std::iter::IntoIterator for RepeatedView<'a, $t> {
type Item = $t;
type IntoIter = RepeatedFieldIter<'a, $t>;
fn into_iter(self) -> Self::IntoIter {
RepeatedFieldIter { inner: self.inner, current_index: 0 }
}
}
impl <'a> std::iter::Iterator for RepeatedFieldIterMut<'a, $t> {
type Item = Mut<'a, $t>;
fn next(&mut self) -> Option<Self::Item> {
if self.current_index >= self.inner.len() {
return None;
}
let elem = PrimitiveMut::Repeated(
// While this appears to allow mutable aliasing
// (multiple `Self::Item`s can co-exist), each `Item`
// only references a specific unique index.
RepeatedMut{ inner: self.inner.inner },
self.current_index,
);
self.current_index += 1;
Some(elem)
}
}
impl<'a> std::iter::IntoIterator for RepeatedMut<'a, $t> {
type Item = Mut<'a, $t>;
type IntoIter = RepeatedFieldIterMut<'a, $t>;
fn into_iter(self) -> Self::IntoIter {
RepeatedFieldIterMut { inner: self, current_index: 0 }
}
}
)*
impl<'msg, T: ?Sized> Debug for RepeatedIter<'msg, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("RepeatedIter")
.field("view", &self.view)
.field("current_index", &self.current_index)
.finish()
}
}
impl_repeated_primitives!(i32, u32, bool, f32, f64, i64, u64);
/// An iterator over the mutators inside of a [`Mut<Repeated<T>>`](RepeatedMut).
pub struct RepeatedIterMut<'msg, T: ?Sized> {
mutator: RepeatedMut<'msg, T>,
current_index: usize,
}
impl<'msg, T: ?Sized> Debug for RepeatedIterMut<'msg, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("RepeatedIterMut")
.field("mutator", &self.mutator)
.field("current_index", &self.current_index)
.finish()
}
}
/// A `repeated` field of `T`, used as the owned target for `Proxied`.
///
/// Users will generally write [`View<Repeated<T>>`](RepeatedView) or
/// [`Mut<Repeated<T>>`](RepeatedMut) to access the repeated elements
pub struct Repeated<T: ?Sized + ProxiedInRepeated> {
inner: InnerRepeatedMut<'static>,
_phantom: PhantomData<T>,
}
impl<T: ?Sized + ProxiedInRepeated> Repeated<T> {
#[allow(dead_code)]
pub(crate) fn new() -> Self {
T::repeated_new(Private)
}
pub(crate) unsafe fn from_inner(inner: InnerRepeatedMut<'static>) -> Self {
Self { inner, _phantom: PhantomData }
}
#[allow(dead_code)]
pub(crate) fn inner(&mut self) -> InnerRepeatedMut<'static> {
self.inner
}
pub(crate) fn as_mut(&mut self) -> RepeatedMut<'_, T> {
RepeatedMut { inner: self.inner, _phantom: PhantomData }
}
}
impl<T: ?Sized + ProxiedInRepeated> Drop for Repeated<T> {
fn drop(&mut self) {
// SAFETY: only called once
unsafe { T::repeated_free(Private, self) }
}
}
// SAFETY: `Repeated` does not allow for shared mutability.
unsafe impl<T: ProxiedInRepeated> Sync for Repeated<T> {}
impl<T> Proxied for Repeated<T>
where
T: ProxiedInRepeated + ?Sized,
{
type View<'msg> = RepeatedView<'msg, T> where Repeated<T>: 'msg;
type Mut<'msg> = RepeatedMut<'msg, T> where Repeated<T>: 'msg;
}
impl<'msg, T> ViewProxy<'msg> for RepeatedView<'msg, T>
where
T: ProxiedInRepeated + ?Sized + 'msg,
{
type Proxied = Repeated<T>;
fn as_view(&self) -> View<'_, Self::Proxied> {
*self
}
fn into_view<'shorter>(self) -> View<'shorter, Self::Proxied>
where
'msg: 'shorter,
{
RepeatedView { raw: self.raw, _phantom: PhantomData }
}
}
impl<'msg, T> ViewProxy<'msg> for RepeatedMut<'msg, T>
where
T: ProxiedInRepeated + ?Sized + 'msg,
{
type Proxied = Repeated<T>;
fn as_view(&self) -> View<'_, Self::Proxied> {
**self
}
fn into_view<'shorter>(self) -> View<'shorter, Self::Proxied>
where
'msg: 'shorter,
{
*self.into_mut::<'shorter>()
}
}
impl<'msg, T> MutProxy<'msg> for RepeatedMut<'msg, T>
where
T: ProxiedInRepeated + ?Sized + 'msg,
{
fn as_mut(&mut self) -> Mut<'_, Self::Proxied> {
RepeatedMut { inner: self.inner, _phantom: PhantomData }
}
fn into_mut<'shorter>(self) -> Mut<'shorter, Self::Proxied>
where
'msg: 'shorter,
{
RepeatedMut { inner: self.inner, _phantom: PhantomData }
}
}
impl<'msg, T> SettableValue<Repeated<T>> for RepeatedView<'msg, T>
where
T: ProxiedInRepeated + ?Sized + 'msg,
{
fn set_on<'b>(self, _private: Private, mutator: Mut<'b, Repeated<T>>)
where
Repeated<T>: 'b,
{
T::repeated_copy_from(self, mutator)
}
}
// TODO: impl ExactSizeIterator
impl<'msg, T> iter::Iterator for RepeatedIter<'msg, T>
where
T: ProxiedInRepeated + ?Sized + 'msg,
{
type Item = View<'msg, T>;
fn next(&mut self) -> Option<Self::Item> {
let val = self.view.get(self.current_index);
if val.is_some() {
self.current_index += 1;
}
val
}
}
impl<'msg, T> iter::IntoIterator for RepeatedView<'msg, T>
where
T: ProxiedInRepeated + ?Sized + 'msg,
{
type Item = View<'msg, T>;
type IntoIter = RepeatedIter<'msg, T>;
fn into_iter(self) -> Self::IntoIter {
RepeatedIter { view: self, current_index: 0 }
}
}
#[cfg(test)]
mod tests {
use super::*;
use googletest::prelude::*;
#[test]
fn test_primitive_repeated() {
macro_rules! primitive_repeated_tests {
($($t:ty => [$($vals:expr),* $(,)?]),* $(,)?) => {
$({
// Constructs a new, owned, `Repeated`, only used for tests.
let mut r = Repeated::<$t>::new();
let mut r = r.as_mut();
assert_that!(r.len(), eq(0));
assert!(r.iter().next().is_none(), "starts with empty iter");
assert!(r.iter().next().is_none(), "starts with empty mut iter");
assert!(r.is_empty(), "starts is_empty");
let mut expected_len = 0usize;
$(
let val: View<$t> = $vals;
r.push(val);
assert_that!(r.get(expected_len), eq(Some(val)));
expected_len += 1;
assert_that!(r.len(), eq(expected_len));
)*
assert_that!(
r.iter().collect::<Vec<$t>>(), elements_are![$(eq($vals)),*]);
r.set(0, <$t as Default>::default());
assert_that!(r.get(0).expect("elem 0"), eq(<$t as Default>::default()));
r.clear();
assert!(r.is_empty(), "is_empty after clear");
assert!(r.iter().next().is_none(), "iter empty after clear");
assert!(r.into_iter().next().is_none(), "mut iter empty after clear");
})*
}
}
primitive_repeated_tests!(
u32 => [1,2,3],
i32 => [1,2],
f64 => [10.0, 0.1234f64],
bool => [false, true, true, false],
);
}
}

View File

@ -13,17 +13,22 @@
use std::fmt;
// There are a number of manual `Debug` and similar impls instead of using their
// derives, in order to to avoid unnecessary bounds on a generic `T`.
// This problem is referred to as "perfect derive".
// https://smallcultfollowing.com/babysteps/blog/2022/04/12/implied-bounds-and-perfect-derive/
/// Everything in `__public` is re-exported in `protobuf.rs`.
/// These are the items protobuf users can access directly.
#[doc(hidden)]
pub mod __public {
pub use crate::map::{MapMut, MapView};
pub use crate::map::{Map, MapMut, MapView};
pub use crate::optional::{AbsentField, FieldEntry, Optional, PresentField};
pub use crate::primitive::{PrimitiveMut, SingularPrimitiveMut};
pub use crate::primitive::PrimitiveMut;
pub use crate::proxied::{
Mut, MutProxy, Proxied, ProxiedWithPresence, SettableValue, View, ViewProxy,
};
pub use crate::repeated::{RepeatedFieldRef, RepeatedMut, RepeatedView};
pub use crate::repeated::{ProxiedInRepeated, Repeated, RepeatedMut, RepeatedView};
pub use crate::string::{BytesMut, ProtoStr, ProtoStrMut};
}
pub use __public::*;

View File

@ -128,15 +128,11 @@ impl ProxiedWithPresence for [u8] {
type PresentMutData<'msg> = BytesPresentMutData<'msg>;
type AbsentMutData<'msg> = BytesAbsentMutData<'msg>;
fn clear_present_field<'a>(
present_mutator: Self::PresentMutData<'a>,
) -> Self::AbsentMutData<'a> {
fn clear_present_field(present_mutator: Self::PresentMutData<'_>) -> Self::AbsentMutData<'_> {
present_mutator.clear()
}
fn set_absent_to_default<'a>(
absent_mutator: Self::AbsentMutData<'a>,
) -> Self::PresentMutData<'a> {
fn set_absent_to_default(absent_mutator: Self::AbsentMutData<'_>) -> Self::PresentMutData<'_> {
absent_mutator.set_absent_to_default()
}
}
@ -185,9 +181,9 @@ impl<'msg> MutProxy<'msg> for BytesMut<'msg> {
}
impl SettableValue<[u8]> for &'_ [u8] {
fn set_on<'a>(self, _private: Private, mutator: Mut<'a, [u8]>)
fn set_on<'msg>(self, _private: Private, mutator: Mut<'msg, [u8]>)
where
[u8]: 'a,
[u8]: 'msg,
{
// SAFETY: this is a `bytes` field with no restriction on UTF-8.
unsafe { mutator.inner.set(self) }

View File

@ -74,7 +74,7 @@ rust_proto_library(
name = "unittest_proto3_optional_rust_proto",
testonly = True,
visibility = [
"//rust/test/shared:__subpackages__",
"//visibility:private", # Only private by automation, not intent. Owner may accept CLs adding visibility. See go/scheuklappen#explicit-private.
],
deps = [
UNITTEST_PROTO3_OPTIONAL_TARGET,
@ -84,20 +84,14 @@ rust_proto_library(
rust_cc_proto_library(
name = "unittest_proto3_optional_cc_rust_proto",
testonly = True,
visibility = [
"//rust/test/cpp:__subpackages__",
"//rust/test/shared:__subpackages__",
],
visibility = ["//rust/test/shared:__subpackages__"],
deps = [UNITTEST_PROTO3_OPTIONAL_CC_TARGET],
)
rust_upb_proto_library(
name = "unittest_proto3_optional_upb_rust_proto",
testonly = True,
visibility = [
"//rust/test/cpp:__subpackages__",
"//rust/test/shared:__subpackages__",
],
visibility = ["//rust/test/shared:__subpackages__"],
deps = [UNITTEST_PROTO3_OPTIONAL_TARGET],
)
@ -180,6 +174,32 @@ rust_upb_proto_library(
deps = [":dots_in_package_proto"],
)
proto_library(
name = "edition2023_proto",
testonly = True,
srcs = ["edition2023.proto"],
)
cc_proto_library(
name = "edition2023_cc_proto",
testonly = True,
deps = [":edition2023_proto"],
)
rust_cc_proto_library(
name = "edition2023_cc_rust_proto",
testonly = True,
visibility = ["//rust/test/shared:__subpackages__"],
deps = [":edition2023_cc_proto"],
)
rust_upb_proto_library(
name = "edition2023_upb_rust_proto",
testonly = True,
visibility = ["//rust/test/shared:__subpackages__"],
deps = [":edition2023_proto"],
)
proto_library(
name = "no_package_import_proto",
testonly = True,

View File

@ -40,9 +40,9 @@ fn mutate_message_in_cpp() {
}
let mut msg2 = TestAllTypes::new();
msg2.optional_int64_set(Some(42));
msg2.optional_int64_mut().set(42);
msg2.optional_bytes_mut().set(b"something mysterious");
msg2.optional_bool_set(Some(false));
msg2.optional_bool_mut().set(false);
proto_assert_eq!(msg1, msg2);
}
@ -50,7 +50,7 @@ fn mutate_message_in_cpp() {
#[test]
fn deserialize_in_rust() {
let mut msg1 = TestAllTypes::new();
msg1.optional_int64_set(Some(-1));
msg1.optional_int64_mut().set(-1);
msg1.optional_bytes_mut().set(b"some cool data I guess");
let serialized =
unsafe { SerializeTestAllTypes(msg1.__unstable_cpp_repr_grant_permission_to_break()) };
@ -63,7 +63,7 @@ fn deserialize_in_rust() {
#[test]
fn deserialize_in_cpp() {
let mut msg1 = TestAllTypes::new();
msg1.optional_int64_set(Some(-1));
msg1.optional_int64_mut().set(-1);
msg1.optional_bytes_mut().set(b"some cool data I guess");
let data = msg1.serialize();

View File

@ -0,0 +1,8 @@
edition = "2023";
package test;
message EditionsMessage {
int32 plain_field = 1;
int32 implicit_presence_field = 2 [features.field_presence = IMPLICIT];
}

View File

@ -11,6 +11,10 @@ package nest;
message Outer {
message Inner {
message InnerSubMsg {
optional bool flag = 1;
}
optional double double = 1;
optional float float = 2;
optional int32 int32 = 3;
@ -26,6 +30,7 @@ message Outer {
optional bool bool = 13;
optional string string = 14;
optional bytes bytes = 15;
optional InnerSubMsg innersubmsg = 16;
message SuperInner {
message DuperInner {
@ -40,4 +45,15 @@ message Outer {
optional Inner inner = 1;
optional .nest.Outer.Inner.SuperInner.DuperInner.EvenMoreInner
.CantBelieveItsSoInner deep = 2;
optional NotInside notinside = 3;
}
message NotInside {
optional int32 num = 1;
}
message Recursive {
optional Recursive rec = 1;
optional int32 num = 2;
}

View File

@ -68,6 +68,32 @@ rust_test(
],
)
rust_test(
name = "edition2023_cpp_test",
srcs = ["edition2023_test.rs"],
tags = [
# TODO: Enable testing on arm once we support sanitizers for Rust on Arm.
"not_build:arm",
],
deps = [
"@crate_index//:googletest",
"//rust/test:edition2023_cc_rust_proto",
],
)
rust_test(
name = "edition2023_upb_test",
srcs = ["edition2023_test.rs"],
tags = [
# TODO: Enable testing on arm once we support sanitizers for Rust on Arm.
"not_build:arm",
],
deps = [
"@crate_index//:googletest",
"//rust/test:edition2023_upb_rust_proto",
],
)
rust_test(
name = "package_cpp_test",
srcs = ["package_test.rs"],
@ -280,6 +306,46 @@ rust_test(
],
)
rust_test(
name = "accessors_repeated_cpp_test",
srcs = ["accessors_repeated_test.rs"],
aliases = {
"//rust:protobuf_cpp": "protobuf",
},
proc_macro_deps = [
"@crate_index//:paste",
],
tags = [
# TODO: Enable testing on arm once we support sanitizers for Rust on Arm.
"not_build:arm",
],
deps = [
"@crate_index//:googletest",
"//rust:protobuf_cpp",
"//rust/test:unittest_cc_rust_proto",
],
)
rust_test(
name = "accessors_repeated_upb_test",
srcs = ["accessors_repeated_test.rs"],
aliases = {
"//rust:protobuf_upb": "protobuf",
},
proc_macro_deps = [
"@crate_index//:paste",
],
tags = [
# TODO: Enable testing on arm once we support sanitizers for Rust on Arm.
"not_build:arm",
],
deps = [
"@crate_index//:googletest",
"//rust:protobuf_upb",
"//rust/test:unittest_upb_rust_proto",
],
)
rust_test(
name = "accessors_map_cpp_test",
srcs = ["accessors_map_test.rs"],

View File

@ -41,3 +41,15 @@ generate_map_primitives_tests!(
(i32, f64, int32, double),
(bool, bool, bool, bool)
);
#[test]
fn test_string_maps() {
let mut msg = TestMap::new();
msg.map_string_string_mut().insert("hello", "world".into());
msg.map_string_string_mut().insert("fizz", "buzz".into());
assert_that!(msg.map_string_string().len(), eq(2));
assert_that!(msg.map_string_string().get("fizz").unwrap(), eq("buzz"));
assert_that!(msg.map_string_string().get("not found"), eq(None));
msg.map_string_string_mut().clear();
assert_that!(msg.map_string_string().len(), eq(0));
}

View File

@ -23,7 +23,7 @@ fn test_fixed32_accessors() {
assert_that!(msg.optional_fixed32_mut().get(), eq(42));
assert_that!(msg.optional_fixed32(), eq(42));
msg.optional_fixed32_mut().clear();
msg.optional_fixed32_mut().set(u32::default());
assert_that!(msg.optional_fixed32(), eq(0));
assert_that!(msg.optional_fixed32_mut().get(), eq(0));
}
@ -38,7 +38,7 @@ fn test_bool_accessors() {
assert_that!(msg.optional_bool(), eq(true));
assert_that!(msg.optional_bool_mut().get(), eq(true));
msg.optional_bool_mut().clear();
msg.optional_bool_mut().set(bool::default());
assert_that!(msg.optional_bool(), eq(false));
assert_that!(msg.optional_bool_mut().get(), eq(false));
}
@ -191,11 +191,11 @@ fn test_oneof_accessors() {
let mut msg = TestAllTypes::new();
assert_that!(msg.oneof_field(), matches_pattern!(not_set(_)));
msg.oneof_uint32_set(Some(7));
msg.oneof_uint32_mut().set(7);
assert_that!(msg.oneof_uint32_opt(), eq(Optional::Set(7)));
assert_that!(msg.oneof_field(), matches_pattern!(OneofUint32(eq(7))));
msg.oneof_uint32_set(None);
msg.oneof_uint32_mut().clear();
assert_that!(msg.oneof_uint32_opt(), eq(Optional::Unset(0)));
assert_that!(msg.oneof_field(), matches_pattern!(not_set(_)));
@ -209,7 +209,7 @@ fn test_oneof_accessors() {
// eq(Optional::Unset(_))); assert_that!(msg.oneof_field(),
// matches_pattern!(OneofNestedMessage(_)));
msg.oneof_uint32_set(Some(7));
msg.oneof_uint32_mut().set(7);
msg.oneof_bytes_mut().set(b"123");
assert_that!(msg.oneof_uint32_opt(), eq(Optional::Unset(0)));
assert_that!(msg.oneof_field(), matches_pattern!(OneofBytes(eq(b"123"))));
@ -225,7 +225,7 @@ fn test_oneof_mut_accessors() {
let mut msg = TestAllTypes::new();
assert_that!(msg.oneof_field_mut(), matches_pattern!(not_set(_)));
msg.oneof_uint32_set(Some(7));
msg.oneof_uint32_mut().set(7);
match msg.oneof_field_mut() {
OneofUint32(mut v) => {
@ -244,10 +244,10 @@ fn test_oneof_mut_accessors() {
matches_pattern!(TestAllTypes_::OneofField::OneofUint32(eq(8)))
);
msg.oneof_uint32_set(None);
msg.oneof_uint32_mut().clear();
assert_that!(msg.oneof_field_mut(), matches_pattern!(not_set(_)));
msg.oneof_uint32_set(Some(7));
msg.oneof_uint32_mut().set(7);
msg.oneof_bytes_mut().set(b"123");
assert_that!(msg.oneof_field_mut(), matches_pattern!(OneofBytes(_)));
}

View File

@ -0,0 +1,122 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2023 Google LLC. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd
use googletest::prelude::*;
use paste::paste;
use unittest_proto::proto2_unittest::TestAllTypes;
macro_rules! generate_repeated_numeric_test {
($(($t: ty, $field: ident)),*) => {
paste! { $(
#[test]
fn [< test_repeated_ $field _accessors >]() {
let mut msg = TestAllTypes::new();
assert_that!(msg.[< repeated_ $field >]().len(), eq(0));
assert_that!(msg.[<repeated_ $field >]().get(0), none());
let mut mutator = msg.[<repeated_ $field _mut >]();
mutator.push(1 as $t);
assert_that!(mutator.len(), eq(1));
assert_that!(mutator.get(0), some(eq(1 as $t)));
mutator.set(0, 2 as $t);
assert_that!(mutator.get(0), some(eq(2 as $t)));
mutator.push(1 as $t);
mutator.push(3 as $t);
mutator.set(2, 4 as $t);
assert_that!(mutator.get(2), some(eq(4 as $t)));
mutator.set(2, 0 as $t);
assert_that!(
mutator.iter().collect::<Vec<_>>(),
eq(vec![2 as $t, 1 as $t, 0 as $t])
);
assert_that!(
(*mutator).into_iter().collect::<Vec<_>>(),
eq(vec![2 as $t, 1 as $t, 0 as $t])
);
for i in 0..mutator.len() {
mutator.set(i, 0 as $t);
}
assert_that!(
msg.[<repeated_ $field _mut >]().iter().all(|v| v == (0 as $t)),
eq(true)
);
}
#[test]
fn [< test_repeated_ $field _set >]() {
let mut msg = TestAllTypes::new();
let mut mutator = msg.[<repeated_ $field _mut>]();
let mut msg2 = TestAllTypes::new();
let mut mutator2 = msg2.[<repeated_ $field _mut>]();
for i in 0..5 {
mutator2.push(i as $t);
}
protobuf::MutProxy::set(&mut mutator, *mutator2);
assert_that!(
mutator.iter().collect::<Vec<_>>(),
eq(mutator2.iter().collect::<Vec<_>>())
);
}
)* }
};
}
generate_repeated_numeric_test!(
(i32, int32),
(u32, uint32),
(i64, int64),
(u64, uint64),
(f32, float),
(f64, double)
);
#[test]
fn test_repeated_bool_accessors() {
let mut msg = TestAllTypes::new();
assert_that!(msg.repeated_bool().len(), eq(0));
assert_that!(msg.repeated_bool().get(0), none());
let mut mutator = msg.repeated_bool_mut();
mutator.push(true);
assert_that!(mutator.len(), eq(1));
assert_that!(mutator.get(0), some(eq(true)));
mutator.set(0, false);
assert_that!(mutator.get(0), some(eq(false)));
mutator.push(true);
mutator.push(false);
mutator.set(2, true);
assert_that!(mutator.get(2), some(eq(true)));
mutator.set(2, false);
assert_that!(mutator.get(2), some(eq(false)));
assert_that!(mutator.iter().collect::<Vec<_>>(), eq(vec![false, true, false]));
assert_that!((*mutator).into_iter().collect::<Vec<_>>(), eq(vec![false, true, false]));
for i in 0..mutator.len() {
mutator.set(i, false);
}
assert_that!(msg.repeated_bool().iter().all(|v| v), eq(false));
}
#[test]
fn test_repeated_bool_set() {
let mut msg = TestAllTypes::new();
let mut mutator = msg.repeated_bool_mut();
let mut msg2 = TestAllTypes::new();
let mut mutator2 = msg2.repeated_bool_mut();
for _ in 0..5 {
mutator2.push(true);
}
protobuf::MutProxy::set(&mut mutator, *mutator2);
assert_that!(mutator.iter().collect::<Vec<_>>(), eq(mutator2.iter().collect::<Vec<_>>()));
}

View File

@ -9,7 +9,6 @@
use googletest::prelude::*;
use matchers::{is_set, is_unset};
use paste::paste;
use protobuf::Optional;
use unittest_proto::proto2_unittest::{TestAllTypes, TestAllTypes_};
@ -34,6 +33,8 @@ fn test_default_accessors() {
default_bool(): eq(true),
})
);
assert_that!(msg.default_string(), eq("hello"));
assert_that!(msg.default_bytes(), eq("world".as_bytes()));
}
#[test]
@ -42,11 +43,11 @@ fn test_optional_fixed32_accessors() {
assert_that!(msg.optional_fixed32_opt(), eq(Optional::Unset(0)));
assert_that!(msg.optional_fixed32(), eq(0));
msg.optional_fixed32_set(Some(99));
msg.optional_fixed32_mut().set(99);
assert_that!(msg.optional_fixed32_opt(), eq(Optional::Set(99)));
assert_that!(msg.optional_fixed32(), eq(99));
msg.optional_fixed32_set(None);
msg.optional_fixed32_mut().clear();
assert_that!(msg.optional_fixed32_opt(), eq(Optional::Unset(0)));
assert_that!(msg.optional_fixed32(), eq(0));
}
@ -84,11 +85,11 @@ fn test_optional_fixed64_accessors() {
assert_that!(msg.optional_fixed64_opt(), eq(Optional::Unset(0)));
assert_that!(msg.optional_fixed64(), eq(0));
msg.optional_fixed64_set(Some(2000));
msg.optional_fixed64_mut().set(2000);
assert_that!(msg.optional_fixed64_opt(), eq(Optional::Set(2000)));
assert_that!(msg.optional_fixed64(), eq(2000));
msg.optional_fixed64_set(None);
msg.optional_fixed64_mut().clear();
assert_that!(msg.optional_fixed64_opt(), eq(Optional::Unset(0)));
assert_that!(msg.optional_fixed64(), eq(0));
}
@ -126,11 +127,11 @@ fn test_optional_int32_accessors() {
assert_that!(msg.optional_int32_opt(), eq(Optional::Unset(0)));
assert_that!(msg.optional_int32(), eq(0));
msg.optional_int32_set(Some(1));
msg.optional_int32_mut().set(1);
assert_that!(msg.optional_int32_opt(), eq(Optional::Set(1)));
assert_that!(msg.optional_int32(), eq(1));
msg.optional_int32_set(None);
msg.optional_int32_mut().clear();
assert_that!(msg.optional_int32_opt(), eq(Optional::Unset(0)));
assert_that!(msg.optional_int32(), eq(0));
}
@ -168,11 +169,11 @@ fn test_optional_int64_accessors() {
assert_that!(msg.optional_int64_opt(), eq(Optional::Unset(0)));
assert_that!(msg.optional_int64(), eq(0));
msg.optional_int64_set(Some(42));
msg.optional_int64_mut().set(42);
assert_that!(msg.optional_int64_opt(), eq(Optional::Set(42)));
assert_that!(msg.optional_int64(), eq(42));
msg.optional_int64_set(None);
msg.optional_int64_mut().clear();
assert_that!(msg.optional_int64_opt(), eq(Optional::Unset(0)));
assert_that!(msg.optional_int64(), eq(0));
}
@ -210,11 +211,11 @@ fn test_optional_sint32_accessors() {
assert_that!(msg.optional_sint32_opt(), eq(Optional::Unset(0)));
assert_that!(msg.optional_sint32(), eq(0));
msg.optional_sint32_set(Some(-22));
msg.optional_sint32_mut().set(-22);
assert_that!(msg.optional_sint32_opt(), eq(Optional::Set(-22)));
assert_that!(msg.optional_sint32(), eq(-22));
msg.optional_sint32_set(None);
msg.optional_sint32_mut().clear();
assert_that!(msg.optional_sint32_opt(), eq(Optional::Unset(0)));
assert_that!(msg.optional_sint32(), eq(0));
}
@ -252,11 +253,11 @@ fn test_optional_sint64_accessors() {
assert_that!(msg.optional_sint64_opt(), eq(Optional::Unset(0)));
assert_that!(msg.optional_sint64(), eq(0));
msg.optional_sint64_set(Some(7000));
msg.optional_sint64_mut().set(7000);
assert_that!(msg.optional_sint64_opt(), eq(Optional::Set(7000)));
assert_that!(msg.optional_sint64(), eq(7000));
msg.optional_sint64_set(None);
msg.optional_sint64_mut().clear();
assert_that!(msg.optional_sint64_opt(), eq(Optional::Unset(0)));
assert_that!(msg.optional_sint64(), eq(0));
}
@ -294,11 +295,11 @@ fn test_optional_uint32_accessors() {
assert_that!(msg.optional_uint32_opt(), eq(Optional::Unset(0)));
assert_that!(msg.optional_uint32(), eq(0));
msg.optional_uint32_set(Some(9001));
msg.optional_uint32_mut().set(9001);
assert_that!(msg.optional_uint32_opt(), eq(Optional::Set(9001)));
assert_that!(msg.optional_uint32(), eq(9001));
msg.optional_uint32_set(None);
msg.optional_uint32_mut().clear();
assert_that!(msg.optional_uint32_opt(), eq(Optional::Unset(0)));
assert_that!(msg.optional_uint32(), eq(0));
}
@ -336,11 +337,11 @@ fn test_optional_uint64_accessors() {
assert_that!(msg.optional_uint64_opt(), eq(Optional::Unset(0)));
assert_that!(msg.optional_uint64(), eq(0));
msg.optional_uint64_set(Some(42));
msg.optional_uint64_mut().set(42);
assert_that!(msg.optional_uint64_opt(), eq(Optional::Set(42)));
assert_that!(msg.optional_uint64(), eq(42));
msg.optional_uint64_set(None);
msg.optional_uint64_mut().clear();
assert_that!(msg.optional_uint64_opt(), eq(Optional::Unset(0)));
assert_that!(msg.optional_uint64(), eq(0));
}
@ -378,11 +379,11 @@ fn test_optional_float_accessors() {
assert_that!(msg.optional_float_opt(), eq(Optional::Unset(0.0)));
assert_that!(msg.optional_float(), eq(0.0));
msg.optional_float_set(Some(std::f32::consts::PI));
msg.optional_float_mut().set(std::f32::consts::PI);
assert_that!(msg.optional_float_opt(), eq(Optional::Set(std::f32::consts::PI)));
assert_that!(msg.optional_float(), eq(std::f32::consts::PI));
msg.optional_float_set(None);
msg.optional_float_mut().clear();
assert_that!(msg.optional_float_opt(), eq(Optional::Unset(0.0)));
assert_that!(msg.optional_float(), eq(0.0));
}
@ -420,11 +421,11 @@ fn test_optional_double_accessors() {
assert_that!(msg.optional_double_opt(), eq(Optional::Unset(0.0)));
assert_that!(msg.optional_double(), eq(0.0));
msg.optional_double_set(Some(-10.99));
msg.optional_double_mut().set(-10.99);
assert_that!(msg.optional_double_opt(), eq(Optional::Set(-10.99)));
assert_that!(msg.optional_double(), eq(-10.99));
msg.optional_double_set(None);
msg.optional_double_mut().clear();
assert_that!(msg.optional_double_opt(), eq(Optional::Unset(0.0)));
assert_that!(msg.optional_double(), eq(0.0));
}
@ -461,10 +462,10 @@ fn test_optional_bool_accessors() {
let mut msg = TestAllTypes::new();
assert_that!(msg.optional_bool_opt(), eq(Optional::Unset(false)));
msg.optional_bool_set(Some(true));
msg.optional_bool_mut().set(true);
assert_that!(msg.optional_bool_opt(), eq(Optional::Set(true)));
msg.optional_bool_set(None);
msg.optional_bool_mut().clear();
assert_that!(msg.optional_bool_opt(), eq(Optional::Unset(false)));
}
@ -686,15 +687,15 @@ fn test_oneof_accessors() {
let mut msg = TestAllTypes::new();
assert_that!(msg.oneof_field(), matches_pattern!(not_set(_)));
msg.oneof_uint32_set(Some(7));
msg.oneof_uint32_mut().set(7);
assert_that!(msg.oneof_uint32_opt(), eq(Optional::Set(7)));
assert_that!(msg.oneof_field(), matches_pattern!(OneofUint32(eq(7))));
msg.oneof_uint32_set(None);
msg.oneof_uint32_mut().clear();
assert_that!(msg.oneof_uint32_opt(), eq(Optional::Unset(0)));
assert_that!(msg.oneof_field(), matches_pattern!(not_set(_)));
msg.oneof_uint32_set(Some(7));
msg.oneof_uint32_mut().set(7);
msg.oneof_bytes_mut().set(b"123");
assert_that!(msg.oneof_uint32_opt(), eq(Optional::Unset(0)));
@ -708,7 +709,7 @@ fn test_oneof_mut_accessors() {
let mut msg = TestAllTypes::new();
assert_that!(msg.oneof_field_mut(), matches_pattern!(not_set(_)));
msg.oneof_uint32_set(Some(7));
msg.oneof_uint32_mut().set(7);
match msg.oneof_field_mut() {
OneofUint32(mut v) => {
@ -727,127 +728,10 @@ fn test_oneof_mut_accessors() {
matches_pattern!(TestAllTypes_::OneofField::OneofUint32(eq(8)))
);
msg.oneof_uint32_set(None);
msg.oneof_uint32_mut().clear();
assert_that!(msg.oneof_field_mut(), matches_pattern!(not_set(_)));
msg.oneof_uint32_set(Some(7));
msg.oneof_uint32_mut().set(7);
msg.oneof_bytes_mut().set(b"123");
assert_that!(msg.oneof_field_mut(), matches_pattern!(OneofBytes(_)));
}
macro_rules! generate_repeated_numeric_test {
($(($t: ty, $field: ident)),*) => {
paste! { $(
#[test]
fn [< test_repeated_ $field _accessors >]() {
let mut msg = TestAllTypes::new();
assert_that!(msg.[< repeated_ $field >]().len(), eq(0));
assert_that!(msg.[<repeated_ $field >]().get(0), none());
let mut mutator = msg.[<repeated_ $field _mut >]();
mutator.push(1 as $t);
assert_that!(mutator.len(), eq(1));
assert_that!(mutator.get(0), some(eq(1 as $t)));
mutator.set(0, 2 as $t);
assert_that!(mutator.get(0), some(eq(2 as $t)));
mutator.push(1 as $t);
mutator.push(3 as $t);
assert_that!(mutator.get_mut(2).is_some(), eq(true));
let mut mut_elem = mutator.get_mut(2).unwrap();
mut_elem.set(4 as $t);
assert_that!(mut_elem.get(), eq(4 as $t));
mut_elem.clear();
assert_that!(mut_elem.get(), eq(0 as $t));
assert_that!(
mutator.iter().collect::<Vec<_>>(),
eq(vec![2 as $t, 1 as $t, 0 as $t])
);
assert_that!(
(*mutator).into_iter().collect::<Vec<_>>(),
eq(vec![2 as $t, 1 as $t, 0 as $t])
);
for mut mutable_elem in msg.[<repeated_ $field _mut >]() {
mutable_elem.set(0 as $t);
}
assert_that!(
msg.[<repeated_ $field _mut >]().iter().all(|v| v == (0 as $t)),
eq(true)
);
}
#[test]
fn [< test_repeated_ $field _set >]() {
let mut msg = TestAllTypes::new();
let mut mutator = msg.[<repeated_ $field _mut>]();
let mut msg2 = TestAllTypes::new();
let mut mutator2 = msg2.[<repeated_ $field _mut>]();
for i in 0..5 {
mutator2.push(i as $t);
}
protobuf::MutProxy::set(&mut mutator, *mutator2);
assert_that!(
mutator.iter().collect::<Vec<_>>(),
eq(mutator2.iter().collect::<Vec<_>>())
);
}
)* }
};
}
generate_repeated_numeric_test!(
(i32, int32),
(u32, uint32),
(i64, int64),
(u64, uint64),
(f32, float),
(f64, double)
);
#[test]
fn test_repeated_bool_accessors() {
let mut msg = TestAllTypes::new();
assert_that!(msg.repeated_bool().len(), eq(0));
assert_that!(msg.repeated_bool().get(0), none());
let mut mutator = msg.repeated_bool_mut();
mutator.push(true);
assert_that!(mutator.len(), eq(1));
assert_that!(mutator.get(0), some(eq(true)));
mutator.set(0, false);
assert_that!(mutator.get(0), some(eq(false)));
mutator.push(true);
mutator.push(false);
assert_that!(mutator.get_mut(2), pat!(Some(_)));
let mut mut_elem = mutator.get_mut(2).unwrap();
mut_elem.set(true);
assert_that!(mut_elem.get(), eq(true));
mut_elem.clear();
assert_that!(mut_elem.get(), eq(false));
assert_that!(mutator.iter().collect::<Vec<_>>(), eq(vec![false, true, false]));
assert_that!((*mutator).into_iter().collect::<Vec<_>>(), eq(vec![false, true, false]));
for mut mutable_elem in msg.repeated_bool_mut() {
mutable_elem.set(false);
}
assert_that!(msg.repeated_bool().iter().all(|v| v), eq(false));
}
#[test]
fn test_repeated_bool_set() {
let mut msg = TestAllTypes::new();
let mut mutator = msg.repeated_bool_mut();
let mut msg2 = TestAllTypes::new();
let mut mutator2 = msg2.repeated_bool_mut();
for _ in 0..5 {
mutator2.push(true);
}
protobuf::MutProxy::set(&mut mutator, *mutator2);
assert_that!(mutator.iter().collect::<Vec<_>>(), eq(mutator2.iter().collect::<Vec<_>>()));
}

View File

@ -0,0 +1,23 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2023 Google LLC. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd
use googletest::prelude::*;
// Tests that an proto file that declares edition="2023" works. Note that this
// is _not_ a test for Rust Edition 2023 (which doesn't exist) but instead
// Protobuf Edition 2023 (which exists).
#[test]
fn check_edition2023_works() {
let mut msg = edition2023_proto::test::EditionsMessage::new();
// plain_field supports presence.
assert_that!(msg.plain_field_mut().or_default().get(), eq(0));
// implicit presence fields' _mut() skips FieldEntry.
assert_that!(msg.implicit_presence_field_mut().get(), eq(0));
}

View File

@ -11,8 +11,8 @@ use unittest_proto::proto2_unittest::TestAllTypes;
#[test]
fn serialize_deserialize_message() {
let mut msg = TestAllTypes::new();
msg.optional_int64_set(Some(42));
msg.optional_bool_set(Some(true));
msg.optional_int64_mut().set(42);
msg.optional_bool_mut().set(true);
msg.optional_bytes_mut().set(b"serialize deserialize test");
let serialized = msg.serialize();

View File

@ -10,6 +10,16 @@ use nested_proto::nest::Outer;
use nested_proto::nest::Outer_::InnerMut;
use nested_proto::nest::Outer_::InnerView;
#[test]
fn test_deeply_nested_definition() {
let deep = nested_proto::nest::Outer_::Inner_::SuperInner_::DuperInner_::EvenMoreInner_
::CantBelieveItsSoInner::new();
assert_that!(deep.num(), eq(0));
let outer_msg = Outer::new();
assert_that!(outer_msg.deep().num(), eq(0));
}
#[test]
fn test_nested_views() {
let outer_msg = Outer::new();
@ -29,37 +39,80 @@ fn test_nested_views() {
assert_that!(inner_msg.bool(), eq(false));
assert_that!(*inner_msg.string().as_bytes(), empty());
assert_that!(*inner_msg.bytes(), empty());
assert_that!(inner_msg.innersubmsg().flag(), eq(false));
}
#[test]
fn test_nested_muts() {
// TODO: add actual mutation logic, this just peeks at InnerMut at
// the moment
// Covers the setting of a mut and the following assertion
// confirming the new value. Replacement example:
// old:
// inner_msg.double_mut().set(543.21);
// assert_that!(inner_msg.double_mut().get(), eq(543.21));
// new:
// set_and_test_mut!(inner_msg => double_mut, 543.21);
macro_rules! set_and_test_mut {
( $a:expr => $($target_mut:ident, $val:literal;)* ) => {
$(
$a.$target_mut().set($val);
assert_that!($a.$target_mut().get(), eq($val));
)*
};
}
let mut outer_msg = Outer::new();
let inner_msg: InnerMut<'_> = outer_msg.inner_mut();
assert_that!(inner_msg.double(), eq(0.0));
assert_that!(inner_msg.float(), eq(0.0));
assert_that!(inner_msg.int32(), eq(0));
assert_that!(inner_msg.int64(), eq(0));
assert_that!(inner_msg.uint32(), eq(0));
assert_that!(inner_msg.uint64(), eq(0));
assert_that!(inner_msg.sint32(), eq(0));
assert_that!(inner_msg.sint64(), eq(0));
assert_that!(inner_msg.fixed32(), eq(0));
assert_that!(inner_msg.fixed64(), eq(0));
assert_that!(inner_msg.sfixed32(), eq(0));
assert_that!(inner_msg.sfixed64(), eq(0));
assert_that!(inner_msg.bool(), eq(false));
assert_that!(*inner_msg.string().as_bytes(), empty());
assert_that!(*inner_msg.bytes(), empty());
assert_that!(
inner_msg,
matches_pattern!(InnerMut{
float(): eq(0.0),
double(): eq(0.0),
int32(): eq(0),
int64(): eq(0),
uint32(): eq(0),
uint64(): eq(0),
sint32(): eq(0),
sint64(): eq(0),
fixed32(): eq(0),
fixed64(): eq(0),
sfixed32(): eq(0),
sfixed64(): eq(0),
bool(): eq(false)
})
);
assert_that!(inner_msg.string_mut().get(), eq(""));
assert_that!(inner_msg.bytes_mut().get(), eq(b""));
set_and_test_mut!(inner_msg =>
double_mut, 543.21;
float_mut, 1.23;
int32_mut, 12;
int64_mut, 42;
uint32_mut, 13;
uint64_mut, 5000;
sint32_mut, -2;
sint64_mut, 322;
fixed32_mut, 77;
fixed64_mut, 999;
bool_mut, true;
string_mut, "hi";
bytes_mut, b"bye";
);
}
#[test]
fn test_deeply_nested_definition() {
let deep = nested_proto::nest::Outer_::Inner_::SuperInner_::DuperInner_::EvenMoreInner_
::CantBelieveItsSoInner::new();
assert_eq!(deep.num(), 0);
let outer_msg = Outer::new();
assert_eq!(outer_msg.deep().num(), 0);
fn test_msg_from_outside() {
// let's make sure that we're not just working for messages nested inside
// messages, messages from without and within should work
let outer = nested_proto::nest::Outer::new();
assert_that!(outer.notinside().num(), eq(0));
}
#[test]
fn test_recursive_msg() {
let rec = nested_proto::nest::Recursive::new();
assert_that!(rec.num(), eq(0));
assert_that!(rec.rec().num(), eq(0));
assert_that!(rec.rec().rec().num(), eq(0)); // turtles all the way down...
assert_that!(rec.rec().rec().rec().num(), eq(0)); // ... ad infinitum
}

View File

@ -7,19 +7,22 @@
//! UPB FFI wrapper code for use by Rust Protobuf.
use crate::ProtoStr;
use crate::__internal::{Private, PtrAndLen, RawArena, RawMap, RawMessage, RawRepeatedField};
use crate::{Mut, ProxiedInRepeated, Repeated, RepeatedMut, RepeatedView, View, ViewProxy};
use core::fmt::Debug;
use paste::paste;
use std::alloc;
use std::alloc::Layout;
use std::cell::UnsafeCell;
use std::ffi::c_int;
use std::fmt;
use std::marker::PhantomData;
use std::mem::{size_of, MaybeUninit};
use std::ops::Deref;
use std::ptr::{self, NonNull};
use std::slice;
use std::sync::Once;
use std::sync::{Once, OnceLock};
/// See `upb/port/def.inc`.
const UPB_MALLOC_ALIGN: usize = 8;
@ -216,7 +219,7 @@ impl fmt::Debug for SerializedData {
pub type BytesPresentMutData<'msg> = crate::vtable::RawVTableOptionalMutatorData<'msg, [u8]>;
pub type BytesAbsentMutData<'msg> = crate::vtable::RawVTableOptionalMutatorData<'msg, [u8]>;
pub type InnerBytesMut<'msg> = crate::vtable::RawVTableMutator<'msg, [u8]>;
pub type InnerPrimitiveMut<'a, T> = crate::vtable::RawVTableMutator<'a, T>;
pub type InnerPrimitiveMut<'msg, T> = crate::vtable::RawVTableMutator<'msg, T>;
/// The raw contents of every generated message.
#[derive(Debug)]
@ -276,10 +279,10 @@ impl<'msg> MutatorMessageRef<'msg> {
}
}
pub fn copy_bytes_in_arena_if_needed_by_runtime<'a>(
msg_ref: MutatorMessageRef<'a>,
val: &'a [u8],
) -> &'a [u8] {
pub fn copy_bytes_in_arena_if_needed_by_runtime<'msg>(
msg_ref: MutatorMessageRef<'msg>,
val: &'msg [u8],
) -> &'msg [u8] {
// SAFETY: the alignment of `[u8]` is less than `UPB_MALLOC_ALIGN`.
let new_alloc = unsafe { msg_ref.arena.alloc(Layout::for_value(val)) };
debug_assert_eq!(new_alloc.len(), val.len());
@ -294,40 +297,28 @@ pub fn copy_bytes_in_arena_if_needed_by_runtime<'a>(
}
}
/// RepeatedFieldInner contains a `upb_Array*` as well as a reference to an
/// `Arena`, most likely that of the containing `Message`. upb requires an Arena
/// to perform mutations on a repeated field.
/// The raw type-erased pointer version of `RepeatedMut`.
///
/// Contains a `upb_Array*` as well as `RawArena`, most likely that of the
/// containing message. upb requires a `RawArena` to perform mutations on
/// a repeated field.
///
/// An owned `Repeated` stores a `InnerRepeatedMut<'static>` and manages the
/// contained `RawArena`.
#[derive(Clone, Copy, Debug)]
pub struct RepeatedFieldInner<'msg> {
pub raw: RawRepeatedField,
pub arena: &'msg Arena,
pub struct InnerRepeatedMut<'msg> {
pub(crate) raw: RawRepeatedField,
// Storing a `RawArena` instead of `&Arena` allows this to be used for
// both `RepeatedMut<T>` and `Repeated<T>`.
arena: RawArena,
_phantom: PhantomData<&'msg Arena>,
}
#[derive(Debug)]
pub struct RepeatedField<'msg, T: ?Sized> {
inner: RepeatedFieldInner<'msg>,
_phantom: PhantomData<&'msg mut T>,
}
// These use manual impls instead of derives to avoid unnecessary bounds on `T`.
// This problem is referred to as "perfect derive".
// https://smallcultfollowing.com/babysteps/blog/2022/04/12/implied-bounds-and-perfect-derive/
impl<'msg, T: ?Sized> Copy for RepeatedField<'msg, T> {}
impl<'msg, T: ?Sized> Clone for RepeatedField<'msg, T> {
fn clone(&self) -> RepeatedField<'msg, T> {
*self
}
}
impl<'msg, T: ?Sized> RepeatedField<'msg, T> {
pub fn len(&self) -> usize {
unsafe { upb_Array_Size(self.inner.raw) }
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn from_inner(_private: Private, inner: RepeatedFieldInner<'msg>) -> Self {
Self { inner, _phantom: PhantomData }
impl<'msg> InnerRepeatedMut<'msg> {
#[doc(hidden)]
#[allow(clippy::needless_pass_by_ref_mut)] // Sound construction requires mutable access.
pub fn new(_private: Private, raw: RawRepeatedField, arena: &'msg Arena) -> Self {
InnerRepeatedMut { raw, arena: arena.raw(), _phantom: PhantomData }
}
}
@ -366,7 +357,6 @@ pub enum UpbCType {
}
extern "C" {
#[allow(dead_code)]
fn upb_Array_New(a: RawArena, r#type: std::ffi::c_int) -> RawRepeatedField;
fn upb_Array_Size(arr: RawRepeatedField) -> usize;
fn upb_Array_Set(arr: RawRepeatedField, i: usize, val: upb_MessageValue);
@ -378,56 +368,65 @@ extern "C" {
}
macro_rules! impl_repeated_primitives {
($(($rs_type:ty, $ufield:ident, $upb_tag:expr)),*) => {
($(($t:ty, $ufield:ident, $upb_tag:expr)),* $(,)?) => {
$(
impl<'msg> RepeatedField<'msg, $rs_type> {
unsafe impl ProxiedInRepeated for $t {
#[allow(dead_code)]
fn new(arena: &'msg Arena) -> Self {
Self {
inner: RepeatedFieldInner {
raw: unsafe { upb_Array_New(arena.raw, $upb_tag as std::ffi::c_int) },
arena,
},
_phantom: PhantomData,
fn repeated_new(_: Private) -> Repeated<$t> {
let arena = Arena::new();
let raw_arena = arena.raw();
std::mem::forget(arena);
unsafe {
Repeated::from_inner(InnerRepeatedMut {
raw: upb_Array_New(raw_arena, $upb_tag as c_int),
arena: raw_arena,
_phantom: PhantomData,
})
}
}
pub fn push(&mut self, val: $rs_type) {
unsafe { upb_Array_Append(
self.inner.raw,
upb_MessageValue { $ufield: val },
self.inner.arena.raw(),
) }
}
pub fn get(&self, i: usize) -> Option<$rs_type> {
if i >= self.len() {
None
} else {
unsafe { Some(upb_Array_Get(self.inner.raw, i).$ufield) }
#[allow(dead_code)]
unsafe fn repeated_free(_: Private, f: &mut Repeated<$t>) {
// Freeing the array itself is handled by `Arena::Drop`
// SAFETY:
// - `f.raw_arena()` is a live `upb_Arena*` as
// - This function is only called once for `f`
unsafe {
upb_Arena_Free(f.inner().arena);
}
}
pub fn set(&self, i: usize, val: $rs_type) {
if i >= self.len() {
return;
}
unsafe { upb_Array_Set(
self.inner.raw,
i,
upb_MessageValue { $ufield: val },
) }
fn repeated_len(f: View<Repeated<$t>>) -> usize {
unsafe { upb_Array_Size(f.as_raw(Private)) }
}
pub fn copy_from(&mut self, src: &RepeatedField<'_, $rs_type>) {
fn repeated_push(mut f: Mut<Repeated<$t>>, v: View<$t>) {
unsafe {
upb_Array_Append(
f.as_raw(Private),
upb_MessageValue { $ufield: v },
f.raw_arena(Private))
}
}
fn repeated_clear(mut f: Mut<Repeated<$t>>) {
unsafe { upb_Array_Resize(f.as_raw(Private), 0, f.raw_arena(Private)); }
}
unsafe fn repeated_get_unchecked(f: View<Repeated<$t>>, i: usize) -> View<$t> {
unsafe { upb_Array_Get(f.as_raw(Private), i).$ufield }
}
unsafe fn repeated_set_unchecked(mut f: Mut<Repeated<$t>>, i: usize, v: View<$t>) {
unsafe { upb_Array_Set(f.as_raw(Private), i, upb_MessageValue { $ufield: v }) }
}
fn repeated_copy_from(src: View<Repeated<$t>>, mut dest: Mut<Repeated<$t>>) {
// SAFETY:
// - `upb_Array_Resize` is unsafe but assumed to be always sound to call.
// - `copy_nonoverlapping` is unsafe but here we guarantee that both pointers
// are valid, the pointers are `#[repr(u8)]`, and the size is correct.
unsafe {
if (!upb_Array_Resize(self.inner.raw, src.len(), self.inner.arena.raw())) {
if (!upb_Array_Resize(dest.as_raw(Private), src.len(), dest.inner.arena)) {
panic!("upb_Array_Resize failed.");
}
ptr::copy_nonoverlapping(
upb_Array_DataPtr(src.inner.raw).cast::<u8>(),
upb_Array_MutableDataPtr(self.inner.raw).cast::<u8>(),
size_of::<$rs_type>() * src.len());
upb_Array_DataPtr(src.as_raw(Private)).cast::<u8>(),
upb_Array_MutableDataPtr(dest.as_raw(Private)).cast::<u8>(),
size_of::<$t>() * src.len());
}
}
}
@ -435,6 +434,14 @@ macro_rules! impl_repeated_primitives {
}
}
impl<'msg, T: ?Sized> RepeatedMut<'msg, T> {
// Returns a `RawArena` which is live for at least `'msg`
#[doc(hidden)]
pub fn raw_arena(&self, _private: Private) -> RawArena {
self.inner.arena
}
}
impl_repeated_primitives!(
(bool, bool_val, UpbCType::Bool),
(f32, float_val, UpbCType::Float),
@ -442,29 +449,28 @@ impl_repeated_primitives!(
(i32, int32_val, UpbCType::Int32),
(u32, uint32_val, UpbCType::UInt32),
(i64, int64_val, UpbCType::Int64),
(u64, uint64_val, UpbCType::UInt64)
(u64, uint64_val, UpbCType::UInt64),
);
/// Returns a static thread-local empty RepeatedFieldInner for use in a
/// RepeatedView.
///
/// # Safety
/// The returned array must never be mutated.
///
/// TODO: Split RepeatedFieldInner into mut and const variants to
/// enforce safety. The returned array must never be mutated.
pub unsafe fn empty_array() -> RepeatedFieldInner<'static> {
// TODO: Consider creating empty array in C.
fn new_repeated_field_inner() -> RepeatedFieldInner<'static> {
let arena = Box::leak::<'static>(Box::new(Arena::new()));
// Provide `i32` as a placeholder type.
RepeatedField::<'static, i32>::new(arena).inner
}
thread_local! {
static REPEATED_FIELD: RepeatedFieldInner<'static> = new_repeated_field_inner();
}
/// Returns a static empty RepeatedView.
pub fn empty_array<T: ?Sized + ProxiedInRepeated>() -> RepeatedView<'static, T> {
// TODO: Consider creating a static empty array in C.
REPEATED_FIELD.with(|inner| *inner)
// Use `i32` for a shared empty repeated for all repeated types on a thread.
static EMPTY_REPEATED_VIEW: OnceLock<RepeatedView<'static, i32>> = OnceLock::new();
// SAFETY:
// - Because the repeated is never mutated, the repeated type is unused and
// therefore valid for `T`.
// - The view is leaked for `'static`.
unsafe {
RepeatedView::from_raw(
Private,
EMPTY_REPEATED_VIEW
.get_or_init(|| Box::leak(Box::new(Repeated::new())).as_mut().into_view())
.as_raw(Private),
)
}
}
/// Returns a static thread-local empty MapInner for use in a
@ -502,9 +508,6 @@ pub struct MapInner<'msg, K: ?Sized, V: ?Sized> {
pub _phantom_value: PhantomData<&'msg mut V>,
}
// These use manual impls instead of derives to avoid unnecessary bounds on `K`
// and `V`. This problem is referred to as "perfect derive".
// https://smallcultfollowing.com/babysteps/blog/2022/04/12/implied-bounds-and-perfect-derive/
impl<'msg, K: ?Sized, V: ?Sized> Copy for MapInner<'msg, K, V> {}
impl<'msg, K: ?Sized, V: ?Sized> Clone for MapInner<'msg, K, V> {
fn clone(&self) -> MapInner<'msg, K, V> {
@ -512,86 +515,27 @@ impl<'msg, K: ?Sized, V: ?Sized> Clone for MapInner<'msg, K, V> {
}
}
macro_rules! impl_scalar_map_for_key_type {
($key_t:ty, $key_ufield:ident, $key_upb_tag:expr, $trait:ident for $($t:ty, $ufield:ident, $upb_tag:expr, $zero_val:literal;)*) => {
paste! { $(
impl $trait for $t {
fn new_map(a: RawArena) -> RawMap {
unsafe { upb_Map_New(a, $key_upb_tag, $upb_tag) }
}
macro_rules! generate_map_key_ops_traits {
($($t:ty, $sized_t:ty;)*) => {
paste! {
$(
pub trait [< MapWith $t:camel KeyOps >] {
type Value<'msg>: Sized;
fn clear(m: RawMap) {
unsafe { upb_Map_Clear(m) }
}
fn size(m: RawMap) -> usize {
unsafe { upb_Map_Size(m) }
}
fn insert(m: RawMap, a: RawArena, key: $key_t, value: $t) -> bool {
unsafe {
upb_Map_Set(
m,
upb_MessageValue { $key_ufield: key },
upb_MessageValue { $ufield: value},
a
)
}
}
fn get(m: RawMap, key: $key_t) -> Option<$t> {
let mut val = upb_MessageValue { $ufield: $zero_val };
let found = unsafe {
upb_Map_Get(m, upb_MessageValue { $key_ufield: key }, &mut val)
};
if !found {
return None;
}
Some(unsafe { val.$ufield })
}
fn remove(m: RawMap, key: $key_t) -> Option<$t> {
let mut val = upb_MessageValue { $ufield: $zero_val };
let removed = unsafe {
upb_Map_Delete(m, upb_MessageValue { $key_ufield: key }, &mut val)
};
if !removed {
return None;
}
Some(unsafe { val.$ufield })
}
}
)* }
}
}
macro_rules! impl_scalar_map_for_key_types {
($($t:ty, $ufield:ident, $upb_tag:expr;)*) => {
paste! { $(
pub trait [< MapWith $t:camel KeyOps >] : Sync + Send + Copy + Clone + Debug {
fn new_map(a: RawArena) -> RawMap;
fn clear(m: RawMap);
fn size(m: RawMap) -> usize;
fn insert(m: RawMap, a: RawArena, key: $t, value: Self) -> bool;
fn get(m: RawMap, key: $t) -> Option<Self>
where
Self: Sized;
fn remove(m: RawMap, key: $t) -> Option<Self>
where
Self: Sized;
fn clear(m: RawMap) {
unsafe { upb_Map_Clear(m) }
}
fn size(m: RawMap) -> usize {
unsafe { upb_Map_Size(m) }
}
fn insert(m: RawMap, a: RawArena, key: $sized_t, value: Self::Value<'_>) -> bool;
fn get<'msg>(m: RawMap, key: $sized_t) -> Option<Self::Value<'msg>>;
fn remove(m: RawMap, key: $sized_t) -> bool;
}
impl_scalar_map_for_key_type!($t, $ufield, $upb_tag, [< MapWith $t:camel KeyOps >] for
f32, float_val, UpbCType::Float, 0f32;
f64, double_val, UpbCType::Double, 0f64;
i32, int32_val, UpbCType::Int32, 0i32;
u32, uint32_val, UpbCType::UInt32, 0u32;
i64, int64_val, UpbCType::Int64, 0i64;
u64, uint64_val, UpbCType::UInt64, 0u64;
bool, bool_val, UpbCType::Bool, false;
);
impl<'msg, V: [< MapWith $t:camel KeyOps >] + ?Sized> MapInner<'msg, $t, V> {
impl<'msg, V: [< MapWith $t:camel KeyOps >]> MapInner<'msg, $t, V> {
pub fn new(arena: &'msg mut Arena) -> Self {
MapInner {
raw: V::new_map(arena.raw()),
@ -609,28 +553,121 @@ macro_rules! impl_scalar_map_for_key_types {
V::clear(self.raw)
}
pub fn get(&self, key: $t) -> Option<V> {
pub fn get<'a>(&self, key: $sized_t) -> Option<V::Value<'a>> {
V::get(self.raw, key)
}
pub fn remove(&mut self, key: $t) -> Option<V> {
pub fn remove(&mut self, key: $sized_t) -> bool {
V::remove(self.raw, key)
}
pub fn insert(&mut self, key: $t, value: V) -> bool {
pub fn insert(&mut self, key: $sized_t, value: V::Value<'_>) -> bool {
V::insert(self.raw, self.arena.raw(), key, value)
}
}
)* }
)*
}
}
}
impl_scalar_map_for_key_types!(
i32, int32_val, UpbCType::Int32;
u32, uint32_val, UpbCType::UInt32;
i64, int64_val, UpbCType::Int64;
u64, uint64_val, UpbCType::UInt64;
bool, bool_val, UpbCType::Bool;
generate_map_key_ops_traits!(
i32, i32;
u32, u32;
i64, i64;
u64, u64;
bool, bool;
ProtoStr, &ProtoStr;
);
macro_rules! impl_scalar_map_key_op_for_scalar_values {
($key_t:ty, $key_msg_val:expr, $key_upb_tag:expr, $trait:ident for $($t:ty, $sized_t:ty, $msg_val:expr, $from_msg_val:expr, $upb_tag:expr, $zero_val:literal;)*) => {
$(
impl $trait for $t {
type Value<'msg> = $sized_t;
fn new_map(a: RawArena) -> RawMap {
unsafe { upb_Map_New(a, $key_upb_tag, $upb_tag) }
}
fn insert(m: RawMap, a: RawArena, key: $key_t, value: Self::Value<'_>) -> bool {
unsafe {
upb_Map_Set(
m,
$key_msg_val(key),
$msg_val(value),
a
)
}
}
fn get<'msg>(m: RawMap, key: $key_t) -> Option<Self::Value<'msg>> {
let mut val = $msg_val($zero_val);
let found = unsafe {
upb_Map_Get(m, $key_msg_val(key), &mut val)
};
if !found {
return None;
}
Some($from_msg_val(val))
}
fn remove(m: RawMap, key: $key_t) -> bool {
let mut val = $msg_val($zero_val);
unsafe {
upb_Map_Delete(m, $key_msg_val(key), &mut val)
}
}
}
)*
}
}
macro_rules! scalar_to_msg {
($ufield:ident) => {
|val| upb_MessageValue { $ufield: val }
};
}
macro_rules! scalar_from_msg {
($ufield:ident) => {
|msg: upb_MessageValue| unsafe { msg.$ufield }
};
}
fn str_to_msg<'msg>(val: impl Into<&'msg ProtoStr>) -> upb_MessageValue {
upb_MessageValue { str_val: val.into().as_bytes().into() }
}
fn msg_to_str<'msg>(msg: upb_MessageValue) -> &'msg ProtoStr {
unsafe { ProtoStr::from_utf8_unchecked(msg.str_val.as_ref()) }
}
macro_rules! impl_map_key_ops_for_scalar_values {
($($t:ty, $t_sized:ty, $key_msg_val:expr, $upb_tag:expr;)*) => {
paste! {
$(
impl_scalar_map_key_op_for_scalar_values!($t_sized, $key_msg_val, $upb_tag, [< MapWith $t:camel KeyOps >] for
f32, f32, scalar_to_msg!(float_val), scalar_from_msg!(float_val), UpbCType::Float, 0f32;
f64, f64, scalar_to_msg!(double_val), scalar_from_msg!(double_val), UpbCType::Double, 0f64;
i32, i32, scalar_to_msg!(int32_val), scalar_from_msg!(int32_val), UpbCType::Int32, 0i32;
u32, u32, scalar_to_msg!(uint32_val), scalar_from_msg!(uint32_val), UpbCType::UInt32, 0u32;
i64, i64, scalar_to_msg!(int64_val), scalar_from_msg!(int64_val), UpbCType::Int64, 0i64;
u64, u64, scalar_to_msg!(uint64_val), scalar_from_msg!(uint64_val), UpbCType::UInt64, 0u64;
bool, bool, scalar_to_msg!(bool_val), scalar_from_msg!(bool_val), UpbCType::Bool, false;
ProtoStr, &'msg ProtoStr, str_to_msg, msg_to_str, UpbCType::String, "";
);
)*
}
}
}
impl_map_key_ops_for_scalar_values!(
i32, i32, scalar_to_msg!(int32_val), UpbCType::Int32;
u32, u32, scalar_to_msg!(uint32_val), UpbCType::UInt32;
i64, i64, scalar_to_msg!(int64_val), UpbCType::Int64;
u64, u64, scalar_to_msg!(uint64_val), UpbCType::UInt64;
bool, bool, scalar_to_msg!(bool_val), UpbCType::Bool;
ProtoStr, &ProtoStr, |val: &ProtoStr| upb_MessageValue { str_val: val.as_bytes().into() }, UpbCType::String;
);
extern "C" {
@ -652,11 +689,17 @@ extern "C" {
}
#[cfg(test)]
pub(crate) fn new_map_inner() -> MapInner<'static, i32, i64> {
pub(crate) fn new_map_i32_i64() -> MapInner<'static, i32, i64> {
let arena = Box::leak::<'static>(Box::new(Arena::new()));
MapInner::<'static, i32, i64>::new(arena)
}
#[cfg(test)]
pub(crate) fn new_map_str_str() -> MapInner<'static, ProtoStr, ProtoStr> {
let arena = Box::leak::<'static>(Box::new(Arena::new()));
MapInner::<'static, ProtoStr, ProtoStr>::new(arena)
}
#[cfg(test)]
mod tests {
use super::*;
@ -684,37 +727,6 @@ mod tests {
assert_that!(&*serialized_data, eq(b"Hello world"));
}
#[test]
fn i32_array() {
let arena = Arena::new();
let mut arr = RepeatedField::<i32>::new(&arena);
assert_that!(arr.len(), eq(0));
arr.push(1);
assert_that!(arr.get(0), eq(Some(1)));
assert_that!(arr.len(), eq(1));
arr.set(0, 3);
assert_that!(arr.get(0), eq(Some(3)));
for i in 0..2048 {
arr.push(i);
assert_that!(arr.get(arr.len() - 1), eq(Some(i)));
}
}
#[test]
fn u32_array() {
let mut arena = Arena::new();
let mut arr = RepeatedField::<u32>::new(&mut arena);
assert_that!(arr.len(), eq(0));
arr.push(1);
assert_that!(arr.get(0), eq(Some(1)));
assert_that!(arr.len(), eq(1));
arr.set(0, 3);
assert_that!(arr.get(0), eq(Some(3)));
for i in 0..2048 {
arr.push(i);
assert_that!(arr.get(arr.len() - 1), eq(Some(i)));
}
}
#[test]
fn i32_i32_map() {
let mut arena = Arena::new();
@ -726,9 +738,9 @@ mod tests {
assert_that!(map.get(3), eq(None));
assert_that!(map.size(), eq(1));
assert_that!(map.remove(1), eq(Some(2)));
assert_that!(map.remove(1), eq(true));
assert_that!(map.size(), eq(0));
assert_that!(map.remove(1), eq(None));
assert_that!(map.remove(1), eq(false));
assert_that!(map.insert(4, 5), eq(true));
assert_that!(map.insert(6, 7), eq(true));
@ -747,13 +759,63 @@ mod tests {
assert_that!(map.get(3), eq(None));
assert_that!(map.size(), eq(1));
assert_that!(map.remove(1), eq(Some(2.5)));
assert_that!(map.remove(1), eq(true));
assert_that!(map.size(), eq(0));
assert_that!(map.remove(1), eq(None));
assert_that!(map.remove(1), eq(false));
assert_that!(map.insert(4, 5.1), eq(true));
assert_that!(map.insert(6, 7.2), eq(true));
map.clear();
assert_that!(map.size(), eq(0));
}
#[test]
fn str_str_map() {
let mut arena = Arena::new();
let mut map = MapInner::<'_, ProtoStr, ProtoStr>::new(&mut arena);
assert_that!(map.size(), eq(0));
map.insert("fizz".into(), "buzz".into());
assert_that!(map.size(), eq(1));
assert_that!(map.remove("fizz".into()), eq(true));
map.clear();
assert_that!(map.size(), eq(0));
}
#[test]
fn u64_str_map() {
let mut arena = Arena::new();
let mut map = MapInner::<'_, u64, ProtoStr>::new(&mut arena);
assert_that!(map.size(), eq(0));
map.insert(1, "fizz".into());
map.insert(2, "buzz".into());
assert_that!(map.size(), eq(2));
assert_that!(map.remove(1), eq(true));
map.clear();
assert_that!(map.size(), eq(0));
}
#[test]
fn test_all_maps_can_be_constructed() {
macro_rules! gen_proto_values {
($key_t:ty, $($value_t:ty),*) => {
let mut arena = Arena::new();
$(
let map = MapInner::<'_, $key_t, $value_t>::new(&mut arena);
assert_that!(map.size(), eq(0));
)*
}
}
macro_rules! gen_proto_keys {
($($key_t:ty),*) => {
$(
gen_proto_values!($key_t, f32, f64, i32, u32, i64, bool, ProtoStr);
)*
}
}
gen_proto_keys!(i32, u32, i64, u64, bool, ProtoStr);
}
}

View File

@ -6,12 +6,16 @@
// https://developers.google.com/open-source/licenses/bsd
use crate::__internal::{Private, PtrAndLen, RawMessage};
use crate::__runtime::{copy_bytes_in_arena_if_needed_by_runtime, MutatorMessageRef};
use crate::__runtime::{
copy_bytes_in_arena_if_needed_by_runtime, InnerPrimitiveMut, MutatorMessageRef,
};
use crate::{
AbsentField, FieldEntry, Mut, MutProxy, Optional, PresentField, Proxied, ProxiedWithPresence,
View, ViewProxy,
AbsentField, FieldEntry, Mut, MutProxy, Optional, PresentField, PrimitiveMut, Proxied,
ProxiedWithPresence, View, ViewProxy,
};
use std::fmt::{self, Debug};
use std::marker::PhantomData;
use std::ptr::NonNull;
/// A proxied type that can use a vtable to provide get/set access for a
/// present field.
@ -65,7 +69,8 @@ where
AbsentMutData<'msg> = RawVTableOptionalMutatorData<'msg, T>,
>,
{
let data = RawVTableOptionalMutatorData { msg_ref, vtable: optional_vtable };
// SAFETY: safe as promised by the caller of the function
let data = unsafe { RawVTableOptionalMutatorData::new(Private, msg_ref, optional_vtable) };
if is_set {
Optional::Set(PresentField::from_inner(Private, data))
} else {
@ -87,26 +92,29 @@ where
///
/// [`RawVTableOptionalMutatorData`] is similar, but also includes the
/// capability to has/clear.
pub struct RawVTableMutator<'msg, T: ProxiedWithRawVTable + ?Sized> {
pub struct RawVTableMutator<'msg, T: ?Sized> {
msg_ref: MutatorMessageRef<'msg>,
vtable: &'static T::VTable,
/// Stores `&'static <T as ProxiedWithRawVTable>::Vtable`
/// as a type-erased pointer to avoid a bound on the struct.
vtable: NonNull<()>,
_phantom: PhantomData<&'msg T>,
}
// These use manual impls instead of derives to avoid unnecessary bounds on `T`.
// This problem is referred to as "perfect derive".
// https://smallcultfollowing.com/babysteps/blog/2022/04/12/implied-bounds-and-perfect-derive/
impl<'msg, T: ProxiedWithRawVTable + ?Sized> Clone for RawVTableMutator<'msg, T> {
impl<'msg, T: ?Sized> Clone for RawVTableMutator<'msg, T> {
fn clone(&self) -> Self {
*self
}
}
impl<'msg, T: ProxiedWithRawVTable + ?Sized> Copy for RawVTableMutator<'msg, T> {}
impl<'msg, T: ?Sized> Copy for RawVTableMutator<'msg, T> {}
impl<'msg, T: ProxiedWithRawVTable + ?Sized> Debug for RawVTableMutator<'msg, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("RawVTableMutator")
.field("msg_ref", &self.msg_ref)
.field("vtable", &self.vtable)
.field("vtable", self.vtable())
.finish()
}
}
@ -123,7 +131,12 @@ impl<'msg, T: ProxiedWithRawVTable + ?Sized> RawVTableMutator<'msg, T> {
msg_ref: MutatorMessageRef<'msg>,
vtable: &'static T::VTable,
) -> Self {
RawVTableMutator { msg_ref, vtable }
RawVTableMutator { msg_ref, vtable: NonNull::from(vtable).cast(), _phantom: PhantomData }
}
fn vtable(self) -> &'static T::VTable {
// SAFETY: This was cast from `&'static T::VTable`.
unsafe { self.vtable.cast().as_ref() }
}
}
@ -136,30 +149,27 @@ impl<'msg, T: ProxiedWithRawVTable + ?Sized> RawVTableMutator<'msg, T> {
///
/// This has the same representation for "present" and "absent" data;
/// differences like default values are obviated by the vtable.
pub struct RawVTableOptionalMutatorData<'msg, T: ProxiedWithRawOptionalVTable + ?Sized> {
pub struct RawVTableOptionalMutatorData<'msg, T: ?Sized> {
msg_ref: MutatorMessageRef<'msg>,
vtable: &'static T::OptionalVTable,
/// Stores `&'static <T as ProxiedWithRawOptionalVTable>::Vtable`
/// as a type-erased pointer to avoid a bound on the struct.
optional_vtable: NonNull<()>,
_phantom: PhantomData<&'msg T>,
}
unsafe impl<'msg, T: ProxiedWithRawOptionalVTable + ?Sized> Sync
for RawVTableOptionalMutatorData<'msg, T>
{
}
// SAFETY: all `T` that can perform mutations don't mutate through a shared
// reference.
unsafe impl<'msg, T: ?Sized> Sync for RawVTableOptionalMutatorData<'msg, T> {}
// These use manual impls instead of derives to avoid unnecessary bounds on `T`.
// This problem is referred to as "perfect derive".
// https://smallcultfollowing.com/babysteps/blog/2022/04/12/implied-bounds-and-perfect-derive/
impl<'msg, T: ProxiedWithRawOptionalVTable + ?Sized> Clone
for RawVTableOptionalMutatorData<'msg, T>
{
impl<'msg, T: ?Sized> Clone for RawVTableOptionalMutatorData<'msg, T> {
fn clone(&self) -> Self {
*self
}
}
impl<'msg, T: ProxiedWithRawOptionalVTable + ?Sized> Copy
for RawVTableOptionalMutatorData<'msg, T>
{
}
impl<'msg, T: ?Sized> Copy for RawVTableOptionalMutatorData<'msg, T> {}
impl<'msg, T: ProxiedWithRawOptionalVTable + ?Sized> Debug
for RawVTableOptionalMutatorData<'msg, T>
@ -167,7 +177,7 @@ impl<'msg, T: ProxiedWithRawOptionalVTable + ?Sized> Debug
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("RawVTableOptionalMutatorData")
.field("msg_ref", &self.msg_ref)
.field("vtable", &self.vtable)
.field("vtable", self.optional_vtable())
.finish()
}
}
@ -184,11 +194,23 @@ impl<'msg, T: ProxiedWithRawOptionalVTable + ?Sized> RawVTableOptionalMutatorDat
msg_ref: MutatorMessageRef<'msg>,
vtable: &'static T::OptionalVTable,
) -> Self {
Self { msg_ref, vtable }
Self { msg_ref, optional_vtable: NonNull::from(vtable).cast(), _phantom: PhantomData }
}
fn optional_vtable(self) -> &'static T::OptionalVTable {
// SAFETY: This was cast from `&'static T::OptionalVTable` in `new`.
unsafe { self.optional_vtable.cast().as_ref() }
}
fn into_raw_mut(self) -> RawVTableMutator<'msg, T> {
RawVTableMutator { msg_ref: self.msg_ref, vtable: T::upcast_vtable(Private, self.vtable) }
// SAFETY: the safety requirements have been met by the caller of `new`.
unsafe {
RawVTableMutator::new(
Private,
self.msg_ref,
T::upcast_vtable(Private, self.optional_vtable()),
)
}
}
}
@ -291,32 +313,6 @@ impl<T> PrimitiveOptionalMutVTable<T> {
}
}
macro_rules! impl_raw_vtable_mutator_get_set {
($($t:ty),*) => {
$(
impl RawVTableMutator<'_, $t> {
pub(crate) fn get(self) -> $t {
// SAFETY:
// - `msg_ref` is valid for the lifetime of `RawVTableMutator` as promised by the
// caller of `new`.
unsafe { (self.vtable.getter)(self.msg_ref.msg()) }
}
/// # Safety
/// - `msg_ref` must be valid for the lifetime of `RawVTableMutator`.
pub(crate) unsafe fn set(self, val: $t) {
// SAFETY:
// - `msg_ref` is valid for the lifetime of `RawVTableMutator` as promised by the
// caller of `new`.
unsafe { (self.vtable.setter)(self.msg_ref.msg(), val) }
}
}
)*
}
}
impl_raw_vtable_mutator_get_set!(bool, f32, f64, i32, i64, u32, u64);
/// A generic thunk vtable for mutating a present `bytes` or `string` field.
#[doc(hidden)]
#[derive(Debug)]
@ -366,7 +362,7 @@ impl<'msg> RawVTableMutator<'msg, [u8]> {
// - `msg_ref` is valid for `'msg` as promised by the caller of `new`.
// - The caller of `BytesMutVTable` promised that the returned `PtrAndLen` is
// valid for `'msg`.
unsafe { (self.vtable.getter)(self.msg_ref.msg()).as_ref() }
unsafe { (self.vtable().getter)(self.msg_ref.msg()).as_ref() }
}
/// # Safety
@ -377,7 +373,7 @@ impl<'msg> RawVTableMutator<'msg, [u8]> {
let val = copy_bytes_in_arena_if_needed_by_runtime(self.msg_ref, val);
// SAFETY:
// - `msg_ref` is valid for `'msg` as promised by the caller of `new`.
unsafe { (self.vtable.setter)(self.msg_ref.msg(), val.into()) }
unsafe { (self.vtable().setter)(self.msg_ref.msg(), val.into()) }
}
pub(crate) fn truncate(&self, len: usize) {
@ -397,7 +393,7 @@ impl<'msg> RawVTableOptionalMutatorData<'msg, [u8]> {
pub(crate) fn set_absent_to_default(self) -> Self {
// SAFETY: The default value is UTF-8 if required by the
// runtime as promised by the caller of `BytesOptionalMutVTable::new`.
unsafe { self.set(self.vtable.default) }
unsafe { self.set(self.optional_vtable().default) }
}
/// # Safety
@ -407,7 +403,7 @@ impl<'msg> RawVTableOptionalMutatorData<'msg, [u8]> {
let val = copy_bytes_in_arena_if_needed_by_runtime(self.msg_ref, val);
// SAFETY:
// - `msg_ref` is valid for `'msg` as promised by the caller.
unsafe { (self.vtable.base.setter)(self.msg_ref.msg(), val.into()) }
unsafe { (self.optional_vtable().base.setter)(self.msg_ref.msg(), val.into()) }
self
}
@ -416,40 +412,96 @@ impl<'msg> RawVTableOptionalMutatorData<'msg, [u8]> {
// - `msg_ref` is valid for `'msg` as promised by the caller.
// - The caller of `new` promised that the returned `PtrAndLen` is valid for
// `'msg`.
unsafe { (self.vtable.clearer)(self.msg_ref.msg()) }
unsafe { (self.optional_vtable().clearer)(self.msg_ref.msg()) }
self
}
}
macro_rules! impl_raw_vtable_optional_mutator_data {
($($t:ty),*) => {
$(
impl<'msg> RawVTableOptionalMutatorData<'msg, $t> {
pub(crate) fn set_absent_to_default(self) -> Self {
// SAFETY:
// - `msg_ref` is valid for the lifetime of `RawVTableOptionalMutatorData` as
// promised by the caller of `new`.
self.set(self.vtable.default)
}
pub(crate) fn set(self, val: $t) -> Self {
// SAFETY:
// - `msg_ref` is valid for the lifetime of `RawVTableOptionalMutatorData` as
// promised by the caller of `new`.
unsafe { (self.vtable.base.setter)(self.msg_ref.msg(), val.into()) }
self
}
pub(crate) fn clear(self) -> Self {
// SAFETY:
// - `msg_ref` is valid for the lifetime of `RawVTableOptionalMutatorData` as
// promised by the caller of `new`.
unsafe { (self.vtable.clearer)(self.msg_ref.msg()) }
self
}
}
)*
}
/// Primitive types using a vtable for message access that are trivial to copy
/// and have a `'static` lifetime.
///
/// Implementing this trait automatically implements `ProxiedWithRawVTable`,
/// `ProxiedWithRawOptionalVTable`, and get/set/clear methods on
/// `RawVTableMutator` and `RawVTableOptionalMutatorData` that use the vtable.
///
/// It doesn't implement `Proxied`, `ViewProxy`, `SettableValue` or
/// `ProxiedWithPresence` for `Self` to avoid future conflicting blanket impls
/// on those traits.
pub trait PrimitiveWithRawVTable:
Copy
+ Debug
+ 'static
+ ProxiedWithPresence
+ Sync
+ Send
+ for<'msg> Proxied<View<'msg> = Self, Mut<'msg> = PrimitiveMut<'msg, Self>>
{
}
impl_raw_vtable_optional_mutator_data!(bool, f32, f64, i32, i64, u32, u64);
impl<T: PrimitiveWithRawVTable> ProxiedWithRawVTable for T {
type VTable = PrimitiveVTable<T>;
fn make_view(_private: Private, mut_inner: InnerPrimitiveMut<'_, Self>) -> Self {
mut_inner.get()
}
fn make_mut(_private: Private, inner: InnerPrimitiveMut<'_, Self>) -> PrimitiveMut<'_, Self> {
// SAFETY: `inner` is valid for the necessary lifetime and `T` as promised by
// the caller of `InnerPrimitiveMut::new`.
unsafe { PrimitiveMut::from_inner(Private, inner) }
}
}
impl<T: PrimitiveWithRawVTable> ProxiedWithRawOptionalVTable for T {
type OptionalVTable = PrimitiveOptionalMutVTable<T>;
fn upcast_vtable(
_private: Private,
optional_vtable: &'static Self::OptionalVTable,
) -> &'static Self::VTable {
&optional_vtable.base
}
}
impl<T: PrimitiveWithRawVTable> RawVTableMutator<'_, T> {
pub(crate) fn get(self) -> T {
// SAFETY:
// - `msg_ref` is valid for the lifetime of `RawVTableMutator` as promised by
// the caller of `new`.
unsafe { (self.vtable().getter)(self.msg_ref.msg()) }
}
/// # Safety
/// - `msg_ref` must be valid for the lifetime of `RawVTableMutator`.
pub(crate) unsafe fn set(self, val: T) {
// SAFETY:
// - `msg_ref` is valid for the lifetime of `RawVTableMutator` as promised by
// the caller of `new`.
unsafe { (self.vtable().setter)(self.msg_ref.msg(), val) }
}
}
impl<'msg, T: PrimitiveWithRawVTable> RawVTableOptionalMutatorData<'msg, T> {
pub(crate) fn set_absent_to_default(self) -> Self {
// SAFETY:
// - `msg_ref` is valid for the lifetime of `RawVTableOptionalMutatorData` as
// promised by the caller of `new`.
self.set(self.optional_vtable().default)
}
pub(crate) fn set(self, val: T) -> Self {
// SAFETY:
// - `msg_ref` is valid for the lifetime of `RawVTableOptionalMutatorData` as
// promised by the caller of `new`.
unsafe { (self.optional_vtable().base.setter)(self.msg_ref.msg(), val) }
self
}
pub(crate) fn clear(self) -> Self {
// SAFETY:
// - `msg_ref` is valid for the lifetime of `RawVTableOptionalMutatorData` as
// promised by the caller of `new`.
unsafe { (self.optional_vtable().clearer)(self.msg_ref.msg()) }
self
}
}

View File

@ -116,7 +116,6 @@ set(libprotobuf_hdrs
${protobuf_SOURCE_DIR}/src/google/protobuf/descriptor.h
${protobuf_SOURCE_DIR}/src/google/protobuf/descriptor.pb.h
${protobuf_SOURCE_DIR}/src/google/protobuf/descriptor_database.h
${protobuf_SOURCE_DIR}/src/google/protobuf/descriptor_legacy.h
${protobuf_SOURCE_DIR}/src/google/protobuf/descriptor_lite.h
${protobuf_SOURCE_DIR}/src/google/protobuf/descriptor_visitor.h
${protobuf_SOURCE_DIR}/src/google/protobuf/dynamic_message.h
@ -287,7 +286,6 @@ set(libprotobuf_lite_hdrs
# @//pkg:protoc
set(libprotoc_srcs
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/allowlists/editions.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/allowlists/empty_package.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/allowlists/open_enum.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/code_generator.cc
@ -651,6 +649,7 @@ set(test_util_srcs
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/annotation_test_util.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/reflection_tester.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/test_util.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/unredacted_debug_format_for_test.cc
)
# @//pkg:test_util
@ -666,6 +665,7 @@ set(test_util_hdrs
${protobuf_SOURCE_DIR}/src/google/protobuf/reflection_tester.h
${protobuf_SOURCE_DIR}/src/google/protobuf/test_util.h
${protobuf_SOURCE_DIR}/src/google/protobuf/test_util.inc
${protobuf_SOURCE_DIR}/src/google/protobuf/unredacted_debug_format_for_test.h
${protobuf_SOURCE_DIR}/src/google/protobuf/wire_format_unittest.inc
)
@ -708,6 +708,8 @@ set(protobuf_test_files
${protobuf_SOURCE_DIR}/src/google/protobuf/string_block_test.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/text_format_unittest.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/unknown_field_set_unittest.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/unredacted_debug_format_for_test.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/unredacted_debug_format_for_test_test.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/varint_shuffle_test.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/well_known_types_unittest.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/wire_format_unittest.cc
@ -795,6 +797,7 @@ set(compiler_test_files
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/names_unittest.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/text_format_decode_data_unittest.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/parser_unittest.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/php/generator_unittest.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/python/plugin_unittest.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/retention_unittest.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/ruby/ruby_generator_unittest.cc

View File

@ -486,7 +486,6 @@ cc_library(
"descriptor.h",
"descriptor.pb.h",
"descriptor_database.h",
"descriptor_legacy.h",
"descriptor_visitor.h",
"dynamic_message.h",
"feature_resolver.h",
@ -581,20 +580,6 @@ cc_library(
strip_include_prefix = "/src",
)
cc_library(
name = "descriptor_legacy",
hdrs = ["descriptor_legacy.h"],
copts = COPTS,
linkopts = LINK_OPTS,
strip_include_prefix = "/src",
visibility = ["//:__subpackages__"],
deps = [
":port_def",
":protobuf_nowkt",
"@com_google_absl//absl/strings",
],
)
cc_library(
name = "descriptor_visitor",
hdrs = ["descriptor_visitor.h"],
@ -1044,7 +1029,6 @@ cc_test(
}),
deps = [
":cc_test_protos",
":descriptor_legacy",
":protobuf",
":test_textproto",
"//src/google/protobuf/compiler:importer",
@ -1340,7 +1324,6 @@ cc_test(
}),
deps = [
":cc_test_protos",
":descriptor_legacy",
":protobuf",
":test_util",
"//src/google/protobuf/stubs",
@ -1570,6 +1553,30 @@ cc_test(
],
)
cc_library(
name = "unredacted_debug_format_for_test",
testonly = True,
srcs = ["unredacted_debug_format_for_test.cc"],
hdrs = ["unredacted_debug_format_for_test.h"],
strip_include_prefix = "/src",
visibility = ["//visibility:public"],
deps = [
":protobuf",
],
)
cc_test(
name = "unredacted_debug_format_for_test_test",
srcs = ["unredacted_debug_format_for_test_test.cc"],
deps = [
":cc_lite_test_protos",
":cc_test_protos",
":protobuf",
":unredacted_debug_format_for_test",
"@com_google_googletest//:gtest_main",
],
)
################################################################################
# Helper targets for Kotlin tests
################################################################################

View File

@ -124,9 +124,6 @@ const ::_pbi::DescriptorTable descriptor_table_google_2fprotobuf_2fany_2eproto =
PROTOBUF_ATTRIBUTE_WEAK const ::_pbi::DescriptorTable* descriptor_table_google_2fprotobuf_2fany_2eproto_getter() {
return &descriptor_table_google_2fprotobuf_2fany_2eproto;
}
// Force running AddDescriptors() at dynamic initialization time.
PROTOBUF_ATTRIBUTE_INIT_PRIORITY2
static ::_pbi::AddDescriptorsRunner dynamic_init_dummy_google_2fprotobuf_2fany_2eproto(&descriptor_table_google_2fprotobuf_2fany_2eproto);
namespace google {
namespace protobuf {
// ===================================================================
@ -198,12 +195,15 @@ inline void Any::SharedDtor() {
const ::google::protobuf::MessageLite::ClassData*
Any::GetClassData() const {
PROTOBUF_CONSTINIT static const ::google::protobuf::MessageLite::ClassData
_data_ = {
Any::MergeImpl,
nullptr, // OnDemandRegisterArenaDtor
&::google::protobuf::Message::kDescriptorMethods,
PROTOBUF_CONSTINIT static const ::google::protobuf::MessageLite::
ClassDataFull _data_ = {
{
nullptr, // OnDemandRegisterArenaDtor
PROTOBUF_FIELD_OFFSET(Any, _impl_._cached_size_),
false,
},
&Any::MergeImpl,
&Any::kDescriptorMethods,
};
return &_data_;
}
@ -360,9 +360,9 @@ void Any::InternalSwap(Any* PROTOBUF_RESTRICT other) {
}
::google::protobuf::Metadata Any::GetMetadata() const {
return ::_pbi::AssignDescriptors(
&descriptor_table_google_2fprotobuf_2fany_2eproto_getter, &descriptor_table_google_2fprotobuf_2fany_2eproto_once,
file_level_metadata_google_2fprotobuf_2fany_2eproto[0]);
return ::_pbi::AssignDescriptors(&descriptor_table_google_2fprotobuf_2fany_2eproto_getter,
&descriptor_table_google_2fprotobuf_2fany_2eproto_once,
file_level_metadata_google_2fprotobuf_2fany_2eproto[0]);
}
// @@protoc_insertion_point(namespace_scope)
} // namespace protobuf
@ -375,4 +375,8 @@ namespace protobuf {
#if defined(__llvm__)
#pragma clang diagnostic pop
#endif // __llvm__
PROTOBUF_ATTRIBUTE_INIT_PRIORITY2
static ::std::false_type _static_init_ PROTOBUF_UNUSED =
(::_pbi::AddDescriptors(&descriptor_table_google_2fprotobuf_2fany_2eproto),
::std::false_type{});
#include "google/protobuf/port_undef.inc"

View File

@ -238,9 +238,6 @@ const ::_pbi::DescriptorTable descriptor_table_google_2fprotobuf_2fapi_2eproto =
PROTOBUF_ATTRIBUTE_WEAK const ::_pbi::DescriptorTable* descriptor_table_google_2fprotobuf_2fapi_2eproto_getter() {
return &descriptor_table_google_2fprotobuf_2fapi_2eproto;
}
// Force running AddDescriptors() at dynamic initialization time.
PROTOBUF_ATTRIBUTE_INIT_PRIORITY2
static ::_pbi::AddDescriptorsRunner dynamic_init_dummy_google_2fprotobuf_2fapi_2eproto(&descriptor_table_google_2fprotobuf_2fapi_2eproto);
namespace google {
namespace protobuf {
// ===================================================================
@ -328,12 +325,15 @@ inline void Api::SharedDtor() {
const ::google::protobuf::MessageLite::ClassData*
Api::GetClassData() const {
PROTOBUF_CONSTINIT static const ::google::protobuf::MessageLite::ClassData
_data_ = {
Api::MergeImpl,
nullptr, // OnDemandRegisterArenaDtor
&::google::protobuf::Message::kDescriptorMethods,
PROTOBUF_CONSTINIT static const ::google::protobuf::MessageLite::
ClassDataFull _data_ = {
{
nullptr, // OnDemandRegisterArenaDtor
PROTOBUF_FIELD_OFFSET(Api, _impl_._cached_size_),
false,
},
&Api::MergeImpl,
&Api::kDescriptorMethods,
};
return &_data_;
}
@ -637,9 +637,9 @@ void Api::InternalSwap(Api* PROTOBUF_RESTRICT other) {
}
::google::protobuf::Metadata Api::GetMetadata() const {
return ::_pbi::AssignDescriptors(
&descriptor_table_google_2fprotobuf_2fapi_2eproto_getter, &descriptor_table_google_2fprotobuf_2fapi_2eproto_once,
file_level_metadata_google_2fprotobuf_2fapi_2eproto[0]);
return ::_pbi::AssignDescriptors(&descriptor_table_google_2fprotobuf_2fapi_2eproto_getter,
&descriptor_table_google_2fprotobuf_2fapi_2eproto_once,
file_level_metadata_google_2fprotobuf_2fapi_2eproto[0]);
}
// ===================================================================
@ -717,12 +717,15 @@ inline void Method::SharedDtor() {
const ::google::protobuf::MessageLite::ClassData*
Method::GetClassData() const {
PROTOBUF_CONSTINIT static const ::google::protobuf::MessageLite::ClassData
_data_ = {
Method::MergeImpl,
nullptr, // OnDemandRegisterArenaDtor
&::google::protobuf::Message::kDescriptorMethods,
PROTOBUF_CONSTINIT static const ::google::protobuf::MessageLite::
ClassDataFull _data_ = {
{
nullptr, // OnDemandRegisterArenaDtor
PROTOBUF_FIELD_OFFSET(Method, _impl_._cached_size_),
false,
},
&Method::MergeImpl,
&Method::kDescriptorMethods,
};
return &_data_;
}
@ -1006,9 +1009,9 @@ void Method::InternalSwap(Method* PROTOBUF_RESTRICT other) {
}
::google::protobuf::Metadata Method::GetMetadata() const {
return ::_pbi::AssignDescriptors(
&descriptor_table_google_2fprotobuf_2fapi_2eproto_getter, &descriptor_table_google_2fprotobuf_2fapi_2eproto_once,
file_level_metadata_google_2fprotobuf_2fapi_2eproto[1]);
return ::_pbi::AssignDescriptors(&descriptor_table_google_2fprotobuf_2fapi_2eproto_getter,
&descriptor_table_google_2fprotobuf_2fapi_2eproto_once,
file_level_metadata_google_2fprotobuf_2fapi_2eproto[1]);
}
// ===================================================================
@ -1064,12 +1067,15 @@ inline void Mixin::SharedDtor() {
const ::google::protobuf::MessageLite::ClassData*
Mixin::GetClassData() const {
PROTOBUF_CONSTINIT static const ::google::protobuf::MessageLite::ClassData
_data_ = {
Mixin::MergeImpl,
nullptr, // OnDemandRegisterArenaDtor
&::google::protobuf::Message::kDescriptorMethods,
PROTOBUF_CONSTINIT static const ::google::protobuf::MessageLite::
ClassDataFull _data_ = {
{
nullptr, // OnDemandRegisterArenaDtor
PROTOBUF_FIELD_OFFSET(Mixin, _impl_._cached_size_),
false,
},
&Mixin::MergeImpl,
&Mixin::kDescriptorMethods,
};
return &_data_;
}
@ -1229,9 +1235,9 @@ void Mixin::InternalSwap(Mixin* PROTOBUF_RESTRICT other) {
}
::google::protobuf::Metadata Mixin::GetMetadata() const {
return ::_pbi::AssignDescriptors(
&descriptor_table_google_2fprotobuf_2fapi_2eproto_getter, &descriptor_table_google_2fprotobuf_2fapi_2eproto_once,
file_level_metadata_google_2fprotobuf_2fapi_2eproto[2]);
return ::_pbi::AssignDescriptors(&descriptor_table_google_2fprotobuf_2fapi_2eproto_getter,
&descriptor_table_google_2fprotobuf_2fapi_2eproto_once,
file_level_metadata_google_2fprotobuf_2fapi_2eproto[2]);
}
// @@protoc_insertion_point(namespace_scope)
} // namespace protobuf
@ -1241,4 +1247,8 @@ namespace protobuf {
} // namespace protobuf
} // namespace google
// @@protoc_insertion_point(global_scope)
PROTOBUF_ATTRIBUTE_INIT_PRIORITY2
static ::std::false_type _static_init_ PROTOBUF_UNUSED =
(::_pbi::AddDescriptors(&descriptor_table_google_2fprotobuf_2fapi_2eproto),
::std::false_type{});
#include "google/protobuf/port_undef.inc"

View File

@ -405,16 +405,15 @@ class PROTOBUF_EXPORT Method final : public ::google::protobuf::Message
public:
void clear_options() ;
::google::protobuf::Option* mutable_options(int index);
::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >*
mutable_options();
::google::protobuf::RepeatedPtrField<::google::protobuf::Option>* mutable_options();
private:
const ::google::protobuf::RepeatedPtrField<::google::protobuf::Option>& _internal_options() const;
::google::protobuf::RepeatedPtrField<::google::protobuf::Option>* _internal_mutable_options();
public:
const ::google::protobuf::Option& options(int index) const;
::google::protobuf::Option* add_options();
const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >&
options() const;
const ::google::protobuf::RepeatedPtrField<::google::protobuf::Option>& options() const;
// string name = 1;
void clear_name() ;
const std::string& name() const;
@ -670,16 +669,15 @@ class PROTOBUF_EXPORT Api final : public ::google::protobuf::Message
public:
void clear_methods() ;
::google::protobuf::Method* mutable_methods(int index);
::google::protobuf::RepeatedPtrField< ::google::protobuf::Method >*
mutable_methods();
::google::protobuf::RepeatedPtrField<::google::protobuf::Method>* mutable_methods();
private:
const ::google::protobuf::RepeatedPtrField<::google::protobuf::Method>& _internal_methods() const;
::google::protobuf::RepeatedPtrField<::google::protobuf::Method>* _internal_mutable_methods();
public:
const ::google::protobuf::Method& methods(int index) const;
::google::protobuf::Method* add_methods();
const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Method >&
methods() const;
const ::google::protobuf::RepeatedPtrField<::google::protobuf::Method>& methods() const;
// repeated .google.protobuf.Option options = 3;
int options_size() const;
private:
@ -688,16 +686,15 @@ class PROTOBUF_EXPORT Api final : public ::google::protobuf::Message
public:
void clear_options() ;
::google::protobuf::Option* mutable_options(int index);
::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >*
mutable_options();
::google::protobuf::RepeatedPtrField<::google::protobuf::Option>* mutable_options();
private:
const ::google::protobuf::RepeatedPtrField<::google::protobuf::Option>& _internal_options() const;
::google::protobuf::RepeatedPtrField<::google::protobuf::Option>* _internal_mutable_options();
public:
const ::google::protobuf::Option& options(int index) const;
::google::protobuf::Option* add_options();
const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >&
options() const;
const ::google::protobuf::RepeatedPtrField<::google::protobuf::Option>& options() const;
// repeated .google.protobuf.Mixin mixins = 6;
int mixins_size() const;
private:
@ -706,16 +703,15 @@ class PROTOBUF_EXPORT Api final : public ::google::protobuf::Message
public:
void clear_mixins() ;
::google::protobuf::Mixin* mutable_mixins(int index);
::google::protobuf::RepeatedPtrField< ::google::protobuf::Mixin >*
mutable_mixins();
::google::protobuf::RepeatedPtrField<::google::protobuf::Mixin>* mutable_mixins();
private:
const ::google::protobuf::RepeatedPtrField<::google::protobuf::Mixin>& _internal_mixins() const;
::google::protobuf::RepeatedPtrField<::google::protobuf::Mixin>* _internal_mutable_mixins();
public:
const ::google::protobuf::Mixin& mixins(int index) const;
::google::protobuf::Mixin* add_mixins();
const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Mixin >&
mixins() const;
const ::google::protobuf::RepeatedPtrField<::google::protobuf::Mixin>& mixins() const;
// string name = 1;
void clear_name() ;
const std::string& name() const;

View File

@ -953,20 +953,6 @@ TEST(ArenaTest, AddAllocatedWithReflection) {
}
TEST(ArenaTest, RepeatedPtrFieldAddClearedTest) {
#ifndef PROTOBUF_FUTURE_REMOVE_CLEARED_API
{
PROTOBUF_IGNORE_DEPRECATION_START
RepeatedPtrField<TestAllTypes> repeated_field;
EXPECT_TRUE(repeated_field.empty());
EXPECT_EQ(0, repeated_field.size());
// Ownership is passed to repeated_field.
TestAllTypes* cleared = new TestAllTypes();
repeated_field.AddCleared(cleared);
EXPECT_TRUE(repeated_field.empty());
EXPECT_EQ(0, repeated_field.size());
PROTOBUF_IGNORE_DEPRECATION_STOP
}
#endif // !PROTOBUF_FUTURE_REMOVE_CLEARED_API
{
RepeatedPtrField<TestAllTypes> repeated_field;
EXPECT_TRUE(repeated_field.empty());

View File

@ -72,5 +72,5 @@ option objc_class_prefix = "GPB";
message MessageSet {
option message_set_wire_format = true;
extensions 4 to max;
extensions 4 to max [verification = UNVERIFIED];
}

View File

@ -133,7 +133,6 @@ cc_library(
":code_generator",
":importer",
":retention",
"//src/google/protobuf:descriptor_legacy",
"//src/google/protobuf:protobuf_nowkt",
"//src/google/protobuf/compiler/allowlists",
"@com_google_absl//absl/algorithm",
@ -279,7 +278,6 @@ cc_library(
deps = [
":code_generator",
"//src/google/protobuf:cc_test_protos",
"//src/google/protobuf:descriptor_legacy",
"//src/google/protobuf:descriptor_visitor",
"//src/google/protobuf/io",
"//src/google/protobuf/stubs",

Some files were not shown because too many files have changed in this diff Show More