Merge branch 'protocolbuffers:main' into main

pull/17035/head
oguzcan oguz 5 months ago committed by GitHub
commit 2b9d55b485
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 3
      .bcr/presubmit.yml
  2. 2
      .github/workflows/test_bazel.yml
  3. 14
      .github/workflows/test_cpp.yml
  4. 8
      .github/workflows/test_java.yml
  5. 12
      .github/workflows/test_ruby.yml
  6. 12
      .github/workflows/test_upb.yml
  7. 2
      .readthedocs.yml
  8. 10
      BUILD.bazel
  9. 51
      MODULE.bazel
  10. 10
      WORKSPACE
  11. 78
      bazel/private/upb_proto_library_internal/aspect.bzl
  12. 17
      bazel/py_proto_library.bzl
  13. 1
      compatibility/BUILD.bazel
  14. 32
      conformance/binary_json_conformance_suite.cc
  15. 30
      conformance/test_protos/test_messages_edition2023.proto
  16. 312
      csharp/src/Google.Protobuf.Test.TestProtos/TestMessagesEdition2023.pb.cs
  17. BIN
      csharp/src/Google.Protobuf.Test/testprotos.pb
  18. 5
      csharp/src/Google.Protobuf/Reflection/Descriptor.pb.cs
  19. 5
      csharp/src/Google.Protobuf/Reflection/FieldDescriptor.cs
  20. 5
      docs/options.md
  21. 16
      editions/BUILD
  22. 0
      hpb_generator/BUILD
  23. 0
      hpb_generator/README.md
  24. 10
      hpb_generator/gen_accessors.cc
  25. 4
      hpb_generator/gen_accessors.h
  26. 6
      hpb_generator/gen_enums.cc
  27. 2
      hpb_generator/gen_enums.h
  28. 6
      hpb_generator/gen_extensions.cc
  29. 2
      hpb_generator/gen_extensions.h
  30. 14
      hpb_generator/gen_messages.cc
  31. 2
      hpb_generator/gen_messages.h
  32. 14
      hpb_generator/gen_repeated_fields.cc
  33. 2
      hpb_generator/gen_repeated_fields.h
  34. 2
      hpb_generator/gen_utils.cc
  35. 0
      hpb_generator/gen_utils.h
  36. 2
      hpb_generator/names.cc
  37. 2
      hpb_generator/names.h
  38. 2
      hpb_generator/output.cc
  39. 0
      hpb_generator/output.h
  40. 38
      hpb_generator/protoc-gen-upb-protos.cc
  41. 13
      hpb_generator/tests/BUILD
  42. 18
      hpb_generator/tests/basic_test_editions.proto
  43. 2
      hpb_generator/tests/child_model.proto
  44. 0
      hpb_generator/tests/legacy-name.proto
  45. 0
      hpb_generator/tests/naming_conflict.proto
  46. 0
      hpb_generator/tests/no_package.proto
  47. 2
      hpb_generator/tests/no_package_enum_user.proto
  48. 0
      hpb_generator/tests/test_enum.proto
  49. 2
      hpb_generator/tests/test_extension.proto
  50. 6
      hpb_generator/tests/test_generated.cc
  51. 2
      hpb_generator/tests/test_model.proto
  52. 6
      java/core/BUILD.bazel
  53. 56
      java/core/src/main/java/com/google/protobuf/Descriptors.java
  54. 43
      java/core/src/main/java/com/google/protobuf/GeneratedMessage.java
  55. 83
      java/core/src/main/java/com/google/protobuf/GeneratedMessageV3.java
  56. 34
      java/core/src/main/java/com/google/protobuf/RepeatedFieldBuilderV3.java
  57. 28
      java/core/src/main/java/com/google/protobuf/SingleFieldBuilderV3.java
  58. 152
      java/core/src/test/java/com/google/protobuf/DescriptorsTest.java
  59. 1
      java/core/src/test/proto/com/google/protobuf/lite_equals_and_hash.proto
  60. 139
      php/ext/google/protobuf/php-upb.c
  61. 217
      php/ext/google/protobuf/php-upb.h
  62. 12
      php/ext/google/protobuf/protobuf.c
  63. 16
      protobuf_deps.bzl
  64. 6
      protos/BUILD
  65. 8
      protos/bazel/upb_cc_proto_library.bzl
  66. 8
      protos/protos_extension_lock_test.cc
  67. 4
      protos/protos_internal_test.cc
  68. 12
      python/dist/system_python.bzl
  69. 3
      python/google/protobuf/descriptor.py
  70. 10
      python/google/protobuf/internal/descriptor_pool_test.py
  71. 13
      python/google/protobuf/internal/message_test.py
  72. 8
      python/google/protobuf/internal/more_messages.proto
  73. 38
      python/google/protobuf/internal/pybind11_test_module.cc
  74. 43
      python/google/protobuf/internal/python_message.py
  75. 44
      python/google/protobuf/internal/recursive_message_pybind11_test.py
  76. 22
      python/google/protobuf/internal/self_recursive.proto
  77. 20
      python/google/protobuf/internal/self_recursive_from_py.proto
  78. 51
      python/google/protobuf/internal/well_known_types.py
  79. 236
      python/google/protobuf/internal/well_known_types_test.py
  80. 16
      python/google/protobuf/message_factory.py
  81. 240
      python/google/protobuf/pyext/message.cc
  82. 5
      python/google/protobuf/text_format.py
  83. 10
      python/map.c
  84. 65
      python/message.c
  85. 4
      python/protobuf.c
  86. 1
      ruby/ext/google/protobuf_c/map.c
  87. 5
      ruby/ext/google/protobuf_c/message.c
  88. 1
      ruby/ext/google/protobuf_c/repeated_field.c
  89. 139
      ruby/ext/google/protobuf_c/ruby-upb.c
  90. 217
      ruby/ext/google/protobuf_c/ruby-upb.h
  91. 5
      rust/cpp.rs
  92. 7
      rust/cpp_kernel/cpp_api.cc
  93. 2
      rust/cpp_kernel/cpp_api.h
  94. 2
      rust/proxied.rs
  95. 8
      rust/repeated.rs
  96. 5
      rust/shared.rs
  97. 17
      rust/test/BUILD
  98. 22
      rust/test/benchmarks/BUILD
  99. 10
      rust/test/benchmarks/rust_protobuf_benchmarks.cc
  100. 12
      rust/test/cpp/debug_test.rs
  101. Some files were not shown because too many files have changed in this diff Show More

@ -13,6 +13,8 @@ tasks:
build_targets:
- '@protobuf//:protobuf'
- '@protobuf//:protobuf_lite'
- '@protobuf//:protobuf_python'
- '@protobuf//:protobuf_rust'
- '@protobuf//:protoc'
- '@protobuf//:test_messages_proto2_cc_proto'
- '@protobuf//:test_messages_proto3_cc_proto'
@ -20,7 +22,6 @@ tasks:
bcr_test_module:
module_path: "examples"
matrix:
platform: ["debian10", "macos", "ubuntu2004", "windows"]
bazel: [6.x, 7.x]
tasks:

@ -17,7 +17,7 @@ jobs:
fail-fast: false
matrix:
runner: [ ubuntu, windows, macos ]
bazelversion: [ '7.1.1' ]
bazelversion: [ '7.1.2' ]
bzlmod: [true, false ]
include:
- runner: ubuntu

@ -26,19 +26,19 @@ jobs:
- { name: No-RTTI, flags: --cxxopt=-fno-rtti }
include:
# Set defaults
- image: us-docker.pkg.dev/protobuf-build/containers/test/linux/sanitize@sha256:04cd765285bc52cbbf51d66c8c66d8603579cf0f19cc42df26b09d2c270541fb
- image: us-docker.pkg.dev/protobuf-build/containers/test/linux/sanitize@sha256:3d959f731dc5c54af4865c31ee2bd581ec40028adcdf4c038f3122581f595191
- 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.1.1-75f2a85ece6526cc3d54087018c0f1097d78d42b"
image: "us-docker.pkg.dev/protobuf-build/containers/common/linux/bazel:7.1.2-cf84e92285ca133b9c8104ad7b14d70e953cbb8e"
targets: "//src/... //third_party/utf8_range/..."
- config: { name: "TCMalloc" }
image: "us-docker.pkg.dev/protobuf-build/containers/test/linux/tcmalloc@sha256:bd39119d74b8a3fad4ae335d4cf5294e70384676331b7e19949459fc7a8d8328"
image: "us-docker.pkg.dev/protobuf-build/containers/test/linux/tcmalloc@sha256:1c5133455481f4d1bb8afa477029604f41f1a3c46cebe4d9958cf1af95b5c87c"
targets: "//src/... //third_party/utf8_range/..."
- config: { name: "aarch64" }
targets: "//src/... //src/google/protobuf/compiler:protoc_aarch64_test //third_party/utf8_range/..."
image: "us-docker.pkg.dev/protobuf-build/containers/test/linux/emulation:aarch64-63dd26c0c7a808d92673a3e52e848189d4ab0f17"
image: "us-docker.pkg.dev/protobuf-build/containers/test/linux/emulation:6.3.0-aarch64-68e662b3a56b881804dc4e9d45f949791cbc4b94"
name: Linux ${{ matrix.config.name }}
runs-on: ${{ matrix.config.runner || 'ubuntu-latest' }}
steps:
@ -102,7 +102,7 @@ jobs:
- name: Run tests
uses: protocolbuffers/protobuf-ci/docker@v3
with:
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/emulation:${{ matrix.arch }}-63dd26c0c7a808d92673a3e52e848189d4ab0f17
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/emulation:${{ matrix.arch }}-384d5abe83a791c6b1ce04f5d7bc0b1f84a30d38
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
entrypoint: bash
command: >
@ -328,7 +328,7 @@ jobs:
os: macos-12
cache_key: macos-12-bazel7
bazel: test //src/... //third_party/utf8_range/...
bazel_version: '7.1.1'
bazel_version: '7.1.2'
- name: MacOS Apple Silicon (build only) Bazel
os: macos-12
cache_key: macos-12-arm
@ -343,7 +343,7 @@ jobs:
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.1.1'
bazel_version: '7.1.2'
name: ${{ matrix.name }}
runs-on: ${{ matrix.os }}
steps:

@ -22,19 +22,19 @@ jobs:
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/java:8-1fdbb997433cb22c1e49ef75ad374a8d6bb88702
# TODO: b/318555165 - enable the layering check. Currently it does
# not work correctly with the toolchain in this Docker image.
targets: //java/... //java/internal:java_version --features=-layering_check
targets: //java/... //java/internal:java_version //compatibility/... --features=-layering_check
- name: OpenJDK 11
version: '11'
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/java:11-1fdbb997433cb22c1e49ef75ad374a8d6bb88702
targets: //java/... //java/internal:java_version
targets: //java/... //java/internal:java_version //compatibility/...
- name: OpenJDK 17
version: '17'
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/java:17-1fdbb997433cb22c1e49ef75ad374a8d6bb88702
targets: //java/... //java/internal:java_version
targets: //java/... //java/internal:java_version //compatibility/...
- name: aarch64
version: 'aarch64'
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/emulation:aarch64-63dd26c0c7a808d92673a3e52e848189d4ab0f17
targets: //java/... //src/google/protobuf/compiler:protoc_aarch64_test
targets: //java/... //compatibility/... //src/google/protobuf/compiler:protoc_aarch64_test
name: Linux ${{ matrix.name }}
runs-on: ubuntu-latest

@ -42,11 +42,13 @@ jobs:
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
bazel-cache: ruby_linux/${{ matrix.ruby }}_${{ matrix.bazel }}
bazel: test //ruby/... //ruby/tests:ruby_version --test_env=KOKORO_RUBY_VERSION --test_env=BAZEL=true ${{ matrix.ffi == 'FFI' && '--//ruby:ffi=enabled --test_env=PROTOCOL_BUFFERS_RUBY_IMPLEMENTATION=FFI' || '' }}
- name: Archive log artifacts
uses: actions/upload-artifact@v4
with:
name: test-logs-${{ matrix.ruby }}_${{ matrix.ffi || 'NATIVE' }}
path: logs
# Useful tool for troubleshooting, but the action introduces flakes as well,
# e.g. https://github.com/actions/upload-artifact/issues/569
# - name: Archive log artifacts
# uses: actions/upload-artifact@v4
# with:
# name: test-logs-${{ matrix.ruby }}_${{ matrix.ffi || 'NATIVE' }}
# path: logs
linux-32bit:
name: Linux 32-bit

@ -40,7 +40,7 @@ jobs:
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/sanitize:${{ matrix.config.bazel_version || '6.3.0' }}-75f2a85ece6526cc3d54087018c0f1097d78d42b
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 }}
bazel: test --cxxopt=-std=c++17 --host_cxxopt=-std=c++17 //bazel/... //benchmarks/... //lua/... //protos/... //hpb_generator/... //python/... //upb/... //upb_generator/... ${{ matrix.config.flags }}
exclude-targets: ${{ matrix.config.exclude-targets }}
linux-gcc:
@ -59,7 +59,7 @@ jobs:
image: "us-docker.pkg.dev/protobuf-build/containers/test/linux/gcc:12.2-6.3.0-63dd26c0c7a808d92673a3e52e848189d4ab0f17"
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
bazel-cache: "upb-bazel-gcc"
bazel: test --cxxopt=-std=c++17 --host_cxxopt=-std=c++17 -c opt //bazel/... //benchmarks/... //lua/... //protos/... //protos_generator/... //python/... //upb/... //upb_generator/...
bazel: test --cxxopt=-std=c++17 --host_cxxopt=-std=c++17 -c opt //bazel/... //benchmarks/... //lua/... //protos/... //hpb_generator/... //python/... //upb/... //upb_generator/...
windows:
strategy:
@ -80,7 +80,7 @@ jobs:
with:
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/...
bazel: test --cxxopt=/std:c++17 --host_cxxopt=/std:c++17 //upb/... //upb_generator/... //python/... //protos/... //hpb_generator/...
version: 6.3.0
exclude-targets: -//python:conformance_test -//upb/reflection:def_builder_test
@ -107,7 +107,7 @@ jobs:
with:
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/...
bazel: ${{ matrix.config.bazel-command }} --cxxopt=-std=c++17 --host_cxxopt=-std=c++17 ${{ matrix.config.flags }} //bazel/... //benchmarks/... //lua/... //protos/... //hpb_generator/... //python/... //upb/... //upb_generator/...
version: 6.3.0
no-python:
@ -144,7 +144,7 @@ jobs:
- name: Build Wheels
uses: protocolbuffers/protobuf-ci/bazel-docker@v3
with:
image: us-docker.pkg.dev/protobuf-build/release-containers/linux/apple@sha256:b3dc9b75d8e599b0e95ed245d89f44b5a4231112f975da89dd02006a484a58df
image: us-docker.pkg.dev/protobuf-build/release-containers/linux/apple:6.3.0-53225851b051e66f8543e972c143f35be757a181
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
bazel-cache: upb-bazel-python
bazel: build --crosstool_top=//toolchain:clang_suite --//toolchain:release=true --symlink_prefix=/ -c dbg //python/dist //python/dist:test_wheel //python/dist:source_wheel
@ -277,7 +277,7 @@ jobs:
run: pip install -vvv --no-index --find-links wheels protobuf protobuftests
- name: Run the unit tests
run: |
TESTS=$(pip show -f protobuftests | grep _test.py | sed 's,/,.,g' | sed -E 's,.py$,,g')
TESTS=$(pip show -f protobuftests | grep _test.py | grep --invert-match _pybind11_test.py | sed 's,/,.,g' | sed -E 's,.py$,,g')
for test in $TESTS; do
python -m unittest -v $test
done

@ -16,7 +16,7 @@ conda:
environment: python/docs/environment.yml
python:
version: 3.7
version: 3.8
install:
- method: setuptools
path: python

@ -444,6 +444,16 @@ alias(
visibility = ["//visibility:public"],
)
################################################################################
# Rust support
################################################################################
alias(
name = "protobuf_rust",
actual = "//rust:protobuf",
visibility = ["//visibility:public"],
)
################################################################################
# Test protos
################################################################################

@ -16,12 +16,57 @@ bazel_dep(name = "abseil-cpp", version = "20230802.0.bcr.1", repo_name = "com_go
bazel_dep(name = "bazel_skylib", version = "1.4.1")
bazel_dep(name = "jsoncpp", version = "1.9.5")
bazel_dep(name = "rules_cc", version = "0.0.9")
bazel_dep(name = "rules_fuzzing", version = "0.5.2")
bazel_dep(name = "rules_java", version = "5.3.5")
bazel_dep(name = "rules_jvm_external", version = "5.1")
bazel_dep(name = "rules_pkg", version = "0.7.0")
bazel_dep(name = "rules_python", version = "0.10.2")
bazel_dep(name = "rules_python", version = "0.28.0")
bazel_dep(name = "rules_rust", version = "0.45.1")
bazel_dep(name = "platforms", version = "0.0.8")
bazel_dep(name = "zlib", version = "1.2.11")
bazel_dep(name = "zlib", version = "1.3.1")
# TODO: remove after toolchain types are moved to protobuf
bazel_dep(name = "rules_proto", version = "4.0.0")
bazel_dep(name = "rules_proto", version = "4.0.0")
SUPPORTED_PYTHON_VERSIONS = [
"3.8",
"3.9",
"3.10",
"3.11",
"3.12",
]
python = use_extension("@rules_python//python/extensions:python.bzl", "python")
[
python.toolchain(
is_default = python_version == SUPPORTED_PYTHON_VERSIONS[-1],
python_version = python_version,
)
for python_version in SUPPORTED_PYTHON_VERSIONS
]
use_repo(python, system_python = "python_{}".format(SUPPORTED_PYTHON_VERSIONS[-1].replace(".", "_")))
pip = use_extension("@rules_python//python/extensions:pip.bzl", "pip")
[
pip.parse(
hub_name = "pip_deps",
python_version = python_version,
requirements_lock = "//python:requirements.txt",
)
for python_version in SUPPORTED_PYTHON_VERSIONS
]
use_repo(pip, "pip_deps")
rust = use_extension("@rules_rust//rust:extensions.bzl", "rust")
rust.toolchain(edition = "2021")
use_repo(rust, "rust_toolchains")
register_toolchains("@rust_toolchains//:all")
crate = use_extension("@rules_rust//crate_universe:extension.bzl", "crate")
crate.spec(
package = "googletest",
version = ">0.0.0",
)
crate.spec(
package = "paste",
version = ">=1",
)
crate.from_specs()
use_repo(crate, crate_index = "crates")

@ -25,6 +25,10 @@ load("@rules_python//python:repositories.bzl", "py_repositories")
py_repositories()
load("@rules_python//python/pip_install:repositories.bzl", "pip_install_dependencies")
pip_install_dependencies()
# Bazel platform rules.
http_archive(
name = "platforms",
@ -177,9 +181,9 @@ install_deps()
http_archive(
name = "rules_fuzzing",
sha256 = "ff52ef4845ab00e95d29c02a9e32e9eff4e0a4c9c8a6bcf8407a2f19eb3f9190",
strip_prefix = "rules_fuzzing-0.4.1",
urls = ["https://github.com/bazelbuild/rules_fuzzing/releases/download/v0.4.1/rules_fuzzing-0.4.1.zip"],
sha256 = "77206c54b71f4dd5335123a6ff2a8ea688eca5378d34b4838114dff71652cf26",
strip_prefix = "rules_fuzzing-0.5.1",
urls = ["https://github.com/bazelbuild/rules_fuzzing/releases/download/v0.5.1/rules_fuzzing-0.5.1.zip"],
patches = ["//third_party:rules_fuzzing.patch"],
patch_args = ["-p1"],
)

@ -1,5 +1,6 @@
"""Implementation of the aspect that powers the upb_*_proto_library() rules."""
load("@bazel_tools//tools/cpp:toolchain_utils.bzl", "find_cpp_toolchain")
load("//bazel/common:proto_common.bzl", "proto_common")
load(":upb_proto_library_internal/cc_library_func.bzl", "cc_library_func")
load(":upb_proto_library_internal/copts.bzl", "UpbProtoLibraryCoptsInfo")
@ -54,7 +55,51 @@ def _merge_generated_srcs(srcs):
thunks = _concat_lists([s.thunks for s in srcs]),
)
def _generate_upb_protos(ctx, generator, proto_info):
def _get_implicit_weak_field_sources(ctx, proto_info):
# Creating one .cc file for each Message in a proto allows the linker to be more aggressive
# about removing unused classes. However, since the number of outputs won't be known at Blaze
# analysis time, all of the generated source files are put in a directory and a TreeArtifact is
# used to represent them.
proto_artifacts = []
for proto_source in proto_info.direct_sources:
# We can have slashes in the target name. For example, proto_source can be:
# dir/a.proto. However proto_source.basename will return a.proto, when in reality
# the BUILD file declares it as dir/a.proto, because target name contains a slash.
# There is no good workaround for this.
# I am using ctx.label.package to check if the name of the target contains slash or not.
# This is similar to what declare_directory does.
if not proto_source.short_path.startswith(ctx.label.package):
fail("This should never happen, proto source {} path does not start with {}.".format(
proto_source.short_path,
ctx.label.package,
))
proto_source_name = proto_source.short_path[len(ctx.label.package) + 1:]
last_dot = proto_source_name.rfind(".")
if last_dot != -1:
proto_source_name = proto_source_name[:last_dot]
proto_artifacts.append(ctx.actions.declare_directory(proto_source_name + ".upb_weak_minitables"))
return proto_artifacts
def _get_feature_configuration(ctx, cc_toolchain, proto_info):
requested_features = list(ctx.features)
# Disable the whole-archive behavior for protobuf generated code when the
# proto_one_output_per_message feature is enabled.
requested_features.append("disable_whole_archive_for_static_lib_if_proto_one_output_per_message")
unsupported_features = list(ctx.disabled_features)
if len(proto_info.direct_sources) != 0:
requested_features.append("header_modules")
else:
unsupported_features.append("header_modules")
return cc_common.configure_features(
ctx = ctx,
cc_toolchain = cc_toolchain,
requested_features = requested_features,
unsupported_features = unsupported_features,
)
def _generate_srcs_list(ctx, generator, proto_info):
if len(proto_info.direct_sources) == 0:
return GeneratedSrcsInfo(srcs = [], hdrs = [], thunks = [], includes = [])
@ -92,19 +137,35 @@ def _generate_upb_protos(ctx, generator, proto_info):
mnemonic = "GenUpbProtosThunks",
)
return GeneratedSrcsInfo(
srcs = srcs,
hdrs = hdrs,
thunks = thunks,
)
def _generate_upb_protos(ctx, generator, proto_info, feature_configuration):
implicit_weak = generator == "upb_minitable" and cc_common.is_enabled(
feature_configuration = feature_configuration,
feature_name = "proto_one_output_per_message",
)
srcs = _generate_srcs_list(ctx, generator, proto_info)
additional_args = ctx.actions.args()
if implicit_weak:
srcs.srcs.extend(_get_implicit_weak_field_sources(ctx, proto_info))
additional_args.add("--upb_minitable_opt=one_output_per_message")
proto_common.compile(
actions = ctx.actions,
proto_info = proto_info,
proto_lang_toolchain_info = _get_lang_toolchain(ctx, generator),
generated_files = srcs + hdrs,
generated_files = srcs.srcs + srcs.hdrs,
experimental_exec_group = "proto_compiler",
additional_args = additional_args,
)
return GeneratedSrcsInfo(
srcs = srcs,
hdrs = hdrs,
thunks = thunks,
)
return srcs
def _generate_name(ctx, generator, thunks = False):
if thunks:
@ -217,10 +278,13 @@ def upb_proto_aspect_impl(
)
else:
proto_info = target[ProtoInfo]
cc_toolchain = find_cpp_toolchain(ctx)
feature_configuration = _get_feature_configuration(ctx, cc_toolchain, proto_info)
files = _generate_upb_protos(
ctx,
generator,
proto_info,
feature_configuration,
)
wrapped_cc_info = _compile_upb_protos(
ctx,

@ -4,7 +4,7 @@ load("@rules_python//python:py_info.bzl", "PyInfo")
load("//bazel/common:proto_common.bzl", "proto_common")
load("//bazel/common:proto_info.bzl", "ProtoInfo")
ProtoLangToolchainInfo = proto_common.ProtoLangToolchainInfo
PY_PROTO_TOOLCHAIN = "@rules_python//python/proto:toolchain_type"
_PyProtoInfo = provider(
doc = "Encapsulates information needed by the Python proto rules.",
@ -22,6 +22,9 @@ _PyProtoInfo = provider(
def _filter_provider(provider, *attrs):
return [dep[provider] for attr in attrs for dep in attr if provider in dep]
def _incompatible_toolchains_enabled():
return getattr(proto_common, "INCOMPATIBLE_ENABLE_PROTO_TOOLCHAIN_RESOLUTION", False)
def _py_proto_aspect_impl(target, ctx):
"""Generates and compiles Python code for a proto_library.
@ -48,7 +51,14 @@ def _py_proto_aspect_impl(target, ctx):
proto.path,
))
proto_lang_toolchain_info = ctx.attr._aspect_proto_toolchain[ProtoLangToolchainInfo]
if _incompatible_toolchains_enabled():
toolchain = ctx.toolchains[PY_PROTO_TOOLCHAIN]
if not toolchain:
fail("No toolchains registered for '%s'." % PY_PROTO_TOOLCHAIN)
proto_lang_toolchain_info = toolchain.proto
else:
proto_lang_toolchain_info = getattr(ctx.attr, "_aspect_proto_toolchain")[proto_common.ProtoLangToolchainInfo]
api_deps = [proto_lang_toolchain_info.runtime]
generated_sources = []
@ -110,7 +120,7 @@ def _py_proto_aspect_impl(target, ctx):
_py_proto_aspect = aspect(
implementation = _py_proto_aspect_impl,
attrs = {
attrs = {} if _incompatible_toolchains_enabled() else {
"_aspect_proto_toolchain": attr.label(
default = "//python:python_toolchain",
),
@ -118,6 +128,7 @@ _py_proto_aspect = aspect(
attr_aspects = ["deps"],
required_providers = [ProtoInfo],
provides = [_PyProtoInfo],
toolchains = [PY_PROTO_TOOLCHAIN] if _incompatible_toolchains_enabled() else [],
)
def _py_proto_library_rule(ctx):

@ -16,5 +16,4 @@ java_runtime_conformance(
java_runtime_conformance(
name = "java_conformance_v3.25.0",
gencode_version = "3.25.0",
tags = ["manual"],
)

@ -156,6 +156,11 @@ std::string group(uint32_t fieldnum, std::string content) {
tag(fieldnum, WireFormatLite::WIRETYPE_END_GROUP));
}
std::string len(uint32_t fieldnum, std::string content) {
return absl::StrCat(tag(fieldnum, WireFormatLite::WIRETYPE_LENGTH_DELIMITED),
delim(content));
}
std::string GetDefaultValue(FieldDescriptor::Type type) {
switch (type) {
case FieldDescriptor::TYPE_INT32:
@ -364,6 +369,33 @@ void BinaryAndJsonConformanceSuite::RunDelimitedFieldTests() {
TestAllTypesEdition2023 prototype;
SetTypeUrl(GetTypeUrl(TestAllTypesEdition2023::GetDescriptor()));
RunValidProtobufTest<TestAllTypesEdition2023>(
absl::StrCat("ValidNonMessage"), REQUIRED,
field(1, WireFormatLite::WIRETYPE_VARINT, varint(99)),
R"pb(optional_int32: 99)pb");
RunValidProtobufTest<TestAllTypesEdition2023>(
absl::StrCat("ValidLengthPrefixedField"), REQUIRED,
len(18, field(1, WireFormatLite::WIRETYPE_VARINT, varint(99))),
R"pb(optional_nested_message { a: 99 })pb");
RunValidProtobufTest<TestAllTypesEdition2023>(
absl::StrCat("ValidMap.Integer"), REQUIRED,
len(56,
absl::StrCat(field(1, WireFormatLite::WIRETYPE_VARINT, varint(99)),
field(2, WireFormatLite::WIRETYPE_VARINT, varint(87)))),
R"pb(map_int32_int32 { key: 99 value: 87 })pb");
RunValidProtobufTest<TestAllTypesEdition2023>(
absl::StrCat("ValidMap.LengthPrefixed"), REQUIRED,
len(71, absl::StrCat(len(1, "a"),
len(2, field(1, WireFormatLite::WIRETYPE_VARINT,
varint(87))))),
R"pb(map_string_nested_message {
key: "a"
value: { a: 87 }
})pb");
RunValidProtobufTest<TestAllTypesEdition2023>(
absl::StrCat("ValidDelimitedField.GroupLike"), REQUIRED,
group(201, field(202, WireFormatLite::WIRETYPE_VARINT, varint(99))),

@ -9,6 +9,7 @@ edition = "2023";
package protobuf_test_messages.editions;
option features.message_encoding = DELIMITED;
option java_package = "com.google.protobuf_test_messages.edition2023";
option java_multiple_files = true;
option objc_class_prefix = "Editions";
@ -20,7 +21,8 @@ message ComplexMessage {
message TestAllTypesEdition2023 {
message NestedMessage {
int32 a = 1;
TestAllTypesEdition2023 corecursive = 2;
TestAllTypesEdition2023 corecursive = 2
[features.message_encoding = LENGTH_PREFIXED];
}
enum NestedEnum {
@ -47,8 +49,10 @@ message TestAllTypesEdition2023 {
string optional_string = 14;
bytes optional_bytes = 15;
NestedMessage optional_nested_message = 18;
ForeignMessageEdition2023 optional_foreign_message = 19;
NestedMessage optional_nested_message = 18
[features.message_encoding = LENGTH_PREFIXED];
ForeignMessageEdition2023 optional_foreign_message = 19
[features.message_encoding = LENGTH_PREFIXED];
NestedEnum optional_nested_enum = 21;
ForeignEnumEdition2023 optional_foreign_enum = 22;
@ -56,7 +60,8 @@ message TestAllTypesEdition2023 {
string optional_string_piece = 24 [ctype = STRING_PIECE];
string optional_cord = 25 [ctype = CORD];
TestAllTypesEdition2023 recursive_message = 27;
TestAllTypesEdition2023 recursive_message = 27
[features.message_encoding = LENGTH_PREFIXED];
// Repeated
repeated int32 repeated_int32 = 31;
@ -75,8 +80,10 @@ message TestAllTypesEdition2023 {
repeated string repeated_string = 44;
repeated bytes repeated_bytes = 45;
repeated NestedMessage repeated_nested_message = 48;
repeated ForeignMessageEdition2023 repeated_foreign_message = 49;
repeated NestedMessage repeated_nested_message = 48
[features.message_encoding = LENGTH_PREFIXED];
repeated ForeignMessageEdition2023 repeated_foreign_message = 49
[features.message_encoding = LENGTH_PREFIXED];
repeated NestedEnum repeated_nested_enum = 51;
repeated ForeignEnumEdition2023 repeated_foreign_enum = 52;
@ -163,7 +170,8 @@ message TestAllTypesEdition2023 {
oneof oneof_field {
uint32 oneof_uint32 = 111;
NestedMessage oneof_nested_message = 112;
NestedMessage oneof_nested_message = 112
[features.message_encoding = LENGTH_PREFIXED];
string oneof_string = 113;
bytes oneof_bytes = 114;
bool oneof_bool = 115;
@ -181,8 +189,8 @@ message TestAllTypesEdition2023 {
int32 group_int32 = 202;
uint32 group_uint32 = 203;
}
GroupLikeType groupliketype = 201 [features.message_encoding = DELIMITED];
GroupLikeType delimited_field = 202 [features.message_encoding = DELIMITED];
GroupLikeType groupliketype = 201;
GroupLikeType delimited_field = 202;
}
message ForeignMessageEdition2023 {
@ -204,6 +212,6 @@ message GroupLikeType {
}
extend TestAllTypesEdition2023 {
GroupLikeType groupliketype = 121 [features.message_encoding = DELIMITED];
GroupLikeType delimited_ext = 122 [features.message_encoding = DELIMITED];
GroupLikeType groupliketype = 121;
GroupLikeType delimited_ext = 122;
}

@ -26,7 +26,7 @@ namespace ProtobufTestMessages.Editions {
string.Concat(
"Cjdjb25mb3JtYW5jZS90ZXN0X3Byb3Rvcy90ZXN0X21lc3NhZ2VzX2VkaXRp",
"b24yMDIzLnByb3RvEh9wcm90b2J1Zl90ZXN0X21lc3NhZ2VzLmVkaXRpb25z",
"IhsKDkNvbXBsZXhNZXNzYWdlEgkKAWQYASABKAUi3DYKF1Rlc3RBbGxUeXBl",
"IhsKDkNvbXBsZXhNZXNzYWdlEgkKAWQYASABKAUi/zYKF1Rlc3RBbGxUeXBl",
"c0VkaXRpb24yMDIzEhYKDm9wdGlvbmFsX2ludDMyGAEgASgFEhYKDm9wdGlv",
"bmFsX2ludDY0GAIgASgDEhcKD29wdGlvbmFsX3VpbnQzMhgDIAEoDRIXCg9v",
"cHRpb25hbF91aW50NjQYBCABKAQSFwoPb3B0aW9uYWxfc2ludDMyGAUgASgR",
@ -35,167 +35,167 @@ namespace ProtobufTestMessages.Editions {
"c2ZpeGVkMzIYCSABKA8SGQoRb3B0aW9uYWxfc2ZpeGVkNjQYCiABKBASFgoO",
"b3B0aW9uYWxfZmxvYXQYCyABKAISFwoPb3B0aW9uYWxfZG91YmxlGAwgASgB",
"EhUKDW9wdGlvbmFsX2Jvb2wYDSABKAgSFwoPb3B0aW9uYWxfc3RyaW5nGA4g",
"ASgJEhYKDm9wdGlvbmFsX2J5dGVzGA8gASgMEmcKF29wdGlvbmFsX25lc3Rl",
"ASgJEhYKDm9wdGlvbmFsX2J5dGVzGA8gASgMEm4KF29wdGlvbmFsX25lc3Rl",
"ZF9tZXNzYWdlGBIgASgLMkYucHJvdG9idWZfdGVzdF9tZXNzYWdlcy5lZGl0",
"aW9ucy5UZXN0QWxsVHlwZXNFZGl0aW9uMjAyMy5OZXN0ZWRNZXNzYWdlElwK",
"GG9wdGlvbmFsX2ZvcmVpZ25fbWVzc2FnZRgTIAEoCzI6LnByb3RvYnVmX3Rl",
"c3RfbWVzc2FnZXMuZWRpdGlvbnMuRm9yZWlnbk1lc3NhZ2VFZGl0aW9uMjAy",
"MxJhChRvcHRpb25hbF9uZXN0ZWRfZW51bRgVIAEoDjJDLnByb3RvYnVmX3Rl",
"aW9ucy5UZXN0QWxsVHlwZXNFZGl0aW9uMjAyMy5OZXN0ZWRNZXNzYWdlQgWq",
"AQIoARJjChhvcHRpb25hbF9mb3JlaWduX21lc3NhZ2UYEyABKAsyOi5wcm90",
"b2J1Zl90ZXN0X21lc3NhZ2VzLmVkaXRpb25zLkZvcmVpZ25NZXNzYWdlRWRp",
"dGlvbjIwMjNCBaoBAigBEmEKFG9wdGlvbmFsX25lc3RlZF9lbnVtGBUgASgO",
"MkMucHJvdG9idWZfdGVzdF9tZXNzYWdlcy5lZGl0aW9ucy5UZXN0QWxsVHlw",
"ZXNFZGl0aW9uMjAyMy5OZXN0ZWRFbnVtElYKFW9wdGlvbmFsX2ZvcmVpZ25f",
"ZW51bRgWIAEoDjI3LnByb3RvYnVmX3Rlc3RfbWVzc2FnZXMuZWRpdGlvbnMu",
"Rm9yZWlnbkVudW1FZGl0aW9uMjAyMxIhChVvcHRpb25hbF9zdHJpbmdfcGll",
"Y2UYGCABKAlCAggCEhkKDW9wdGlvbmFsX2NvcmQYGSABKAlCAggBEloKEXJl",
"Y3Vyc2l2ZV9tZXNzYWdlGBsgASgLMjgucHJvdG9idWZfdGVzdF9tZXNzYWdl",
"cy5lZGl0aW9ucy5UZXN0QWxsVHlwZXNFZGl0aW9uMjAyM0IFqgECKAESFgoO",
"cmVwZWF0ZWRfaW50MzIYHyADKAUSFgoOcmVwZWF0ZWRfaW50NjQYICADKAMS",
"FwoPcmVwZWF0ZWRfdWludDMyGCEgAygNEhcKD3JlcGVhdGVkX3VpbnQ2NBgi",
"IAMoBBIXCg9yZXBlYXRlZF9zaW50MzIYIyADKBESFwoPcmVwZWF0ZWRfc2lu",
"dDY0GCQgAygSEhgKEHJlcGVhdGVkX2ZpeGVkMzIYJSADKAcSGAoQcmVwZWF0",
"ZWRfZml4ZWQ2NBgmIAMoBhIZChFyZXBlYXRlZF9zZml4ZWQzMhgnIAMoDxIZ",
"ChFyZXBlYXRlZF9zZml4ZWQ2NBgoIAMoEBIWCg5yZXBlYXRlZF9mbG9hdBgp",
"IAMoAhIXCg9yZXBlYXRlZF9kb3VibGUYKiADKAESFQoNcmVwZWF0ZWRfYm9v",
"bBgrIAMoCBIXCg9yZXBlYXRlZF9zdHJpbmcYLCADKAkSFgoOcmVwZWF0ZWRf",
"Ynl0ZXMYLSADKAwSbgoXcmVwZWF0ZWRfbmVzdGVkX21lc3NhZ2UYMCADKAsy",
"Ri5wcm90b2J1Zl90ZXN0X21lc3NhZ2VzLmVkaXRpb25zLlRlc3RBbGxUeXBl",
"c0VkaXRpb24yMDIzLk5lc3RlZE1lc3NhZ2VCBaoBAigBEmMKGHJlcGVhdGVk",
"X2ZvcmVpZ25fbWVzc2FnZRgxIAMoCzI6LnByb3RvYnVmX3Rlc3RfbWVzc2Fn",
"ZXMuZWRpdGlvbnMuRm9yZWlnbk1lc3NhZ2VFZGl0aW9uMjAyM0IFqgECKAES",
"YQoUcmVwZWF0ZWRfbmVzdGVkX2VudW0YMyADKA4yQy5wcm90b2J1Zl90ZXN0",
"X21lc3NhZ2VzLmVkaXRpb25zLlRlc3RBbGxUeXBlc0VkaXRpb24yMDIzLk5l",
"c3RlZEVudW0SVgoVcmVwZWF0ZWRfZm9yZWlnbl9lbnVtGDQgAygOMjcucHJv",
"dG9idWZfdGVzdF9tZXNzYWdlcy5lZGl0aW9ucy5Gb3JlaWduRW51bUVkaXRp",
"b24yMDIzEiEKFXJlcGVhdGVkX3N0cmluZ19waWVjZRg2IAMoCUICCAISGQoN",
"cmVwZWF0ZWRfY29yZBg3IAMoCUICCAESGwoMcGFja2VkX2ludDMyGEsgAygF",
"QgWqAQIYARIbCgxwYWNrZWRfaW50NjQYTCADKANCBaoBAhgBEhwKDXBhY2tl",
"ZF91aW50MzIYTSADKA1CBaoBAhgBEhwKDXBhY2tlZF91aW50NjQYTiADKARC",
"BaoBAhgBEhwKDXBhY2tlZF9zaW50MzIYTyADKBFCBaoBAhgBEhwKDXBhY2tl",
"ZF9zaW50NjQYUCADKBJCBaoBAhgBEh0KDnBhY2tlZF9maXhlZDMyGFEgAygH",
"QgWqAQIYARIdCg5wYWNrZWRfZml4ZWQ2NBhSIAMoBkIFqgECGAESHgoPcGFj",
"a2VkX3NmaXhlZDMyGFMgAygPQgWqAQIYARIeCg9wYWNrZWRfc2ZpeGVkNjQY",
"VCADKBBCBaoBAhgBEhsKDHBhY2tlZF9mbG9hdBhVIAMoAkIFqgECGAESHAoN",
"cGFja2VkX2RvdWJsZRhWIAMoAUIFqgECGAESGgoLcGFja2VkX2Jvb2wYVyAD",
"KAhCBaoBAhgBEmYKEnBhY2tlZF9uZXN0ZWRfZW51bRhYIAMoDjJDLnByb3Rv",
"YnVmX3Rlc3RfbWVzc2FnZXMuZWRpdGlvbnMuVGVzdEFsbFR5cGVzRWRpdGlv",
"bjIwMjMuTmVzdGVkRW51bUIFqgECGAESHQoOdW5wYWNrZWRfaW50MzIYWSAD",
"KAVCBaoBAhgCEh0KDnVucGFja2VkX2ludDY0GFogAygDQgWqAQIYAhIeCg91",
"bnBhY2tlZF91aW50MzIYWyADKA1CBaoBAhgCEh4KD3VucGFja2VkX3VpbnQ2",
"NBhcIAMoBEIFqgECGAISHgoPdW5wYWNrZWRfc2ludDMyGF0gAygRQgWqAQIY",
"AhIeCg91bnBhY2tlZF9zaW50NjQYXiADKBJCBaoBAhgCEh8KEHVucGFja2Vk",
"X2ZpeGVkMzIYXyADKAdCBaoBAhgCEh8KEHVucGFja2VkX2ZpeGVkNjQYYCAD",
"KAZCBaoBAhgCEiAKEXVucGFja2VkX3NmaXhlZDMyGGEgAygPQgWqAQIYAhIg",
"ChF1bnBhY2tlZF9zZml4ZWQ2NBhiIAMoEEIFqgECGAISHQoOdW5wYWNrZWRf",
"ZmxvYXQYYyADKAJCBaoBAhgCEh4KD3VucGFja2VkX2RvdWJsZRhkIAMoAUIF",
"qgECGAISHAoNdW5wYWNrZWRfYm9vbBhlIAMoCEIFqgECGAISaAoUdW5wYWNr",
"ZWRfbmVzdGVkX2VudW0YZiADKA4yQy5wcm90b2J1Zl90ZXN0X21lc3NhZ2Vz",
"LmVkaXRpb25zLlRlc3RBbGxUeXBlc0VkaXRpb24yMDIzLk5lc3RlZEVudW1C",
"BaoBAhgCEmQKD21hcF9pbnQzMl9pbnQzMhg4IAMoCzJLLnByb3RvYnVmX3Rl",
"c3RfbWVzc2FnZXMuZWRpdGlvbnMuVGVzdEFsbFR5cGVzRWRpdGlvbjIwMjMu",
"TmVzdGVkRW51bRJWChVvcHRpb25hbF9mb3JlaWduX2VudW0YFiABKA4yNy5w",
"cm90b2J1Zl90ZXN0X21lc3NhZ2VzLmVkaXRpb25zLkZvcmVpZ25FbnVtRWRp",
"dGlvbjIwMjMSIQoVb3B0aW9uYWxfc3RyaW5nX3BpZWNlGBggASgJQgIIAhIZ",
"Cg1vcHRpb25hbF9jb3JkGBkgASgJQgIIARJTChFyZWN1cnNpdmVfbWVzc2Fn",
"ZRgbIAEoCzI4LnByb3RvYnVmX3Rlc3RfbWVzc2FnZXMuZWRpdGlvbnMuVGVz",
"dEFsbFR5cGVzRWRpdGlvbjIwMjMSFgoOcmVwZWF0ZWRfaW50MzIYHyADKAUS",
"FgoOcmVwZWF0ZWRfaW50NjQYICADKAMSFwoPcmVwZWF0ZWRfdWludDMyGCEg",
"AygNEhcKD3JlcGVhdGVkX3VpbnQ2NBgiIAMoBBIXCg9yZXBlYXRlZF9zaW50",
"MzIYIyADKBESFwoPcmVwZWF0ZWRfc2ludDY0GCQgAygSEhgKEHJlcGVhdGVk",
"X2ZpeGVkMzIYJSADKAcSGAoQcmVwZWF0ZWRfZml4ZWQ2NBgmIAMoBhIZChFy",
"ZXBlYXRlZF9zZml4ZWQzMhgnIAMoDxIZChFyZXBlYXRlZF9zZml4ZWQ2NBgo",
"IAMoEBIWCg5yZXBlYXRlZF9mbG9hdBgpIAMoAhIXCg9yZXBlYXRlZF9kb3Vi",
"bGUYKiADKAESFQoNcmVwZWF0ZWRfYm9vbBgrIAMoCBIXCg9yZXBlYXRlZF9z",
"dHJpbmcYLCADKAkSFgoOcmVwZWF0ZWRfYnl0ZXMYLSADKAwSZwoXcmVwZWF0",
"ZWRfbmVzdGVkX21lc3NhZ2UYMCADKAsyRi5wcm90b2J1Zl90ZXN0X21lc3Nh",
"Z2VzLmVkaXRpb25zLlRlc3RBbGxUeXBlc0VkaXRpb24yMDIzLk5lc3RlZE1l",
"c3NhZ2USXAoYcmVwZWF0ZWRfZm9yZWlnbl9tZXNzYWdlGDEgAygLMjoucHJv",
"dG9idWZfdGVzdF9tZXNzYWdlcy5lZGl0aW9ucy5Gb3JlaWduTWVzc2FnZUVk",
"aXRpb24yMDIzEmEKFHJlcGVhdGVkX25lc3RlZF9lbnVtGDMgAygOMkMucHJv",
"dG9idWZfdGVzdF9tZXNzYWdlcy5lZGl0aW9ucy5UZXN0QWxsVHlwZXNFZGl0",
"aW9uMjAyMy5OZXN0ZWRFbnVtElYKFXJlcGVhdGVkX2ZvcmVpZ25fZW51bRg0",
"IAMoDjI3LnByb3RvYnVmX3Rlc3RfbWVzc2FnZXMuZWRpdGlvbnMuRm9yZWln",
"bkVudW1FZGl0aW9uMjAyMxIhChVyZXBlYXRlZF9zdHJpbmdfcGllY2UYNiAD",
"KAlCAggCEhkKDXJlcGVhdGVkX2NvcmQYNyADKAlCAggBEhsKDHBhY2tlZF9p",
"bnQzMhhLIAMoBUIFqgECGAESGwoMcGFja2VkX2ludDY0GEwgAygDQgWqAQIY",
"ARIcCg1wYWNrZWRfdWludDMyGE0gAygNQgWqAQIYARIcCg1wYWNrZWRfdWlu",
"dDY0GE4gAygEQgWqAQIYARIcCg1wYWNrZWRfc2ludDMyGE8gAygRQgWqAQIY",
"ARIcCg1wYWNrZWRfc2ludDY0GFAgAygSQgWqAQIYARIdCg5wYWNrZWRfZml4",
"ZWQzMhhRIAMoB0IFqgECGAESHQoOcGFja2VkX2ZpeGVkNjQYUiADKAZCBaoB",
"AhgBEh4KD3BhY2tlZF9zZml4ZWQzMhhTIAMoD0IFqgECGAESHgoPcGFja2Vk",
"X3NmaXhlZDY0GFQgAygQQgWqAQIYARIbCgxwYWNrZWRfZmxvYXQYVSADKAJC",
"BaoBAhgBEhwKDXBhY2tlZF9kb3VibGUYViADKAFCBaoBAhgBEhoKC3BhY2tl",
"ZF9ib29sGFcgAygIQgWqAQIYARJmChJwYWNrZWRfbmVzdGVkX2VudW0YWCAD",
"KA4yQy5wcm90b2J1Zl90ZXN0X21lc3NhZ2VzLmVkaXRpb25zLlRlc3RBbGxU",
"eXBlc0VkaXRpb24yMDIzLk5lc3RlZEVudW1CBaoBAhgBEh0KDnVucGFja2Vk",
"X2ludDMyGFkgAygFQgWqAQIYAhIdCg51bnBhY2tlZF9pbnQ2NBhaIAMoA0IF",
"qgECGAISHgoPdW5wYWNrZWRfdWludDMyGFsgAygNQgWqAQIYAhIeCg91bnBh",
"Y2tlZF91aW50NjQYXCADKARCBaoBAhgCEh4KD3VucGFja2VkX3NpbnQzMhhd",
"IAMoEUIFqgECGAISHgoPdW5wYWNrZWRfc2ludDY0GF4gAygSQgWqAQIYAhIf",
"ChB1bnBhY2tlZF9maXhlZDMyGF8gAygHQgWqAQIYAhIfChB1bnBhY2tlZF9m",
"aXhlZDY0GGAgAygGQgWqAQIYAhIgChF1bnBhY2tlZF9zZml4ZWQzMhhhIAMo",
"D0IFqgECGAISIAoRdW5wYWNrZWRfc2ZpeGVkNjQYYiADKBBCBaoBAhgCEh0K",
"DnVucGFja2VkX2Zsb2F0GGMgAygCQgWqAQIYAhIeCg91bnBhY2tlZF9kb3Vi",
"bGUYZCADKAFCBaoBAhgCEhwKDXVucGFja2VkX2Jvb2wYZSADKAhCBaoBAhgC",
"EmgKFHVucGFja2VkX25lc3RlZF9lbnVtGGYgAygOMkMucHJvdG9idWZfdGVz",
"dF9tZXNzYWdlcy5lZGl0aW9ucy5UZXN0QWxsVHlwZXNFZGl0aW9uMjAyMy5O",
"ZXN0ZWRFbnVtQgWqAQIYAhJkCg9tYXBfaW50MzJfaW50MzIYOCADKAsySy5w",
"cm90b2J1Zl90ZXN0X21lc3NhZ2VzLmVkaXRpb25zLlRlc3RBbGxUeXBlc0Vk",
"aXRpb24yMDIzLk1hcEludDMySW50MzJFbnRyeRJkCg9tYXBfaW50NjRfaW50",
"NjQYOSADKAsySy5wcm90b2J1Zl90ZXN0X21lc3NhZ2VzLmVkaXRpb25zLlRl",
"c3RBbGxUeXBlc0VkaXRpb24yMDIzLk1hcEludDY0SW50NjRFbnRyeRJoChFt",
"YXBfdWludDMyX3VpbnQzMhg6IAMoCzJNLnByb3RvYnVmX3Rlc3RfbWVzc2Fn",
"ZXMuZWRpdGlvbnMuVGVzdEFsbFR5cGVzRWRpdGlvbjIwMjMuTWFwVWludDMy",
"VWludDMyRW50cnkSaAoRbWFwX3VpbnQ2NF91aW50NjQYOyADKAsyTS5wcm90",
"b2J1Zl90ZXN0X21lc3NhZ2VzLmVkaXRpb25zLlRlc3RBbGxUeXBlc0VkaXRp",
"b24yMDIzLk1hcFVpbnQ2NFVpbnQ2NEVudHJ5EmgKEW1hcF9zaW50MzJfc2lu",
"dDMyGDwgAygLMk0ucHJvdG9idWZfdGVzdF9tZXNzYWdlcy5lZGl0aW9ucy5U",
"ZXN0QWxsVHlwZXNFZGl0aW9uMjAyMy5NYXBTaW50MzJTaW50MzJFbnRyeRJo",
"ChFtYXBfc2ludDY0X3NpbnQ2NBg9IAMoCzJNLnByb3RvYnVmX3Rlc3RfbWVz",
"c2FnZXMuZWRpdGlvbnMuVGVzdEFsbFR5cGVzRWRpdGlvbjIwMjMuTWFwU2lu",
"dDY0U2ludDY0RW50cnkSbAoTbWFwX2ZpeGVkMzJfZml4ZWQzMhg+IAMoCzJP",
"TWFwSW50MzJJbnQzMkVudHJ5EmQKD21hcF9pbnQ2NF9pbnQ2NBg5IAMoCzJL",
"LnByb3RvYnVmX3Rlc3RfbWVzc2FnZXMuZWRpdGlvbnMuVGVzdEFsbFR5cGVz",
"RWRpdGlvbjIwMjMuTWFwRml4ZWQzMkZpeGVkMzJFbnRyeRJsChNtYXBfZml4",
"ZWQ2NF9maXhlZDY0GD8gAygLMk8ucHJvdG9idWZfdGVzdF9tZXNzYWdlcy5l",
"ZGl0aW9ucy5UZXN0QWxsVHlwZXNFZGl0aW9uMjAyMy5NYXBGaXhlZDY0Rml4",
"ZWQ2NEVudHJ5EnAKFW1hcF9zZml4ZWQzMl9zZml4ZWQzMhhAIAMoCzJRLnBy",
"b3RvYnVmX3Rlc3RfbWVzc2FnZXMuZWRpdGlvbnMuVGVzdEFsbFR5cGVzRWRp",
"dGlvbjIwMjMuTWFwU2ZpeGVkMzJTZml4ZWQzMkVudHJ5EnAKFW1hcF9zZml4",
"ZWQ2NF9zZml4ZWQ2NBhBIAMoCzJRLnByb3RvYnVmX3Rlc3RfbWVzc2FnZXMu",
"ZWRpdGlvbnMuVGVzdEFsbFR5cGVzRWRpdGlvbjIwMjMuTWFwU2ZpeGVkNjRT",
"Zml4ZWQ2NEVudHJ5EmQKD21hcF9pbnQzMl9mbG9hdBhCIAMoCzJLLnByb3Rv",
"YnVmX3Rlc3RfbWVzc2FnZXMuZWRpdGlvbnMuVGVzdEFsbFR5cGVzRWRpdGlv",
"bjIwMjMuTWFwSW50MzJGbG9hdEVudHJ5EmYKEG1hcF9pbnQzMl9kb3VibGUY",
"QyADKAsyTC5wcm90b2J1Zl90ZXN0X21lc3NhZ2VzLmVkaXRpb25zLlRlc3RB",
"bGxUeXBlc0VkaXRpb24yMDIzLk1hcEludDMyRG91YmxlRW50cnkSYAoNbWFw",
"X2Jvb2xfYm9vbBhEIAMoCzJJLnByb3RvYnVmX3Rlc3RfbWVzc2FnZXMuZWRp",
"dGlvbnMuVGVzdEFsbFR5cGVzRWRpdGlvbjIwMjMuTWFwQm9vbEJvb2xFbnRy",
"eRJoChFtYXBfc3RyaW5nX3N0cmluZxhFIAMoCzJNLnByb3RvYnVmX3Rlc3Rf",
"RWRpdGlvbjIwMjMuTWFwSW50NjRJbnQ2NEVudHJ5EmgKEW1hcF91aW50MzJf",
"dWludDMyGDogAygLMk0ucHJvdG9idWZfdGVzdF9tZXNzYWdlcy5lZGl0aW9u",
"cy5UZXN0QWxsVHlwZXNFZGl0aW9uMjAyMy5NYXBVaW50MzJVaW50MzJFbnRy",
"eRJoChFtYXBfdWludDY0X3VpbnQ2NBg7IAMoCzJNLnByb3RvYnVmX3Rlc3Rf",
"bWVzc2FnZXMuZWRpdGlvbnMuVGVzdEFsbFR5cGVzRWRpdGlvbjIwMjMuTWFw",
"U3RyaW5nU3RyaW5nRW50cnkSZgoQbWFwX3N0cmluZ19ieXRlcxhGIAMoCzJM",
"VWludDY0VWludDY0RW50cnkSaAoRbWFwX3NpbnQzMl9zaW50MzIYPCADKAsy",
"TS5wcm90b2J1Zl90ZXN0X21lc3NhZ2VzLmVkaXRpb25zLlRlc3RBbGxUeXBl",
"c0VkaXRpb24yMDIzLk1hcFNpbnQzMlNpbnQzMkVudHJ5EmgKEW1hcF9zaW50",
"NjRfc2ludDY0GD0gAygLMk0ucHJvdG9idWZfdGVzdF9tZXNzYWdlcy5lZGl0",
"aW9ucy5UZXN0QWxsVHlwZXNFZGl0aW9uMjAyMy5NYXBTaW50NjRTaW50NjRF",
"bnRyeRJsChNtYXBfZml4ZWQzMl9maXhlZDMyGD4gAygLMk8ucHJvdG9idWZf",
"dGVzdF9tZXNzYWdlcy5lZGl0aW9ucy5UZXN0QWxsVHlwZXNFZGl0aW9uMjAy",
"My5NYXBGaXhlZDMyRml4ZWQzMkVudHJ5EmwKE21hcF9maXhlZDY0X2ZpeGVk",
"NjQYPyADKAsyTy5wcm90b2J1Zl90ZXN0X21lc3NhZ2VzLmVkaXRpb25zLlRl",
"c3RBbGxUeXBlc0VkaXRpb24yMDIzLk1hcEZpeGVkNjRGaXhlZDY0RW50cnkS",
"cAoVbWFwX3NmaXhlZDMyX3NmaXhlZDMyGEAgAygLMlEucHJvdG9idWZfdGVz",
"dF9tZXNzYWdlcy5lZGl0aW9ucy5UZXN0QWxsVHlwZXNFZGl0aW9uMjAyMy5N",
"YXBTZml4ZWQzMlNmaXhlZDMyRW50cnkScAoVbWFwX3NmaXhlZDY0X3NmaXhl",
"ZDY0GEEgAygLMlEucHJvdG9idWZfdGVzdF9tZXNzYWdlcy5lZGl0aW9ucy5U",
"ZXN0QWxsVHlwZXNFZGl0aW9uMjAyMy5NYXBTZml4ZWQ2NFNmaXhlZDY0RW50",
"cnkSZAoPbWFwX2ludDMyX2Zsb2F0GEIgAygLMksucHJvdG9idWZfdGVzdF9t",
"ZXNzYWdlcy5lZGl0aW9ucy5UZXN0QWxsVHlwZXNFZGl0aW9uMjAyMy5NYXBJ",
"bnQzMkZsb2F0RW50cnkSZgoQbWFwX2ludDMyX2RvdWJsZRhDIAMoCzJMLnBy",
"b3RvYnVmX3Rlc3RfbWVzc2FnZXMuZWRpdGlvbnMuVGVzdEFsbFR5cGVzRWRp",
"dGlvbjIwMjMuTWFwSW50MzJEb3VibGVFbnRyeRJgCg1tYXBfYm9vbF9ib29s",
"GEQgAygLMkkucHJvdG9idWZfdGVzdF9tZXNzYWdlcy5lZGl0aW9ucy5UZXN0",
"QWxsVHlwZXNFZGl0aW9uMjAyMy5NYXBCb29sQm9vbEVudHJ5EmgKEW1hcF9z",
"dHJpbmdfc3RyaW5nGEUgAygLMk0ucHJvdG9idWZfdGVzdF9tZXNzYWdlcy5l",
"ZGl0aW9ucy5UZXN0QWxsVHlwZXNFZGl0aW9uMjAyMy5NYXBTdHJpbmdTdHJp",
"bmdFbnRyeRJmChBtYXBfc3RyaW5nX2J5dGVzGEYgAygLMkwucHJvdG9idWZf",
"dGVzdF9tZXNzYWdlcy5lZGl0aW9ucy5UZXN0QWxsVHlwZXNFZGl0aW9uMjAy",
"My5NYXBTdHJpbmdCeXRlc0VudHJ5EncKGW1hcF9zdHJpbmdfbmVzdGVkX21l",
"c3NhZ2UYRyADKAsyVC5wcm90b2J1Zl90ZXN0X21lc3NhZ2VzLmVkaXRpb25z",
"LlRlc3RBbGxUeXBlc0VkaXRpb24yMDIzLk1hcFN0cmluZ05lc3RlZE1lc3Nh",
"Z2VFbnRyeRJ5ChptYXBfc3RyaW5nX2ZvcmVpZ25fbWVzc2FnZRhIIAMoCzJV",
"LnByb3RvYnVmX3Rlc3RfbWVzc2FnZXMuZWRpdGlvbnMuVGVzdEFsbFR5cGVz",
"RWRpdGlvbjIwMjMuTWFwU3RyaW5nQnl0ZXNFbnRyeRJ3ChltYXBfc3RyaW5n",
"X25lc3RlZF9tZXNzYWdlGEcgAygLMlQucHJvdG9idWZfdGVzdF9tZXNzYWdl",
"cy5lZGl0aW9ucy5UZXN0QWxsVHlwZXNFZGl0aW9uMjAyMy5NYXBTdHJpbmdO",
"ZXN0ZWRNZXNzYWdlRW50cnkSeQoabWFwX3N0cmluZ19mb3JlaWduX21lc3Nh",
"Z2UYSCADKAsyVS5wcm90b2J1Zl90ZXN0X21lc3NhZ2VzLmVkaXRpb25zLlRl",
"c3RBbGxUeXBlc0VkaXRpb24yMDIzLk1hcFN0cmluZ0ZvcmVpZ25NZXNzYWdl",
"RW50cnkScQoWbWFwX3N0cmluZ19uZXN0ZWRfZW51bRhJIAMoCzJRLnByb3Rv",
"YnVmX3Rlc3RfbWVzc2FnZXMuZWRpdGlvbnMuVGVzdEFsbFR5cGVzRWRpdGlv",
"bjIwMjMuTWFwU3RyaW5nTmVzdGVkRW51bUVudHJ5EnMKF21hcF9zdHJpbmdf",
"Zm9yZWlnbl9lbnVtGEogAygLMlIucHJvdG9idWZfdGVzdF9tZXNzYWdlcy5l",
"ZGl0aW9ucy5UZXN0QWxsVHlwZXNFZGl0aW9uMjAyMy5NYXBTdHJpbmdGb3Jl",
"aWduRW51bUVudHJ5EhYKDG9uZW9mX3VpbnQzMhhvIAEoDUgAEmYKFG9uZW9m",
"X25lc3RlZF9tZXNzYWdlGHAgASgLMkYucHJvdG9idWZfdGVzdF9tZXNzYWdl",
"cy5lZGl0aW9ucy5UZXN0QWxsVHlwZXNFZGl0aW9uMjAyMy5OZXN0ZWRNZXNz",
"YWdlSAASFgoMb25lb2Zfc3RyaW5nGHEgASgJSAASFQoLb25lb2ZfYnl0ZXMY",
"ciABKAxIABIUCgpvbmVvZl9ib29sGHMgASgISAASFgoMb25lb2ZfdWludDY0",
"GHQgASgESAASFQoLb25lb2ZfZmxvYXQYdSABKAJIABIWCgxvbmVvZl9kb3Vi",
"bGUYdiABKAFIABJZCgpvbmVvZl9lbnVtGHcgASgOMkMucHJvdG9idWZfdGVz",
"dF9tZXNzYWdlcy5lZGl0aW9ucy5UZXN0QWxsVHlwZXNFZGl0aW9uMjAyMy5O",
"ZXN0ZWRFbnVtSAASZQoNZ3JvdXBsaWtldHlwZRjJASABKAsyRi5wcm90b2J1",
"RWRpdGlvbjIwMjMuTWFwU3RyaW5nRm9yZWlnbk1lc3NhZ2VFbnRyeRJxChZt",
"YXBfc3RyaW5nX25lc3RlZF9lbnVtGEkgAygLMlEucHJvdG9idWZfdGVzdF9t",
"ZXNzYWdlcy5lZGl0aW9ucy5UZXN0QWxsVHlwZXNFZGl0aW9uMjAyMy5NYXBT",
"dHJpbmdOZXN0ZWRFbnVtRW50cnkScwoXbWFwX3N0cmluZ19mb3JlaWduX2Vu",
"dW0YSiADKAsyUi5wcm90b2J1Zl90ZXN0X21lc3NhZ2VzLmVkaXRpb25zLlRl",
"c3RBbGxUeXBlc0VkaXRpb24yMDIzLk1hcFN0cmluZ0ZvcmVpZ25FbnVtRW50",
"cnkSFgoMb25lb2ZfdWludDMyGG8gASgNSAASbQoUb25lb2ZfbmVzdGVkX21l",
"c3NhZ2UYcCABKAsyRi5wcm90b2J1Zl90ZXN0X21lc3NhZ2VzLmVkaXRpb25z",
"LlRlc3RBbGxUeXBlc0VkaXRpb24yMDIzLk5lc3RlZE1lc3NhZ2VCBaoBAigB",
"SAASFgoMb25lb2Zfc3RyaW5nGHEgASgJSAASFQoLb25lb2ZfYnl0ZXMYciAB",
"KAxIABIUCgpvbmVvZl9ib29sGHMgASgISAASFgoMb25lb2ZfdWludDY0GHQg",
"ASgESAASFQoLb25lb2ZfZmxvYXQYdSABKAJIABIWCgxvbmVvZl9kb3VibGUY",
"diABKAFIABJZCgpvbmVvZl9lbnVtGHcgASgOMkMucHJvdG9idWZfdGVzdF9t",
"ZXNzYWdlcy5lZGl0aW9ucy5UZXN0QWxsVHlwZXNFZGl0aW9uMjAyMy5OZXN0",
"ZWRFbnVtSAASXgoNZ3JvdXBsaWtldHlwZRjJASABKAsyRi5wcm90b2J1Zl90",
"ZXN0X21lc3NhZ2VzLmVkaXRpb25zLlRlc3RBbGxUeXBlc0VkaXRpb24yMDIz",
"Lkdyb3VwTGlrZVR5cGUSYAoPZGVsaW1pdGVkX2ZpZWxkGMoBIAEoCzJGLnBy",
"b3RvYnVmX3Rlc3RfbWVzc2FnZXMuZWRpdGlvbnMuVGVzdEFsbFR5cGVzRWRp",
"dGlvbjIwMjMuR3JvdXBMaWtlVHlwZRpwCg1OZXN0ZWRNZXNzYWdlEgkKAWEY",
"ASABKAUSVAoLY29yZWN1cnNpdmUYAiABKAsyOC5wcm90b2J1Zl90ZXN0X21l",
"c3NhZ2VzLmVkaXRpb25zLlRlc3RBbGxUeXBlc0VkaXRpb24yMDIzQgWqAQIo",
"ARo0ChJNYXBJbnQzMkludDMyRW50cnkSCwoDa2V5GAEgASgFEg0KBXZhbHVl",
"GAIgASgFOgI4ARo0ChJNYXBJbnQ2NEludDY0RW50cnkSCwoDa2V5GAEgASgD",
"Eg0KBXZhbHVlGAIgASgDOgI4ARo2ChRNYXBVaW50MzJVaW50MzJFbnRyeRIL",
"CgNrZXkYASABKA0SDQoFdmFsdWUYAiABKA06AjgBGjYKFE1hcFVpbnQ2NFVp",
"bnQ2NEVudHJ5EgsKA2tleRgBIAEoBBINCgV2YWx1ZRgCIAEoBDoCOAEaNgoU",
"TWFwU2ludDMyU2ludDMyRW50cnkSCwoDa2V5GAEgASgREg0KBXZhbHVlGAIg",
"ASgROgI4ARo2ChRNYXBTaW50NjRTaW50NjRFbnRyeRILCgNrZXkYASABKBIS",
"DQoFdmFsdWUYAiABKBI6AjgBGjgKFk1hcEZpeGVkMzJGaXhlZDMyRW50cnkS",
"CwoDa2V5GAEgASgHEg0KBXZhbHVlGAIgASgHOgI4ARo4ChZNYXBGaXhlZDY0",
"Rml4ZWQ2NEVudHJ5EgsKA2tleRgBIAEoBhINCgV2YWx1ZRgCIAEoBjoCOAEa",
"OgoYTWFwU2ZpeGVkMzJTZml4ZWQzMkVudHJ5EgsKA2tleRgBIAEoDxINCgV2",
"YWx1ZRgCIAEoDzoCOAEaOgoYTWFwU2ZpeGVkNjRTZml4ZWQ2NEVudHJ5EgsK",
"A2tleRgBIAEoEBINCgV2YWx1ZRgCIAEoEDoCOAEaNAoSTWFwSW50MzJGbG9h",
"dEVudHJ5EgsKA2tleRgBIAEoBRINCgV2YWx1ZRgCIAEoAjoCOAEaNQoTTWFw",
"SW50MzJEb3VibGVFbnRyeRILCgNrZXkYASABKAUSDQoFdmFsdWUYAiABKAE6",
"AjgBGjIKEE1hcEJvb2xCb29sRW50cnkSCwoDa2V5GAEgASgIEg0KBXZhbHVl",
"GAIgASgIOgI4ARo2ChRNYXBTdHJpbmdTdHJpbmdFbnRyeRILCgNrZXkYASAB",
"KAkSDQoFdmFsdWUYAiABKAk6AjgBGjUKE01hcFN0cmluZ0J5dGVzRW50cnkS",
"CwoDa2V5GAEgASgJEg0KBXZhbHVlGAIgASgMOgI4ARqFAQobTWFwU3RyaW5n",
"TmVzdGVkTWVzc2FnZUVudHJ5EgsKA2tleRgBIAEoCRJVCgV2YWx1ZRgCIAEo",
"CzJGLnByb3RvYnVmX3Rlc3RfbWVzc2FnZXMuZWRpdGlvbnMuVGVzdEFsbFR5",
"cGVzRWRpdGlvbjIwMjMuTmVzdGVkTWVzc2FnZToCOAEaegocTWFwU3RyaW5n",
"Rm9yZWlnbk1lc3NhZ2VFbnRyeRILCgNrZXkYASABKAkSSQoFdmFsdWUYAiAB",
"KAsyOi5wcm90b2J1Zl90ZXN0X21lc3NhZ2VzLmVkaXRpb25zLkZvcmVpZ25N",
"ZXNzYWdlRWRpdGlvbjIwMjM6AjgBGn8KGE1hcFN0cmluZ05lc3RlZEVudW1F",
"bnRyeRILCgNrZXkYASABKAkSUgoFdmFsdWUYAiABKA4yQy5wcm90b2J1Zl90",
"ZXN0X21lc3NhZ2VzLmVkaXRpb25zLlRlc3RBbGxUeXBlc0VkaXRpb24yMDIz",
"Lk5lc3RlZEVudW06AjgBGnQKGU1hcFN0cmluZ0ZvcmVpZ25FbnVtRW50cnkS",
"CwoDa2V5GAEgASgJEkYKBXZhbHVlGAIgASgOMjcucHJvdG9idWZfdGVzdF9t",
"ZXNzYWdlcy5lZGl0aW9ucy5Gb3JlaWduRW51bUVkaXRpb24yMDIzOgI4ARo8",
"Cg1Hcm91cExpa2VUeXBlEhQKC2dyb3VwX2ludDMyGMoBIAEoBRIVCgxncm91",
"cF91aW50MzIYywEgASgNIjkKCk5lc3RlZEVudW0SBwoDRk9PEAASBwoDQkFS",
"EAESBwoDQkFaEAISEAoDTkVHEP///////////wEqBQh4EMkBQg0KC29uZW9m",
"X2ZpZWxkIiYKGUZvcmVpZ25NZXNzYWdlRWRpdGlvbjIwMjMSCQoBYxgBIAEo",
"BSIaCg1Hcm91cExpa2VUeXBlEgkKAWMYASABKAUqSwoWRm9yZWlnbkVudW1F",
"ZGl0aW9uMjAyMxIPCgtGT1JFSUdOX0ZPTxAAEg8KC0ZPUkVJR05fQkFSEAES",
"DwoLRk9SRUlHTl9CQVoQAjpRCg9leHRlbnNpb25faW50MzISOC5wcm90b2J1",
"Zl90ZXN0X21lc3NhZ2VzLmVkaXRpb25zLlRlc3RBbGxUeXBlc0VkaXRpb24y",
"MDIzLkdyb3VwTGlrZVR5cGVCBaoBAigCEmcKD2RlbGltaXRlZF9maWVsZBjK",
"ASABKAsyRi5wcm90b2J1Zl90ZXN0X21lc3NhZ2VzLmVkaXRpb25zLlRlc3RB",
"bGxUeXBlc0VkaXRpb24yMDIzLkdyb3VwTGlrZVR5cGVCBaoBAigCGmkKDU5l",
"c3RlZE1lc3NhZ2USCQoBYRgBIAEoBRJNCgtjb3JlY3Vyc2l2ZRgCIAEoCzI4",
"LnByb3RvYnVmX3Rlc3RfbWVzc2FnZXMuZWRpdGlvbnMuVGVzdEFsbFR5cGVz",
"RWRpdGlvbjIwMjMaNAoSTWFwSW50MzJJbnQzMkVudHJ5EgsKA2tleRgBIAEo",
"BRINCgV2YWx1ZRgCIAEoBToCOAEaNAoSTWFwSW50NjRJbnQ2NEVudHJ5EgsK",
"A2tleRgBIAEoAxINCgV2YWx1ZRgCIAEoAzoCOAEaNgoUTWFwVWludDMyVWlu",
"dDMyRW50cnkSCwoDa2V5GAEgASgNEg0KBXZhbHVlGAIgASgNOgI4ARo2ChRN",
"YXBVaW50NjRVaW50NjRFbnRyeRILCgNrZXkYASABKAQSDQoFdmFsdWUYAiAB",
"KAQ6AjgBGjYKFE1hcFNpbnQzMlNpbnQzMkVudHJ5EgsKA2tleRgBIAEoERIN",
"CgV2YWx1ZRgCIAEoEToCOAEaNgoUTWFwU2ludDY0U2ludDY0RW50cnkSCwoD",
"a2V5GAEgASgSEg0KBXZhbHVlGAIgASgSOgI4ARo4ChZNYXBGaXhlZDMyRml4",
"ZWQzMkVudHJ5EgsKA2tleRgBIAEoBxINCgV2YWx1ZRgCIAEoBzoCOAEaOAoW",
"TWFwRml4ZWQ2NEZpeGVkNjRFbnRyeRILCgNrZXkYASABKAYSDQoFdmFsdWUY",
"AiABKAY6AjgBGjoKGE1hcFNmaXhlZDMyU2ZpeGVkMzJFbnRyeRILCgNrZXkY",
"ASABKA8SDQoFdmFsdWUYAiABKA86AjgBGjoKGE1hcFNmaXhlZDY0U2ZpeGVk",
"NjRFbnRyeRILCgNrZXkYASABKBASDQoFdmFsdWUYAiABKBA6AjgBGjQKEk1h",
"cEludDMyRmxvYXRFbnRyeRILCgNrZXkYASABKAUSDQoFdmFsdWUYAiABKAI6",
"AjgBGjUKE01hcEludDMyRG91YmxlRW50cnkSCwoDa2V5GAEgASgFEg0KBXZh",
"bHVlGAIgASgBOgI4ARoyChBNYXBCb29sQm9vbEVudHJ5EgsKA2tleRgBIAEo",
"CBINCgV2YWx1ZRgCIAEoCDoCOAEaNgoUTWFwU3RyaW5nU3RyaW5nRW50cnkS",
"CwoDa2V5GAEgASgJEg0KBXZhbHVlGAIgASgJOgI4ARo1ChNNYXBTdHJpbmdC",
"eXRlc0VudHJ5EgsKA2tleRgBIAEoCRINCgV2YWx1ZRgCIAEoDDoCOAEahQEK",
"G01hcFN0cmluZ05lc3RlZE1lc3NhZ2VFbnRyeRILCgNrZXkYASABKAkSVQoF",
"dmFsdWUYAiABKAsyRi5wcm90b2J1Zl90ZXN0X21lc3NhZ2VzLmVkaXRpb25z",
"LlRlc3RBbGxUeXBlc0VkaXRpb24yMDIzLk5lc3RlZE1lc3NhZ2U6AjgBGnoK",
"HE1hcFN0cmluZ0ZvcmVpZ25NZXNzYWdlRW50cnkSCwoDa2V5GAEgASgJEkkK",
"BXZhbHVlGAIgASgLMjoucHJvdG9idWZfdGVzdF9tZXNzYWdlcy5lZGl0aW9u",
"cy5Gb3JlaWduTWVzc2FnZUVkaXRpb24yMDIzOgI4ARp/ChhNYXBTdHJpbmdO",
"ZXN0ZWRFbnVtRW50cnkSCwoDa2V5GAEgASgJElIKBXZhbHVlGAIgASgOMkMu",
"cHJvdG9idWZfdGVzdF9tZXNzYWdlcy5lZGl0aW9ucy5UZXN0QWxsVHlwZXNF",
"ZGl0aW9uMjAyMy5OZXN0ZWRFbnVtOgI4ARp0ChlNYXBTdHJpbmdGb3JlaWdu",
"RW51bUVudHJ5EgsKA2tleRgBIAEoCRJGCgV2YWx1ZRgCIAEoDjI3LnByb3Rv",
"YnVmX3Rlc3RfbWVzc2FnZXMuZWRpdGlvbnMuRm9yZWlnbkVudW1FZGl0aW9u",
"MjAyMzoCOAEaPAoNR3JvdXBMaWtlVHlwZRIUCgtncm91cF9pbnQzMhjKASAB",
"KAUSFQoMZ3JvdXBfdWludDMyGMsBIAEoDSI5CgpOZXN0ZWRFbnVtEgcKA0ZP",
"TxAAEgcKA0JBUhABEgcKA0JBWhACEhAKA05FRxD///////////8BKgUIeBDJ",
"AUINCgtvbmVvZl9maWVsZCImChlGb3JlaWduTWVzc2FnZUVkaXRpb24yMDIz",
"EgkKAWMYASABKAUiGgoNR3JvdXBMaWtlVHlwZRIJCgFjGAEgASgFKksKFkZv",
"cmVpZ25FbnVtRWRpdGlvbjIwMjMSDwoLRk9SRUlHTl9GT08QABIPCgtGT1JF",
"SUdOX0JBUhABEg8KC0ZPUkVJR05fQkFaEAI6UQoPZXh0ZW5zaW9uX2ludDMy",
"EjgucHJvdG9idWZfdGVzdF9tZXNzYWdlcy5lZGl0aW9ucy5UZXN0QWxsVHlw",
"ZXNFZGl0aW9uMjAyMxh4IAEoBTqGAQoNZ3JvdXBsaWtldHlwZRI4LnByb3Rv",
"YnVmX3Rlc3RfbWVzc2FnZXMuZWRpdGlvbnMuVGVzdEFsbFR5cGVzRWRpdGlv",
"bjIwMjMYeSABKAsyLi5wcm90b2J1Zl90ZXN0X21lc3NhZ2VzLmVkaXRpb25z",
"Lkdyb3VwTGlrZVR5cGVCBaoBAigCOoYBCg1kZWxpbWl0ZWRfZXh0EjgucHJv",
"dG9idWZfdGVzdF9tZXNzYWdlcy5lZGl0aW9ucy5UZXN0QWxsVHlwZXNFZGl0",
"aW9uMjAyMxh6IAEoCzIuLnByb3RvYnVmX3Rlc3RfbWVzc2FnZXMuZWRpdGlv",
"bnMuR3JvdXBMaWtlVHlwZUIFqgECKAJCPAotY29tLmdvb2dsZS5wcm90b2J1",
"Zl90ZXN0X21lc3NhZ2VzLmVkaXRpb24yMDIzUAGiAghFZGl0aW9uc2IIZWRp",
"dGlvbnNw6Ac="));
"MDIzGHggASgFOn8KDWdyb3VwbGlrZXR5cGUSOC5wcm90b2J1Zl90ZXN0X21l",
"c3NhZ2VzLmVkaXRpb25zLlRlc3RBbGxUeXBlc0VkaXRpb24yMDIzGHkgASgL",
"Mi4ucHJvdG9idWZfdGVzdF9tZXNzYWdlcy5lZGl0aW9ucy5Hcm91cExpa2VU",
"eXBlOn8KDWRlbGltaXRlZF9leHQSOC5wcm90b2J1Zl90ZXN0X21lc3NhZ2Vz",
"LmVkaXRpb25zLlRlc3RBbGxUeXBlc0VkaXRpb24yMDIzGHogASgLMi4ucHJv",
"dG9idWZfdGVzdF9tZXNzYWdlcy5lZGl0aW9ucy5Hcm91cExpa2VUeXBlQkEK",
"LWNvbS5nb29nbGUucHJvdG9idWZfdGVzdF9tZXNzYWdlcy5lZGl0aW9uMjAy",
"M1ABogIIRWRpdGlvbnOSAwIoAmIIZWRpdGlvbnNw6Ac="));
descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
new pbr::FileDescriptor[] { },
new pbr::GeneratedClrTypeInfo(new[] {typeof(global::ProtobufTestMessages.Editions.ForeignEnumEdition2023), }, new pb::Extension[] { TestMessagesEdition2023Extensions.ExtensionInt32, TestMessagesEdition2023Extensions.GroupLikeType, TestMessagesEdition2023Extensions.DelimitedExt }, new pbr::GeneratedClrTypeInfo[] {

@ -8027,12 +8027,13 @@ namespace Google.Protobuf.Reflection {
private global::Google.Protobuf.Reflection.FieldOptions.Types.CType ctype_;
/// <summary>
/// NOTE: ctype is deprecated. Use `features.(pb.cpp).string_type` instead.
/// The ctype option instructs the C++ code generator to use a different
/// representation of the field than it normally would. See the specific
/// options below. This option is only implemented to support use of
/// [ctype=CORD] and [ctype=STRING] (the default) on non-repeated fields of
/// type "bytes" in the open source release -- sorry, we'll try to include
/// other types in a future version!
/// type "bytes" in the open source release.
/// TODO: make ctype actually deprecated.
/// </summary>
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]

@ -412,6 +412,11 @@ namespace Google.Protobuf.Reflection
throw new DescriptorValidationException(this, $"\"{Proto.TypeName}\" is not a message type.");
}
messageType = m;
if (m.Proto.Options?.MapEntry == true || ContainingType?.Proto.Options?.MapEntry == true)
{
// Maps can't inherit delimited encoding.
FieldType = FieldType.Message;
}
if (Proto.HasDefaultValue)
{

@ -501,3 +501,8 @@ with info about your project (name and website) so we can add an entry for you.
* Website: https://github.com/solo-io/protoc-gen-openapi
* Extensions: 1188-1189
1. Wire enumMode
* Website: https://square.github.io/wire/
* Extensions: 1190

@ -87,18 +87,6 @@ cc_library(
],
)
cc_proto_library(
name = "cpp_features_cc_proto",
testonly = True,
deps = ["//src/google/protobuf:cpp_features_proto"],
)
cc_proto_library(
name = "java_features_cc_proto",
testonly = True,
deps = ["//java/core:java_features_proto"],
)
cc_test(
name = "defaults_test",
srcs = ["defaults_test.cc"],
@ -109,11 +97,11 @@ cc_test(
":test_defaults_future",
],
deps = [
":cpp_features_cc_proto",
":defaults_test_embedded",
":java_features_cc_proto",
"//:protobuf",
"//java/core:java_features_cc_proto",
"//src/google/protobuf",
"//src/google/protobuf:cpp_features_cc_proto",
"//src/google/protobuf:port",
"//src/google/protobuf:protobuf_lite",
"//src/google/protobuf:test_textproto",

@ -5,7 +5,7 @@
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd
#include "protos_generator/gen_accessors.h"
#include "hpb_generator/gen_accessors.h"
#include <string>
@ -14,10 +14,10 @@
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#include "google/protobuf/descriptor.h"
#include "protos_generator/gen_repeated_fields.h"
#include "protos_generator/gen_utils.h"
#include "protos_generator/names.h"
#include "protos_generator/output.h"
#include "hpb_generator/gen_repeated_fields.h"
#include "hpb_generator/gen_utils.h"
#include "hpb_generator/names.h"
#include "hpb_generator/output.h"
#include "upb_generator/common.h"
#include "upb_generator/keywords.h"
#include "upb_generator/names.h"

@ -9,8 +9,8 @@
#define UPB_PROTOS_GENERATOR_ACCESSORS_H_
#include "google/protobuf/descriptor.h"
#include "protos_generator/gen_utils.h"
#include "protos_generator/output.h"
#include "hpb_generator/gen_utils.h"
#include "hpb_generator/output.h"
namespace protos_generator {

@ -5,7 +5,7 @@
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd
#include "protos_generator/gen_enums.h"
#include "hpb_generator/gen_enums.h"
#include <algorithm>
#include <limits>
@ -14,8 +14,8 @@
#include "google/protobuf/descriptor.pb.h"
#include "google/protobuf/descriptor.h"
#include "protos_generator/gen_utils.h"
#include "protos_generator/names.h"
#include "hpb_generator/gen_utils.h"
#include "hpb_generator/names.h"
namespace protos_generator {

@ -9,7 +9,7 @@
#define UPB_PROTOS_GENERATOR_ENUMS_H_
#include "google/protobuf/descriptor.h"
#include "protos_generator/output.h"
#include "hpb_generator/output.h"
namespace protos_generator {

@ -5,11 +5,11 @@
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd
#include "protos_generator/gen_extensions.h"
#include "hpb_generator/gen_extensions.h"
#include "absl/strings/str_cat.h"
#include "protos_generator/gen_utils.h"
#include "protos_generator/names.h"
#include "hpb_generator/gen_utils.h"
#include "hpb_generator/names.h"
namespace protos_generator {

@ -9,7 +9,7 @@
#define UPB_PROTOS_GENERATOR_GEN_EXTENSIONS_H_
#include "google/protobuf/descriptor.h"
#include "protos_generator/output.h"
#include "hpb_generator/output.h"
namespace protos_generator {

@ -5,7 +5,7 @@
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd
#include "protos_generator/gen_messages.h"
#include "hpb_generator/gen_messages.h"
#include <cstddef>
#include <string>
@ -16,12 +16,12 @@
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#include "google/protobuf/descriptor.h"
#include "protos_generator/gen_accessors.h"
#include "protos_generator/gen_enums.h"
#include "protos_generator/gen_extensions.h"
#include "protos_generator/gen_utils.h"
#include "protos_generator/names.h"
#include "protos_generator/output.h"
#include "hpb_generator/gen_accessors.h"
#include "hpb_generator/gen_enums.h"
#include "hpb_generator/gen_extensions.h"
#include "hpb_generator/gen_utils.h"
#include "hpb_generator/names.h"
#include "hpb_generator/output.h"
#include "upb_generator/common.h"
#include "upb_generator/file_layout.h"

@ -9,7 +9,7 @@
#define UPB_PROTOS_GENERATOR_GEN_MESSAGES_H_
#include "google/protobuf/descriptor.h"
#include "protos_generator/output.h"
#include "hpb_generator/output.h"
namespace protos_generator {
namespace protobuf = ::google::protobuf;

@ -5,7 +5,7 @@
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd
#include "protos_generator/gen_repeated_fields.h"
#include "hpb_generator/gen_repeated_fields.h"
#include <string>
#include <vector>
@ -13,12 +13,12 @@
#include "google/protobuf/descriptor.pb.h"
#include "absl/strings/string_view.h"
#include "google/protobuf/descriptor.h"
#include "protos_generator/gen_accessors.h"
#include "protos_generator/gen_enums.h"
#include "protos_generator/gen_extensions.h"
#include "protos_generator/gen_utils.h"
#include "protos_generator/names.h"
#include "protos_generator/output.h"
#include "hpb_generator/gen_accessors.h"
#include "hpb_generator/gen_enums.h"
#include "hpb_generator/gen_extensions.h"
#include "hpb_generator/gen_utils.h"
#include "hpb_generator/names.h"
#include "hpb_generator/output.h"
#include "upb_generator/common.h"
#include "upb_generator/file_layout.h"
#include "upb_generator/names.h"

@ -10,7 +10,7 @@
#include "absl/strings/string_view.h"
#include "google/protobuf/descriptor.h"
#include "protos_generator/output.h"
#include "hpb_generator/output.h"
namespace protos_generator {
namespace protobuf = ::google::protobuf;

@ -5,7 +5,7 @@
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd
#include "protos_generator/gen_utils.h"
#include "hpb_generator/gen_utils.h"
#include <algorithm>
#include <string>

@ -5,7 +5,7 @@
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd
#include "protos_generator/names.h"
#include "hpb_generator/names.h"
#include <string>

@ -11,7 +11,7 @@
#include <string>
#include "google/protobuf/descriptor.pb.h"
#include "protos_generator/output.h"
#include "hpb_generator/output.h"
namespace protos_generator {

@ -5,7 +5,7 @@
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd
#include "protos_generator/output.h"
#include "hpb_generator/output.h"
#include <string>

@ -5,19 +5,22 @@
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd
#include <cstdint>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "google/protobuf/descriptor.pb.h"
#include "google/protobuf/compiler/code_generator.h"
#include "google/protobuf/compiler/plugin.h"
#include "google/protobuf/descriptor.h"
#include "protos_generator/gen_enums.h"
#include "protos_generator/gen_extensions.h"
#include "protos_generator/gen_messages.h"
#include "protos_generator/gen_utils.h"
#include "protos_generator/names.h"
#include "protos_generator/output.h"
#include "upb_generator/file_layout.h"
#include "hpb_generator/gen_enums.h"
#include "hpb_generator/gen_extensions.h"
#include "hpb_generator/gen_messages.h"
#include "hpb_generator/gen_utils.h"
#include "hpb_generator/names.h"
#include "hpb_generator/output.h"
namespace protos_generator {
namespace {
@ -25,6 +28,7 @@ namespace {
namespace protoc = ::google::protobuf::compiler;
namespace protobuf = ::google::protobuf;
using FileDescriptor = ::google::protobuf::FileDescriptor;
using google::protobuf::Edition;
void WriteSource(const protobuf::FileDescriptor* file, Output& output,
bool fasttable_enabled);
@ -42,13 +46,16 @@ void WriteHeaderMessageForwardDecls(const protobuf::FileDescriptor* file,
class Generator : public protoc::CodeGenerator {
public:
~Generator() override {}
~Generator() override = default;
bool Generate(const protobuf::FileDescriptor* file,
const std::string& parameter, protoc::GeneratorContext* context,
std::string* error) const override;
uint64_t GetSupportedFeatures() const override {
return FEATURE_PROTO3_OPTIONAL;
return Feature::FEATURE_PROTO3_OPTIONAL |
Feature::FEATURE_SUPPORTS_EDITIONS;
}
Edition GetMinimumEdition() const override { return Edition::EDITION_PROTO2; }
Edition GetMaximumEdition() const override { return Edition::EDITION_2023; }
};
bool Generator::Generate(const protobuf::FileDescriptor* file,
@ -71,14 +78,21 @@ bool Generator::Generate(const protobuf::FileDescriptor* file,
}
// Write model.upb.fwd.h
Output forwarding_header_output(
std::unique_ptr<google::protobuf::io::ZeroCopyOutputStream> output_stream(
context->Open(ForwardingHeaderFilename(file)));
Output forwarding_header_output(output_stream.get());
WriteForwardingHeader(file, forwarding_header_output);
// Write model.upb.proto.h
Output header_output(context->Open(CppHeaderFilename(file)));
std::unique_ptr<google::protobuf::io::ZeroCopyOutputStream> header_output_stream(
context->Open(CppHeaderFilename(file)));
Output header_output(header_output_stream.get());
WriteHeader(file, header_output);
// Write model.upb.proto.cc
Output cc_output(context->Open(CppSourceFilename(file)));
std::unique_ptr<google::protobuf::io::ZeroCopyOutputStream> cc_output_stream(
context->Open(CppSourceFilename(file)));
Output cc_output(cc_output_stream.get());
WriteSource(file, cc_output, fasttable_enabled);
return true;
}

@ -112,6 +112,19 @@ cc_proto_library(
# visibility = ["//visibility:private"],
# deps = [":legacy_name_proto"],
# )
#
# proto_library(
# name = "basic_editions_proto",
# srcs = [
# "basic_test_editions.proto",
# ],
# )
#
# upb_cc_proto_library(
# name = "basic_test_editions_proto",
# visibility = ["//visibility:private"],
# deps = [":basic_editions_proto"],
# )
# end:google_only
cc_test(

@ -0,0 +1,18 @@
edition = "2023";
package editions_upb_test;
option features.enum_type = CLOSED;
option features.field_presence = IMPLICIT;
message TestFeaturesMessage {
int32 implicit = 1;
int32 explicit = 2 [features.field_presence = EXPLICIT];
int32 legacy_required = 3 [features.field_presence = LEGACY_REQUIRED];
repeated int32 packed = 50;
repeated int32 expanded = 51 [features.repeated_field_encoding = EXPANDED];
TestFeaturesMessage delimited = 100 [features.message_encoding = DELIMITED];
TestFeaturesMessage length_prefixed = 101;
}

@ -9,7 +9,7 @@ syntax = "proto3";
package protos_generator.test;
import public "protos_generator/tests/test_enum.proto";
import public "hpb_generator/tests/test_enum.proto";
message ChildModel1 {
optional bool child_b1 = 44;

@ -9,7 +9,7 @@ syntax = "proto2";
package protos_generator.tests;
import "protos_generator/tests/no_package.proto";
import "hpb_generator/tests/no_package.proto";
// option java_multiple_files = true;

@ -9,7 +9,7 @@ syntax = "proto2";
package protos_generator.test.someotherpackage;
import "protos_generator/tests/test_model.proto";
import "hpb_generator/tests/test_model.proto";
// Define extension that is extending proto outside this package with a type
// defined in different file.

@ -18,13 +18,13 @@
#include <gtest/gtest.h>
#include "absl/status/statusor.h"
#include "absl/strings/string_view.h"
#include "hpb_generator/tests/child_model.upb.proto.h"
#include "hpb_generator/tests/no_package.upb.proto.h"
#include "hpb_generator/tests/test_model.upb.proto.h"
#include "protos/protos.h"
#include "protos/repeated_field.h"
#include "protos/repeated_field_iterator.h"
#include "protos/requires.h"
#include "protos_generator/tests/child_model.upb.proto.h"
#include "protos_generator/tests/no_package.upb.proto.h"
#include "protos_generator/tests/test_model.upb.proto.h"
#include "upb/mem/arena.h"
#include "upb/mem/arena.hpp"

@ -9,7 +9,7 @@ syntax = "proto2";
package protos_generator.test;
import "protos_generator/tests/child_model.proto";
import "hpb_generator/tests/child_model.proto";
message TestModelContainer {
repeated TestModel models = 1;

@ -196,6 +196,12 @@ proto_library(
deps = ["//:descriptor_proto"],
)
cc_proto_library(
name = "java_features_cc_proto",
visibility = ["//editions:__pkg__"],
deps = [":java_features_proto"],
)
filegroup(
name = "java_features_proto_srcs",
srcs = ["src/main/resources/google/protobuf/java_features.proto"],

@ -1297,6 +1297,8 @@ public final class Descriptors {
// since these are used before feature resolution when parsing java feature set defaults
// (custom options) into unknown fields.
if (type == Type.MESSAGE
&& !(messageType != null && messageType.toProto().getOptions().getMapEntry())
&& !(containingType != null && containingType.toProto().getOptions().getMapEntry())
&& this.features != null
&& getFeatures().getMessageEncoding() == FeatureSet.MessageEncoding.DELIMITED) {
return Type.GROUP;
@ -1476,8 +1478,7 @@ public final class Descriptors {
* been upgraded to editions.
*/
boolean isGroupLike() {
if (getFeatures().getMessageEncoding()
!= DescriptorProtos.FeatureSet.MessageEncoding.DELIMITED) {
if (getType() != Type.GROUP) {
// Groups are always tag-delimited.
return false;
}
@ -1900,7 +1901,9 @@ public final class Descriptors {
}
}
if (getJavaType() == JavaType.MESSAGE) {
// Use raw type since inferred type considers messageType which may not be fully cross
// linked yet.
if (type.getJavaType() == JavaType.MESSAGE) {
if (!(typeDescriptor instanceof Descriptor)) {
throw new DescriptorValidationException(
this, '\"' + proto.getTypeName() + "\" is not a message type.");
@ -1910,7 +1913,7 @@ public final class Descriptors {
if (proto.hasDefaultValue()) {
throw new DescriptorValidationException(this, "Messages can't have default values.");
}
} else if (getJavaType() == JavaType.ENUM) {
} else if (type.getJavaType() == JavaType.ENUM) {
if (!(typeDescriptor instanceof EnumDescriptor)) {
throw new DescriptorValidationException(
this, '\"' + proto.getTypeName() + "\" is not an enum type.");
@ -1920,7 +1923,7 @@ public final class Descriptors {
throw new DescriptorValidationException(this, "Field with primitive type has type_name.");
}
} else {
if (getJavaType() == JavaType.MESSAGE || getJavaType() == JavaType.ENUM) {
if (type.getJavaType() == JavaType.MESSAGE || type.getJavaType() == JavaType.ENUM) {
throw new DescriptorValidationException(
this, "Field with message or enum type missing type_name.");
}
@ -1941,7 +1944,7 @@ public final class Descriptors {
}
try {
switch (getType()) {
switch (type) {
case INT32:
case SINT32:
case SFIXED32:
@ -2016,7 +2019,7 @@ public final class Descriptors {
if (isRepeated()) {
defaultValue = Collections.emptyList();
} else {
switch (getJavaType()) {
switch (type.getJavaType()) {
case ENUM:
// We guarantee elsewhere that an enum type always has at least
// one possible value.
@ -2026,7 +2029,7 @@ public final class Descriptors {
defaultValue = null;
break;
default:
defaultValue = getJavaType().defaultDefault;
defaultValue = type.getJavaType().defaultDefault;
break;
}
}
@ -2782,10 +2785,30 @@ public final class Descriptors {
public abstract FileDescriptor getFile();
void resolveFeatures(FeatureSet unresolvedFeatures) throws DescriptorValidationException {
// Unknown java features may be passed by users via public buildFrom but should not occur from
// generated code.
if (!unresolvedFeatures.getUnknownFields().isEmpty()
&& unresolvedFeatures.getUnknownFields().hasField(JavaFeaturesProto.java_.getNumber())) {
if (this.parent != null
&& unresolvedFeatures.equals(FeatureSet.getDefaultInstance())
&& !hasInferredLegacyProtoFeatures()) {
this.features = this.parent.features;
validateFeatures();
return;
}
// Java features from a custom pool (i.e. buildFrom) may end up in unknown fields or
// use a different descriptor from the generated pool used by the Java runtime.
boolean hasPossibleCustomJavaFeature = false;
for (FieldDescriptor f : unresolvedFeatures.getExtensionFields().keySet()) {
if (f.getNumber() == JavaFeaturesProto.java_.getNumber()
&& f != JavaFeaturesProto.java_.getDescriptor()) {
hasPossibleCustomJavaFeature = true;
continue;
}
}
boolean hasPossibleUnknownJavaFeature =
!unresolvedFeatures.getUnknownFields().isEmpty()
&& unresolvedFeatures
.getUnknownFields()
.hasField(JavaFeaturesProto.java_.getNumber());
if (hasPossibleCustomJavaFeature || hasPossibleUnknownJavaFeature) {
ExtensionRegistry registry = ExtensionRegistry.newInstance();
registry.add(JavaFeaturesProto.java_);
ByteString bytes = unresolvedFeatures.toByteString();
@ -2796,14 +2819,7 @@ public final class Descriptors {
this, "Failed to parse features with Java feature extension registry.", e);
}
}
if (this.parent != null
&& unresolvedFeatures.equals(FeatureSet.getDefaultInstance())
&& !hasInferredLegacyProtoFeatures()) {
this.features = this.parent.features;
validateFeatures();
return;
}
FeatureSet.Builder features;
if (this.parent == null) {
Edition edition = getFile().getEdition();

@ -1025,10 +1025,28 @@ public abstract class GeneratedMessage extends AbstractMessage implements Serial
/**
* Used by subclasses to serialize extensions. Extension ranges may be interleaved with field
* numbers, but we must write them in canonical (sorted by field number) order. ExtensionWriter
* helps us write individual ranges of extensions at once.
* numbers, but we must write them in canonical (sorted by field number) order.
* ExtensionSerializer helps us write individual ranges of extensions at once.
*/
protected class ExtensionWriter {
protected interface ExtensionSerializer {
public void writeUntil(final int end, final CodedOutputStream output) throws IOException;
}
/** No-op implementation that writes nothing, for messages with no extensions. */
private static final class NoOpExtensionSerializer implements ExtensionSerializer {
// Singleton instance so we can avoid allocating a new one for each message serialization.
private static final NoOpExtensionSerializer INSTANCE = new NoOpExtensionSerializer();
@Override
public void writeUntil(final int end, final CodedOutputStream output) {
// no-op
}
}
/**
* ExtensionSerializer that writes extensions from the FieldSet, for messages with extensions.
*/
protected class ExtensionWriter implements ExtensionSerializer {
// Imagine how much simpler this code would be if Java iterators had
// a way to get the next element without advancing the iterator.
@ -1043,6 +1061,7 @@ public abstract class GeneratedMessage extends AbstractMessage implements Serial
this.messageSetWireFormat = messageSetWireFormat;
}
@Override
public void writeUntil(final int end, final CodedOutputStream output) throws IOException {
while (next != null && next.getKey().getNumber() < end) {
FieldDescriptor descriptor = next.getKey();
@ -1075,14 +1094,32 @@ public abstract class GeneratedMessage extends AbstractMessage implements Serial
}
}
// TODO: Remove, replace with newExtensionSerializer().
protected ExtensionWriter newExtensionWriter() {
return new ExtensionWriter(false);
}
protected ExtensionSerializer newExtensionSerializer() {
// Avoid allocation in the common case of no extensions.
if (extensions.isEmpty()) {
return NoOpExtensionSerializer.INSTANCE;
}
return new ExtensionWriter(false);
}
// TODO: Remove, replace with newMessageSetExtensionSerializer().
protected ExtensionWriter newMessageSetExtensionWriter() {
return new ExtensionWriter(true);
}
protected ExtensionSerializer newMessageSetExtensionSerializer() {
// Avoid allocation in the common case of no extensions.
if (extensions.isEmpty()) {
return NoOpExtensionSerializer.INSTANCE;
}
return new ExtensionWriter(true);
}
/** Called by subclasses to compute the size of extensions. */
protected int extensionsSerializedSize() {
return extensions.getSerializedSize();

@ -0,0 +1,83 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2024 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
package com.google.protobuf;
import java.util.List;
/**
* Stub for GeneratedMessageV3 wrapping GeneratedMessage for compatibility with older gencode.
*
* @deprecated This class is deprecated, and slated for removal in the next Java breaking change
* (5.x in 2025 Q1). Users should update gencode to >= 4.26.x which uses GeneratedMessage
* instead of GeneratedMessageV3.
*/
@Deprecated
public abstract class GeneratedMessageV3 extends GeneratedMessage {
private static final long serialVersionUID = 1L;
protected GeneratedMessageV3() {
super();
}
protected GeneratedMessageV3(Builder<?> builder) {
super(builder);
}
/**
* Stub for GeneratedMessageV3.ExtendableBuilder wrapping GeneratedMessage.ExtendableBuilder for
* compatibility with older gencode.
*
* @deprecated This class is deprecated, and slated for removal in the next Java breaking change
* (5.x in 2025 Q1). Users should update gencode to >= 4.26.x which uses
* GeneratedMessage.ExtendableBuilder instead of GeneratedMessageV3.ExtendableBuilder.
*/
@Deprecated
public abstract static class ExtendableBuilder<
MessageT extends ExtendableMessage<MessageT>,
BuilderT extends ExtendableBuilder<MessageT, BuilderT>>
extends GeneratedMessage.ExtendableBuilder<MessageT, BuilderT>
implements GeneratedMessage.ExtendableMessageOrBuilder<MessageT> {
protected ExtendableBuilder() {
super();
}
protected ExtendableBuilder(BuilderParent parent) {
super(parent);
}
// Support old gencode override method removed in
// https://github.com/protocolbuffers/protobuf/commit/7bff169d32710b143951ec6ce2c4ea9a56e2ad24
public <T> BuilderT setExtension(
final GeneratedMessage.GeneratedExtension<MessageT, T> extension, final T value) {
return setExtension((ExtensionLite<MessageT, T>) extension, value);
}
// Support old gencode override method removed in
// https://github.com/protocolbuffers/protobuf/commit/7bff169d32710b143951ec6ce2c4ea9a56e2ad24
public <T> BuilderT setExtension(
final GeneratedMessage.GeneratedExtension<MessageT, List<T>> extension,
final int index,
final T value) {
return setExtension((ExtensionLite<MessageT, List<T>>) extension, index, value);
}
// Support old gencode override method removed in
// https://github.com/protocolbuffers/protobuf/commit/7bff169d32710b143951ec6ce2c4ea9a56e2ad24
public <T> BuilderT addExtension(
final GeneratedMessage.GeneratedExtension<MessageT, List<T>> extension, final T value) {
return addExtension((ExtensionLite<MessageT, List<T>>) extension, value);
}
// Support old gencode override method removed in
// https://github.com/protocolbuffers/protobuf/commit/7bff169d32710b143951ec6ce2c4ea9a56e2ad24
public <T> BuilderT clearExtension(
final GeneratedMessage.GeneratedExtension<MessageT, T> extension) {
return clearExtension((ExtensionLite<MessageT, T>) extension);
}
}
}

@ -0,0 +1,34 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2024 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
package com.google.protobuf;
import java.util.List;
/**
* Stub for RepeatedFieldBuilderV3 wrapping RepeatedFieldBuilder for compatibility with older
* gencode.
*
* @deprecated This class is deprecated, and slated for removal in the next breaking change. Users
* should update gencode to >= 4.26.x which replaces RepeatedFieldBuilderV3 with
* RepeatedFieldBuilder.
*/
@Deprecated
public class RepeatedFieldBuilderV3<
MType extends GeneratedMessage,
BType extends GeneratedMessage.Builder,
IType extends MessageOrBuilder>
extends RepeatedFieldBuilder<MType, BType, IType> {
public RepeatedFieldBuilderV3(
List<MType> messages,
boolean isMessagesListMutable,
GeneratedMessage.BuilderParent parent,
boolean isClean) {
super(messages, isMessagesListMutable, parent, isClean);
}
}

@ -0,0 +1,28 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2024 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
package com.google.protobuf;
/**
* Stub for SingleFieldBuilderV3 wrapping SingleFieldBuilder for compatibility with older gencode.
*
* @deprecated This class is deprecated, and slated for removal in the next breaking change. Users
* should update gencode to >= 4.26.x which replaces SingleFieldBuilderV3 with
* SingleFieldBuilder.
*/
@Deprecated
public class SingleFieldBuilderV3<
MType extends GeneratedMessage,
BType extends GeneratedMessage.Builder,
IType extends MessageOrBuilder>
extends SingleFieldBuilder<MType, BType, IType> {
public SingleFieldBuilderV3(
MType message, GeneratedMessage.BuilderParent parent, boolean isClean) {
super(message, parent, isClean);
}
}

@ -352,8 +352,9 @@ public class DescriptorsTest {
}
@Test
public void testProto2FieldDescriptorLegacyEnumFieldTreatedAsClosed() throws Exception {
// Make an open enum definition.
public void testFieldDescriptorLegacyEnumFieldTreatedAsOpen() throws Exception {
// Make an open enum definition and message that treats enum fields as open.
FileDescriptorProto openEnumFile =
FileDescriptorProto.newBuilder()
.setName("open_enum.proto")
@ -367,30 +368,9 @@ public class DescriptorsTest {
.setNumber(0)
.build())
.build())
.build();
FileDescriptor openFileDescriptor =
Descriptors.FileDescriptor.buildFrom(openEnumFile, new FileDescriptor[0]);
EnumDescriptor openEnum = openFileDescriptor.getEnumTypes().get(0);
assertThat(openEnum.isClosed()).isFalse();
// Create a message that treats enum fields as closed.
FileDescriptorProto closedEnumFile =
FileDescriptorProto.newBuilder()
.setName("closed_enum_field.proto")
.addDependency("open_enum.proto")
.setSyntax("proto2")
.addEnumType(
EnumDescriptorProto.newBuilder()
.setName("TestEnum")
.addValue(
EnumValueDescriptorProto.newBuilder()
.setName("TestEnum_VALUE0")
.setNumber(0)
.build())
.build())
.addMessageType(
DescriptorProto.newBuilder()
.setName("TestClosedEnumField")
.setName("TestOpenEnumField")
.addField(
FieldDescriptorProto.newBuilder()
.setName("int_field")
@ -406,32 +386,21 @@ public class DescriptorsTest {
.setTypeName("TestEnumOpen")
.setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
.build())
.addField(
FieldDescriptorProto.newBuilder()
.setName("closed_enum")
.setNumber(3)
.setType(FieldDescriptorProto.Type.TYPE_ENUM)
.setTypeName("TestEnum")
.setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
.build())
.build())
.build();
Descriptor closedMessage =
Descriptors.FileDescriptor.buildFrom(
closedEnumFile, new FileDescriptor[] {openFileDescriptor})
.getMessageTypes()
.get(0);
assertThat(closedMessage.findFieldByName("int_field").legacyEnumFieldTreatedAsClosed())
FileDescriptor openEnumFileDescriptor =
Descriptors.FileDescriptor.buildFrom(openEnumFile, new FileDescriptor[0]);
Descriptor openMessage = openEnumFileDescriptor.getMessageTypes().get(0);
EnumDescriptor openEnum = openEnumFileDescriptor.findEnumTypeByName("TestEnumOpen");
assertThat(openEnum.isClosed()).isFalse();
assertThat(openMessage.findFieldByName("int_field").legacyEnumFieldTreatedAsClosed())
.isFalse();
assertThat(openMessage.findFieldByName("open_enum").legacyEnumFieldTreatedAsClosed())
.isFalse();
assertThat(closedMessage.findFieldByName("closed_enum").legacyEnumFieldTreatedAsClosed())
.isTrue();
assertThat(closedMessage.findFieldByName("open_enum").legacyEnumFieldTreatedAsClosed())
.isTrue();
}
@Test
public void testEditionFieldDescriptorLegacyEnumFieldTreatedAsClosed() throws Exception {
public void testEditionFieldDescriptorLegacyEnumFieldTreatedAsClosedUnknown() throws Exception {
// Make an open enum definition.
FileDescriptorProto openEnumFile =
FileDescriptorProto.newBuilder()
@ -536,12 +505,19 @@ public class DescriptorsTest {
}
@Test
public void testFieldDescriptorLegacyEnumFieldTreatedAsOpen() throws Exception {
// Make an open enum definition and message that treats enum fields as open.
public void testEditionFieldDescriptorLegacyEnumFieldTreatedAsClosedCustomPool()
throws Exception {
FileDescriptor javaFeaturesDescriptor =
Descriptors.FileDescriptor.buildFrom(
JavaFeaturesProto.getDescriptor().toProto(),
new FileDescriptor[] {DescriptorProtos.getDescriptor()});
// Make an open enum definition.
FileDescriptorProto openEnumFile =
FileDescriptorProto.newBuilder()
.setName("open_enum.proto")
.setSyntax("proto3")
.setSyntax("editions")
.setEdition(Edition.EDITION_2023)
.addEnumType(
EnumDescriptorProto.newBuilder()
.setName("TestEnumOpen")
@ -551,9 +527,38 @@ public class DescriptorsTest {
.setNumber(0)
.build())
.build())
.build();
FileDescriptor openFileDescriptor =
Descriptors.FileDescriptor.buildFrom(openEnumFile, new FileDescriptor[0]);
EnumDescriptor openEnum = openFileDescriptor.getEnumTypes().get(0);
assertThat(openEnum.isClosed()).isFalse();
// Create a message that treats enum fields as closed.
FileDescriptorProto editionsClosedEnumFile =
FileDescriptorProto.newBuilder()
.setName("editions_closed_enum_field.proto")
.addDependency("open_enum.proto")
.setSyntax("editions")
.setEdition(Edition.EDITION_2023)
.setOptions(
FileOptions.newBuilder()
.setFeatures(
DescriptorProtos.FeatureSet.newBuilder()
.setEnumType(DescriptorProtos.FeatureSet.EnumType.CLOSED)
.build())
.build())
.addEnumType(
EnumDescriptorProto.newBuilder()
.setName("TestEnum")
.addValue(
EnumValueDescriptorProto.newBuilder()
.setName("TestEnum_VALUE0")
.setNumber(0)
.build())
.build())
.addMessageType(
DescriptorProto.newBuilder()
.setName("TestOpenEnumField")
.setName("TestClosedEnumField")
.addField(
FieldDescriptorProto.newBuilder()
.setName("int_field")
@ -568,18 +573,53 @@ public class DescriptorsTest {
.setType(FieldDescriptorProto.Type.TYPE_ENUM)
.setTypeName("TestEnumOpen")
.setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
.setOptions(
DescriptorProtos.FieldOptions.newBuilder()
.setFeatures(
DescriptorProtos.FeatureSet.newBuilder()
.setExtension(
// Extension cannot be directly set using custom
// descriptor, so set using generated for now.
JavaFeaturesProto.java_,
JavaFeaturesProto.JavaFeatures.newBuilder()
.setLegacyClosedEnum(true)
.build())
.build())
.build())
.build())
.addField(
FieldDescriptorProto.newBuilder()
.setName("closed_enum")
.setNumber(3)
.setType(FieldDescriptorProto.Type.TYPE_ENUM)
.setTypeName("TestEnum")
.setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
.build())
.build())
.build();
FileDescriptor openEnumFileDescriptor =
Descriptors.FileDescriptor.buildFrom(openEnumFile, new FileDescriptor[0]);
Descriptor openMessage = openEnumFileDescriptor.getMessageTypes().get(0);
EnumDescriptor openEnum = openEnumFileDescriptor.findEnumTypeByName("TestEnumOpen");
assertThat(openEnum.isClosed()).isFalse();
assertThat(openMessage.findFieldByName("int_field").legacyEnumFieldTreatedAsClosed())
.isFalse();
assertThat(openMessage.findFieldByName("open_enum").legacyEnumFieldTreatedAsClosed())
// Reparse using custom java features descriptor.
ExtensionRegistry registry = ExtensionRegistry.newInstance();
registry.add(
javaFeaturesDescriptor.getExtensions().get(0),
DynamicMessage.getDefaultInstance(
javaFeaturesDescriptor.getExtensions().get(0).getMessageType()));
editionsClosedEnumFile =
FileDescriptorProto.parseFrom(editionsClosedEnumFile.toByteString(), registry);
Descriptor editionsClosedMessage =
Descriptors.FileDescriptor.buildFrom(
editionsClosedEnumFile,
new FileDescriptor[] {openFileDescriptor, javaFeaturesDescriptor})
.getMessageTypes()
.get(0);
assertThat(
editionsClosedMessage.findFieldByName("int_field").legacyEnumFieldTreatedAsClosed())
.isFalse();
assertThat(
editionsClosedMessage.findFieldByName("closed_enum").legacyEnumFieldTreatedAsClosed())
.isTrue();
assertThat(
editionsClosedMessage.findFieldByName("open_enum").legacyEnumFieldTreatedAsClosed())
.isTrue();
}
@Test

@ -30,7 +30,6 @@ message Foo {
MyGroup mygroup = 5 [features.message_encoding = DELIMITED];
}
// LINT: ALLOW_GROUPS
message MyGroup {
int32 value = 1;
}

@ -378,7 +378,7 @@ error UPB_TRACING_ENABLED Tracing should be disabled in production builds
#define UPB_LINKARR_DECLARE(name, type) \
extern type const __start_linkarr_##name; \
extern type const __stop_linkarr_##name; \
UPB_LINKARR_APPEND(name) type UPB_linkarr_internal_empty_##name[1] = {0}
UPB_LINKARR_APPEND(name) type UPB_linkarr_internal_empty_##name[1]
#define UPB_LINKARR_START(name) (&__start_linkarr_##name)
#define UPB_LINKARR_STOP(name) (&__stop_linkarr_##name)
@ -386,14 +386,14 @@ error UPB_TRACING_ENABLED Tracing should be disabled in production builds
/* As described in: https://stackoverflow.com/a/22366882 */
#define UPB_LINKARR_APPEND(name) \
__attribute__((retain, used, section("__DATA,la_" #name)))
__attribute__((retain, used, section("__DATA,__la_" #name)))
#define UPB_LINKARR_DECLARE(name, type) \
extern type const __start_linkarr_##name __asm( \
"section$start$__DATA$la_" #name); \
"section$start$__DATA$__la_" #name); \
extern type const __stop_linkarr_##name __asm( \
"section$end$__DATA$" \
"la_" #name); \
UPB_LINKARR_APPEND(name) type UPB_linkarr_internal_empty_##name[1] = {0}
"__la_" #name); \
UPB_LINKARR_APPEND(name) type UPB_linkarr_internal_empty_##name[1]
#define UPB_LINKARR_START(name) (&__start_linkarr_##name)
#define UPB_LINKARR_STOP(name) (&__stop_linkarr_##name)
@ -487,6 +487,7 @@ void upb_Status_VAppendErrorFormat(upb_Status* status, const char* fmt,
// Must be last.
extern const struct upb_MiniTable UPB_PRIVATE(_kUpb_MiniTable_StaticallyTreeShaken);
static const upb_MiniTableSubInternal google_protobuf_FileDescriptorSet_submsgs[1] = {
{.UPB_PRIVATE(submsg) = &google__protobuf__FileDescriptorProto_msg_init_ptr},
};
@ -1641,42 +1642,6 @@ const upb_MiniTable google__protobuf__GeneratedCodeInfo__Annotation_msg_init = {
};
const upb_MiniTable* google__protobuf__GeneratedCodeInfo__Annotation_msg_init_ptr = &google__protobuf__GeneratedCodeInfo__Annotation_msg_init;
static const upb_MiniTable *messages_layout[33] = {
&google__protobuf__FileDescriptorSet_msg_init,
&google__protobuf__FileDescriptorProto_msg_init,
&google__protobuf__DescriptorProto_msg_init,
&google__protobuf__DescriptorProto__ExtensionRange_msg_init,
&google__protobuf__DescriptorProto__ReservedRange_msg_init,
&google__protobuf__ExtensionRangeOptions_msg_init,
&google__protobuf__ExtensionRangeOptions__Declaration_msg_init,
&google__protobuf__FieldDescriptorProto_msg_init,
&google__protobuf__OneofDescriptorProto_msg_init,
&google__protobuf__EnumDescriptorProto_msg_init,
&google__protobuf__EnumDescriptorProto__EnumReservedRange_msg_init,
&google__protobuf__EnumValueDescriptorProto_msg_init,
&google__protobuf__ServiceDescriptorProto_msg_init,
&google__protobuf__MethodDescriptorProto_msg_init,
&google__protobuf__FileOptions_msg_init,
&google__protobuf__MessageOptions_msg_init,
&google__protobuf__FieldOptions_msg_init,
&google__protobuf__FieldOptions__EditionDefault_msg_init,
&google__protobuf__FieldOptions__FeatureSupport_msg_init,
&google__protobuf__OneofOptions_msg_init,
&google__protobuf__EnumOptions_msg_init,
&google__protobuf__EnumValueOptions_msg_init,
&google__protobuf__ServiceOptions_msg_init,
&google__protobuf__MethodOptions_msg_init,
&google__protobuf__UninterpretedOption_msg_init,
&google__protobuf__UninterpretedOption__NamePart_msg_init,
&google__protobuf__FeatureSet_msg_init,
&google__protobuf__FeatureSetDefaults_msg_init,
&google__protobuf__FeatureSetDefaults__FeatureSetEditionDefault_msg_init,
&google__protobuf__SourceCodeInfo_msg_init,
&google__protobuf__SourceCodeInfo__Location_msg_init,
&google__protobuf__GeneratedCodeInfo_msg_init,
&google__protobuf__GeneratedCodeInfo__Annotation_msg_init,
};
const upb_MiniTableEnum google_protobuf_Edition_enum_init = {
64,
9,
@ -1839,6 +1804,42 @@ const upb_MiniTableEnum google_protobuf_MethodOptions_IdempotencyLevel_enum_init
},
};
static const upb_MiniTable *messages_layout[33] = {
&google__protobuf__FileDescriptorSet_msg_init,
&google__protobuf__FileDescriptorProto_msg_init,
&google__protobuf__DescriptorProto_msg_init,
&google__protobuf__DescriptorProto__ExtensionRange_msg_init,
&google__protobuf__DescriptorProto__ReservedRange_msg_init,
&google__protobuf__ExtensionRangeOptions_msg_init,
&google__protobuf__ExtensionRangeOptions__Declaration_msg_init,
&google__protobuf__FieldDescriptorProto_msg_init,
&google__protobuf__OneofDescriptorProto_msg_init,
&google__protobuf__EnumDescriptorProto_msg_init,
&google__protobuf__EnumDescriptorProto__EnumReservedRange_msg_init,
&google__protobuf__EnumValueDescriptorProto_msg_init,
&google__protobuf__ServiceDescriptorProto_msg_init,
&google__protobuf__MethodDescriptorProto_msg_init,
&google__protobuf__FileOptions_msg_init,
&google__protobuf__MessageOptions_msg_init,
&google__protobuf__FieldOptions_msg_init,
&google__protobuf__FieldOptions__EditionDefault_msg_init,
&google__protobuf__FieldOptions__FeatureSupport_msg_init,
&google__protobuf__OneofOptions_msg_init,
&google__protobuf__EnumOptions_msg_init,
&google__protobuf__EnumValueOptions_msg_init,
&google__protobuf__ServiceOptions_msg_init,
&google__protobuf__MethodOptions_msg_init,
&google__protobuf__UninterpretedOption_msg_init,
&google__protobuf__UninterpretedOption__NamePart_msg_init,
&google__protobuf__FeatureSet_msg_init,
&google__protobuf__FeatureSetDefaults_msg_init,
&google__protobuf__FeatureSetDefaults__FeatureSetEditionDefault_msg_init,
&google__protobuf__SourceCodeInfo_msg_init,
&google__protobuf__SourceCodeInfo__Location_msg_init,
&google__protobuf__GeneratedCodeInfo_msg_init,
&google__protobuf__GeneratedCodeInfo__Annotation_msg_init,
};
static const upb_MiniTableEnum *enums_layout[17] = {
&google_protobuf_Edition_enum_init,
&google_protobuf_ExtensionRangeOptions_VerificationState_enum_init,
@ -7567,15 +7568,15 @@ failure:
#ifdef UPB_LINKARR_DECLARE
UPB_LINKARR_DECLARE(upb_AllExts, const upb_MiniTableExtension*);
UPB_LINKARR_DECLARE(upb_AllExts, upb_MiniTableExtension);
bool upb_ExtensionRegistry_AddAllLinkedExtensions(upb_ExtensionRegistry* r) {
const upb_MiniTableExtension* const* start = UPB_LINKARR_START(upb_AllExts);
const upb_MiniTableExtension* const* stop = UPB_LINKARR_STOP(upb_AllExts);
for (const upb_MiniTableExtension* const* p = start; p < stop; p++) {
const upb_MiniTableExtension* start = UPB_LINKARR_START(upb_AllExts);
const upb_MiniTableExtension* stop = UPB_LINKARR_STOP(upb_AllExts);
for (const upb_MiniTableExtension* p = start; p < stop; p++) {
// Windows can introduce zero padding, so we have to skip zeroes.
if (*p != 0) {
if (!upb_ExtensionRegistry_Add(r, *p)) return false;
if (upb_MiniTableExtension_Number(p) != 0) {
if (!upb_ExtensionRegistry_Add(r, p)) return false;
}
}
return true;
@ -12614,7 +12615,12 @@ char* upb_MtDataEncoder_EndEnum(upb_MtDataEncoder* e, char* ptr) {
// Must be last.
// A MiniTable for an empty message, used for unlinked sub-messages.
// A MiniTable for an empty message, used for unlinked sub-messages that are
// built via MiniDescriptors. Messages that use this MiniTable may possibly
// be linked later, in which case this MiniTable will be replaced with a real
// one. This pattern is known as "dynamic tree shaking", and it introduces
// complication because sub-messages may either be the "empty" type or the
// "real" type. A tagged bit indicates the difference.
const struct upb_MiniTable UPB_PRIVATE(_kUpb_MiniTable_Empty) = {
.UPB_PRIVATE(subs) = NULL,
.UPB_PRIVATE(fields) = NULL,
@ -12626,6 +12632,21 @@ const struct upb_MiniTable UPB_PRIVATE(_kUpb_MiniTable_Empty) = {
.UPB_PRIVATE(required_count) = 0,
};
// A MiniTable for a statically tree shaken message. Messages that use this
// MiniTable are guaranteed to remain unlinked; unlike the empty message, this
// MiniTable is never replaced, which greatly simplifies everything, because the
// type of a sub-message is always known, without consulting a tagged bit.
const struct upb_MiniTable UPB_PRIVATE(_kUpb_MiniTable_StaticallyTreeShaken) = {
.UPB_PRIVATE(subs) = NULL,
.UPB_PRIVATE(fields) = NULL,
.UPB_PRIVATE(size) = sizeof(struct upb_Message),
.UPB_PRIVATE(field_count) = 0,
.UPB_PRIVATE(ext) = kUpb_ExtMode_NonExtendable,
.UPB_PRIVATE(dense_below) = 0,
.UPB_PRIVATE(table_mask) = -1,
.UPB_PRIVATE(required_count) = 0,
};
// Must be last.
@ -13944,8 +13965,7 @@ bool _upb_FieldDef_ValidateUtf8(const upb_FieldDef* f) {
bool _upb_FieldDef_IsGroupLike(const upb_FieldDef* f) {
// Groups are always tag-delimited.
if (UPB_DESC(FeatureSet_message_encoding)(upb_FieldDef_ResolvedFeatures(f)) !=
UPB_DESC(FeatureSet_DELIMITED)) {
if (f->type_ != kUpb_FieldType_Group) {
return false;
}
@ -14382,12 +14402,6 @@ static void _upb_FieldDef_Create(upb_DefBuilder* ctx, const char* prefix,
UPB_DESC(FieldDescriptorProto_has_type_name)(field_proto);
f->type_ = (int)UPB_DESC(FieldDescriptorProto_type)(field_proto);
if (f->type_ == kUpb_FieldType_Message &&
// TODO: remove once we can deprecate kUpb_FieldType_Group.
UPB_DESC(FeatureSet_message_encoding)(f->resolved_features) ==
UPB_DESC(FeatureSet_DELIMITED)) {
f->type_ = kUpb_FieldType_Group;
}
if (has_type) {
switch (f->type_) {
@ -14408,7 +14422,7 @@ static void _upb_FieldDef_Create(upb_DefBuilder* ctx, const char* prefix,
}
}
if (!has_type && has_type_name) {
if ((!has_type && has_type_name) || f->type_ == kUpb_FieldType_Message) {
f->type_ =
UPB_FIELD_TYPE_UNSPECIFIED; // We'll assign this in resolve_subdef()
} else {
@ -14558,8 +14572,15 @@ static void resolve_subdef(upb_DefBuilder* ctx, const char* prefix,
break;
case UPB_DEFTYPE_MSG:
f->sub.msgdef = def;
f->type_ = kUpb_FieldType_Message; // It appears there is no way of
// this being a group.
f->type_ = kUpb_FieldType_Message;
// TODO: remove once we can deprecate
// kUpb_FieldType_Group.
if (UPB_DESC(FeatureSet_message_encoding)(f->resolved_features) ==
UPB_DESC(FeatureSet_DELIMITED) &&
!upb_MessageDef_IsMapEntry(def) &&
!(f->msgdef && upb_MessageDef_IsMapEntry(f->msgdef))) {
f->type_ = kUpb_FieldType_Group;
}
f->has_presence = !upb_FieldDef_IsRepeated(f);
break;
default:

File diff suppressed because it is too large Load Diff

@ -143,11 +143,11 @@ static PHP_GINIT_FUNCTION(protobuf) { protobuf_globals->global_symtab = NULL; }
static PHP_RINIT_FUNCTION(protobuf) {
// Create the global generated pool.
// Reuse the symtab (if any) left to us by the last request.
upb_DefPool* symtab = PROTOBUF_G(global_symtab);
if (!symtab) {
PROTOBUF_G(global_symtab) = symtab = upb_DefPool_New();
zend_hash_init(&PROTOBUF_G(name_msg_cache), 64, NULL, NULL, 0);
zend_hash_init(&PROTOBUF_G(name_enum_cache), 64, NULL, NULL, 0);
if (!PROTOBUF_G(global_symtab)) {
zend_bool persistent = PROTOBUF_G(keep_descriptor_pool_after_request);
PROTOBUF_G(global_symtab) = upb_DefPool_New();
zend_hash_init(&PROTOBUF_G(name_msg_cache), 64, NULL, NULL, persistent);
zend_hash_init(&PROTOBUF_G(name_enum_cache), 64, NULL, NULL, persistent);
}
zend_hash_init(&PROTOBUF_G(object_cache), 64, NULL, NULL, 0);
@ -308,7 +308,7 @@ zend_module_entry protobuf_module_entry = {
protobuf_functions, // function list
PHP_MINIT(protobuf), // process startup
PHP_MSHUTDOWN(protobuf), // process shutdown
PHP_RINIT(protobuf), // request shutdown
PHP_RINIT(protobuf), // request startup
PHP_RSHUTDOWN(protobuf), // request shutdown
NULL, // extension info
PHP_PROTOBUF_VERSION, // extension version

@ -54,11 +54,11 @@ def protobuf_deps():
http_archive(
name = "zlib",
build_file = Label("//:third_party/zlib.BUILD"),
sha256 = "d14c38e313afc35a9a8760dadf26042f51ea0f5d154b0630a31da0540107fb98",
strip_prefix = "zlib-1.2.13",
sha256 = "38ef96b8dfe510d42707d9c781877914792541133e1870841463bfa73f883e32",
strip_prefix = "zlib-1.3.1",
urls = [
"https://github.com/madler/zlib/releases/download/v1.2.13/zlib-1.2.13.tar.xz",
"https://zlib.net/zlib-1.2.13.tar.xz",
"https://github.com/madler/zlib/releases/download/v1.3.1/zlib-1.3.1.tar.xz",
"https://zlib.net/zlib-1.3.1.tar.xz",
],
)
@ -100,15 +100,15 @@ def protobuf_deps():
if not native.existing_rule("rules_python"):
http_archive(
name = "rules_python",
sha256 = "9d04041ac92a0985e344235f5d946f71ac543f1b1565f2cdbc9a2aaee8adf55b",
strip_prefix = "rules_python-0.26.0",
url = "https://github.com/bazelbuild/rules_python/releases/download/0.26.0/rules_python-0.26.0.tar.gz",
sha256 = "d70cd72a7a4880f0000a6346253414825c19cdd40a28289bdf67b8e6480edff8",
strip_prefix = "rules_python-0.28.0",
url = "https://github.com/bazelbuild/rules_python/releases/download/0.28.0/rules_python-0.28.0.tar.gz",
)
if not native.existing_rule("system_python"):
system_python(
name = "system_python",
minimum_python_version = "3.7",
minimum_python_version = "3.8",
)
if not native.existing_rule("rules_jvm_external"):

@ -129,8 +129,8 @@ cc_test(
copts = UPB_DEFAULT_CPPOPTS,
deps = [
":protos_internal",
"//protos_generator/tests:test_model_upb_cc_proto",
"//protos_generator/tests:test_model_upb_proto",
"//hpb_generator/tests:test_model_upb_cc_proto",
"//hpb_generator/tests:test_model_upb_proto",
"//upb:mem",
"@com_google_googletest//:gtest",
"@com_google_googletest//:gtest_main",
@ -157,9 +157,9 @@ cc_test(
name = "protos_extension_lock_test",
srcs = ["protos_extension_lock_test.cc"],
deps = [
"//hpb_generator/tests:test_model_upb_cc_proto",
"//protos",
"//protos:protos_extension_lock",
"//protos_generator/tests:test_model_upb_cc_proto",
"//upb:mem",
"@com_google_absl//absl/hash",
"@com_google_absl//absl/log:absl_check",

@ -63,11 +63,7 @@ def _generate_output_file(ctx, src, extension):
return ret
def _filter_none(elems):
out = []
for elem in elems:
if elem:
out.append(elem)
return out
return [e for e in elems if e]
def _cc_library_func(ctx, name, hdrs, srcs, copts, dep_ccinfos):
"""Like cc_library(), but callable from rules.
@ -244,7 +240,7 @@ _upb_cc_proto_library_aspect = aspect(
"_gen_upbprotos": attr.label(
executable = True,
cfg = "exec",
default = "//protos_generator:protoc-gen-upb-protos",
default = "//hpb_generator:protoc-gen-upb-protos",
),
"_protoc": attr.label(
executable = True,

@ -16,8 +16,8 @@
#include <gtest/gtest.h>
#include "absl/hash/hash.h"
#include "absl/log/absl_check.h"
#include "hpb_generator/tests/test_model.upb.proto.h"
#include "protos/protos.h"
#include "protos_generator/tests/test_model.upb.proto.h"
#include "upb/mem/arena.hpp"
#ifndef ASSERT_OK
@ -102,6 +102,8 @@ void TestConcurrentExtensionAccess(::protos::ExtensionRegistry registry) {
test_theme();
test_theme_extension();
}
#ifndef _MSC_VER
// TODO Re-enable this once github runner issue is resolved.
TEST(CppGeneratedCode, ConcurrentAccessDoesNotRaceBothLazy) {
::upb::Arena arena;
@ -120,5 +122,7 @@ TEST(CppGeneratedCode, ConcurrentAccessDoesNotRaceBothEager) {
{{&theme, &ThemeExtension::theme_extension}, arena});
}
#endif // _MSC_VER
} // namespace
} // namespace protos_generator::test::protos
} // namespace protos_generator::test::protos

@ -9,8 +9,8 @@
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "protos_generator/tests/test_model.upb.h"
#include "protos_generator/tests/test_model.upb.proto.h"
#include "hpb_generator/tests/test_model.upb.h"
#include "hpb_generator/tests/test_model.upb.proto.h"
#include "upb/mem/arena.h"
namespace protos::testing {

@ -36,7 +36,7 @@ pip_parse = pip_install
# Alias rules_python's pip.bzl for cases where a system python is found.
_alias_pip = """
load("@rules_python//python:pip.bzl", _pip_install = "pip_install", _pip_parse = "pip_parse")
load("@rules_python//python:pip.bzl", _pip_parse = "pip_parse")
def _get_requirements(requirements, requirements_overrides):
for version, override in requirements_overrides.items():
@ -45,18 +45,14 @@ def _get_requirements(requirements, requirements_overrides):
break
return requirements
def pip_install(requirements, requirements_overrides={{}}, **kwargs):
_pip_install(
python_interpreter_target = "@{repo}//:interpreter",
requirements = _get_requirements(requirements, requirements_overrides),
**kwargs,
)
def pip_parse(requirements, requirements_overrides={{}}, **kwargs):
_pip_parse(
python_interpreter_target = "@{repo}//:interpreter",
requirements = _get_requirements(requirements, requirements_overrides),
requirements_lock = _get_requirements(requirements, requirements_overrides),
**kwargs,
)
pip_install = pip_parse
"""
_mock_fuzzing_py = """

@ -708,6 +708,9 @@ class FieldDescriptor(DescriptorBase):
if (
self._GetFeatures().message_encoding
== _FEATURESET_MESSAGE_ENCODING_DELIMITED
and self.message_type
and not self.message_type.GetOptions().map_entry
and not self.containing_type.GetOptions().map_entry
):
return FieldDescriptor.TYPE_GROUP
return self._type

@ -29,6 +29,8 @@ from google.protobuf.internal import more_messages_pb2
from google.protobuf.internal import no_package_pb2
from google.protobuf.internal import testing_refleaks
from google.protobuf import duration_pb2
from google.protobuf import timestamp_pb2
from google.protobuf import unittest_features_pb2
from google.protobuf import unittest_import_pb2
from google.protobuf import unittest_import_public_pb2
@ -435,6 +437,8 @@ class DescriptorPoolTestBase(object):
self.assertEqual(file2.name,
'google/protobuf/internal/factory_test2.proto')
self.testFindMessageTypeByName()
self.pool.AddSerializedFile(timestamp_pb2.DESCRIPTOR.serialized_pb)
self.pool.AddSerializedFile(duration_pb2.DESCRIPTOR.serialized_pb)
file_json = self.pool.AddSerializedFile(
more_messages_pb2.DESCRIPTOR.serialized_pb)
field = file_json.message_types_by_name['class'].fields_by_name['int_field']
@ -542,12 +546,18 @@ class DescriptorPoolTestBase(object):
# that uses a DescriptorDatabase.
# TODO: Fix python and cpp extension diff.
return
timestamp_desc = descriptor_pb2.FileDescriptorProto.FromString(
timestamp_pb2.DESCRIPTOR.serialized_pb)
duration_desc = descriptor_pb2.FileDescriptorProto.FromString(
duration_pb2.DESCRIPTOR.serialized_pb)
more_messages_desc = descriptor_pb2.FileDescriptorProto.FromString(
more_messages_pb2.DESCRIPTOR.serialized_pb)
test1_desc = descriptor_pb2.FileDescriptorProto.FromString(
descriptor_pool_test1_pb2.DESCRIPTOR.serialized_pb)
test2_desc = descriptor_pb2.FileDescriptorProto.FromString(
descriptor_pool_test2_pb2.DESCRIPTOR.serialized_pb)
self.pool.Add(timestamp_desc)
self.pool.Add(duration_desc)
self.pool.Add(more_messages_desc)
self.pool.Add(test1_desc)
self.pool.Add(test2_desc)

@ -82,6 +82,19 @@ class MessageTest(unittest.TestCase):
golden_copy = copy.deepcopy(golden_message)
self.assertEqual(golden_data, golden_copy.SerializeToString())
def testGoldenMessageBytearray(self, message_module):
# bytearray was broken, test that it works again
if message_module is unittest_pb2:
golden_data = test_util.GoldenFileData('golden_message_oneof_implemented')
else:
golden_data = test_util.GoldenFileData('golden_message_proto3')
golden_message = message_module.TestAllTypes()
golden_message.ParseFromString(bytearray(golden_data))
if message_module is unittest_pb2:
test_util.ExpectAllFieldsSet(self, golden_message)
self.assertEqual(golden_data, golden_message.SerializeToString())
def testGoldenPackedMessage(self, message_module):
golden_data = test_util.GoldenFileData('golden_packed_fields_message')
golden_message = message_module.TestPackedTypes()

@ -13,6 +13,9 @@ syntax = "proto2";
package google.protobuf.internal;
import "google/protobuf/duration.proto";
import "google/protobuf/timestamp.proto";
// A message where tag numbers are listed out of order, to allow us to test our
// canonicalization of serialized output, which should always be in tag order.
// We also mix in some extensions for extra fun.
@ -348,3 +351,8 @@ message ConflictJsonName {
optional int32 value = 1 [json_name = "old_value"];
optional int32 new_value = 2 [json_name = "value"];
}
message WKTMessage {
optional Timestamp optional_timestamp = 1;
optional Duration optional_duration = 2;
}

@ -0,0 +1,38 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2024 Google Inc. 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
// Author: timdn@google.com (Tim Niemueller)
#include <pybind11/pybind11.h>
#include <memory>
#include "google/protobuf/message.h"
#include "google/protobuf/internal/self_recursive.pb.h"
#include "third_party/pybind11_protobuf/native_proto_caster.h"
namespace google::protobuf::python {
namespace py = pybind11;
void invoke_callback_on_message(py::object callback,
const google::protobuf::Message& exemplar) {
std::shared_ptr<google::protobuf::Message> new_msg(exemplar.New());
callback(new_msg);
}
PYBIND11_MODULE(pybind11_test_module, m) {
pybind11_protobuf::ImportNativeProtoCasters();
google::protobuf::LinkMessageReflection<
google::protobuf::python::internal::SelfRecursive>();
m.def("invoke_callback_on_message", &invoke_callback_on_message,
py::arg("callback"), py::arg("message"));
}
} // namespace protobuf
} // namespace google::python

@ -27,6 +27,7 @@ this file*.
__author__ = 'robinson@google.com (Will Robinson)'
import datetime
from io import BytesIO
import struct
import sys
@ -536,13 +537,30 @@ def _AddInitMethod(message_descriptor, cls):
self._fields[field] = copy
elif field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE:
copy = field._default_constructor(self)
new_val = field_value
if isinstance(field_value, dict):
new_val = None
if isinstance(field_value, message_mod.Message):
new_val = field_value
elif isinstance(field_value, dict):
new_val = field.message_type._concrete_class(**field_value)
try:
copy.MergeFrom(new_val)
except TypeError:
_ReraiseTypeErrorWithFieldName(message_descriptor.name, field_name)
elif field.message_type.full_name == 'google.protobuf.Timestamp':
copy.FromDatetime(field_value)
elif field.message_type.full_name == 'google.protobuf.Duration':
copy.FromTimedelta(field_value)
else:
raise TypeError(
'Message field {0}.{1} must be initialized with a '
'dict or instance of same class, got {2}.'.format(
message_descriptor.name,
field_name,
type(field_value).__name__,
)
)
if new_val:
try:
copy.MergeFrom(new_val)
except TypeError:
_ReraiseTypeErrorWithFieldName(message_descriptor.name, field_name)
self._fields[field] = copy
else:
if field.cpp_type == _FieldDescriptor.CPPTYPE_ENUM:
@ -753,8 +771,17 @@ def _AddPropertiesForNonRepeatedCompositeField(field, cls):
# We define a setter just so we can throw an exception with a more
# helpful error message.
def setter(self, new_value):
raise AttributeError('Assignment not allowed to composite field '
'"%s" in protocol message object.' % proto_field_name)
if field.message_type.full_name == 'google.protobuf.Timestamp':
getter(self)
self._fields[field].FromDatetime(new_value)
elif field.message_type.full_name == 'google.protobuf.Duration':
getter(self)
self._fields[field].FromTimedelta(new_value)
else:
raise AttributeError(
'Assignment not allowed to composite field '
'"%s" in protocol message object.' % proto_field_name
)
# Add a property to encapsulate the getter.
doc = 'Magic attribute generated for "%s" proto field.' % proto_field_name

@ -0,0 +1,44 @@
"""Regression test for self or indirect recursive messages with pybind11."""
from google.protobuf.internal import pybind11_test_module
from google.protobuf.internal import self_recursive_from_py_pb2
from google3.testing.pybase import unittest
class RecursiveMessagePybind11Test(unittest.TestCase):
def test_self_recursive_message_callback(self):
called = False
def callback(
msg: self_recursive_from_py_pb2.ContainsSelfRecursive,
) -> None:
nonlocal called
called = True
# Without proper handling of message factories (in pyext/message.cc New)
# this will stack overflow
pybind11_test_module.invoke_callback_on_message(
callback, self_recursive_from_py_pb2.ContainsSelfRecursive()
)
self.assertTrue(called)
def test_indirect_recursive_message_callback(self):
called = False
def callback(
msg: self_recursive_from_py_pb2.ContainsIndirectRecursive,
) -> None:
nonlocal called
called = True
# Without proper handling of message factories (in pyext/message.cc New)
# this will stack overflow
pybind11_test_module.invoke_callback_on_message(
callback, self_recursive_from_py_pb2.ContainsIndirectRecursive()
)
self.assertTrue(called)
if __name__ == "__main__":
unittest.main()

@ -0,0 +1,22 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2024 Google Inc. 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
syntax = "proto2";
package google.protobuf.python.internal;
message SelfRecursive {
optional SelfRecursive sub = 1;
}
message IndirectRecursive {
optional IntermediateRecursive intermediate = 1;
}
message IntermediateRecursive {
optional IndirectRecursive indirect = 1;
}

@ -0,0 +1,20 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2024 Google Inc. 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
syntax = "proto2";
package google.protobuf.python.internal;
import "google/protobuf/internal/self_recursive.proto";
message ContainsSelfRecursive {
optional SelfRecursive recursive = 1;
}
message ContainsIndirectRecursive {
optional IndirectRecursive recursive = 1;
}

@ -21,8 +21,8 @@ import calendar
import collections.abc
import datetime
import warnings
from google.protobuf.internal import field_mask
from typing import Union
FieldMask = field_mask.FieldMask
@ -271,12 +271,35 @@ class Timestamp(object):
# manipulated into a long value of seconds. During the conversion from
# struct_time to long, the source date in UTC, and so it follows that the
# correct transformation is calendar.timegm()
seconds = calendar.timegm(dt.utctimetuple())
nanos = dt.microsecond * _NANOS_PER_MICROSECOND
try:
seconds = calendar.timegm(dt.utctimetuple())
nanos = dt.microsecond * _NANOS_PER_MICROSECOND
except AttributeError as e:
raise AttributeError(
'Fail to convert to Timestamp. Expected a datetime like '
'object got {0} : {1}'.format(type(dt).__name__, e)
) from e
_CheckTimestampValid(seconds, nanos)
self.seconds = seconds
self.nanos = nanos
def __add__(self, value) -> datetime.datetime:
if isinstance(value, Duration):
return self.ToDatetime() + value.ToTimedelta()
return self.ToDatetime() + value
__radd__ = __add__
def __sub__(self, value) -> Union[datetime.datetime, datetime.timedelta]:
if isinstance(value, Timestamp):
return self.ToDatetime() - value.ToDatetime()
elif isinstance(value, Duration):
return self.ToDatetime() - value.ToTimedelta()
return self.ToDatetime() - value
def __rsub__(self, dt) -> datetime.timedelta:
return dt - self.ToDatetime()
def _CheckTimestampValid(seconds, nanos):
if seconds < _TIMESTAMP_SECONDS_MIN or seconds > _TIMESTAMP_SECONDS_MAX:
@ -408,8 +431,16 @@ class Duration(object):
def FromTimedelta(self, td):
"""Converts timedelta to Duration."""
self._NormalizeDuration(td.seconds + td.days * _SECONDS_PER_DAY,
td.microseconds * _NANOS_PER_MICROSECOND)
try:
self._NormalizeDuration(
td.seconds + td.days * _SECONDS_PER_DAY,
td.microseconds * _NANOS_PER_MICROSECOND,
)
except AttributeError as e:
raise AttributeError(
'Fail to convert to Duration. Expected a timedelta like '
'object got {0}: {1}'.format(type(td).__name__, e)
) from e
def _NormalizeDuration(self, seconds, nanos):
"""Set Duration by seconds and nanos."""
@ -420,6 +451,16 @@ class Duration(object):
self.seconds = seconds
self.nanos = nanos
def __add__(self, value) -> Union[datetime.datetime, datetime.timedelta]:
if isinstance(value, Timestamp):
return self.ToTimedelta() + value.ToDatetime()
return self.ToTimedelta() + value
__radd__ = __add__
def __rsub__(self, dt) -> Union[datetime.datetime, datetime.timedelta]:
return dt - self.ToTimedelta()
def _CheckDurationValid(seconds, nanos):
if seconds < -_DURATION_SECONDS_MAX or seconds > _DURATION_SECONDS_MAX:

@ -13,13 +13,15 @@ import collections.abc as collections_abc
import datetime
import unittest
from google.protobuf import any_pb2
from google.protobuf import text_format
from google.protobuf.internal import any_test_pb2
from google.protobuf.internal import more_messages_pb2
from google.protobuf.internal import well_known_types
from google.protobuf import any_pb2
from google.protobuf import duration_pb2
from google.protobuf import struct_pb2
from google.protobuf import timestamp_pb2
from google.protobuf.internal import well_known_types
from google.protobuf import text_format
from google.protobuf.internal import _parameterized
from google.protobuf import unittest_pb2
@ -351,6 +353,123 @@ class TimeUtilTest(TimeUtilTestBase):
tz_aware_min_datetime, ts.ToDatetime(datetime.timezone.utc)
)
# Two hours after the Unix Epoch, around the world.
@_parameterized.named_parameters(
('London', [1970, 1, 1, 2], datetime.timezone.utc),
('Tokyo', [1970, 1, 1, 11], _TZ_JAPAN),
('LA', [1969, 12, 31, 18], _TZ_PACIFIC),
)
def testTimestampAssignment(self, date_parts, tzinfo):
original_datetime = datetime.datetime(*date_parts, tzinfo=tzinfo) # pylint:disable=g-tzinfo-datetime
msg = more_messages_pb2.WKTMessage()
msg.optional_timestamp = original_datetime
self.assertEqual(7200, msg.optional_timestamp.seconds)
self.assertEqual(0, msg.optional_timestamp.nanos)
# Two hours after the Unix Epoch, around the world.
@_parameterized.named_parameters(
('London', [1970, 1, 1, 2], datetime.timezone.utc),
('Tokyo', [1970, 1, 1, 11], _TZ_JAPAN),
('LA', [1969, 12, 31, 18], _TZ_PACIFIC),
)
def testTimestampCreation(self, date_parts, tzinfo):
original_datetime = datetime.datetime(*date_parts, tzinfo=tzinfo) # pylint:disable=g-tzinfo-datetime
msg = more_messages_pb2.WKTMessage(optional_timestamp=original_datetime)
self.assertEqual(7200, msg.optional_timestamp.seconds)
self.assertEqual(0, msg.optional_timestamp.nanos)
msg2 = more_messages_pb2.WKTMessage(
optional_timestamp=msg.optional_timestamp
)
self.assertEqual(7200, msg2.optional_timestamp.seconds)
self.assertEqual(0, msg2.optional_timestamp.nanos)
@_parameterized.named_parameters(
(
'tz_aware_min_dt',
datetime.datetime(1, 1, 1, tzinfo=datetime.timezone.utc),
datetime.timedelta(hours=9),
-62135564400,
0,
),
(
'no_change',
datetime.datetime(1970, 1, 1, 11, tzinfo=_TZ_JAPAN),
datetime.timedelta(hours=0),
7200,
0,
),
)
def testTimestampAdd(self, old_time, time_delta, expected_sec, expected_nano):
msg = more_messages_pb2.WKTMessage()
msg.optional_timestamp = old_time
# Timestamp + timedelta
new_msg1 = more_messages_pb2.WKTMessage()
new_msg1.optional_timestamp = msg.optional_timestamp + time_delta
self.assertEqual(expected_sec, new_msg1.optional_timestamp.seconds)
self.assertEqual(expected_nano, new_msg1.optional_timestamp.nanos)
# timedelta + Timestamp
new_msg2 = more_messages_pb2.WKTMessage()
new_msg2.optional_timestamp = time_delta + msg.optional_timestamp
self.assertEqual(expected_sec, new_msg2.optional_timestamp.seconds)
self.assertEqual(expected_nano, new_msg2.optional_timestamp.nanos)
# Timestamp + Duration
msg.optional_duration.FromTimedelta(time_delta)
new_msg3 = more_messages_pb2.WKTMessage()
new_msg3.optional_timestamp = msg.optional_timestamp + msg.optional_duration
self.assertEqual(expected_sec, new_msg3.optional_timestamp.seconds)
self.assertEqual(expected_nano, new_msg3.optional_timestamp.nanos)
@_parameterized.named_parameters(
(
'test1',
datetime.datetime(999, 1, 1, tzinfo=datetime.timezone.utc),
datetime.timedelta(hours=9),
-30641792400,
0,
),
(
'no_change',
datetime.datetime(1970, 1, 1, 11, tzinfo=_TZ_JAPAN),
datetime.timedelta(hours=0),
7200,
0,
),
)
def testTimestampSub(self, old_time, time_delta, expected_sec, expected_nano):
msg = more_messages_pb2.WKTMessage()
msg.optional_timestamp = old_time
# Timestamp - timedelta
new_msg1 = more_messages_pb2.WKTMessage()
new_msg1.optional_timestamp = msg.optional_timestamp - time_delta
self.assertEqual(expected_sec, new_msg1.optional_timestamp.seconds)
self.assertEqual(expected_nano, new_msg1.optional_timestamp.nanos)
# Timestamp - Duration
msg.optional_duration = time_delta
new_msg2 = more_messages_pb2.WKTMessage()
new_msg2.optional_timestamp = msg.optional_timestamp - msg.optional_duration
self.assertEqual(expected_sec, new_msg2.optional_timestamp.seconds)
self.assertEqual(expected_nano, new_msg2.optional_timestamp.nanos)
result_msg = more_messages_pb2.WKTMessage()
result_msg.optional_timestamp = old_time - time_delta
# Timestamp - Timestamp
td = msg.optional_timestamp - result_msg.optional_timestamp
self.assertEqual(time_delta, td)
# Timestamp - datetime
td1 = msg.optional_timestamp - result_msg.optional_timestamp.ToDatetime()
self.assertEqual(time_delta, td1)
# datetime - Timestamp
td2 = msg.optional_timestamp.ToDatetime() - result_msg.optional_timestamp
self.assertEqual(time_delta, td2)
def testNanosOneSecond(self):
tz = _TZ_PACIFIC
ts = timestamp_pb2.Timestamp(nanos=1_000_000_000)
@ -413,6 +532,18 @@ class TimeUtilTest(TimeUtilTestBase):
message.ToJsonString)
self.assertRaisesRegex(ValueError, 'Timestamp is not valid',
message.FromSeconds, -62135596801)
msg = more_messages_pb2.WKTMessage()
with self.assertRaises(AttributeError):
msg.optional_timestamp = 1
with self.assertRaises(AttributeError):
msg2 = more_messages_pb2.WKTMessage(optional_timestamp=1)
with self.assertRaises(TypeError):
msg.optional_timestamp + ''
with self.assertRaises(TypeError):
msg.optional_timestamp - 123
def testInvalidDuration(self):
message = duration_pb2.Duration()
@ -446,6 +577,105 @@ class TimeUtilTest(TimeUtilTestBase):
self.assertRaisesRegex(ValueError,
r'Duration is not valid\: Sign mismatch.',
message.ToJsonString)
msg = more_messages_pb2.WKTMessage()
with self.assertRaises(AttributeError):
msg.optional_duration = 1
with self.assertRaises(AttributeError):
msg2 = more_messages_pb2.WKTMessage(optional_duration=1)
with self.assertRaises(TypeError):
msg.optional_duration + ''
with self.assertRaises(TypeError):
123 - msg.optional_duration
@_parameterized.named_parameters(
('test1', -1999999, -1, -999999000), ('test2', 1999999, 1, 999999000)
)
def testDurationAssignment(self, microseconds, expected_sec, expected_nano):
message = more_messages_pb2.WKTMessage()
expected_td = datetime.timedelta(microseconds=microseconds)
message.optional_duration = expected_td
self.assertEqual(expected_td, message.optional_duration.ToTimedelta())
self.assertEqual(expected_sec, message.optional_duration.seconds)
self.assertEqual(expected_nano, message.optional_duration.nanos)
@_parameterized.named_parameters(
('test1', -1999999, -1, -999999000), ('test2', 1999999, 1, 999999000)
)
def testDurationCreation(self, microseconds, expected_sec, expected_nano):
message = more_messages_pb2.WKTMessage(
optional_duration=datetime.timedelta(microseconds=microseconds)
)
expected_td = datetime.timedelta(microseconds=microseconds)
self.assertEqual(expected_td, message.optional_duration.ToTimedelta())
self.assertEqual(expected_sec, message.optional_duration.seconds)
self.assertEqual(expected_nano, message.optional_duration.nanos)
@_parameterized.named_parameters(
(
'tz_aware_min_dt',
datetime.datetime(1, 1, 1, tzinfo=datetime.timezone.utc),
datetime.timedelta(hours=9),
-62135564400,
0,
),
(
'no_change',
datetime.datetime(1970, 1, 1, 11, tzinfo=_TZ_JAPAN),
datetime.timedelta(hours=0),
7200,
0,
),
)
def testDurationAdd(self, old_time, time_delta, expected_sec, expected_nano):
msg = more_messages_pb2.WKTMessage()
msg.optional_duration = time_delta
msg.optional_timestamp = old_time
# Duration + datetime
msg1 = more_messages_pb2.WKTMessage()
msg1.optional_timestamp = msg.optional_duration + old_time
self.assertEqual(expected_sec, msg1.optional_timestamp.seconds)
self.assertEqual(expected_nano, msg1.optional_timestamp.nanos)
# datetime + Duration
msg2 = more_messages_pb2.WKTMessage()
msg2.optional_timestamp = old_time + msg.optional_duration
self.assertEqual(expected_sec, msg2.optional_timestamp.seconds)
self.assertEqual(expected_nano, msg2.optional_timestamp.nanos)
# Duration + Timestamp
msg3 = more_messages_pb2.WKTMessage()
msg3.optional_timestamp = msg.optional_duration + msg.optional_timestamp
self.assertEqual(expected_sec, msg3.optional_timestamp.seconds)
self.assertEqual(expected_nano, msg3.optional_timestamp.nanos)
@_parameterized.named_parameters(
(
'test1',
datetime.datetime(999, 1, 1, tzinfo=datetime.timezone.utc),
datetime.timedelta(hours=9),
-30641792400,
0,
),
(
'no_change',
datetime.datetime(1970, 1, 1, 11, tzinfo=_TZ_JAPAN),
datetime.timedelta(hours=0),
7200,
0,
),
)
def testDurationSub(self, old_time, time_delta, expected_sec, expected_nano):
msg = more_messages_pb2.WKTMessage()
msg.optional_duration = time_delta
# datetime - Duration
msg.optional_timestamp = old_time - msg.optional_duration
self.assertEqual(expected_sec, msg.optional_timestamp.seconds)
self.assertEqual(expected_nano, msg.optional_timestamp.nanos)
class StructTest(unittest.TestCase):

@ -18,9 +18,9 @@ __author__ = 'matthewtoia@google.com (Matt Toia)'
import warnings
from google.protobuf.internal import api_implementation
from google.protobuf import descriptor_pool
from google.protobuf import message
from google.protobuf.internal import api_implementation
if api_implementation.Type() == 'python':
from google.protobuf.internal import python_message as message_impl
@ -58,8 +58,7 @@ def GetMessageClassesForFiles(files, pool):
Args:
files: The file names to extract messages from.
pool: The descriptor pool to find the files including the dependent
files.
pool: The descriptor pool to find the files including the dependent files.
Returns:
A dictionary mapping proto names to the message classes.
@ -80,7 +79,7 @@ def GetMessageClassesForFiles(files, pool):
# an error if they were different.
for extension in file_desc.extensions_by_name.values():
extended_class = GetMessageClass(extension.containing_type)
_ = GetMessageClass(extension.containing_type)
if api_implementation.Type() != 'python':
# TODO: Remove this check here. Duplicate extension
# register check should be in descriptor_pool.
@ -113,10 +112,12 @@ def _InternalCreateMessageClass(descriptor):
'DESCRIPTOR': descriptor,
# If module not set, it wrongly points to message_factory module.
'__module__': None,
})
},
)
for field in descriptor.fields:
if field.message_type:
GetMessageClass(field.message_type)
for extension in result_class.DESCRIPTOR.extensions:
extended_class = GetMessageClass(extension.containing_type)
if api_implementation.Type() != 'python':
@ -221,13 +222,16 @@ def GetMessages(file_protos, pool=None):
# message in topological order of the dependency graph.
des_pool = pool or descriptor_pool.DescriptorPool()
file_by_name = {file_proto.name: file_proto for file_proto in file_protos}
def _AddFile(file_proto):
for dependency in file_proto.dependency:
if dependency in file_by_name:
# Remove from elements to be visited, in order to cut cycles.
_AddFile(file_by_name.pop(dependency))
des_pool.Add(file_proto)
while file_by_name:
_AddFile(file_by_name.popitem()[1])
return GetMessageClassesForFiles(
[file_proto.name for file_proto in file_protos], des_pool)
[file_proto.name for file_proto in file_protos], des_pool
)

@ -96,6 +96,7 @@ class MessageReflectionFriend {
};
static PyObject* kDESCRIPTOR;
static PyObject* kMessageFactory;
PyObject* EnumTypeWrapper_class;
static PyObject* PythonMessage_class;
static PyObject* kEmptyWeakref;
@ -143,8 +144,8 @@ static int AddDescriptors(PyObject* cls, const Descriptor* descriptor) {
if (wrapped == nullptr) {
return -1;
}
if (PyObject_SetAttrString(
cls, enum_descriptor->name().c_str(), wrapped.get()) == -1) {
if (PyObject_SetAttrString(cls, enum_descriptor->name().c_str(),
wrapped.get()) == -1) {
return -1;
}
@ -177,8 +178,8 @@ static int AddDescriptors(PyObject* cls, const Descriptor* descriptor) {
}
// Add the extension field to the message class.
if (PyObject_SetAttrString(
cls, field->name().c_str(), extension_field.get()) == -1) {
if (PyObject_SetAttrString(cls, field->name().c_str(),
extension_field.get()) == -1) {
return -1;
}
}
@ -279,7 +280,17 @@ static PyObject* New(PyTypeObject* type, PyObject* args, PyObject* kwargs) {
if (py_descriptor_pool == nullptr) {
return nullptr;
}
newtype->py_message_factory = py_descriptor_pool->py_message_factory;
PyObject* py_message_factory_obj = PyDict_GetItem(dict, kMessageFactory);
PyMessageFactory* py_message_factory = nullptr;
if (py_message_factory_obj == nullptr) {
py_message_factory = py_descriptor_pool->py_message_factory;
} else {
py_message_factory =
reinterpret_cast<PyMessageFactory*>(py_message_factory_obj);
}
newtype->py_message_factory = py_message_factory;
Py_INCREF(newtype->py_message_factory);
// Register the message in the MessageFactory.
@ -324,7 +335,7 @@ static PyGetSetDef Getters[] = {
// Compute some class attributes on the fly:
// - All the _FIELD_NUMBER attributes, for all fields and nested extensions.
// Returns a new reference, or NULL with an exception set.
static PyObject* GetClassAttribute(CMessageClass *self, PyObject* name) {
static PyObject* GetClassAttribute(CMessageClass* self, PyObject* name) {
char* attr;
Py_ssize_t attr_size;
static const char kSuffix[] = "_FIELD_NUMBER";
@ -441,9 +452,8 @@ static const Descriptor* GetMessageDescriptor(PyTypeObject* cls) {
// Forward declarations
namespace cmessage {
int InternalReleaseFieldByDescriptor(
CMessage* self,
const FieldDescriptor* field_descriptor);
int InternalReleaseFieldByDescriptor(CMessage* self,
const FieldDescriptor* field_descriptor);
} // namespace cmessage
// ---------------------------------------------------------------------
@ -460,26 +470,23 @@ void FormatTypeError(PyObject* arg, const char* expected_types) {
PyErr_Clear();
PyObject* repr = PyObject_Repr(arg);
if (repr) {
PyErr_Format(PyExc_TypeError,
"%.100s has type %.100s, but expected one of: %s",
PyString_AsString(repr),
Py_TYPE(arg)->tp_name,
expected_types);
PyErr_Format(
PyExc_TypeError, "%.100s has type %.100s, but expected one of: %s",
PyString_AsString(repr), Py_TYPE(arg)->tp_name, expected_types);
Py_DECREF(repr);
}
}
void OutOfRangeError(PyObject* arg) {
PyObject *s = PyObject_Str(arg);
PyObject* s = PyObject_Str(arg);
if (s) {
PyErr_Format(PyExc_ValueError,
"Value out of range: %s",
PyErr_Format(PyExc_ValueError, "Value out of range: %s",
PyString_AsString(s));
Py_DECREF(s);
}
}
template<class RangeType, class ValueType>
template <class RangeType, class ValueType>
bool VerifyIntegerCastAndRange(PyObject* arg, ValueType value) {
if (PROTOBUF_PREDICT_FALSE(value == -1 && PyErr_Occurred())) {
if (PyErr_ExceptionMatches(PyExc_OverflowError)) {
@ -641,12 +648,9 @@ PyObject* CheckString(PyObject* arg, const FieldDescriptor* descriptor) {
return encoded_string;
}
bool CheckAndSetString(
PyObject* arg, Message* message,
const FieldDescriptor* descriptor,
const Reflection* reflection,
bool append,
int index) {
bool CheckAndSetString(PyObject* arg, Message* message,
const FieldDescriptor* descriptor,
const Reflection* reflection, bool append, int index) {
ScopedPyObjectPtr encoded_string(CheckString(arg, descriptor));
if (encoded_string.get() == nullptr) {
@ -708,9 +712,8 @@ PyMessageFactory* GetFactoryForMessage(CMessage* message) {
return reinterpret_cast<CMessageClass*>(Py_TYPE(message))->py_message_factory;
}
static int MaybeReleaseOverlappingOneofField(
CMessage* cmessage,
const FieldDescriptor* field) {
static int MaybeReleaseOverlappingOneofField(CMessage* cmessage,
const FieldDescriptor* field) {
Message* message = cmessage->message;
const Reflection* reflection = message->GetReflection();
if (!field->containing_oneof() ||
@ -849,10 +852,8 @@ static PyObject* GetIntegerEnumValue(const FieldDescriptor& descriptor,
// The only way to remove items in C++ protos is to delete the last one,
// so we swap items to move the deleted ones at the end, and then strip the
// sequence.
int DeleteRepeatedField(
CMessage* self,
const FieldDescriptor* field_descriptor,
PyObject* slice) {
int DeleteRepeatedField(CMessage* self, const FieldDescriptor* field_descriptor,
PyObject* slice) {
Py_ssize_t length, from, to, step, slice_length;
Message* message = self->message;
const Reflection* reflection = message->GetReflection();
@ -1092,9 +1093,41 @@ int InitAttributes(CMessage* self, PyObject* args, PyObject* kwargs) {
return -1;
}
} else {
ScopedPyObjectPtr merged(MergeFrom(cmessage, value));
if (merged == nullptr) {
return -1;
if (PyObject_TypeCheck(value, CMessage_Type)) {
ScopedPyObjectPtr merged(MergeFrom(cmessage, value));
if (merged == nullptr) {
return -1;
}
} else {
switch (descriptor->message_type()->well_known_type()) {
case Descriptor::WELLKNOWNTYPE_TIMESTAMP: {
AssureWritable(cmessage);
ScopedPyObjectPtr ok(
PyObject_CallMethod(reinterpret_cast<PyObject*>(cmessage),
"FromDatetime", "O", value));
if (ok.get() == nullptr) {
return -1;
}
break;
}
case Descriptor::WELLKNOWNTYPE_DURATION: {
AssureWritable(cmessage);
ScopedPyObjectPtr ok(
PyObject_CallMethod(reinterpret_cast<PyObject*>(cmessage),
"FromTimedelta", "O", value));
if (ok.get() == nullptr) {
return -1;
}
break;
}
default:
PyErr_Format(
PyExc_TypeError,
"Parameter to initialize message field must be "
"dict or instance of same class: expected %s got %s.",
descriptor->full_name().c_str(), Py_TYPE(value)->tp_name);
return -1;
}
}
}
} else {
@ -1117,8 +1150,8 @@ int InitAttributes(CMessage* self, PyObject* args, PyObject* kwargs) {
// Allocates an incomplete Python Message: the caller must fill self->message
// and eventually self->parent.
CMessage* NewEmptyMessage(CMessageClass* type) {
CMessage* self = reinterpret_cast<CMessage*>(
PyType_GenericAlloc(&type->super.ht_type, 0));
CMessage* self =
reinterpret_cast<CMessage*>(PyType_GenericAlloc(&type->super.ht_type, 0));
if (self == nullptr) {
return nullptr;
}
@ -1160,7 +1193,7 @@ static CMessage* NewCMessage(CMessageClass* type) {
return nullptr;
}
self->message = prototype->New(nullptr); // Ensures no arena is used.
self->parent = nullptr; // This message owns its data.
self->parent = nullptr; // This message owns its data.
return self;
}
@ -1225,8 +1258,7 @@ PyObject* IsInitialized(CMessage* self, PyObject* args) {
Py_RETURN_TRUE;
}
if (errors != nullptr) {
ScopedPyObjectPtr initialization_errors(
FindInitializationErrors(self));
ScopedPyObjectPtr initialization_errors(FindInitializationErrors(self));
if (initialization_errors == nullptr) {
return nullptr;
}
@ -1267,8 +1299,7 @@ const FieldDescriptor* FindFieldWithOneofs(const Message* message,
if (field_descriptor != nullptr) {
return field_descriptor;
}
const OneofDescriptor* oneof_desc =
descriptor->FindOneofByName(field_name);
const OneofDescriptor* oneof_desc = descriptor->FindOneofByName(field_name);
if (oneof_desc != nullptr) {
*in_oneof = true;
return message->GetReflection()->GetOneofFieldDescriptor(*message,
@ -1444,9 +1475,8 @@ static int InternalReparentFields(
return 0;
}
int InternalReleaseFieldByDescriptor(
CMessage* self,
const FieldDescriptor* field_descriptor) {
int InternalReleaseFieldByDescriptor(CMessage* self,
const FieldDescriptor* field_descriptor) {
if (!field_descriptor->is_repeated() &&
field_descriptor->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) {
// Single scalars are not in any cache.
@ -1503,8 +1533,8 @@ PyObject* ClearField(CMessage* self, PyObject* arg) {
// We gave the name of a oneof, and none of its fields are set.
Py_RETURN_NONE;
} else {
PyErr_Format(PyExc_ValueError,
"Protocol message has no \"%s\" field.", field_name);
PyErr_Format(PyExc_ValueError, "Protocol message has no \"%s\" field.",
field_name);
return nullptr;
}
}
@ -1548,9 +1578,9 @@ static std::string GetMessageName(CMessage* self) {
}
}
static PyObject* InternalSerializeToString(
CMessage* self, PyObject* args, PyObject* kwargs,
bool require_initialized) {
static PyObject* InternalSerializeToString(CMessage* self, PyObject* args,
PyObject* kwargs,
bool require_initialized) {
// Parse the "deterministic" kwarg; defaults to False.
static const char* kwlist[] = {"deterministic", nullptr};
PyObject* deterministic_obj = Py_None;
@ -1588,8 +1618,8 @@ static PyObject* InternalSerializeToString(
// return the EncodeError from a previous load of the module, which won't
// match a user's attempt to catch EncodeError. So we have to look it up
// again every time.
ScopedPyObjectPtr message_module(PyImport_ImportModule(
"google.protobuf.message"));
ScopedPyObjectPtr message_module(
PyImport_ImportModule("google.protobuf.message"));
if (message_module.get() == nullptr) {
return nullptr;
}
@ -1633,14 +1663,14 @@ static PyObject* InternalSerializeToString(
return result;
}
static PyObject* SerializeToString(
CMessage* self, PyObject* args, PyObject* kwargs) {
static PyObject* SerializeToString(CMessage* self, PyObject* args,
PyObject* kwargs) {
return InternalSerializeToString(self, args, kwargs,
/*require_initialized=*/true);
}
static PyObject* SerializePartialToString(
CMessage* self, PyObject* args, PyObject* kwargs) {
static PyObject* SerializePartialToString(CMessage* self, PyObject* args,
PyObject* kwargs) {
return InternalSerializeToString(self, args, kwargs,
/*require_initialized=*/false);
}
@ -1876,7 +1906,7 @@ static PyObject* SetInParent(CMessage* self, PyObject* args) {
static PyObject* WhichOneof(CMessage* self, PyObject* arg) {
Py_ssize_t name_size;
char *name_data;
char* name_data;
if (PyString_AsStringAndSize(arg, &name_data, &name_size) < 0) return nullptr;
const OneofDescriptor* oneof_desc =
self->message->GetDescriptor()->FindOneofByName(
@ -1887,8 +1917,8 @@ static PyObject* WhichOneof(CMessage* self, PyObject* arg) {
return nullptr;
}
const FieldDescriptor* field_in_oneof =
self->message->GetReflection()->GetOneofFieldDescriptor(
*self->message, oneof_desc);
self->message->GetReflection()->GetOneofFieldDescriptor(*self->message,
oneof_desc);
if (field_in_oneof == nullptr) {
Py_RETURN_NONE;
} else {
@ -1897,7 +1927,7 @@ static PyObject* WhichOneof(CMessage* self, PyObject* arg) {
}
}
static PyObject* GetExtensionDict(CMessage* self, void *closure);
static PyObject* GetExtensionDict(CMessage* self, void* closure);
static PyObject* ListFields(CMessage* self) {
std::vector<const FieldDescriptor*> fields;
@ -1941,8 +1971,8 @@ static PyObject* ListFields(CMessage* self) {
return nullptr;
}
// 'extension' reference later stolen by PyTuple_SET_ITEM.
PyObject* extension = PyObject_GetItem(
extensions.get(), extension_field.get());
PyObject* extension =
PyObject_GetItem(extensions.get(), extension_field.get());
if (extension == nullptr) {
return nullptr;
}
@ -2098,16 +2128,16 @@ PyObject* InternalGetScalar(const Message* message,
break;
}
default:
PyErr_Format(
PyExc_SystemError, "Getting a value from a field of unknown type %d",
field_descriptor->cpp_type());
PyErr_Format(PyExc_SystemError,
"Getting a value from a field of unknown type %d",
field_descriptor->cpp_type());
}
return result;
}
CMessage* InternalGetSubMessage(
CMessage* self, const FieldDescriptor* field_descriptor) {
CMessage* InternalGetSubMessage(CMessage* self,
const FieldDescriptor* field_descriptor) {
const Reflection* reflection = self->message->GetReflection();
PyMessageFactory* factory = GetFactoryForMessage(self);
@ -2146,10 +2176,9 @@ CMessage* InternalGetSubMessage(
return cmsg;
}
int InternalSetNonOneofScalar(
Message* message,
const FieldDescriptor* field_descriptor,
PyObject* arg) {
int InternalSetNonOneofScalar(Message* message,
const FieldDescriptor* field_descriptor,
PyObject* arg) {
const Reflection* reflection = message->GetReflection();
if (!CheckFieldBelongsToMessage(field_descriptor, message)) {
@ -2193,8 +2222,8 @@ int InternalSetNonOneofScalar(
break;
}
case FieldDescriptor::CPPTYPE_STRING: {
if (!CheckAndSetString(
arg, message, field_descriptor, reflection, false, -1)) {
if (!CheckAndSetString(arg, message, field_descriptor, reflection, false,
-1)) {
return -1;
}
break;
@ -2217,19 +2246,17 @@ int InternalSetNonOneofScalar(
break;
}
default:
PyErr_Format(
PyExc_SystemError, "Setting value to a field of unknown type %d",
field_descriptor->cpp_type());
PyErr_Format(PyExc_SystemError,
"Setting value to a field of unknown type %d",
field_descriptor->cpp_type());
return -1;
}
return 0;
}
int InternalSetScalar(
CMessage* self,
const FieldDescriptor* field_descriptor,
PyObject* arg) {
int InternalSetScalar(CMessage* self, const FieldDescriptor* field_descriptor,
PyObject* arg) {
if (!CheckFieldBelongsToMessage(field_descriptor, self->message)) {
return -1;
}
@ -2357,7 +2384,7 @@ PyObject* _CheckCalledFromGeneratedFile(PyObject* unused,
Py_RETURN_NONE;
}
static PyObject* GetExtensionDict(CMessage* self, void *closure) {
static PyObject* GetExtensionDict(CMessage* self, void* closure) {
// If there are extension_ranges, the message is "extendable". Allocate a
// dictionary to store the extension fields.
const Descriptor* descriptor = GetMessageDescriptor(Py_TYPE(self));
@ -2462,8 +2489,8 @@ bool SetSubmessage(CMessage* self, CMessage* submessage) {
PyObject* GetAttr(PyObject* pself, PyObject* name) {
CMessage* self = reinterpret_cast<CMessage*>(pself);
PyObject* result = PyObject_GenericGetAttr(
reinterpret_cast<PyObject*>(self), name);
PyObject* result =
PyObject_GenericGetAttr(reinterpret_cast<PyObject*>(self), name);
if (result != nullptr) {
return result;
}
@ -2472,8 +2499,8 @@ PyObject* GetAttr(PyObject* pself, PyObject* name) {
}
PyErr_Clear();
return message_meta::GetClassAttribute(
CheckMessageClass(Py_TYPE(self)), name);
return message_meta::GetClassAttribute(CheckMessageClass(Py_TYPE(self)),
name);
}
PyObject* GetFieldValue(CMessage* self,
@ -2491,8 +2518,7 @@ PyObject* GetFieldValue(CMessage* self,
if (self->message->GetDescriptor() != field_descriptor->containing_type()) {
PyErr_Format(PyExc_TypeError,
"descriptor to field '%s' doesn't apply to '%s' object",
field_descriptor->full_name().c_str(),
Py_TYPE(self)->tp_name);
field_descriptor->full_name().c_str(), Py_TYPE(self)->tp_name);
return nullptr;
}
@ -2529,8 +2555,7 @@ PyObject* GetFieldValue(CMessage* self,
py_container =
repeated_scalar_container::NewContainer(self, field_descriptor);
}
} else if (field_descriptor->cpp_type() ==
FieldDescriptor::CPPTYPE_MESSAGE) {
} else if (field_descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
py_container = InternalGetSubMessage(self, field_descriptor);
} else {
PyErr_SetString(PyExc_SystemError, "Should never happen");
@ -2551,8 +2576,7 @@ int SetFieldValue(CMessage* self, const FieldDescriptor* field_descriptor,
if (self->message->GetDescriptor() != field_descriptor->containing_type()) {
PyErr_Format(PyExc_TypeError,
"descriptor to field '%s' doesn't apply to '%s' object",
field_descriptor->full_name().c_str(),
Py_TYPE(self)->tp_name);
field_descriptor->full_name().c_str(), Py_TYPE(self)->tp_name);
return -1;
} else if (field_descriptor->label() == FieldDescriptor::LABEL_REPEATED) {
PyErr_Format(PyExc_AttributeError,
@ -2561,11 +2585,34 @@ int SetFieldValue(CMessage* self, const FieldDescriptor* field_descriptor,
field_descriptor->name().c_str());
return -1;
} else if (field_descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
PyErr_Format(PyExc_AttributeError,
"Assignment not allowed to "
"field \"%s\" in protocol message object.",
field_descriptor->name().c_str());
return -1;
switch (field_descriptor->message_type()->well_known_type()) {
case Descriptor::WELLKNOWNTYPE_TIMESTAMP: {
AssureWritable(self);
PyObject* sub_message = GetFieldValue(self, field_descriptor);
ScopedPyObjectPtr ok(
PyObject_CallMethod(sub_message, "FromDatetime", "O", value));
if (ok.get() == nullptr) {
return -1;
}
return 0;
}
case Descriptor::WELLKNOWNTYPE_DURATION: {
AssureWritable(self);
PyObject* sub_message = GetFieldValue(self, field_descriptor);
ScopedPyObjectPtr ok(
PyObject_CallMethod(sub_message, "FromTimedelta", "O", value));
if (ok.get() == nullptr) {
return -1;
}
return 0;
}
default:
PyErr_Format(PyExc_AttributeError,
"Assignment not allowed to "
"field \"%s\" in protocol message object.",
field_descriptor->name().c_str());
return -1;
}
} else {
AssureWritable(self);
return InternalSetScalar(self, field_descriptor, value);
@ -2814,13 +2861,14 @@ void InitGlobals() {
// the error (MemoryError) on up to result in an import failure. These should
// also be freed and reset to NULL during finalization.
kDESCRIPTOR = PyUnicode_FromString("DESCRIPTOR");
kMessageFactory = PyUnicode_FromString("message_factory");
PyObject* dummy_obj = PySet_New(nullptr);
kEmptyWeakref = PyWeakref_NewRef(dummy_obj, nullptr);
Py_DECREF(dummy_obj);
}
bool InitProto2MessageModule(PyObject *m) {
bool InitProto2MessageModule(PyObject* m) {
// Initialize types and globals in descriptor.cc
if (!InitDescriptor()) {
return false;

@ -195,10 +195,7 @@ def _IsGroupLike(field):
True if this field is group-like, false otherwise.
"""
# Groups are always tag-delimited.
if (
field._GetFeatures().message_encoding
!= descriptor._FEATURESET_MESSAGE_ENCODING_DELIMITED
):
if field.type != descriptor.FieldDescriptor.TYPE_GROUP:
return False
# Group fields always are always the lowercase type name.

@ -259,16 +259,6 @@ static Py_ssize_t PyUpb_MapContainer_Length(PyObject* _self) {
return map ? upb_Map_Size(map) : 0;
}
static PyUpb_MapContainer* PyUpb_MapContainer_Check(PyObject* _self) {
PyUpb_ModuleState* state = PyUpb_ModuleState_Get();
if (!PyObject_TypeCheck(_self, state->message_map_container_type) &&
!PyObject_TypeCheck(_self, state->scalar_map_container_type)) {
PyErr_Format(PyExc_TypeError, "Expected protobuf map, but got %R", _self);
return NULL;
}
return (PyUpb_MapContainer*)_self;
}
int PyUpb_Message_InitMapAttributes(PyObject* map, PyObject* value,
const upb_FieldDef* f);

@ -433,6 +433,7 @@ err:
}
static bool PyUpb_Message_InitMessageAttribute(PyObject* _self, PyObject* name,
const upb_FieldDef* field,
PyObject* value) {
PyObject* submsg = PyUpb_Message_GetAttr(_self, name);
if (!submsg) return -1;
@ -446,10 +447,24 @@ static bool PyUpb_Message_InitMessageAttribute(PyObject* _self, PyObject* name,
assert(!PyErr_Occurred());
ok = PyUpb_Message_InitAttributes(submsg, NULL, value) >= 0;
} else {
const upb_MessageDef* m = PyUpb_Message_GetMsgdef(_self);
PyErr_Format(PyExc_TypeError, "Message must be initialized with a dict: %s",
upb_MessageDef_FullName(m));
ok = false;
const upb_MessageDef* msgdef = upb_FieldDef_MessageSubDef(field);
switch (upb_MessageDef_WellKnownType(msgdef)) {
case kUpb_WellKnown_Timestamp: {
ok = PyObject_CallMethod(submsg, "FromDatetime", "O", value);
break;
}
case kUpb_WellKnown_Duration: {
ok = PyObject_CallMethod(submsg, "FromTimedelta", "O", value);
break;
}
default: {
const upb_MessageDef* m = PyUpb_Message_GetMsgdef(_self);
PyErr_Format(PyExc_TypeError,
"Message must be initialized with a dict: %s",
upb_MessageDef_FullName(m));
ok = false;
}
}
}
Py_DECREF(submsg);
return ok;
@ -502,7 +517,7 @@ int PyUpb_Message_InitAttributes(PyObject* _self, PyObject* args,
} else if (upb_FieldDef_IsRepeated(f)) {
if (!PyUpb_Message_InitRepeatedAttribute(_self, name, value)) return -1;
} else if (upb_FieldDef_IsSubMessage(f)) {
if (!PyUpb_Message_InitMessageAttribute(_self, name, value)) return -1;
if (!PyUpb_Message_InitMessageAttribute(_self, name, f, value)) return -1;
} else {
if (!PyUpb_Message_InitScalarAttribute(msg, f, value, arena)) return -1;
}
@ -935,9 +950,9 @@ int PyUpb_Message_SetFieldValue(PyObject* _self, const upb_FieldDef* field,
PyUpb_Message* self = (void*)_self;
assert(value);
if (upb_FieldDef_IsSubMessage(field) || upb_FieldDef_IsRepeated(field)) {
if (upb_FieldDef_IsRepeated(field)) {
PyErr_Format(exc,
"Assignment not allowed to message, map, or repeated "
"Assignment not allowed to map, or repeated "
"field \"%s\" in protocol message object.",
upb_FieldDef_Name(field));
return -1;
@ -945,6 +960,34 @@ int PyUpb_Message_SetFieldValue(PyObject* _self, const upb_FieldDef* field,
PyUpb_Message_EnsureReified(self);
if (upb_FieldDef_IsSubMessage(field)) {
const upb_MessageDef* msgdef = upb_FieldDef_MessageSubDef(field);
switch (upb_MessageDef_WellKnownType(msgdef)) {
case kUpb_WellKnown_Timestamp: {
PyObject* sub_message = PyUpb_Message_GetFieldValue(_self, field);
PyObject* ok =
PyObject_CallMethod(sub_message, "FromDatetime", "O", value);
if (!ok) return -1;
Py_DECREF(ok);
return 0;
}
case kUpb_WellKnown_Duration: {
PyObject* sub_message = PyUpb_Message_GetFieldValue(_self, field);
PyObject* ok =
PyObject_CallMethod(sub_message, "FromTimedelta", "O", value);
if (!ok) return -1;
Py_DECREF(ok);
return 0;
}
default:
PyErr_Format(exc,
"Assignment not allowed to message "
"field \"%s\" in protocol message object.",
upb_FieldDef_Name(field));
return -1;
}
}
upb_MessageValue val;
upb_Arena* arena = PyUpb_Arena_Get(self->arena);
if (!PyUpb_PyToUpb(value, field, &val, arena)) {
@ -1286,6 +1329,9 @@ PyObject* PyUpb_Message_MergeFromString(PyObject* _self, PyObject* arg) {
int err = PyBytes_AsStringAndSize(bytes, &buf, &size);
(void)err;
assert(err >= 0);
} else if (PyByteArray_Check(arg)) {
buf = PyByteArray_AsString(arg);
size = PyByteArray_Size(arg);
} else if (PyBytes_AsStringAndSize(arg, &buf, &size) < 0) {
return NULL;
}
@ -1304,7 +1350,9 @@ PyObject* PyUpb_Message_MergeFromString(PyObject* _self, PyObject* arg) {
upb_Decode(buf, size, self->ptr.msg, layout, extreg, options, arena);
Py_XDECREF(bytes);
if (status != kUpb_DecodeStatus_Ok) {
PyErr_Format(state->decode_error_class, "Error parsing message");
PyErr_Format(state->decode_error_class,
"Error parsing message with type '%s'",
upb_MessageDef_FullName(msgdef));
return NULL;
}
PyUpb_Message_SyncSubobjs(self);
@ -1622,7 +1670,6 @@ static PyObject* PyUpb_Message_WhichOneof(PyObject* _self, PyObject* name) {
}
PyObject* DeepCopy(PyObject* _self, PyObject* arg) {
PyUpb_Message* self = (void*)_self;
const upb_MessageDef* def = PyUpb_Message_GetMsgdef(_self);
const upb_MiniTable* mini_table = upb_MessageDef_MiniTable(def);
upb_Message* msg = PyUpb_Message_GetIfReified(_self);

@ -216,7 +216,7 @@ typedef struct {
// memory to the OS. Without this call, we appear to leak memory, at least
// as measured in RSS.
//
// We opt not to use this instead of PyMalloc (which would also solve the
// We opt to use this instead of PyMalloc (which would also solve the
// problem) because the latter requires the GIL to be held. This would make
// our messages unsafe to share with other languages that could free at
// unpredictable
@ -240,7 +240,7 @@ static void* upb_trim_allocfunc(upb_alloc* alloc, void* ptr, size_t oldsize,
}
}
static upb_alloc trim_alloc = {&upb_trim_allocfunc};
static const upb_alloc* global_alloc = &trim_alloc;
static upb_alloc* global_alloc = &trim_alloc;
// end:github_only
static upb_Arena* PyUpb_NewArena(void) {

@ -66,6 +66,7 @@ static VALUE Map_alloc(VALUE klass) {
VALUE Map_GetRubyWrapper(const upb_Map* map, upb_CType key_type,
TypeInfo value_type, VALUE arena) {
PBRUBY_ASSERT(map);
PBRUBY_ASSERT(arena != Qnil);
VALUE val = ObjectCache_Get(map);

@ -86,6 +86,7 @@ upb_Message* Message_GetMutable(VALUE msg_rb, const upb_MessageDef** m) {
}
void Message_InitPtr(VALUE self_, const upb_Message* msg, VALUE arena) {
PBRUBY_ASSERT(arena != Qnil);
Message* self = ruby_to_Message(self_);
self->msg = msg;
RB_OBJ_WRITE(self_, &self->arena, arena);
@ -299,14 +300,14 @@ VALUE Message_getfield_frozen(const upb_Message* msg, const upb_FieldDef* f,
const upb_FieldDef* val_f = map_field_value(f);
upb_CType key_type = upb_FieldDef_CType(key_f);
TypeInfo value_type_info = TypeInfo_get(val_f);
return Map_GetRubyWrapper(msgval.map_val, key_type, value_type_info, Qnil);
return Map_GetRubyWrapper(msgval.map_val, key_type, value_type_info, arena);
}
if (upb_FieldDef_IsRepeated(f)) {
if (msgval.array_val == NULL) {
return RepeatedField_EmptyFrozen(f);
}
return RepeatedField_GetRubyWrapper(msgval.array_val, TypeInfo_get(f),
Qnil);
arena);
}
VALUE ret;
if (upb_FieldDef_IsSubMessage(f)) {

@ -82,6 +82,7 @@ VALUE RepeatedField_EmptyFrozen(const upb_FieldDef* f) {
VALUE RepeatedField_GetRubyWrapper(const upb_Array* array, TypeInfo type_info,
VALUE arena) {
PBRUBY_ASSERT(array);
PBRUBY_ASSERT(arena != Qnil);
VALUE val = ObjectCache_Get(array);
if (val == Qnil) {

@ -378,7 +378,7 @@ error UPB_TRACING_ENABLED Tracing should be disabled in production builds
#define UPB_LINKARR_DECLARE(name, type) \
extern type const __start_linkarr_##name; \
extern type const __stop_linkarr_##name; \
UPB_LINKARR_APPEND(name) type UPB_linkarr_internal_empty_##name[1] = {0}
UPB_LINKARR_APPEND(name) type UPB_linkarr_internal_empty_##name[1]
#define UPB_LINKARR_START(name) (&__start_linkarr_##name)
#define UPB_LINKARR_STOP(name) (&__stop_linkarr_##name)
@ -386,14 +386,14 @@ error UPB_TRACING_ENABLED Tracing should be disabled in production builds
/* As described in: https://stackoverflow.com/a/22366882 */
#define UPB_LINKARR_APPEND(name) \
__attribute__((retain, used, section("__DATA,la_" #name)))
__attribute__((retain, used, section("__DATA,__la_" #name)))
#define UPB_LINKARR_DECLARE(name, type) \
extern type const __start_linkarr_##name __asm( \
"section$start$__DATA$la_" #name); \
"section$start$__DATA$__la_" #name); \
extern type const __stop_linkarr_##name __asm( \
"section$end$__DATA$" \
"la_" #name); \
UPB_LINKARR_APPEND(name) type UPB_linkarr_internal_empty_##name[1] = {0}
"__la_" #name); \
UPB_LINKARR_APPEND(name) type UPB_linkarr_internal_empty_##name[1]
#define UPB_LINKARR_START(name) (&__start_linkarr_##name)
#define UPB_LINKARR_STOP(name) (&__stop_linkarr_##name)
@ -487,6 +487,7 @@ void upb_Status_VAppendErrorFormat(upb_Status* status, const char* fmt,
// Must be last.
extern const struct upb_MiniTable UPB_PRIVATE(_kUpb_MiniTable_StaticallyTreeShaken);
static const upb_MiniTableSubInternal google_protobuf_FileDescriptorSet_submsgs[1] = {
{.UPB_PRIVATE(submsg) = &google__protobuf__FileDescriptorProto_msg_init_ptr},
};
@ -1641,42 +1642,6 @@ const upb_MiniTable google__protobuf__GeneratedCodeInfo__Annotation_msg_init = {
};
const upb_MiniTable* google__protobuf__GeneratedCodeInfo__Annotation_msg_init_ptr = &google__protobuf__GeneratedCodeInfo__Annotation_msg_init;
static const upb_MiniTable *messages_layout[33] = {
&google__protobuf__FileDescriptorSet_msg_init,
&google__protobuf__FileDescriptorProto_msg_init,
&google__protobuf__DescriptorProto_msg_init,
&google__protobuf__DescriptorProto__ExtensionRange_msg_init,
&google__protobuf__DescriptorProto__ReservedRange_msg_init,
&google__protobuf__ExtensionRangeOptions_msg_init,
&google__protobuf__ExtensionRangeOptions__Declaration_msg_init,
&google__protobuf__FieldDescriptorProto_msg_init,
&google__protobuf__OneofDescriptorProto_msg_init,
&google__protobuf__EnumDescriptorProto_msg_init,
&google__protobuf__EnumDescriptorProto__EnumReservedRange_msg_init,
&google__protobuf__EnumValueDescriptorProto_msg_init,
&google__protobuf__ServiceDescriptorProto_msg_init,
&google__protobuf__MethodDescriptorProto_msg_init,
&google__protobuf__FileOptions_msg_init,
&google__protobuf__MessageOptions_msg_init,
&google__protobuf__FieldOptions_msg_init,
&google__protobuf__FieldOptions__EditionDefault_msg_init,
&google__protobuf__FieldOptions__FeatureSupport_msg_init,
&google__protobuf__OneofOptions_msg_init,
&google__protobuf__EnumOptions_msg_init,
&google__protobuf__EnumValueOptions_msg_init,
&google__protobuf__ServiceOptions_msg_init,
&google__protobuf__MethodOptions_msg_init,
&google__protobuf__UninterpretedOption_msg_init,
&google__protobuf__UninterpretedOption__NamePart_msg_init,
&google__protobuf__FeatureSet_msg_init,
&google__protobuf__FeatureSetDefaults_msg_init,
&google__protobuf__FeatureSetDefaults__FeatureSetEditionDefault_msg_init,
&google__protobuf__SourceCodeInfo_msg_init,
&google__protobuf__SourceCodeInfo__Location_msg_init,
&google__protobuf__GeneratedCodeInfo_msg_init,
&google__protobuf__GeneratedCodeInfo__Annotation_msg_init,
};
const upb_MiniTableEnum google_protobuf_Edition_enum_init = {
64,
9,
@ -1839,6 +1804,42 @@ const upb_MiniTableEnum google_protobuf_MethodOptions_IdempotencyLevel_enum_init
},
};
static const upb_MiniTable *messages_layout[33] = {
&google__protobuf__FileDescriptorSet_msg_init,
&google__protobuf__FileDescriptorProto_msg_init,
&google__protobuf__DescriptorProto_msg_init,
&google__protobuf__DescriptorProto__ExtensionRange_msg_init,
&google__protobuf__DescriptorProto__ReservedRange_msg_init,
&google__protobuf__ExtensionRangeOptions_msg_init,
&google__protobuf__ExtensionRangeOptions__Declaration_msg_init,
&google__protobuf__FieldDescriptorProto_msg_init,
&google__protobuf__OneofDescriptorProto_msg_init,
&google__protobuf__EnumDescriptorProto_msg_init,
&google__protobuf__EnumDescriptorProto__EnumReservedRange_msg_init,
&google__protobuf__EnumValueDescriptorProto_msg_init,
&google__protobuf__ServiceDescriptorProto_msg_init,
&google__protobuf__MethodDescriptorProto_msg_init,
&google__protobuf__FileOptions_msg_init,
&google__protobuf__MessageOptions_msg_init,
&google__protobuf__FieldOptions_msg_init,
&google__protobuf__FieldOptions__EditionDefault_msg_init,
&google__protobuf__FieldOptions__FeatureSupport_msg_init,
&google__protobuf__OneofOptions_msg_init,
&google__protobuf__EnumOptions_msg_init,
&google__protobuf__EnumValueOptions_msg_init,
&google__protobuf__ServiceOptions_msg_init,
&google__protobuf__MethodOptions_msg_init,
&google__protobuf__UninterpretedOption_msg_init,
&google__protobuf__UninterpretedOption__NamePart_msg_init,
&google__protobuf__FeatureSet_msg_init,
&google__protobuf__FeatureSetDefaults_msg_init,
&google__protobuf__FeatureSetDefaults__FeatureSetEditionDefault_msg_init,
&google__protobuf__SourceCodeInfo_msg_init,
&google__protobuf__SourceCodeInfo__Location_msg_init,
&google__protobuf__GeneratedCodeInfo_msg_init,
&google__protobuf__GeneratedCodeInfo__Annotation_msg_init,
};
static const upb_MiniTableEnum *enums_layout[17] = {
&google_protobuf_Edition_enum_init,
&google_protobuf_ExtensionRangeOptions_VerificationState_enum_init,
@ -7055,15 +7056,15 @@ failure:
#ifdef UPB_LINKARR_DECLARE
UPB_LINKARR_DECLARE(upb_AllExts, const upb_MiniTableExtension*);
UPB_LINKARR_DECLARE(upb_AllExts, upb_MiniTableExtension);
bool upb_ExtensionRegistry_AddAllLinkedExtensions(upb_ExtensionRegistry* r) {
const upb_MiniTableExtension* const* start = UPB_LINKARR_START(upb_AllExts);
const upb_MiniTableExtension* const* stop = UPB_LINKARR_STOP(upb_AllExts);
for (const upb_MiniTableExtension* const* p = start; p < stop; p++) {
const upb_MiniTableExtension* start = UPB_LINKARR_START(upb_AllExts);
const upb_MiniTableExtension* stop = UPB_LINKARR_STOP(upb_AllExts);
for (const upb_MiniTableExtension* p = start; p < stop; p++) {
// Windows can introduce zero padding, so we have to skip zeroes.
if (*p != 0) {
if (!upb_ExtensionRegistry_Add(r, *p)) return false;
if (upb_MiniTableExtension_Number(p) != 0) {
if (!upb_ExtensionRegistry_Add(r, p)) return false;
}
}
return true;
@ -12102,7 +12103,12 @@ char* upb_MtDataEncoder_EndEnum(upb_MtDataEncoder* e, char* ptr) {
// Must be last.
// A MiniTable for an empty message, used for unlinked sub-messages.
// A MiniTable for an empty message, used for unlinked sub-messages that are
// built via MiniDescriptors. Messages that use this MiniTable may possibly
// be linked later, in which case this MiniTable will be replaced with a real
// one. This pattern is known as "dynamic tree shaking", and it introduces
// complication because sub-messages may either be the "empty" type or the
// "real" type. A tagged bit indicates the difference.
const struct upb_MiniTable UPB_PRIVATE(_kUpb_MiniTable_Empty) = {
.UPB_PRIVATE(subs) = NULL,
.UPB_PRIVATE(fields) = NULL,
@ -12114,6 +12120,21 @@ const struct upb_MiniTable UPB_PRIVATE(_kUpb_MiniTable_Empty) = {
.UPB_PRIVATE(required_count) = 0,
};
// A MiniTable for a statically tree shaken message. Messages that use this
// MiniTable are guaranteed to remain unlinked; unlike the empty message, this
// MiniTable is never replaced, which greatly simplifies everything, because the
// type of a sub-message is always known, without consulting a tagged bit.
const struct upb_MiniTable UPB_PRIVATE(_kUpb_MiniTable_StaticallyTreeShaken) = {
.UPB_PRIVATE(subs) = NULL,
.UPB_PRIVATE(fields) = NULL,
.UPB_PRIVATE(size) = sizeof(struct upb_Message),
.UPB_PRIVATE(field_count) = 0,
.UPB_PRIVATE(ext) = kUpb_ExtMode_NonExtendable,
.UPB_PRIVATE(dense_below) = 0,
.UPB_PRIVATE(table_mask) = -1,
.UPB_PRIVATE(required_count) = 0,
};
// Must be last.
@ -13432,8 +13453,7 @@ bool _upb_FieldDef_ValidateUtf8(const upb_FieldDef* f) {
bool _upb_FieldDef_IsGroupLike(const upb_FieldDef* f) {
// Groups are always tag-delimited.
if (UPB_DESC(FeatureSet_message_encoding)(upb_FieldDef_ResolvedFeatures(f)) !=
UPB_DESC(FeatureSet_DELIMITED)) {
if (f->type_ != kUpb_FieldType_Group) {
return false;
}
@ -13870,12 +13890,6 @@ static void _upb_FieldDef_Create(upb_DefBuilder* ctx, const char* prefix,
UPB_DESC(FieldDescriptorProto_has_type_name)(field_proto);
f->type_ = (int)UPB_DESC(FieldDescriptorProto_type)(field_proto);
if (f->type_ == kUpb_FieldType_Message &&
// TODO: remove once we can deprecate kUpb_FieldType_Group.
UPB_DESC(FeatureSet_message_encoding)(f->resolved_features) ==
UPB_DESC(FeatureSet_DELIMITED)) {
f->type_ = kUpb_FieldType_Group;
}
if (has_type) {
switch (f->type_) {
@ -13896,7 +13910,7 @@ static void _upb_FieldDef_Create(upb_DefBuilder* ctx, const char* prefix,
}
}
if (!has_type && has_type_name) {
if ((!has_type && has_type_name) || f->type_ == kUpb_FieldType_Message) {
f->type_ =
UPB_FIELD_TYPE_UNSPECIFIED; // We'll assign this in resolve_subdef()
} else {
@ -14046,8 +14060,15 @@ static void resolve_subdef(upb_DefBuilder* ctx, const char* prefix,
break;
case UPB_DEFTYPE_MSG:
f->sub.msgdef = def;
f->type_ = kUpb_FieldType_Message; // It appears there is no way of
// this being a group.
f->type_ = kUpb_FieldType_Message;
// TODO: remove once we can deprecate
// kUpb_FieldType_Group.
if (UPB_DESC(FeatureSet_message_encoding)(f->resolved_features) ==
UPB_DESC(FeatureSet_DELIMITED) &&
!upb_MessageDef_IsMapEntry(def) &&
!(f->msgdef && upb_MessageDef_IsMapEntry(f->msgdef))) {
f->type_ = kUpb_FieldType_Group;
}
f->has_presence = !upb_FieldDef_IsRepeated(f);
break;
default:

File diff suppressed because it is too large Load Diff

@ -228,12 +228,17 @@ impl From<RustStringRawParts> for String {
extern "C" {
fn utf8_debug_string(msg: RawMessage) -> RustStringRawParts;
fn utf8_debug_string_lite(msg: RawMessage) -> RustStringRawParts;
}
pub fn debug_string(_private: Private, msg: RawMessage, f: &mut fmt::Formatter<'_>) -> fmt::Result {
// SAFETY:
// - `msg` is a valid protobuf message.
#[cfg(not(lite_runtime))]
let dbg_str: String = unsafe { utf8_debug_string(msg) }.into();
#[cfg(lite_runtime)]
let dbg_str: String = unsafe { utf8_debug_string_lite(msg) }.into();
write!(f, "{dbg_str}")
}

@ -7,6 +7,7 @@
#include "google/protobuf/map.h"
#include "google/protobuf/message.h"
#include "google/protobuf/message_lite.h"
#include "google/protobuf/repeated_field.h"
#include "google/protobuf/repeated_ptr_field.h"
@ -141,6 +142,12 @@ google::protobuf::rust_internal::RustStringRawParts utf8_debug_string(
std::string text = google::protobuf::Utf8Format(*msg);
return google::protobuf::rust_internal::RustStringRawParts(text);
}
google::protobuf::rust_internal::RustStringRawParts utf8_debug_string_lite(
const google::protobuf::MessageLite* msg) {
std::string text = google::protobuf::Utf8Format(*msg);
return google::protobuf::rust_internal::RustStringRawParts(text);
}
}
namespace google {

@ -179,6 +179,8 @@ struct RustStringRawParts {
};
extern "C" RustStringRawParts utf8_debug_string(const google::protobuf::Message* msg);
extern "C" RustStringRawParts utf8_debug_string_lite(
const google::protobuf::MessageLite* msg);
} // namespace rust_internal
} // namespace protobuf
} // namespace google

@ -217,7 +217,7 @@ where
/// runtime. We expect it to change in backwards incompatible ways in the
/// future.
pub trait IntoProxied<T: Proxied> {
fn into(self, _private: Private) -> T;
fn into_proxied(self, _private: Private) -> T;
}
#[cfg(test)]

@ -241,7 +241,7 @@ impl<T> IntoProxied<Repeated<T>> for Repeated<T>
where
T: ?Sized + ProxiedInRepeated,
{
fn into(self, _private: Private) -> Repeated<T> {
fn into_proxied(self, _private: Private) -> Repeated<T> {
self
}
}
@ -250,7 +250,7 @@ impl<'msg, T> IntoProxied<Repeated<T>> for RepeatedView<'msg, T>
where
T: 'msg + ?Sized + ProxiedInRepeated,
{
fn into(self, _private: Private) -> Repeated<T> {
fn into_proxied(self, _private: Private) -> Repeated<T> {
let mut repeated: Repeated<T> = Repeated::new();
T::repeated_copy_from(self, repeated.as_mut());
repeated
@ -261,8 +261,8 @@ impl<'msg, T> IntoProxied<Repeated<T>> for RepeatedMut<'msg, T>
where
T: 'msg + ?Sized + ProxiedInRepeated,
{
fn into(self, _private: Private) -> Repeated<T> {
IntoProxied::into(self.as_view(), _private)
fn into_proxied(self, _private: Private) -> Repeated<T> {
IntoProxied::into_proxied(self.as_view(), _private)
}
}

@ -61,6 +61,11 @@ mod proxied;
mod repeated;
mod string;
// If the Upb and C++ kernels are both linked into the same binary, this symbol
// will be defined twice and cause a link error.
#[no_mangle]
extern "C" fn __Disallow_Upb_And_Cpp_In_Same_Binary() {}
/// An error that happened during parsing.
#[derive(Debug, Clone)]
pub struct ParseError;

@ -10,6 +10,8 @@ UNITTEST_PROTO3_TARGET = "//src/google/protobuf:test_protos"
UNITTEST_PROTO3_OPTIONAL_TARGET = "//src/google/protobuf:test_protos"
UNITTEST_EDITION_TARGET = "//src/google/protobuf:test_protos"
rust_upb_proto_library(
name = "unittest_upb_rust_proto",
testonly = True,
@ -55,6 +57,20 @@ rust_upb_proto_library(
deps = [UNITTEST_PROTO3_OPTIONAL_TARGET],
)
rust_cc_proto_library(
name = "unittest_edition_cpp_rust_proto",
testonly = True,
visibility = ["//rust/test/shared:__subpackages__"],
deps = [UNITTEST_EDITION_TARGET],
)
rust_upb_proto_library(
name = "unittest_edition_upb_rust_proto",
testonly = True,
visibility = ["//rust/test/shared:__subpackages__"],
deps = [UNITTEST_EDITION_TARGET],
)
proto_library(
name = "parent_proto",
srcs = ["parent.proto"],
@ -120,6 +136,7 @@ proto_library(
name = "edition2023_proto",
testonly = True,
srcs = ["edition2023.proto"],
deps = ["//src/google/protobuf:cpp_features_proto"],
)
rust_cc_proto_library(

@ -40,7 +40,7 @@ upb_cc_proto_library(
)
cc_test(
name = "rust_protobuf_benchmarks",
name = "rust_protobuf_benchmarks_cpp",
testonly = True,
srcs = ["rust_protobuf_benchmarks.cc"],
deps = [
@ -48,6 +48,26 @@ cc_test(
":bench_data_upb_cc_proto",
":benchmarks",
":proto_benchmarks_cpp", # build_cleaner: keep
"//protos",
"//protos:repeated_field",
"//src/google/protobuf:protobuf_lite",
"//testing/base/public:gunit",
"//third_party/benchmark",
"@com_google_absl//absl/log:absl_check",
"@com_google_googletest//:gtest",
"@com_google_googletest//:gtest_main",
],
)
cc_test(
name = "rust_protobuf_benchmarks_upb",
testonly = True,
srcs = ["rust_protobuf_benchmarks.cc"],
defines = ["BENCHMARK_UPB"],
deps = [
":bench_data_cc_proto",
":bench_data_upb_cc_proto",
":benchmarks",
":proto_benchmarks_upb", # build_cleaner: keep
"//protos",
"//protos:repeated_field",

@ -12,6 +12,12 @@
using benchmarks::BenchData;
#ifdef BENCHMARK_UPB
#define PROTO_BENCHMARK(NAME) EXTERN_BENCHMARK(NAME##_upb);
#else
#define PROTO_BENCHMARK(NAME) EXTERN_BENCHMARK(NAME##_cpp);
#endif
#define EXTERN_BENCHMARK(NAME) \
extern "C" { \
void NAME##_bench(); \
@ -23,10 +29,6 @@ using benchmarks::BenchData;
} \
BENCHMARK(BM_##NAME);
#define PROTO_BENCHMARK(NAME) \
EXTERN_BENCHMARK(NAME##_cpp); \
EXTERN_BENCHMARK(NAME##_upb);
void BM_set_string_cpp(benchmark::State& state) {
for (auto s : state) {
auto data = std::make_unique<BenchData>();

@ -1,6 +1,7 @@
use debug_rust_proto::DebugMsg;
use googletest::prelude::*;
#[cfg(not(lite_runtime))]
#[test]
fn test_debug() {
let mut msg = DebugMsg::new();
@ -10,3 +11,14 @@ fn test_debug() {
assert_that!(format!("{msg:?}"), contains_substring("id: 1"));
assert_that!(format!("{msg:?}"), not(contains_substring("password")));
}
#[cfg(lite_runtime)]
#[test]
fn test_debug_lite() {
let mut msg = DebugMsg::new();
msg.set_id(1);
msg.set_secret_user_data("password");
assert_that!(format!("{msg:?}"), contains_substring("MessageLite"));
assert_that!(format!("{msg:?}"), not(contains_substring("password")));
}

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

Loading…
Cancel
Save