diff --git a/.github/workflows/codespell.yml b/.github/workflows/codespell.yml
index f9795e190c..a138098c94 100644
--- a/.github/workflows/codespell.yml
+++ b/.github/workflows/codespell.yml
@@ -13,4 +13,4 @@ jobs:
with:
check_filenames: true
skip: ./.git,./conformance/third_party,*.snk,*.pb,*.pb.cc,*.pb.h,./src/google/protobuf/testdata,./objectivec/Tests,./python/compatibility_tests/v2.5.0/tests/google/protobuf/internal
- ignore_words_list: "alow,alse,ba,cleare,copyable,cloneable,dedup,dur,errorprone,files',fo,fundementals,hel,importd,inout,leapyear,nd,ois,ons,parseable,process',te,testof,ue,unparseable,wasn,wee,gae,keyserver,objext,od"
+ ignore_words_list: "alow,alse,ba,cleare,copyable,cloneable,dedup,dur,errorprone,files',fo,fundementals,hel,importd,inout,leapyear,nd,nin,ois,ons,parseable,process',te,testof,ue,unparseable,wasn,wee,gae,keyserver,objext,od"
diff --git a/.gitignore b/.gitignore
index e06aedea6b..44ab2d49ef 100644
--- a/.gitignore
+++ b/.gitignore
@@ -137,6 +137,7 @@ conformance/*.class
# php test output
composer.lock
+php/.phpunit.result.cache
php/tests/.phpunit.result.cache
php/tests/generated/
php/tests/old_protoc
@@ -162,6 +163,7 @@ php/ext/google/protobuf/configure.ac
php/ext/google/protobuf/configure.in
php/ext/google/protobuf/mkinstalldirs
php/ext/google/protobuf/run-tests.php
+php/ext/google/protobuf/third_party/
vendor/
# JavaScript artifacts
@@ -190,6 +192,7 @@ ruby/tests/generated_code_pb.rb
ruby/tests/test_import_pb.rb
ruby/tests/test_ruby_package_pb.rb
ruby/tests/generated_code_proto2_pb.rb
+ruby/tests/multi_level_nesting_test_pb.rb
ruby/tests/test_import_proto2_pb.rb
ruby/tests/test_ruby_package_proto2_pb.rb
ruby/Gemfile.lock
diff --git a/CHANGES.txt b/CHANGES.txt
index da3e51bc53..b55e275deb 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,3 +1,29 @@
+Unreleased Changes (C++/Java/Python/PHP/Objective-C/C#/Ruby/JavaScript)
+
+ C++
+ * MessageDifferencer: fixed bug when using custom ignore with multiple
+ unknown fields
+ * Use init_seg in MSVC to push initialization to an earlier phase.
+ * Runtime no longer triggers -Wsign-compare warnings.
+ * Fixed -Wtautological-constant-out-of-range-compare warning.
+ * DynamicCastToGenerated works for nullptr input for even if RTTI is disabled
+ * Arena is refactored and optimized.
+ * Clarified/specified that the exact value of Arena::SpaceAllocated() is an
+ implementation detail users must not rely on. It should not be used in
+ unit tests.
+ * Change the signature of Any::PackFrom() to return false on error.
+
+ Java
+ * Avoid possible UnsupportedOperationException when using CodedInputSteam
+ with a direct ByteBuffer.
+ * Make Durations.comparator() and Timestamps.comparator() Serializable.
+ * Add more detailed error information for dynamic message field type
+ validation failure
+
+ Python
+ * Provided an override for the reverse() method that will reverse the internal
+ collection directly instead of using the other methods of the BaseContainer.
+
2020-11-11 version 3.14.0 (C++/Java/Python/PHP/Objective-C/C#/Ruby/JavaScript)
Protocol Compiler
diff --git a/Makefile.am b/Makefile.am
index b7b67fdb4f..707f7823d2 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -89,6 +89,7 @@ csharp_EXTRA_DIST= \
csharp/src/Google.Protobuf.Benchmarks/BenchmarkDatasetConfig.cs \
csharp/src/Google.Protobuf.Benchmarks/BenchmarkMessage1Proto3.cs \
csharp/src/Google.Protobuf.Benchmarks/Benchmarks.cs \
+ csharp/src/Google.Protobuf.Benchmarks/ByteStringBenchmark.cs \
csharp/src/Google.Protobuf.Benchmarks/Google.Protobuf.Benchmarks.csproj \
csharp/src/Google.Protobuf.Benchmarks/GoogleMessageBenchmark.cs \
csharp/src/Google.Protobuf.Benchmarks/ParseMessagesBenchmark.cs \
@@ -171,6 +172,7 @@ csharp_EXTRA_DIST= \
csharp/src/Google.Protobuf.sln \
csharp/src/Google.Protobuf/ByteArray.cs \
csharp/src/Google.Protobuf/ByteString.cs \
+ csharp/src/Google.Protobuf/ByteStringAsync.cs \
csharp/src/Google.Protobuf/CodedInputStream.cs \
csharp/src/Google.Protobuf/CodedOutputStream.ComputeSize.cs \
csharp/src/Google.Protobuf/CodedOutputStream.cs \
@@ -268,7 +270,8 @@ csharp_EXTRA_DIST= \
csharp/src/Google.Protobuf/WriteContext.cs \
csharp/src/Google.Protobuf/WriteBufferHelper.cs \
csharp/src/Google.Protobuf/UnknownField.cs \
- csharp/src/Google.Protobuf/UnknownFieldSet.cs
+ csharp/src/Google.Protobuf/UnknownFieldSet.cs \
+ csharp/src/Google.Protobuf/UnsafeByteOperations.cs
java_EXTRA_DIST= \
java/README.md \
@@ -772,13 +775,11 @@ php_EXTRA_DIST= \
php/ext/google/protobuf/arena.h \
php/ext/google/protobuf/array.c \
php/ext/google/protobuf/array.h \
- php/ext/google/protobuf/bundled_php.h \
php/ext/google/protobuf/config.m4 \
php/ext/google/protobuf/convert.c \
php/ext/google/protobuf/convert.h \
php/ext/google/protobuf/def.c \
php/ext/google/protobuf/def.h \
- php/ext/google/protobuf/make-preload.php \
php/ext/google/protobuf/map.c \
php/ext/google/protobuf/map.h \
php/ext/google/protobuf/message.c \
@@ -790,8 +791,10 @@ php_EXTRA_DIST= \
php/ext/google/protobuf/php-upb.h \
php/ext/google/protobuf/protobuf.c \
php/ext/google/protobuf/protobuf.h \
+ php/ext/google/protobuf/wkt.inc \
php/generate_descriptor_protos.sh \
php/phpunit.xml \
+ php/prepare_c_extension.sh \
php/release.sh \
php/src/GPBMetadata/Google/Protobuf/Any.php \
php/src/GPBMetadata/Google/Protobuf/Api.php \
@@ -827,6 +830,7 @@ php_EXTRA_DIST= \
php/src/Google/Protobuf/GPBEmpty.php \
php/src/Google/Protobuf/Int32Value.php \
php/src/Google/Protobuf/Int64Value.php \
+ php/src/Google/Protobuf/Internal/AnyBase.php \
php/src/Google/Protobuf/Internal/CodedInputStream.php \
php/src/Google/Protobuf/Internal/CodedOutputStream.php \
php/src/Google/Protobuf/Internal/Descriptor.php \
@@ -886,6 +890,7 @@ php_EXTRA_DIST= \
php/src/Google/Protobuf/Internal/ServiceOptions.php \
php/src/Google/Protobuf/Internal/SourceCodeInfo.php \
php/src/Google/Protobuf/Internal/SourceCodeInfo/Location.php \
+ php/src/Google/Protobuf/Internal/TimestampBase.php \
php/src/Google/Protobuf/Internal/UninterpretedOption.php \
php/src/Google/Protobuf/Internal/UninterpretedOption/NamePart.php \
php/src/Google/Protobuf/Internal/DescriptorProto_ExtensionRange.php \
@@ -1110,13 +1115,15 @@ ruby_EXTRA_DIST= \
ruby/src/main/java/com/google/protobuf/jruby/RubyBuilder.java \
ruby/src/main/java/com/google/protobuf/jruby/RubyDescriptor.java \
ruby/src/main/java/com/google/protobuf/jruby/RubyDescriptorPool.java \
+ ruby/src/main/java/com/google/protobuf/jruby/RubyEnum.java \
ruby/src/main/java/com/google/protobuf/jruby/RubyEnumBuilderContext.java \
ruby/src/main/java/com/google/protobuf/jruby/RubyEnumDescriptor.java \
- ruby/src/main/java/com/google/protobuf/jruby/RubyEnum.java \
ruby/src/main/java/com/google/protobuf/jruby/RubyFieldDescriptor.java \
+ ruby/src/main/java/com/google/protobuf/jruby/RubyFileBuilderContext.java \
+ ruby/src/main/java/com/google/protobuf/jruby/RubyFileDescriptor.java \
ruby/src/main/java/com/google/protobuf/jruby/RubyMap.java \
- ruby/src/main/java/com/google/protobuf/jruby/RubyMessageBuilderContext.java \
ruby/src/main/java/com/google/protobuf/jruby/RubyMessage.java \
+ ruby/src/main/java/com/google/protobuf/jruby/RubyMessageBuilderContext.java \
ruby/src/main/java/com/google/protobuf/jruby/RubyOneofBuilderContext.java \
ruby/src/main/java/com/google/protobuf/jruby/RubyOneofDescriptor.java \
ruby/src/main/java/com/google/protobuf/jruby/RubyProtobuf.java \
@@ -1390,6 +1397,8 @@ EXTRA_DIST = $(@DIST_LANG@_EXTRA_DIST) \
python/release/wheel/README.md \
third_party/six.BUILD \
third_party/zlib.BUILD \
+ third_party/wyhash/LICENSE \
+ third_party/wyhash/wyhash.h \
util/python/BUILD
diff --git a/Protobuf-C++.podspec b/Protobuf-C++.podspec
index 82dc8c6002..3f250e2f2a 100644
--- a/Protobuf-C++.podspec
+++ b/Protobuf-C++.podspec
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'Protobuf-C++'
- s.version = '3.13.0'
+ s.version = '3.14.0'
s.summary = 'Protocol Buffers v3 runtime library for C++.'
s.homepage = 'https://github.com/google/protobuf'
s.license = '3-Clause BSD License'
diff --git a/README.md b/README.md
index d5155ae9ab..118b896668 100644
--- a/README.md
+++ b/README.md
@@ -54,15 +54,15 @@ how to install protobuf runtime for that specific language:
| Language | Source | Ubuntu | MacOS | Windows |
|--------------------------------------|-------------------------------------------------------------|--------|-------|---------|
-| C++ (include C++ runtime and protoc) | [src](src) | [![Build status](https://storage.googleapis.com/protobuf-kokoro-results/status-badge/linux-cpp_distcheck.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fubuntu%2Fcpp_distcheck%2Fcontinuous)
[![Build status](https://storage.googleapis.com/protobuf-kokoro-results/status-badge/linux-bazel.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fubuntu%2Fbazel%2Fcontinuous)
[![Build status](https://storage.googleapis.com/protobuf-kokoro-results/status-badge/linux-dist_install.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fubuntu%2Fdist_install%2Fcontinuous) | [![Build status](https://storage.googleapis.com/protobuf-kokoro-results/status-badge/macos-cpp.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fmacos%2Fcpp%2Fcontinuous)
[![Build status](https://storage.googleapis.com/protobuf-kokoro-results/status-badge/macos-cpp_distcheck.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fmacos%2Fcpp_distcheck%2Fcontinuous) | [![Build status](https://ci.appveyor.com/api/projects/status/73ctee6ua4w2ruin?svg=true)](https://ci.appveyor.com/project/protobuf/protobuf) |
-| Java | [java](java) | [![Build status](https://storage.googleapis.com/protobuf-kokoro-results/status-badge/linux-java_compatibility.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fubuntu%2Fjava_compatibility%2Fcontinuous)
[![Build status](https://storage.googleapis.com/protobuf-kokoro-results/status-badge/linux-java_jdk7.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fubuntu%2Fjava_jdk7%2Fcontinuous)
[![Build status](https://storage.googleapis.com/protobuf-kokoro-results/status-badge/linux-java_oracle7.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fubuntu%2Fjava_oracle7%2Fcontinuous)
[![Build status](https://storage.googleapis.com/protobuf-kokoro-results/status-badge/linux-java_linkage_monitor.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fubuntu%2Fjava_linkage_monitor%2Fcontinuous) | | |
-| Python | [python](python) | [![Build status](https://storage.googleapis.com/protobuf-kokoro-results/status-badge/linux-python27.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fubuntu%2Fpython27%2Fcontinuous)
[![Build status](https://storage.googleapis.com/protobuf-kokoro-results/status-badge/linux-python35.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fubuntu%2Fpython35%2Fcontinuous)
[![Build status](https://storage.googleapis.com/protobuf-kokoro-results/status-badge/linux-python36.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fubuntu%2Fpython36%2Fcontinuous)
[![Build status](https://storage.googleapis.com/protobuf-kokoro-results/status-badge/linux-python37.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fubuntu%2Fpython37%2Fcontinuous)
[![Build status](https://storage.googleapis.com/protobuf-kokoro-results/status-badge/linux-python_compatibility.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fubuntu%2Fpython_compatibility%2Fcontinuous)
[![Build status](https://storage.googleapis.com/protobuf-kokoro-results/status-badge/linux-python27_cpp.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fubuntu%2Fpython27_cpp%2Fcontinuous)
[![Build status](https://storage.googleapis.com/protobuf-kokoro-results/status-badge/linux-python35_cpp.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fubuntu%2Fpython35_cpp%2Fcontinuous)
[![Build status](https://storage.googleapis.com/protobuf-kokoro-results/status-badge/linux-python36_cpp.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fubuntu%2Fpython36_cpp%2Fcontinuous)
[![Build status](https://storage.googleapis.com/protobuf-kokoro-results/status-badge/linux-python37_cpp.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fubuntu%2Fpython37_cpp%2Fcontinuous)
[![Build status](https://storage.googleapis.com/protobuf-kokoro-results/status-badge/linux-python-release.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fubuntu%2Fpython_release%2Fcontinuous) | [![Build status](https://storage.googleapis.com/protobuf-kokoro-results/status-badge/macos-python.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fmacos%2Fpython%2Fcontinuous)
[![Build status](https://storage.googleapis.com/protobuf-kokoro-results/status-badge/macos-python_cpp.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fmacos%2Fpython_cpp%2Fcontinuous)
[![Build status](https://storage.googleapis.com/protobuf-kokoro-results/status-badge/macos-python-release.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fmacos%2Fpython_release%2Fcontinuous) | [![Build status](https://storage.googleapis.com/protobuf-kokoro-results/status-badge/windows-python-release.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fwindows%2Fpython_release%2Fcontinuous) |
-| Objective-C | [objectivec](objectivec) | | [![Build status](https://storage.googleapis.com/protobuf-kokoro-results/status-badge/macos-objectivec_cocoapods_integration.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fmacos%2Fobjectivec_cocoapods_integration%2Fcontinuous)
[![Build status](https://storage.googleapis.com/protobuf-kokoro-results/status-badge/macos-objectivec_ios_debug.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fmacos%2Fobjectivec_ios_debug%2Fcontinuous)
[![Build status](https://storage.googleapis.com/protobuf-kokoro-results/status-badge/macos-objectivec_ios_release.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fmacos%2Fobjectivec_ios_release%2Fcontinuous)
[![Build status](https://storage.googleapis.com/protobuf-kokoro-results/status-badge/macos-objectivec_osx.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fmacos%2Fobjectivec_osx%2Fcontinuous) | |
-| C# | [csharp](csharp) | [![Build status](https://storage.googleapis.com/protobuf-kokoro-results/status-badge/linux-csharp.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fubuntu%2Fcsharp%2Fcontinuous) | | [![Build status](https://ci.appveyor.com/api/projects/status/73ctee6ua4w2ruin?svg=true)](https://ci.appveyor.com/project/protobuf/protobuf)
[![Build status](https://storage.googleapis.com/protobuf-kokoro-results/status-badge/windows-csharp-release.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fwindows%2Fcsharp_release%2Fcontinuous) |
-| JavaScript | [js](js) | [![Build status](https://storage.googleapis.com/protobuf-kokoro-results/status-badge/linux-javascript.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fubuntu%2Fjavascript%2Fcontinuous) | [![Build status](https://storage.googleapis.com/protobuf-kokoro-results/status-badge/macos-javascript.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fmacos%2Fjavascript%2Fcontinuous) | |
-| Ruby | [ruby](ruby) | [![Build status](https://storage.googleapis.com/protobuf-kokoro-results/status-badge/linux-ruby23.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fubuntu%2Fruby23%2Fcontinuous)
[![Build status](https://storage.googleapis.com/protobuf-kokoro-results/status-badge/linux-ruby24.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fubuntu%2Fruby24%2Fcontinuous)
[![Build status](https://storage.googleapis.com/protobuf-kokoro-results/status-badge/linux-ruby25.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fubuntu%2Fruby25%2Fcontinuous)
[![Build status](https://storage.googleapis.com/protobuf-kokoro-results/status-badge/linux-ruby26.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fubuntu%2Fruby26%2Fcontinuous)
[![Build status](https://storage.googleapis.com/protobuf-kokoro-results/status-badge/linux-ruby-release.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fubuntu%2Fruby_release%2Fcontinuous) | [![Build status](https://storage.googleapis.com/protobuf-kokoro-results/status-badge/macos-ruby23.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fmacos%2Fruby23%2Fcontinuous)
[![Build status](https://storage.googleapis.com/protobuf-kokoro-results/status-badge/macos-ruby24.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fmacos%2Fruby24%2Fcontinuous)
[![Build status](https://storage.googleapis.com/protobuf-kokoro-results/status-badge/macos-ruby25.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fmacos%2Fruby25%2Fcontinuous)
[![Build status](https://storage.googleapis.com/protobuf-kokoro-results/status-badge/macos-ruby26.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fmacos%2Fruby26%2Fcontinuous)
[![Build status](https://storage.googleapis.com/protobuf-kokoro-results/status-badge/macos-ruby-release.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fmacos%2Fruby_release%2Fcontinuous) | |
+| C++ (include C++ runtime and protoc) | [src](src) | [![Build status](https://storage.googleapis.com/protobuf-kokoro-badges/status-badge/linux-cpp_distcheck.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fubuntu%2Fcpp_distcheck%2Fcontinuous)
[![Build status](https://storage.googleapis.com/protobuf-kokoro-badges/status-badge/linux-bazel.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fubuntu%2Fbazel%2Fcontinuous)
[![Build status](https://storage.googleapis.com/protobuf-kokoro-badges/status-badge/linux-dist_install.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fubuntu%2Fdist_install%2Fcontinuous) | [![Build status](https://storage.googleapis.com/protobuf-kokoro-badges/status-badge/macos-cpp.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fmacos%2Fcpp%2Fcontinuous)
[![Build status](https://storage.googleapis.com/protobuf-kokoro-badges/status-badge/macos-cpp_distcheck.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fmacos%2Fcpp_distcheck%2Fcontinuous) | [![Build status](https://ci.appveyor.com/api/projects/status/73ctee6ua4w2ruin?svg=true)](https://ci.appveyor.com/project/protobuf/protobuf) |
+| Java | [java](java) | [![Build status](https://storage.googleapis.com/protobuf-kokoro-badges/status-badge/linux-java_compatibility.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fubuntu%2Fjava_compatibility%2Fcontinuous)
[![Build status](https://storage.googleapis.com/protobuf-kokoro-badges/status-badge/linux-java_jdk7.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fubuntu%2Fjava_jdk7%2Fcontinuous)
[![Build status](https://storage.googleapis.com/protobuf-kokoro-badges/status-badge/linux-java_oracle7.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fubuntu%2Fjava_oracle7%2Fcontinuous)
[![Build status](https://storage.googleapis.com/protobuf-kokoro-badges/status-badge/linux-java_linkage_monitor.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fubuntu%2Fjava_linkage_monitor%2Fcontinuous) | | |
+| Python | [python](python) | [![Build status](https://storage.googleapis.com/protobuf-kokoro-badges/status-badge/linux-python27.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fubuntu%2Fpython27%2Fcontinuous)
[![Build status](https://storage.googleapis.com/protobuf-kokoro-badges/status-badge/linux-python35.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fubuntu%2Fpython35%2Fcontinuous)
[![Build status](https://storage.googleapis.com/protobuf-kokoro-badges/status-badge/linux-python36.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fubuntu%2Fpython36%2Fcontinuous)
[![Build status](https://storage.googleapis.com/protobuf-kokoro-badges/status-badge/linux-python37.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fubuntu%2Fpython37%2Fcontinuous)
[![Build status](https://storage.googleapis.com/protobuf-kokoro-badges/status-badge/linux-python_compatibility.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fubuntu%2Fpython_compatibility%2Fcontinuous)
[![Build status](https://storage.googleapis.com/protobuf-kokoro-badges/status-badge/linux-python27_cpp.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fubuntu%2Fpython27_cpp%2Fcontinuous)
[![Build status](https://storage.googleapis.com/protobuf-kokoro-badges/status-badge/linux-python35_cpp.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fubuntu%2Fpython35_cpp%2Fcontinuous)
[![Build status](https://storage.googleapis.com/protobuf-kokoro-badges/status-badge/linux-python36_cpp.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fubuntu%2Fpython36_cpp%2Fcontinuous)
[![Build status](https://storage.googleapis.com/protobuf-kokoro-badges/status-badge/linux-python37_cpp.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fubuntu%2Fpython37_cpp%2Fcontinuous)
[![Build status](https://storage.googleapis.com/protobuf-kokoro-badges/status-badge/linux-python-release.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fubuntu%2Fpython_release%2Fcontinuous) | [![Build status](https://storage.googleapis.com/protobuf-kokoro-badges/status-badge/macos-python.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fmacos%2Fpython%2Fcontinuous)
[![Build status](https://storage.googleapis.com/protobuf-kokoro-badges/status-badge/macos-python_cpp.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fmacos%2Fpython_cpp%2Fcontinuous)
[![Build status](https://storage.googleapis.com/protobuf-kokoro-badges/status-badge/macos-python-release.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fmacos%2Fpython_release%2Fcontinuous) | [![Build status](https://storage.googleapis.com/protobuf-kokoro-badges/status-badge/windows-python-release.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fwindows%2Fpython_release%2Fcontinuous) |
+| Objective-C | [objectivec](objectivec) | | [![Build status](https://storage.googleapis.com/protobuf-kokoro-badges/status-badge/macos-objectivec_cocoapods_integration.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fmacos%2Fobjectivec_cocoapods_integration%2Fcontinuous)
[![Build status](https://storage.googleapis.com/protobuf-kokoro-badges/status-badge/macos-objectivec_ios_debug.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fmacos%2Fobjectivec_ios_debug%2Fcontinuous)
[![Build status](https://storage.googleapis.com/protobuf-kokoro-badges/status-badge/macos-objectivec_ios_release.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fmacos%2Fobjectivec_ios_release%2Fcontinuous)
[![Build status](https://storage.googleapis.com/protobuf-kokoro-badges/status-badge/macos-objectivec_osx.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fmacos%2Fobjectivec_osx%2Fcontinuous) | |
+| C# | [csharp](csharp) | [![Build status](https://storage.googleapis.com/protobuf-kokoro-badges/status-badge/linux-csharp.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fubuntu%2Fcsharp%2Fcontinuous) | | [![Build status](https://ci.appveyor.com/api/projects/status/73ctee6ua4w2ruin?svg=true)](https://ci.appveyor.com/project/protobuf/protobuf)
[![Build status](https://storage.googleapis.com/protobuf-kokoro-badges/status-badge/windows-csharp-release.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fwindows%2Fcsharp_release%2Fcontinuous) |
+| JavaScript | [js](js) | [![Build status](https://storage.googleapis.com/protobuf-kokoro-badges/status-badge/linux-javascript.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fubuntu%2Fjavascript%2Fcontinuous) | [![Build status](https://storage.googleapis.com/protobuf-kokoro-badges/status-badge/macos-javascript.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fmacos%2Fjavascript%2Fcontinuous) | |
+| Ruby | [ruby](ruby) | [![Build status](https://storage.googleapis.com/protobuf-kokoro-badges/status-badge/linux-ruby23.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fubuntu%2Fruby23%2Fcontinuous)
[![Build status](https://storage.googleapis.com/protobuf-kokoro-badges/status-badge/linux-ruby24.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fubuntu%2Fruby24%2Fcontinuous)
[![Build status](https://storage.googleapis.com/protobuf-kokoro-badges/status-badge/linux-ruby25.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fubuntu%2Fruby25%2Fcontinuous)
[![Build status](https://storage.googleapis.com/protobuf-kokoro-badges/status-badge/linux-ruby26.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fubuntu%2Fruby26%2Fcontinuous)
[![Build status](https://storage.googleapis.com/protobuf-kokoro-badges/status-badge/linux-ruby-release.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fubuntu%2Fruby_release%2Fcontinuous) | [![Build status](https://storage.googleapis.com/protobuf-kokoro-badges/status-badge/macos-ruby23.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fmacos%2Fruby23%2Fcontinuous)
[![Build status](https://storage.googleapis.com/protobuf-kokoro-badges/status-badge/macos-ruby24.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fmacos%2Fruby24%2Fcontinuous)
[![Build status](https://storage.googleapis.com/protobuf-kokoro-badges/status-badge/macos-ruby25.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fmacos%2Fruby25%2Fcontinuous)
[![Build status](https://storage.googleapis.com/protobuf-kokoro-badges/status-badge/macos-ruby26.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fmacos%2Fruby26%2Fcontinuous)
[![Build status](https://storage.googleapis.com/protobuf-kokoro-badges/status-badge/macos-ruby-release.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fmacos%2Fruby_release%2Fcontinuous) | |
| Go | [protocolbuffers/protobuf-go](https://github.com/protocolbuffers/protobuf-go) | | | |
-| PHP | [php](php) | [![Build status](https://storage.googleapis.com/protobuf-kokoro-results/status-badge/linux-php_all.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fubuntu%2Fphp_all%2Fcontinuous)
[![Build status](https://storage.googleapis.com/protobuf-kokoro-results/status-badge/linux-32-bit.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fubuntu%2F32-bit%2Fcontinuous) | [![Build status](https://storage.googleapis.com/protobuf-kokoro-results/status-badge/macos-php5.6_mac.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fmacos%2Fphp5.6_mac%2Fcontinuous)
[![Build status](https://storage.googleapis.com/protobuf-kokoro-results/status-badge/macos-php7.0_mac.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fmacos%2Fphp7.0_mac%2Fcontinuous) | |
+| PHP | [php](php) | [![Build status](https://storage.googleapis.com/protobuf-kokoro-badges/status-badge/linux-php_all.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fubuntu%2Fphp_all%2Fcontinuous)
[![Build status](https://storage.googleapis.com/protobuf-kokoro-badges/status-badge/linux-32-bit.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fubuntu%2F32-bit%2Fcontinuous)
[![Build status](https://storage.googleapis.com/protobuf-kokoro-badges/status-badge/linux-php80.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fubuntu%2Fphp80%2Fcontinuous) | [![Build status](https://storage.googleapis.com/protobuf-kokoro-badges/status-badge/macos-php5.6_mac.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fmacos%2Fphp5.6_mac%2Fcontinuous)
[![Build status](https://storage.googleapis.com/protobuf-kokoro-badges/status-badge/macos-php7.0_mac.png)](https://fusion.corp.google.com/projectanalysis/current/KOKORO/prod:protobuf%2Fgithub%2Fmaster%2Fmacos%2Fphp7.0_mac%2Fcontinuous) | |
| Dart | [dart-lang/protobuf](https://github.com/dart-lang/protobuf) | [![Build Status](https://travis-ci.org/dart-lang/protobuf.svg?branch=master)](https://travis-ci.org/dart-lang/protobuf) | | |
Quick Start
diff --git a/cmake/conformance.cmake b/cmake/conformance.cmake
index 76eae8a3ac..056b5d0c60 100644
--- a/cmake/conformance.cmake
+++ b/cmake/conformance.cmake
@@ -21,7 +21,6 @@ add_custom_command(
add_executable(conformance_test_runner
${protobuf_source_dir}/conformance/conformance.pb.cc
${protobuf_source_dir}/conformance/conformance_test.cc
- ${protobuf_source_dir}/conformance/binary_json_conformance_main.cc
${protobuf_source_dir}/conformance/binary_json_conformance_suite.cc
${protobuf_source_dir}/conformance/binary_json_conformance_suite.h
${protobuf_source_dir}/conformance/conformance_test_runner.cc
diff --git a/cmake/install.cmake b/cmake/install.cmake
index 4091bc8af9..9dd6e7710f 100644
--- a/cmake/install.cmake
+++ b/cmake/install.cmake
@@ -102,12 +102,16 @@ endforeach()
# Install configuration
set(_cmakedir_desc "Directory relative to CMAKE_INSTALL to install the cmake configuration files")
+set(_exampledir_desc "Directory relative to CMAKE_INSTALL_DATA to install examples")
if(NOT MSVC)
set(CMAKE_INSTALL_CMAKEDIR "${CMAKE_INSTALL_LIBDIR}/cmake/protobuf" CACHE STRING "${_cmakedir_desc}")
+ set(CMAKE_INSTALL_EXAMPLEDIR "${CMAKE_INSTALL_DATADIR}/protobuf/examples" CACHE STRING "${_exampledir_desc}")
else()
set(CMAKE_INSTALL_CMAKEDIR "cmake" CACHE STRING "${_cmakedir_desc}")
+ set(CMAKE_INSTALL_EXAMPLEDIR "examples" CACHE STRING "${_exampledir_desc}")
endif()
mark_as_advanced(CMAKE_INSTALL_CMAKEDIR)
+mark_as_advanced(CMAKE_INSTALL_EXAMPLEDIR)
configure_file(protobuf-config.cmake.in
${CMAKE_INSTALL_CMAKEDIR}/protobuf-config.cmake @ONLY)
@@ -145,6 +149,7 @@ install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_CMAKEDIR}/
option(protobuf_INSTALL_EXAMPLES "Install the examples folder" OFF)
if(protobuf_INSTALL_EXAMPLES)
- install(DIRECTORY ../examples/ DESTINATION examples
+ install(DIRECTORY ../examples/
+ DESTINATION "${CMAKE_INSTALL_EXAMPLEDIR}"
COMPONENT protobuf-examples)
endif()
diff --git a/cmake/protobuf-lite.pc.cmake b/cmake/protobuf-lite.pc.cmake
index cbe5426afa..9745cb89c7 100644
--- a/cmake/protobuf-lite.pc.cmake
+++ b/cmake/protobuf-lite.pc.cmake
@@ -7,5 +7,5 @@ Name: Protocol Buffers
Description: Google's Data Interchange Format
Version: @protobuf_VERSION@
Libs: -L${libdir} -lprotobuf-lite @CMAKE_THREAD_LIBS_INIT@
-Cflags: -I${includedir} @CMAKE_THREAD_LIBS_INIT@
+Cflags: -I${includedir}
Conflicts: protobuf
diff --git a/cmake/protobuf.pc.cmake b/cmake/protobuf.pc.cmake
index d33e98cca8..f068e6926e 100644
--- a/cmake/protobuf.pc.cmake
+++ b/cmake/protobuf.pc.cmake
@@ -7,5 +7,5 @@ Name: Protocol Buffers
Description: Google's Data Interchange Format
Version: @protobuf_VERSION@
Libs: -L${libdir} -lprotobuf @CMAKE_THREAD_LIBS_INIT@
-Cflags: -I${includedir} @CMAKE_THREAD_LIBS_INIT@
+Cflags: -I${includedir}
Conflicts: protobuf-lite
diff --git a/configure.ac b/configure.ac
index 2f82be284b..eb70a76e16 100644
--- a/configure.ac
+++ b/configure.ac
@@ -17,7 +17,7 @@ AC_PREREQ(2.59)
# In the SVN trunk, the version should always be the next anticipated release
# version with the "-pre" suffix. (We used to use "-SNAPSHOT" but this pushed
# the size of one file name in the dist tarfile over the 99-char limit.)
-AC_INIT([Protocol Buffers],[3.13.0],[protobuf@googlegroups.com],[protobuf])
+AC_INIT([Protocol Buffers],[3.14.0],[protobuf@googlegroups.com],[protobuf])
AM_MAINTAINER_MODE([enable])
diff --git a/conformance/Makefile.am b/conformance/Makefile.am
index 5b82a4241e..0adfb83600 100644
--- a/conformance/Makefile.am
+++ b/conformance/Makefile.am
@@ -347,15 +347,15 @@ test_csharp: protoc_middleman conformance-test-runner conformance-csharp
test_ruby: protoc_middleman conformance-test-runner $(other_language_protoc_outputs)
RUBYLIB=../ruby/lib:. ./conformance-test-runner --enforce_recommended --failure_list failure_list_ruby.txt --text_format_failure_list text_format_failure_list_ruby.txt ./conformance_ruby.rb
+test_jruby: protoc_middleman conformance-test-runner $(other_language_protoc_outputs)
+ RUBYLIB=../ruby/lib:. ./conformance-test-runner --enforce_recommended --failure_list failure_list_jruby.txt --text_format_failure_list text_format_failure_list_jruby.txt ./conformance_ruby.rb
+
test_php: protoc_middleman conformance-test-runner conformance-php $(other_language_protoc_outputs)
./conformance-test-runner --enforce_recommended --failure_list failure_list_php.txt --text_format_failure_list text_format_failure_list_php.txt ./conformance-php
test_php_c: protoc_middleman conformance-test-runner conformance-php-c $(other_language_protoc_outputs)
./conformance-test-runner --enforce_recommended --failure_list failure_list_php_c.txt --text_format_failure_list text_format_failure_list_php.txt ./conformance-php-c
-test_php_c_32: protoc_middleman conformance-test-runner conformance-php-c $(other_language_protoc_outputs)
- ./conformance-test-runner --enforce_recommended --failure_list failure_list_php_c_32.txt --text_format_failure_list text_format_failure_list_php.txt ./conformance-php-c
-
# These depend on library paths being properly set up. The easiest way to
# run them is to just use "tox" from the python dir.
test_python: protoc_middleman conformance-test-runner
diff --git a/conformance/conformance_ruby.rb b/conformance/conformance_ruby.rb
index 79d8d3dd9e..4af7659b09 100755
--- a/conformance/conformance_ruby.rb
+++ b/conformance/conformance_ruby.rb
@@ -32,6 +32,7 @@
require 'conformance_pb'
require 'google/protobuf/test_messages_proto3_pb'
+require 'google/protobuf/test_messages_proto2_pb'
$test_count = 0
$verbose = false
@@ -39,39 +40,39 @@ $verbose = false
def do_test(request)
test_message = ProtobufTestMessages::Proto3::TestAllTypesProto3.new
response = Conformance::ConformanceResponse.new
+ descriptor = Google::Protobuf::DescriptorPool.generated_pool.lookup(request.message_type)
+
+ unless descriptor
+ response.skipped = "Unknown message type: " + request.message_type
+ end
begin
case request.payload
when :protobuf_payload
- if request.message_type.eql?('protobuf_test_messages.proto3.TestAllTypesProto3')
- begin
- test_message = ProtobufTestMessages::Proto3::TestAllTypesProto3.decode(
- request.protobuf_payload)
- rescue Google::Protobuf::ParseError => err
- response.parse_error = err.message.encode('utf-8')
- return response
- end
- elsif request.message_type.eql?('protobuf_test_messages.proto2.TestAllTypesProto2')
- response.skipped = "Ruby doesn't support proto2"
+ begin
+ test_message = descriptor.msgclass.decode(request.protobuf_payload)
+ rescue Google::Protobuf::ParseError => err
+ response.parse_error = err.message.encode('utf-8')
return response
- else
- fail "Protobuf request doesn't have specific payload type"
end
when :json_payload
begin
- test_message = ProtobufTestMessages::Proto3::TestAllTypesProto3.decode_json(
- request.json_payload)
+ options = {}
+ if request.test_category == :JSON_IGNORE_UNKNOWN_PARSING_TEST
+ options[:ignore_unknown_fields] = true
+ end
+ test_message = descriptor.msgclass.decode_json(request.json_payload, options)
rescue Google::Protobuf::ParseError => err
response.parse_error = err.message.encode('utf-8')
return response
end
-
- when :text_payload
- begin
- response.skipped = "Ruby doesn't support proto2"
- return response
- end
+
+ when :text_payload
+ begin
+ response.skipped = "Ruby doesn't support text format"
+ return response
+ end
when nil
fail "Request didn't have payload"
@@ -82,10 +83,18 @@ def do_test(request)
fail 'Unspecified output format'
when :PROTOBUF
- response.protobuf_payload = test_message.to_proto
+ begin
+ response.protobuf_payload = test_message.to_proto
+ rescue Google::Protobuf::ParseError => err
+ response.serialize_error = err.message.encode('utf-8')
+ end
when :JSON
- response.json_payload = test_message.to_json
+ begin
+ response.json_payload = test_message.to_json
+ rescue Google::Protobuf::ParseError => err
+ response.serialize_error = err.message.encode('utf-8')
+ end
when nil
fail "Request didn't have requested output format"
diff --git a/conformance/failure_list_ruby.txt b/conformance/failure_list_ruby.txt
index 1aea14560c..4938202ad7 100644
--- a/conformance/failure_list_ruby.txt
+++ b/conformance/failure_list_ruby.txt
@@ -1,114 +1,58 @@
-Recommended.FieldMaskNumbersDontRoundTrip.JsonOutput
-Recommended.FieldMaskPathsDontRoundTrip.JsonOutput
-Recommended.FieldMaskTooManyUnderscore.JsonOutput
Recommended.Proto2.JsonInput.FieldNameExtension.Validator
-Recommended.Proto3.JsonInput.BytesFieldBase64Url.JsonOutput
-Recommended.Proto3.JsonInput.BytesFieldBase64Url.ProtobufOutput
-Recommended.Proto3.JsonInput.DurationHas3FractionalDigits.Validator
-Recommended.Proto3.JsonInput.DurationHas6FractionalDigits.Validator
-Recommended.Proto3.JsonInput.FieldMaskInvalidCharacter
-Recommended.Proto3.JsonInput.MapFieldValueIsNull
-Recommended.Proto3.JsonInput.NullValueInNormalMessage.Validator
-Recommended.Proto3.JsonInput.NullValueInOtherOneofNewFormat.Validator
-Recommended.Proto3.JsonInput.NullValueInOtherOneofOldFormat.Validator
-Recommended.Proto3.JsonInput.RepeatedFieldMessageElementIsNull
-Recommended.Proto3.JsonInput.RepeatedFieldPrimitiveElementIsNull
-Recommended.Proto3.JsonInput.StringEndsWithEscapeChar
-Recommended.Proto3.JsonInput.StringFieldSurrogateInWrongOrder
-Recommended.Proto3.JsonInput.StringFieldUnpairedHighSurrogate
-Recommended.Proto3.JsonInput.StringFieldUnpairedLowSurrogate
-Recommended.Proto3.JsonInput.TimestampHas3FractionalDigits.Validator
-Recommended.Proto3.JsonInput.TimestampHas6FractionalDigits.Validator
-Recommended.Proto3.ProtobufInput.ValidDataRepeated.BOOL.PackedInput.DefaultOutput.ProtobufOutput
-Recommended.Proto3.ProtobufInput.ValidDataRepeated.BOOL.PackedInput.PackedOutput.ProtobufOutput
-Recommended.Proto3.ProtobufInput.ValidDataRepeated.BOOL.UnpackedInput.DefaultOutput.ProtobufOutput
-Recommended.Proto3.ProtobufInput.ValidDataRepeated.BOOL.UnpackedInput.PackedOutput.ProtobufOutput
-Recommended.Proto3.ProtobufInput.ValidDataRepeated.DOUBLE.PackedInput.DefaultOutput.ProtobufOutput
-Recommended.Proto3.ProtobufInput.ValidDataRepeated.DOUBLE.PackedInput.PackedOutput.ProtobufOutput
-Recommended.Proto3.ProtobufInput.ValidDataRepeated.DOUBLE.UnpackedInput.DefaultOutput.ProtobufOutput
-Recommended.Proto3.ProtobufInput.ValidDataRepeated.DOUBLE.UnpackedInput.PackedOutput.ProtobufOutput
-Recommended.Proto3.ProtobufInput.ValidDataRepeated.ENUM.PackedInput.DefaultOutput.ProtobufOutput
-Recommended.Proto3.ProtobufInput.ValidDataRepeated.ENUM.PackedInput.PackedOutput.ProtobufOutput
+Recommended.Proto2.ProtobufInput.ValidDataRepeated.BOOL.PackedInput.PackedOutput.ProtobufOutput
+Recommended.Proto2.ProtobufInput.ValidDataRepeated.BOOL.UnpackedInput.PackedOutput.ProtobufOutput
+Recommended.Proto2.ProtobufInput.ValidDataRepeated.DOUBLE.PackedInput.PackedOutput.ProtobufOutput
+Recommended.Proto2.ProtobufInput.ValidDataRepeated.DOUBLE.UnpackedInput.PackedOutput.ProtobufOutput
+Recommended.Proto2.ProtobufInput.ValidDataRepeated.ENUM.PackedInput.PackedOutput.ProtobufOutput
+Recommended.Proto2.ProtobufInput.ValidDataRepeated.ENUM.UnpackedInput.PackedOutput.ProtobufOutput
+Recommended.Proto2.ProtobufInput.ValidDataRepeated.FIXED32.PackedInput.PackedOutput.ProtobufOutput
+Recommended.Proto2.ProtobufInput.ValidDataRepeated.FIXED32.UnpackedInput.PackedOutput.ProtobufOutput
+Recommended.Proto2.ProtobufInput.ValidDataRepeated.FIXED64.PackedInput.PackedOutput.ProtobufOutput
+Recommended.Proto2.ProtobufInput.ValidDataRepeated.FIXED64.UnpackedInput.PackedOutput.ProtobufOutput
+Recommended.Proto2.ProtobufInput.ValidDataRepeated.FLOAT.PackedInput.PackedOutput.ProtobufOutput
+Recommended.Proto2.ProtobufInput.ValidDataRepeated.FLOAT.UnpackedInput.PackedOutput.ProtobufOutput
+Recommended.Proto2.ProtobufInput.ValidDataRepeated.INT32.PackedInput.PackedOutput.ProtobufOutput
+Recommended.Proto2.ProtobufInput.ValidDataRepeated.INT32.UnpackedInput.PackedOutput.ProtobufOutput
+Recommended.Proto2.ProtobufInput.ValidDataRepeated.INT64.PackedInput.PackedOutput.ProtobufOutput
+Recommended.Proto2.ProtobufInput.ValidDataRepeated.INT64.UnpackedInput.PackedOutput.ProtobufOutput
+Recommended.Proto2.ProtobufInput.ValidDataRepeated.SFIXED32.PackedInput.PackedOutput.ProtobufOutput
+Recommended.Proto2.ProtobufInput.ValidDataRepeated.SFIXED32.UnpackedInput.PackedOutput.ProtobufOutput
+Recommended.Proto2.ProtobufInput.ValidDataRepeated.SFIXED64.PackedInput.PackedOutput.ProtobufOutput
+Recommended.Proto2.ProtobufInput.ValidDataRepeated.SFIXED64.UnpackedInput.PackedOutput.ProtobufOutput
+Recommended.Proto2.ProtobufInput.ValidDataRepeated.SINT32.PackedInput.PackedOutput.ProtobufOutput
+Recommended.Proto2.ProtobufInput.ValidDataRepeated.SINT32.UnpackedInput.PackedOutput.ProtobufOutput
+Recommended.Proto2.ProtobufInput.ValidDataRepeated.SINT64.PackedInput.PackedOutput.ProtobufOutput
+Recommended.Proto2.ProtobufInput.ValidDataRepeated.SINT64.UnpackedInput.PackedOutput.ProtobufOutput
+Recommended.Proto2.ProtobufInput.ValidDataRepeated.UINT32.PackedInput.PackedOutput.ProtobufOutput
+Recommended.Proto2.ProtobufInput.ValidDataRepeated.UINT32.UnpackedInput.PackedOutput.ProtobufOutput
+Recommended.Proto2.ProtobufInput.ValidDataRepeated.UINT64.PackedInput.PackedOutput.ProtobufOutput
+Recommended.Proto2.ProtobufInput.ValidDataRepeated.UINT64.UnpackedInput.PackedOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataOneofBinary.MESSAGE.Merge.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.BOOL.PackedInput.UnpackedOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.BOOL.UnpackedInput.UnpackedOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.DOUBLE.PackedInput.UnpackedOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.DOUBLE.UnpackedInput.UnpackedOutput.ProtobufOutput
Recommended.Proto3.ProtobufInput.ValidDataRepeated.ENUM.PackedInput.UnpackedOutput.ProtobufOutput
-Recommended.Proto3.ProtobufInput.ValidDataRepeated.ENUM.UnpackedInput.DefaultOutput.ProtobufOutput
-Recommended.Proto3.ProtobufInput.ValidDataRepeated.ENUM.UnpackedInput.PackedOutput.ProtobufOutput
Recommended.Proto3.ProtobufInput.ValidDataRepeated.ENUM.UnpackedInput.UnpackedOutput.ProtobufOutput
-Recommended.Proto3.ProtobufInput.ValidDataRepeated.FIXED32.PackedInput.DefaultOutput.ProtobufOutput
-Recommended.Proto3.ProtobufInput.ValidDataRepeated.FIXED32.PackedInput.PackedOutput.ProtobufOutput
-Recommended.Proto3.ProtobufInput.ValidDataRepeated.FIXED32.UnpackedInput.DefaultOutput.ProtobufOutput
-Recommended.Proto3.ProtobufInput.ValidDataRepeated.FIXED32.UnpackedInput.PackedOutput.ProtobufOutput
-Recommended.Proto3.ProtobufInput.ValidDataRepeated.FIXED64.PackedInput.DefaultOutput.ProtobufOutput
-Recommended.Proto3.ProtobufInput.ValidDataRepeated.FIXED64.PackedInput.PackedOutput.ProtobufOutput
-Recommended.Proto3.ProtobufInput.ValidDataRepeated.FIXED64.UnpackedInput.DefaultOutput.ProtobufOutput
-Recommended.Proto3.ProtobufInput.ValidDataRepeated.FIXED64.UnpackedInput.PackedOutput.ProtobufOutput
-Recommended.Proto3.ProtobufInput.ValidDataRepeated.FLOAT.PackedInput.DefaultOutput.ProtobufOutput
-Recommended.Proto3.ProtobufInput.ValidDataRepeated.FLOAT.PackedInput.PackedOutput.ProtobufOutput
-Recommended.Proto3.ProtobufInput.ValidDataRepeated.FLOAT.UnpackedInput.DefaultOutput.ProtobufOutput
-Recommended.Proto3.ProtobufInput.ValidDataRepeated.FLOAT.UnpackedInput.PackedOutput.ProtobufOutput
-Recommended.Proto3.ProtobufInput.ValidDataRepeated.INT32.PackedInput.DefaultOutput.ProtobufOutput
-Recommended.Proto3.ProtobufInput.ValidDataRepeated.INT32.PackedInput.PackedOutput.ProtobufOutput
-Recommended.Proto3.ProtobufInput.ValidDataRepeated.INT32.UnpackedInput.DefaultOutput.ProtobufOutput
-Recommended.Proto3.ProtobufInput.ValidDataRepeated.INT32.UnpackedInput.PackedOutput.ProtobufOutput
-Recommended.Proto3.ProtobufInput.ValidDataRepeated.INT64.PackedInput.DefaultOutput.ProtobufOutput
-Recommended.Proto3.ProtobufInput.ValidDataRepeated.INT64.PackedInput.PackedOutput.ProtobufOutput
-Recommended.Proto3.ProtobufInput.ValidDataRepeated.INT64.UnpackedInput.DefaultOutput.ProtobufOutput
-Recommended.Proto3.ProtobufInput.ValidDataRepeated.INT64.UnpackedInput.PackedOutput.ProtobufOutput
-Recommended.Proto3.ProtobufInput.ValidDataRepeated.SFIXED32.PackedInput.DefaultOutput.ProtobufOutput
-Recommended.Proto3.ProtobufInput.ValidDataRepeated.SFIXED32.PackedInput.PackedOutput.ProtobufOutput
-Recommended.Proto3.ProtobufInput.ValidDataRepeated.SFIXED32.UnpackedInput.DefaultOutput.ProtobufOutput
-Recommended.Proto3.ProtobufInput.ValidDataRepeated.SFIXED32.UnpackedInput.PackedOutput.ProtobufOutput
-Recommended.Proto3.ProtobufInput.ValidDataRepeated.SFIXED64.PackedInput.DefaultOutput.ProtobufOutput
-Recommended.Proto3.ProtobufInput.ValidDataRepeated.SFIXED64.PackedInput.PackedOutput.ProtobufOutput
-Recommended.Proto3.ProtobufInput.ValidDataRepeated.SFIXED64.UnpackedInput.DefaultOutput.ProtobufOutput
-Recommended.Proto3.ProtobufInput.ValidDataRepeated.SFIXED64.UnpackedInput.PackedOutput.ProtobufOutput
-Recommended.Proto3.ProtobufInput.ValidDataRepeated.SINT32.PackedInput.DefaultOutput.ProtobufOutput
-Recommended.Proto3.ProtobufInput.ValidDataRepeated.SINT32.PackedInput.PackedOutput.ProtobufOutput
-Recommended.Proto3.ProtobufInput.ValidDataRepeated.SINT32.UnpackedInput.DefaultOutput.ProtobufOutput
-Recommended.Proto3.ProtobufInput.ValidDataRepeated.SINT32.UnpackedInput.PackedOutput.ProtobufOutput
-Recommended.Proto3.ProtobufInput.ValidDataRepeated.SINT64.PackedInput.DefaultOutput.ProtobufOutput
-Recommended.Proto3.ProtobufInput.ValidDataRepeated.SINT64.PackedInput.PackedOutput.ProtobufOutput
-Recommended.Proto3.ProtobufInput.ValidDataRepeated.SINT64.UnpackedInput.DefaultOutput.ProtobufOutput
-Recommended.Proto3.ProtobufInput.ValidDataRepeated.SINT64.UnpackedInput.PackedOutput.ProtobufOutput
-Recommended.Proto3.ProtobufInput.ValidDataRepeated.UINT32.PackedInput.DefaultOutput.ProtobufOutput
-Recommended.Proto3.ProtobufInput.ValidDataRepeated.UINT32.PackedInput.PackedOutput.ProtobufOutput
-Recommended.Proto3.ProtobufInput.ValidDataRepeated.UINT32.UnpackedInput.DefaultOutput.ProtobufOutput
-Recommended.Proto3.ProtobufInput.ValidDataRepeated.UINT32.UnpackedInput.PackedOutput.ProtobufOutput
-Recommended.Proto3.ProtobufInput.ValidDataRepeated.UINT64.PackedInput.DefaultOutput.ProtobufOutput
-Recommended.Proto3.ProtobufInput.ValidDataRepeated.UINT64.PackedInput.PackedOutput.ProtobufOutput
-Recommended.Proto3.ProtobufInput.ValidDataRepeated.UINT64.UnpackedInput.DefaultOutput.ProtobufOutput
-Recommended.Proto3.ProtobufInput.ValidDataRepeated.UINT64.UnpackedInput.PackedOutput.ProtobufOutput
-Recommended.Proto3.ProtobufInput.ValidDataScalarBinary.ENUM[3].ProtobufOutput
-Recommended.Proto3.ProtobufInput.ValidDataScalarBinary.ENUM[4].ProtobufOutput
-Required.DurationProtoInputTooLarge.JsonOutput
-Required.DurationProtoInputTooSmall.JsonOutput
-Required.Proto2.JsonInput.StoresDefaultPrimitive.Validator
-Required.Proto3.JsonInput.DoubleFieldMaxNegativeValue.JsonOutput
-Required.Proto3.JsonInput.DoubleFieldMaxNegativeValue.ProtobufOutput
-Required.Proto3.JsonInput.DoubleFieldMinPositiveValue.JsonOutput
-Required.Proto3.JsonInput.DoubleFieldMinPositiveValue.ProtobufOutput
-Required.Proto3.JsonInput.DoubleFieldNan.JsonOutput
-Required.Proto3.JsonInput.DurationMinValue.JsonOutput
-Required.Proto3.JsonInput.DurationRepeatedValue.JsonOutput
-Required.Proto3.JsonInput.FloatFieldInfinity.JsonOutput
-Required.Proto3.JsonInput.FloatFieldNan.JsonOutput
-Required.Proto3.JsonInput.FloatFieldNegativeInfinity.JsonOutput
-Required.Proto3.JsonInput.IgnoreUnknownJsonFalse.ProtobufOutput
-Required.Proto3.JsonInput.IgnoreUnknownJsonNull.ProtobufOutput
-Required.Proto3.JsonInput.IgnoreUnknownJsonNumber.ProtobufOutput
-Required.Proto3.JsonInput.IgnoreUnknownJsonObject.ProtobufOutput
-Required.Proto3.JsonInput.IgnoreUnknownJsonString.ProtobufOutput
-Required.Proto3.JsonInput.IgnoreUnknownJsonTrue.ProtobufOutput
-Required.Proto3.JsonInput.OneofFieldDuplicate
-Required.Proto3.JsonInput.RejectTopLevelNull
-Required.Proto3.JsonInput.StringFieldSurrogatePair.JsonOutput
-Required.Proto3.JsonInput.StringFieldSurrogatePair.ProtobufOutput
-Required.Proto3.ProtobufInput.DoubleFieldNormalizeQuietNan.JsonOutput
-Required.Proto3.ProtobufInput.DoubleFieldNormalizeSignalingNan.JsonOutput
-Required.Proto3.ProtobufInput.FloatFieldNormalizeQuietNan.JsonOutput
-Required.Proto3.ProtobufInput.FloatFieldNormalizeSignalingNan.JsonOutput
-Required.Proto3.ProtobufInput.ValidDataMap.STRING.MESSAGE.MissingDefault.JsonOutput
-Required.Proto3.ProtobufInput.ValidDataRepeated.FLOAT.PackedInput.JsonOutput
-Required.Proto3.ProtobufInput.ValidDataRepeated.FLOAT.UnpackedInput.JsonOutput
-Required.Proto3.ProtobufInput.ValidDataScalar.FLOAT[2].JsonOutput
-Required.TimestampProtoInputTooLarge.JsonOutput
-Required.TimestampProtoInputTooSmall.JsonOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.FIXED32.PackedInput.UnpackedOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.FIXED32.UnpackedInput.UnpackedOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.FIXED64.PackedInput.UnpackedOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.FIXED64.UnpackedInput.UnpackedOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.FLOAT.PackedInput.UnpackedOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.FLOAT.UnpackedInput.UnpackedOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.INT32.PackedInput.UnpackedOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.INT32.UnpackedInput.UnpackedOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.INT64.PackedInput.UnpackedOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.INT64.UnpackedInput.UnpackedOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.SFIXED32.PackedInput.UnpackedOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.SFIXED32.UnpackedInput.UnpackedOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.SFIXED64.PackedInput.UnpackedOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.SFIXED64.UnpackedInput.UnpackedOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.SINT32.PackedInput.UnpackedOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.SINT32.UnpackedInput.UnpackedOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.SINT64.PackedInput.UnpackedOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.SINT64.UnpackedInput.UnpackedOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.UINT32.PackedInput.UnpackedOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.UINT32.UnpackedInput.UnpackedOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.UINT64.PackedInput.UnpackedOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.UINT64.UnpackedInput.UnpackedOutput.ProtobufOutput
diff --git a/csharp/compatibility_tests/v3.0.0/src/Google.Protobuf.Test/Google.Protobuf.Test.csproj b/csharp/compatibility_tests/v3.0.0/src/Google.Protobuf.Test/Google.Protobuf.Test.csproj
index d9b1e86ebb..cbb6fee5f7 100644
--- a/csharp/compatibility_tests/v3.0.0/src/Google.Protobuf.Test/Google.Protobuf.Test.csproj
+++ b/csharp/compatibility_tests/v3.0.0/src/Google.Protobuf.Test/Google.Protobuf.Test.csproj
@@ -5,7 +5,6 @@
net451;netcoreapp2.1
../../keys/Google.Protobuf.snk
true
- true
False
diff --git a/csharp/src/Google.Protobuf.Benchmarks/Google.Protobuf.Benchmarks.csproj b/csharp/src/Google.Protobuf.Benchmarks/Google.Protobuf.Benchmarks.csproj
index 37bbc3ef2f..73042f358c 100644
--- a/csharp/src/Google.Protobuf.Benchmarks/Google.Protobuf.Benchmarks.csproj
+++ b/csharp/src/Google.Protobuf.Benchmarks/Google.Protobuf.Benchmarks.csproj
@@ -5,7 +5,6 @@
netcoreapp3.1
../../keys/Google.Protobuf.snk
true
- true
False
pdbonly
true
diff --git a/csharp/src/Google.Protobuf.Test.TestProtos/Google.Protobuf.Test.TestProtos.csproj b/csharp/src/Google.Protobuf.Test.TestProtos/Google.Protobuf.Test.TestProtos.csproj
index 1af85e0a54..9f2ba6b0de 100644
--- a/csharp/src/Google.Protobuf.Test.TestProtos/Google.Protobuf.Test.TestProtos.csproj
+++ b/csharp/src/Google.Protobuf.Test.TestProtos/Google.Protobuf.Test.TestProtos.csproj
@@ -10,7 +10,6 @@
3.0
../../keys/Google.Protobuf.snk
true
- true
False
diff --git a/csharp/src/Google.Protobuf.Test/Google.Protobuf.Test.csproj b/csharp/src/Google.Protobuf.Test/Google.Protobuf.Test.csproj
index 89fe5d4feb..7bd3f84e45 100644
--- a/csharp/src/Google.Protobuf.Test/Google.Protobuf.Test.csproj
+++ b/csharp/src/Google.Protobuf.Test/Google.Protobuf.Test.csproj
@@ -4,7 +4,6 @@
net451;netcoreapp2.1
../../keys/Google.Protobuf.snk
true
- true
False
True
diff --git a/csharp/src/Google.Protobuf/Google.Protobuf.csproj b/csharp/src/Google.Protobuf/Google.Protobuf.csproj
index 45541c537a..f16063418b 100644
--- a/csharp/src/Google.Protobuf/Google.Protobuf.csproj
+++ b/csharp/src/Google.Protobuf/Google.Protobuf.csproj
@@ -12,7 +12,6 @@
true
../../keys/Google.Protobuf.snk
true
- true
Protocol;Buffers;Binary;Serialization;Format;Google;proto;proto3
C# proto3 support
https://github.com/protocolbuffers/protobuf
diff --git a/docs/options.md b/docs/options.md
index 3aee392185..df0c828ebb 100644
--- a/docs/options.md
+++ b/docs/options.md
@@ -252,3 +252,11 @@ with info about your project (name and website) so we can add an entry for you.
1. Confluent Schema Registry
* Website: https://github.com/confluentinc/schema-registry
* Extensions: 1088
+
+1. ScalaPB Validate
+ * Website: https://scalapb.github.io/docs/validation
+ * Extension: 1089
+
+1. Astounding (Currently Private)
+ * Website: https://github.com/PbPipes/Astounding
+ * Extension: 1090
diff --git a/java/core/src/main/java/com/google/protobuf/Descriptors.java b/java/core/src/main/java/com/google/protobuf/Descriptors.java
index c30b00ddf7..51597fa3db 100644
--- a/java/core/src/main/java/com/google/protobuf/Descriptors.java
+++ b/java/core/src/main/java/com/google/protobuf/Descriptors.java
@@ -190,7 +190,7 @@ public final class Descriptors {
name = packageName + '.' + name;
}
final GenericDescriptor result = pool.findSymbol(name);
- if (result != null && result instanceof Descriptor && result.getFile() == this) {
+ if (result instanceof Descriptor && result.getFile() == this) {
return (Descriptor) result;
} else {
return null;
@@ -214,7 +214,7 @@ public final class Descriptors {
name = packageName + '.' + name;
}
final GenericDescriptor result = pool.findSymbol(name);
- if (result != null && result instanceof EnumDescriptor && result.getFile() == this) {
+ if (result instanceof EnumDescriptor && result.getFile() == this) {
return (EnumDescriptor) result;
} else {
return null;
@@ -238,7 +238,7 @@ public final class Descriptors {
name = packageName + '.' + name;
}
final GenericDescriptor result = pool.findSymbol(name);
- if (result != null && result instanceof ServiceDescriptor && result.getFile() == this) {
+ if (result instanceof ServiceDescriptor && result.getFile() == this) {
return (ServiceDescriptor) result;
} else {
return null;
@@ -260,7 +260,7 @@ public final class Descriptors {
name = packageName + '.' + name;
}
final GenericDescriptor result = pool.findSymbol(name);
- if (result != null && result instanceof FieldDescriptor && result.getFile() == this) {
+ if (result instanceof FieldDescriptor && result.getFile() == this) {
return (FieldDescriptor) result;
} else {
return null;
@@ -338,7 +338,7 @@ public final class Descriptors {
final Class> descriptorOuterClass,
final String[] dependencyClassNames,
final String[] dependencyFileNames) {
- List descriptors = new ArrayList();
+ List descriptors = new ArrayList<>();
for (int i = 0; i < dependencyClassNames.length; i++) {
try {
Class> clazz = descriptorOuterClass.getClassLoader().loadClass(dependencyClassNames[i]);
@@ -507,11 +507,11 @@ public final class Descriptors {
this.pool = pool;
this.proto = proto;
this.dependencies = dependencies.clone();
- HashMap nameToFileMap = new HashMap();
+ HashMap nameToFileMap = new HashMap<>();
for (FileDescriptor file : dependencies) {
nameToFileMap.put(file.getName(), file);
}
- List publicDependencies = new ArrayList();
+ List publicDependencies = new ArrayList<>();
for (int i = 0; i < proto.getPublicDependencyCount(); i++) {
int index = proto.getPublicDependency(i);
if (index < 0 || index >= proto.getDependencyCount()) {
@@ -758,7 +758,7 @@ public final class Descriptors {
* y" ranges declared on it.
*/
public boolean isExtendable() {
- return proto.getExtensionRangeList().size() != 0;
+ return !proto.getExtensionRangeList().isEmpty();
}
/**
@@ -772,7 +772,7 @@ public final class Descriptors {
*/
public FieldDescriptor findFieldByName(final String name) {
final GenericDescriptor result = file.pool.findSymbol(fullName + '.' + name);
- if (result != null && result instanceof FieldDescriptor) {
+ if (result instanceof FieldDescriptor) {
return (FieldDescriptor) result;
} else {
return null;
@@ -797,7 +797,7 @@ public final class Descriptors {
*/
public Descriptor findNestedTypeByName(final String name) {
final GenericDescriptor result = file.pool.findSymbol(fullName + '.' + name);
- if (result != null && result instanceof Descriptor) {
+ if (result instanceof Descriptor) {
return (Descriptor) result;
} else {
return null;
@@ -812,7 +812,7 @@ public final class Descriptors {
*/
public EnumDescriptor findEnumTypeByName(final String name) {
final GenericDescriptor result = file.pool.findSymbol(fullName + '.' + name);
- if (result != null && result instanceof EnumDescriptor) {
+ if (result instanceof EnumDescriptor) {
return (EnumDescriptor) result;
} else {
return null;
@@ -1701,7 +1701,7 @@ public final class Descriptors {
*/
public EnumValueDescriptor findValueByName(final String name) {
final GenericDescriptor result = file.pool.findSymbol(fullName + '.' + name);
- if (result != null && result instanceof EnumValueDescriptor) {
+ if (result instanceof EnumValueDescriptor) {
return (EnumValueDescriptor) result;
} else {
return null;
@@ -1785,7 +1785,7 @@ public final class Descriptors {
private final Descriptor containingType;
private EnumValueDescriptor[] values;
private final WeakHashMap> unknownValues =
- new WeakHashMap>();
+ new WeakHashMap<>();
private EnumDescriptor(
final EnumDescriptorProto proto,
@@ -1991,7 +1991,7 @@ public final class Descriptors {
*/
public MethodDescriptor findMethodByName(final String name) {
final GenericDescriptor result = file.pool.findSymbol(fullName + '.' + name);
- if (result != null && result instanceof MethodDescriptor) {
+ if (result instanceof MethodDescriptor) {
return (MethodDescriptor) result;
} else {
return null;
@@ -2265,12 +2265,12 @@ public final class Descriptors {
}
DescriptorPool(final FileDescriptor[] dependencies, boolean allowUnknownDependencies) {
- this.dependencies = new HashSet();
+ this.dependencies = new HashSet<>();
this.allowUnknownDependencies = allowUnknownDependencies;
- for (int i = 0; i < dependencies.length; i++) {
- this.dependencies.add(dependencies[i]);
- importPublicDependencies(dependencies[i]);
+ for (Descriptors.FileDescriptor dependency : dependencies) {
+ this.dependencies.add(dependency);
+ importPublicDependencies(dependency);
}
for (final FileDescriptor dependency : this.dependencies) {
@@ -2297,12 +2297,9 @@ public final class Descriptors {
private final Set dependencies;
private boolean allowUnknownDependencies;
- private final Map descriptorsByName =
- new HashMap();
- private final Map fieldsByNumber =
- new HashMap();
- private final Map enumValuesByNumber =
- new HashMap();
+ private final Map descriptorsByName = new HashMap<>();
+ private final Map fieldsByNumber = new HashMap<>();
+ private final Map enumValuesByNumber = new HashMap<>();
/** Find a generic descriptor by fully-qualified name. */
GenericDescriptor findSymbol(final String fullName) {
diff --git a/java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java b/java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java
index 27f5210097..5e3ee0f755 100644
--- a/java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java
+++ b/java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java
@@ -266,12 +266,14 @@ public abstract class GeneratedMessageLite<
memoizedSerializedSize = size;
}
+ @Override
public void writeTo(CodedOutputStream output) throws IOException {
Protobuf.getInstance()
.schemaFor(this)
.writeTo(this, CodedOutputStreamWriter.forCodedOutput(output));
}
+ @Override
public int getSerializedSize() {
if (memoizedSerializedSize == -1) {
memoizedSerializedSize = Protobuf.getInstance().schemaFor(this).getSerializedSize(this);
diff --git a/java/core/src/main/java/com/google/protobuf/RawMessageInfo.java b/java/core/src/main/java/com/google/protobuf/RawMessageInfo.java
index 72f56ed88e..3fbfaa108d 100644
--- a/java/core/src/main/java/com/google/protobuf/RawMessageInfo.java
+++ b/java/core/src/main/java/com/google/protobuf/RawMessageInfo.java
@@ -80,14 +80,15 @@ final class RawMessageInfo implements MessageInfo {
* [1]: field type with extra bits:
*
* - v & 0xFF = field type as defined in the FieldType class
- *
- v & 0x100 = is required?
- *
- v & 0x200 = is checkUtf8?
- *
- v & 0x400 = needs isInitialized check?
- *
- v & 0x800 = is map field with proto2 enum value?
+ *
- v & 0x0100 = is required?
+ *
- v & 0x0200 = is checkUtf8?
+ *
- v & 0x0400 = needs isInitialized check?
+ *
- v & 0x0800 = is map field with proto2 enum value?
+ *
- v & 0x1000 = supports presence checking?
*
*
*
- * If the file is proto2 and this is a singular field:
+ * If the (singular) field supports presence checking:
*
*
* - [2]: hasbits offset
@@ -180,8 +181,32 @@ final class RawMessageInfo implements MessageInfo {
this.defaultInstance = defaultInstance;
this.info = info;
this.objects = objects;
- int position = 0;
- int value = (int) info.charAt(position++);
+ int value;
+ try {
+ value = (int) info.charAt(0);
+ } catch (ArrayIndexOutOfBoundsException e) {
+ // This is a fix for issues
+ // that error out on a subset of phones on charAt(0) with an index out of bounds exception.
+ char[] infoChars = info.toCharArray();
+ info = new String(infoChars);
+ try {
+ value = (int) info.charAt(0);
+ } catch (ArrayIndexOutOfBoundsException e2) {
+ try {
+ char[] infoChars2 = new char[info.length()];
+ info.getChars(0, info.length(), infoChars2, 0);
+ info = new String(infoChars2);
+ value = (int) info.charAt(0);
+ } catch (ArrayIndexOutOfBoundsException e3) {
+ throw new IllegalStateException(
+ String.format(
+ "Failed parsing '%s' with charArray.length of %d", info, infoChars.length),
+ e3);
+ }
+ }
+ }
+ int position = 1;
+
if (value < 0xD800) {
flags = value;
} else {
diff --git a/java/core/src/main/java/com/google/protobuf/UnsafeUtil.java b/java/core/src/main/java/com/google/protobuf/UnsafeUtil.java
index b9b32af158..0acf22e571 100644
--- a/java/core/src/main/java/com/google/protobuf/UnsafeUtil.java
+++ b/java/core/src/main/java/com/google/protobuf/UnsafeUtil.java
@@ -332,83 +332,18 @@ final class UnsafeUtil {
return new JvmMemoryAccessor(UNSAFE);
}
- /** Indicates whether or not unsafe array operations are supported on this platform. */
private static boolean supportsUnsafeArrayOperations() {
- if (UNSAFE == null) {
+ if (MEMORY_ACCESSOR == null) {
return false;
}
- try {
- Class> clazz = UNSAFE.getClass();
- clazz.getMethod("objectFieldOffset", Field.class);
- clazz.getMethod("arrayBaseOffset", Class.class);
- clazz.getMethod("arrayIndexScale", Class.class);
- clazz.getMethod("getInt", Object.class, long.class);
- clazz.getMethod("putInt", Object.class, long.class, int.class);
- clazz.getMethod("getLong", Object.class, long.class);
- clazz.getMethod("putLong", Object.class, long.class, long.class);
- clazz.getMethod("getObject", Object.class, long.class);
- clazz.getMethod("putObject", Object.class, long.class, Object.class);
- if (Android.isOnAndroidDevice()) {
- return true;
- }
- clazz.getMethod("getByte", Object.class, long.class);
- clazz.getMethod("putByte", Object.class, long.class, byte.class);
- clazz.getMethod("getBoolean", Object.class, long.class);
- clazz.getMethod("putBoolean", Object.class, long.class, boolean.class);
- clazz.getMethod("getFloat", Object.class, long.class);
- clazz.getMethod("putFloat", Object.class, long.class, float.class);
- clazz.getMethod("getDouble", Object.class, long.class);
- clazz.getMethod("putDouble", Object.class, long.class, double.class);
-
- return true;
- } catch (Throwable e) {
- // Because log statements are fairly sparse in this class, this logger is initialized
- // non-statically. Static initialization adds undue runtime costs to the first client to
- // initialize this class.
- Logger.getLogger(UnsafeUtil.class.getName())
- .log(
- Level.WARNING,
- "platform method missing - proto runtime falling back to safer methods: " + e);
- }
- return false;
+ return MEMORY_ACCESSOR.supportsUnsafeArrayOperations();
}
private static boolean supportsUnsafeByteBufferOperations() {
- if (UNSAFE == null) {
+ if (MEMORY_ACCESSOR == null) {
return false;
}
- try {
- Class> clazz = UNSAFE.getClass();
- // Methods for getting direct buffer address.
- clazz.getMethod("objectFieldOffset", Field.class);
- clazz.getMethod("getLong", Object.class, long.class);
-
- if (bufferAddressField() == null) {
- return false;
- }
-
- if (Android.isOnAndroidDevice()) {
- return false;
- }
- clazz.getMethod("getByte", long.class);
- clazz.getMethod("putByte", long.class, byte.class);
- clazz.getMethod("getInt", long.class);
- clazz.getMethod("putInt", long.class, int.class);
- clazz.getMethod("getLong", long.class);
- clazz.getMethod("putLong", long.class, long.class);
- clazz.getMethod("copyMemory", long.class, long.class, long.class);
- clazz.getMethod("copyMemory", Object.class, long.class, Object.class, long.class, long.class);
- return true;
- } catch (Throwable e) {
- // Because log statements are fairly sparse in this class, this logger is initialized
- // non-statically. Static initialization adds undue runtime costs to the first client to
- // initialize this class.
- Logger.getLogger(UnsafeUtil.class.getName())
- .log(
- Level.WARNING,
- "platform method missing - proto runtime falling back to safer methods: " + e);
- }
- return false;
+ return MEMORY_ACCESSOR.supportsUnsafeByteBufferOperations();
}
private static boolean determineAndroidSupportByAddressSize(Class> addressClass) {
@@ -553,6 +488,43 @@ final class UnsafeUtil {
return unsafe.objectFieldOffset(field);
}
+ public final int arrayBaseOffset(Class> clazz) {
+ return unsafe.arrayBaseOffset(clazz);
+ }
+
+ public final int arrayIndexScale(Class> clazz) {
+ return unsafe.arrayIndexScale(clazz);
+ }
+
+ public abstract Object getStaticObject(Field field);
+
+ // Relative Address Operations ---------------------------------------------
+
+ // Indicates whether the following relative address operations are supported
+ // by this memory accessor.
+ public boolean supportsUnsafeArrayOperations() {
+ if (unsafe == null) {
+ return false;
+ }
+ try {
+ Class> clazz = unsafe.getClass();
+ clazz.getMethod("objectFieldOffset", Field.class);
+ clazz.getMethod("arrayBaseOffset", Class.class);
+ clazz.getMethod("arrayIndexScale", Class.class);
+ clazz.getMethod("getInt", Object.class, long.class);
+ clazz.getMethod("putInt", Object.class, long.class, int.class);
+ clazz.getMethod("getLong", Object.class, long.class);
+ clazz.getMethod("putLong", Object.class, long.class, long.class);
+ clazz.getMethod("getObject", Object.class, long.class);
+ clazz.getMethod("putObject", Object.class, long.class, Object.class);
+
+ return true;
+ } catch (Throwable e) {
+ logMissingMethod(e);
+ }
+ return false;
+ }
+
public abstract byte getByte(Object target, long offset);
public abstract void putByte(Object target, long offset, byte value);
@@ -593,12 +565,29 @@ final class UnsafeUtil {
unsafe.putObject(target, offset, value);
}
- public final int arrayBaseOffset(Class> clazz) {
- return unsafe.arrayBaseOffset(clazz);
- }
+ // Absolute Address Operations --------------------------------------------
- public final int arrayIndexScale(Class> clazz) {
- return unsafe.arrayIndexScale(clazz);
+ // Indicates whether the following absolute address operations are
+ // supported by this memory accessor.
+ public boolean supportsUnsafeByteBufferOperations() {
+ if (unsafe == null) {
+ return false;
+ }
+ try {
+ Class> clazz = unsafe.getClass();
+ // Methods for getting direct buffer address.
+ clazz.getMethod("objectFieldOffset", Field.class);
+ clazz.getMethod("getLong", Object.class, long.class);
+
+ if (bufferAddressField() == null) {
+ return false;
+ }
+
+ return true;
+ } catch (Throwable e) {
+ logMissingMethod(e);
+ }
+ return false;
}
public abstract byte getByte(long address);
@@ -613,8 +602,6 @@ final class UnsafeUtil {
public abstract void putLong(long address, long value);
- public abstract Object getStaticObject(Field field);
-
public abstract void copyMemory(long srcOffset, byte[] target, long targetIndex, long length);
public abstract void copyMemory(byte[] src, long srcIndex, long targetOffset, long length);
@@ -627,33 +614,32 @@ final class UnsafeUtil {
}
@Override
- public byte getByte(long address) {
- return unsafe.getByte(address);
- }
-
- @Override
- public void putByte(long address, byte value) {
- unsafe.putByte(address, value);
- }
-
- @Override
- public int getInt(long address) {
- return unsafe.getInt(address);
+ public Object getStaticObject(Field field) {
+ return getObject(unsafe.staticFieldBase(field), unsafe.staticFieldOffset(field));
}
@Override
- public void putInt(long address, int value) {
- unsafe.putInt(address, value);
- }
+ public boolean supportsUnsafeArrayOperations() {
+ if (!super.supportsUnsafeArrayOperations()) {
+ return false;
+ }
- @Override
- public long getLong(long address) {
- return unsafe.getLong(address);
- }
+ try {
+ Class> clazz = unsafe.getClass();
+ clazz.getMethod("getByte", Object.class, long.class);
+ clazz.getMethod("putByte", Object.class, long.class, byte.class);
+ clazz.getMethod("getBoolean", Object.class, long.class);
+ clazz.getMethod("putBoolean", Object.class, long.class, boolean.class);
+ clazz.getMethod("getFloat", Object.class, long.class);
+ clazz.getMethod("putFloat", Object.class, long.class, float.class);
+ clazz.getMethod("getDouble", Object.class, long.class);
+ clazz.getMethod("putDouble", Object.class, long.class, double.class);
- @Override
- public void putLong(long address, long value) {
- unsafe.putLong(address, value);
+ return true;
+ } catch (Throwable e) {
+ logMissingMethod(e);
+ }
+ return false;
}
@Override
@@ -697,55 +683,83 @@ final class UnsafeUtil {
}
@Override
- public void copyMemory(long srcOffset, byte[] target, long targetIndex, long length) {
- unsafe.copyMemory(null, srcOffset, target, BYTE_ARRAY_BASE_OFFSET + targetIndex, length);
+ public boolean supportsUnsafeByteBufferOperations() {
+ if (!super.supportsUnsafeByteBufferOperations()) {
+ return false;
+ }
+
+ try {
+ Class> clazz = unsafe.getClass();
+ clazz.getMethod("getByte", long.class);
+ clazz.getMethod("putByte", long.class, byte.class);
+ clazz.getMethod("getInt", long.class);
+ clazz.getMethod("putInt", long.class, int.class);
+ clazz.getMethod("getLong", long.class);
+ clazz.getMethod("putLong", long.class, long.class);
+ clazz.getMethod("copyMemory", long.class, long.class, long.class);
+ clazz.getMethod(
+ "copyMemory", Object.class, long.class, Object.class, long.class, long.class);
+ return true;
+ } catch (Throwable e) {
+ logMissingMethod(e);
+ }
+ return false;
}
@Override
- public void copyMemory(byte[] src, long srcIndex, long targetOffset, long length) {
- unsafe.copyMemory(src, BYTE_ARRAY_BASE_OFFSET + srcIndex, null, targetOffset, length);
+ public byte getByte(long address) {
+ return unsafe.getByte(address);
}
@Override
- public Object getStaticObject(Field field) {
- return getObject(unsafe.staticFieldBase(field), unsafe.staticFieldOffset(field));
+ public void putByte(long address, byte value) {
+ unsafe.putByte(address, value);
}
- }
-
- private static final class Android64MemoryAccessor extends MemoryAccessor {
- Android64MemoryAccessor(sun.misc.Unsafe unsafe) {
- super(unsafe);
+ @Override
+ public int getInt(long address) {
+ return unsafe.getInt(address);
}
@Override
- public byte getByte(long address) {
- throw new UnsupportedOperationException();
+ public void putInt(long address, int value) {
+ unsafe.putInt(address, value);
}
@Override
- public void putByte(long address, byte value) {
- throw new UnsupportedOperationException();
+ public long getLong(long address) {
+ return unsafe.getLong(address);
}
@Override
- public int getInt(long address) {
- throw new UnsupportedOperationException();
+ public void putLong(long address, long value) {
+ unsafe.putLong(address, value);
}
@Override
- public void putInt(long address, int value) {
- throw new UnsupportedOperationException();
+ public void copyMemory(long srcOffset, byte[] target, long targetIndex, long length) {
+ unsafe.copyMemory(null, srcOffset, target, BYTE_ARRAY_BASE_OFFSET + targetIndex, length);
}
@Override
- public long getLong(long address) {
- throw new UnsupportedOperationException();
+ public void copyMemory(byte[] src, long srcIndex, long targetOffset, long length) {
+ unsafe.copyMemory(src, BYTE_ARRAY_BASE_OFFSET + srcIndex, null, targetOffset, length);
+ }
+ }
+
+ private static final class Android64MemoryAccessor extends MemoryAccessor {
+
+ Android64MemoryAccessor(sun.misc.Unsafe unsafe) {
+ super(unsafe);
}
@Override
- public void putLong(long address, long value) {
- throw new UnsupportedOperationException();
+ public Object getStaticObject(Field field) {
+ try {
+ return field.get(null);
+ } catch (IllegalAccessException e) {
+ return null;
+ }
}
@Override
@@ -805,67 +819,72 @@ final class UnsafeUtil {
}
@Override
- public void copyMemory(long srcOffset, byte[] target, long targetIndex, long length) {
- throw new UnsupportedOperationException();
+ public boolean supportsUnsafeByteBufferOperations() {
+ return false;
}
@Override
- public void copyMemory(byte[] src, long srcIndex, long targetOffset, long length) {
+ public byte getByte(long address) {
throw new UnsupportedOperationException();
}
@Override
- public Object getStaticObject(Field field) {
- try {
- return field.get(null);
- } catch (IllegalAccessException e) {
- return null;
- }
- }
- }
-
- private static final class Android32MemoryAccessor extends MemoryAccessor {
-
- /** Mask used to convert a 64 bit memory address to a 32 bit address. */
- private static final long SMALL_ADDRESS_MASK = 0x00000000FFFFFFFF;
-
- /** Truncate a {@code long} address into a short {@code int} address. */
- private static int smallAddress(long address) {
- return (int) (SMALL_ADDRESS_MASK & address);
+ public void putByte(long address, byte value) {
+ throw new UnsupportedOperationException();
}
- Android32MemoryAccessor(sun.misc.Unsafe unsafe) {
- super(unsafe);
+ @Override
+ public int getInt(long address) {
+ throw new UnsupportedOperationException();
}
@Override
- public byte getByte(long address) {
+ public void putInt(long address, int value) {
throw new UnsupportedOperationException();
}
@Override
- public void putByte(long address, byte value) {
+ public long getLong(long address) {
throw new UnsupportedOperationException();
}
@Override
- public int getInt(long address) {
+ public void putLong(long address, long value) {
throw new UnsupportedOperationException();
}
@Override
- public void putInt(long address, int value) {
+ public void copyMemory(long srcOffset, byte[] target, long targetIndex, long length) {
throw new UnsupportedOperationException();
}
@Override
- public long getLong(long address) {
+ public void copyMemory(byte[] src, long srcIndex, long targetOffset, long length) {
throw new UnsupportedOperationException();
}
+ }
+
+ private static final class Android32MemoryAccessor extends MemoryAccessor {
+
+ /** Mask used to convert a 64 bit memory address to a 32 bit address. */
+ private static final long SMALL_ADDRESS_MASK = 0x00000000FFFFFFFF;
+
+ /** Truncate a {@code long} address into a short {@code int} address. */
+ private static int smallAddress(long address) {
+ return (int) (SMALL_ADDRESS_MASK & address);
+ }
+
+ Android32MemoryAccessor(sun.misc.Unsafe unsafe) {
+ super(unsafe);
+ }
@Override
- public void putLong(long address, long value) {
- throw new UnsupportedOperationException();
+ public Object getStaticObject(Field field) {
+ try {
+ return field.get(null);
+ } catch (IllegalAccessException e) {
+ return null;
+ }
}
@Override
@@ -925,22 +944,48 @@ final class UnsafeUtil {
}
@Override
- public void copyMemory(long srcOffset, byte[] target, long targetIndex, long length) {
+ public boolean supportsUnsafeByteBufferOperations() {
+ return false;
+ }
+
+ @Override
+ public byte getByte(long address) {
throw new UnsupportedOperationException();
}
@Override
- public void copyMemory(byte[] src, long srcIndex, long targetOffset, long length) {
+ public void putByte(long address, byte value) {
throw new UnsupportedOperationException();
}
@Override
- public Object getStaticObject(Field field) {
- try {
- return field.get(null);
- } catch (IllegalAccessException e) {
- return null;
- }
+ public int getInt(long address) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void putInt(long address, int value) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public long getLong(long address) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void putLong(long address, long value) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void copyMemory(long srcOffset, byte[] target, long targetIndex, long length) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void copyMemory(byte[] src, long srcIndex, long targetOffset, long length) {
+ throw new UnsupportedOperationException();
}
}
@@ -981,4 +1026,11 @@ final class UnsafeUtil {
private static void putBooleanLittleEndian(Object target, long offset, boolean value) {
putByteLittleEndian(target, offset, (byte) (value ? 1 : 0));
}
+
+ private static void logMissingMethod(Throwable e) {
+ Logger.getLogger(UnsafeUtil.class.getName())
+ .log(
+ Level.WARNING,
+ "platform method missing - proto runtime falling back to safer methods: " + e);
+ }
}
diff --git a/java/core/src/test/java/com/google/protobuf/FieldPresenceTest.java b/java/core/src/test/java/com/google/protobuf/FieldPresenceTest.java
index a1c98c0cef..726672980c 100644
--- a/java/core/src/test/java/com/google/protobuf/FieldPresenceTest.java
+++ b/java/core/src/test/java/com/google/protobuf/FieldPresenceTest.java
@@ -66,6 +66,11 @@ public class FieldPresenceTest extends TestCase {
assertFalse(hasMethod(classWithoutFieldPresence, "has" + camelName));
}
+ private static void assertHasMethodExisting(Class> clazz, String camelName) {
+ assertTrue(hasMethod(clazz, "get" + camelName));
+ assertTrue(hasMethod(clazz, "has" + camelName));
+ }
+
public void testHasMethod() {
// Optional non-message fields don't have a hasFoo() method generated.
assertHasMethodRemoved(UnittestProto.TestAllTypes.class, TestAllTypes.class, "OptionalInt32");
@@ -87,19 +92,16 @@ public class FieldPresenceTest extends TestCase {
assertFalse(TestAllTypes.getDefaultInstance().hasOptionalNestedMessage());
assertFalse(TestAllTypes.newBuilder().hasOptionalNestedMessage());
- // oneof fields don't have hasFoo() methods for non-message types.
- assertHasMethodRemoved(UnittestProto.TestAllTypes.class, TestAllTypes.class, "OneofUint32");
- assertHasMethodRemoved(UnittestProto.TestAllTypes.class, TestAllTypes.class, "OneofString");
- assertHasMethodRemoved(UnittestProto.TestAllTypes.class, TestAllTypes.class, "OneofBytes");
+ // oneof fields support hasFoo() methods for non-message types.
+ assertHasMethodExisting(TestAllTypes.class, "OneofUint32");
+ assertHasMethodExisting(TestAllTypes.class, "OneofString");
+ assertHasMethodExisting(TestAllTypes.class, "OneofBytes");
assertFalse(TestAllTypes.getDefaultInstance().hasOneofNestedMessage());
assertFalse(TestAllTypes.newBuilder().hasOneofNestedMessage());
- assertHasMethodRemoved(
- UnittestProto.TestAllTypes.Builder.class, TestAllTypes.Builder.class, "OneofUint32");
- assertHasMethodRemoved(
- UnittestProto.TestAllTypes.Builder.class, TestAllTypes.Builder.class, "OneofString");
- assertHasMethodRemoved(
- UnittestProto.TestAllTypes.Builder.class, TestAllTypes.Builder.class, "OneofBytes");
+ assertHasMethodExisting(TestAllTypes.Builder.class, "OneofUint32");
+ assertHasMethodExisting(TestAllTypes.Builder.class, "OneofString");
+ assertHasMethodExisting(TestAllTypes.Builder.class, "OneofBytes");
}
public void testHasMethodForProto3Optional() throws Exception {
diff --git a/java/core/src/test/java/com/google/protobuf/Proto3MessageLiteInfoFactory.java b/java/core/src/test/java/com/google/protobuf/Proto3MessageLiteInfoFactory.java
index 66e406af7d..3c0c629c20 100644
--- a/java/core/src/test/java/com/google/protobuf/Proto3MessageLiteInfoFactory.java
+++ b/java/core/src/test/java/com/google/protobuf/Proto3MessageLiteInfoFactory.java
@@ -139,12 +139,12 @@ public final class Proto3MessageLiteInfoFactory implements MessageInfoFactory {
// the content of the generated buildMessageInfo() method here.
java.lang.String info =
"\u0000@\u0001\u0000\u0001D@\u0000\u001f\u0000\u0001\u0000\u0002\u0001\u0003\u0002"
- + "\u0004\u0003\u0005\u0004\u0006\u0005\u0007\u0006\b\u0007\t\u0208\n\t\u000b\n\f\u000b"
- + "\r\f\u000e\r\u000f\u000e\u0010\u000f\u0011\u0010\u0012\u0012\u0013\u0013\u0014\u0014"
- + "\u0015\u0015\u0016\u0016\u0017\u0017\u0018\u0018\u0019\u0019\u001a\u021a\u001b\u001b"
- + "\u001c\u001c\u001d\u001d\u001e\u001e\u001f\u001f !!\"\"##$$%%&&\'\'(())**++,,--"
- + "..//0053\u000064\u000075\u000086\u000097\u0000:8\u0000;9\u0000<:\u0000=\u023b\u0000"
- + "><\u0000?=\u0000@>\u0000A@\u0000BA\u0000CB\u0000DC\u0000";
+ + "\u0004\u0003\u0005\u0004\u0006\u0005\u0007\u0006\b\u0007\t\u0208\n\t\u000b\n\f\u000b"
+ + "\r\f\u000e\r\u000f\u000e\u0010\u000f\u0011\u0010\u0012\u0012\u0013\u0013\u0014\u0014"
+ + "\u0015\u0015\u0016\u0016\u0017\u0017\u0018\u0018\u0019\u0019\u001a\u021a\u001b\u001b"
+ + "\u001c\u001c\u001d\u001d\u001e\u001e\u001f\u001f !!\"\"##$$%%&&\'\'(())**++,,--"
+ + "..//0053\u000064\u000075\u000086\u000097\u0000:8\u0000;9\u0000<:\u0000=\u023b\u0000"
+ + "><\u0000?=\u0000@>\u0000A@\u0000BA\u0000CB\u0000DC\u0000";
return new RawMessageInfo(Proto3MessageLite.getDefaultInstance(), info, objects);
}
diff --git a/java/core/src/test/java/com/google/protobuf/TextFormatTest.java b/java/core/src/test/java/com/google/protobuf/TextFormatTest.java
index 915dddf392..a919f3b9ff 100644
--- a/java/core/src/test/java/com/google/protobuf/TextFormatTest.java
+++ b/java/core/src/test/java/com/google/protobuf/TextFormatTest.java
@@ -1507,9 +1507,9 @@ public class TextFormatTest extends TestCase {
+ " value: -1\n"
+ "}\n";
TestMap msg = TextFormat.parse(input, TestMap.class);
- int i1 = msg.getInt32ToInt32Field().get(1);
+ int i1 = msg.getInt32ToInt32FieldMap().get(1);
TestMap msg2 = TextFormat.parse(msg.toString(), TestMap.class);
- int i2 = msg2.getInt32ToInt32Field().get(1);
+ int i2 = msg2.getInt32ToInt32FieldMap().get(1);
assertEquals(i1, i2);
}
@@ -1521,10 +1521,10 @@ public class TextFormatTest extends TestCase {
TestMap.Builder dest = TestMap.newBuilder();
parserWithOverwriteForbidden.merge(text, dest);
TestMap message = dest.build();
- assertEquals(2, message.getStringToInt32Field().size());
- assertEquals(2, message.getInt32ToMessageField().size());
- assertEquals(10, message.getStringToInt32Field().get("x").intValue());
- assertEquals(200, message.getInt32ToMessageField().get(2).getValue());
+ assertEquals(2, message.getStringToInt32FieldMap().size());
+ assertEquals(2, message.getInt32ToMessageFieldMap().size());
+ assertEquals(10, message.getStringToInt32FieldMap().get("x").intValue());
+ assertEquals(200, message.getInt32ToMessageFieldMap().get(2).getValue());
}
public void testMapShortFormEmpty() throws Exception {
@@ -1532,8 +1532,8 @@ public class TextFormatTest extends TestCase {
TestMap.Builder dest = TestMap.newBuilder();
parserWithOverwriteForbidden.merge(text, dest);
TestMap message = dest.build();
- assertEquals(0, message.getStringToInt32Field().size());
- assertEquals(0, message.getInt32ToMessageField().size());
+ assertEquals(0, message.getStringToInt32FieldMap().size());
+ assertEquals(0, message.getInt32ToMessageFieldMap().size());
}
public void testMapShortFormTrailingComma() throws Exception {
@@ -1558,8 +1558,8 @@ public class TextFormatTest extends TestCase {
TestMap.Builder builder = TestMap.newBuilder();
defaultParser.merge(text, builder);
TestMap map = builder.build();
- assertEquals(2, map.getInt32ToInt32Field().size());
- assertEquals(30, map.getInt32ToInt32Field().get(1).intValue());
+ assertEquals(2, map.getInt32ToInt32FieldMap().size());
+ assertEquals(30, map.getInt32ToInt32FieldMap().get(1).intValue());
}
{
@@ -1568,8 +1568,8 @@ public class TextFormatTest extends TestCase {
TestMap.Builder builder = TestMap.newBuilder();
parserWithOverwriteForbidden.merge(text, builder);
TestMap map = builder.build();
- assertEquals(2, map.getInt32ToInt32Field().size());
- assertEquals(30, map.getInt32ToInt32Field().get(1).intValue());
+ assertEquals(2, map.getInt32ToInt32FieldMap().size());
+ assertEquals(30, map.getInt32ToInt32FieldMap().get(1).intValue());
}
{
@@ -1580,8 +1580,8 @@ public class TextFormatTest extends TestCase {
TestMap map =
TestMap.parseFrom(
builder.build().toByteString(), ExtensionRegistryLite.getEmptyRegistry());
- assertEquals(2, map.getInt32ToInt32Field().size());
- assertEquals(30, map.getInt32ToInt32Field().get(1).intValue());
+ assertEquals(2, map.getInt32ToInt32FieldMap().size());
+ assertEquals(30, map.getInt32ToInt32FieldMap().get(1).intValue());
}
}
diff --git a/java/pom.xml b/java/pom.xml
index 3283268afc..2ce55db1bf 100644
--- a/java/pom.xml
+++ b/java/pom.xml
@@ -93,12 +93,12 @@
com.google.guava
guava
- 29.0-android
+ 30.0-android
com.google.guava
guava-testlib
- 29.0-android
+ 30.0-android
test
diff --git a/java/util/src/test/java/com/google/protobuf/util/JsonFormatTest.java b/java/util/src/test/java/com/google/protobuf/util/JsonFormatTest.java
index 46d3cc4c35..6133bb49a8 100644
--- a/java/util/src/test/java/com/google/protobuf/util/JsonFormatTest.java
+++ b/java/util/src/test/java/com/google/protobuf/util/JsonFormatTest.java
@@ -1697,6 +1697,7 @@ public class JsonFormatTest extends TestCase {
public void testJsonException() throws Exception {
InputStream throwingInputStream =
new InputStream() {
+ @Override
public int read() throws IOException {
throw new IOException("12345");
}
diff --git a/js/binary/decoder_test.js b/js/binary/decoder_test.js
index 9900e65bc5..0fddc4b344 100644
--- a/js/binary/decoder_test.js
+++ b/js/binary/decoder_test.js
@@ -315,6 +315,9 @@ describe('binaryDecoderTest', function() {
// 64-bit extremes, not in dev guide.
{original: '9223372036854775807', zigzag: '18446744073709551614'},
{original: '-9223372036854775808', zigzag: '18446744073709551615'},
+ // None of the above catch: bitsLow < 0 && bitsHigh > 0 && bitsHigh <
+ // 0x1FFFFF. The following used to be broken.
+ {original: '72000000000', zigzag: '144000000000'},
];
var encoder = new jspb.BinaryEncoder();
testCases.forEach(function(c) {
diff --git a/js/binary/utils.js b/js/binary/utils.js
index 6cd15e3644..4d743310cf 100644
--- a/js/binary/utils.js
+++ b/js/binary/utils.js
@@ -511,7 +511,7 @@ jspb.utils.joinUnsignedDecimalString = function(bitsLow, bitsHigh) {
// Skip the expensive conversion if the number is small enough to use the
// built-in conversions.
if (bitsHigh <= 0x1FFFFF) {
- return '' + (jspb.BinaryConstants.TWO_TO_32 * bitsHigh + bitsLow);
+ return '' + jspb.utils.joinUint64(bitsLow, bitsHigh);
}
// What this code is doing is essentially converting the input number from
diff --git a/js/package.json b/js/package.json
index a3d9ba32e5..6bbc115c04 100644
--- a/js/package.json
+++ b/js/package.json
@@ -1,6 +1,6 @@
{
"name": "google-protobuf",
- "version": "3.13.0",
+ "version": "3.14.0",
"description": "Protocol Buffers for JavaScript",
"main": "google-protobuf.js",
"files": [
diff --git a/kokoro/linux/dockerfile/test/php/Dockerfile b/kokoro/linux/dockerfile/test/php/Dockerfile
index a540177c06..f2fe836a55 100644
--- a/kokoro/linux/dockerfile/test/php/Dockerfile
+++ b/kokoro/linux/dockerfile/test/php/Dockerfile
@@ -55,66 +55,6 @@ RUN mv composer.phar /usr/local/bin/composer
# Download php source code
RUN git clone https://github.com/php/php-src
-# php 5.5
-RUN cd php-src \
- && git checkout PHP-5.5.38 \
- && ./buildconf --force
-RUN cd php-src \
- && ./configure \
- --enable-bcmath \
- --with-gmp \
- --with-openssl \
- --with-zlib \
- --prefix=/usr/local/php-5.5 \
- && make \
- && make install \
- && make clean
-RUN cd php-src \
- && ./configure \
- --enable-maintainer-zts \
- --with-gmp \
- --with-openssl \
- --with-zlib \
- --prefix=/usr/local/php-5.5-zts \
- && make \
- && make install \
- && make clean
-
-RUN wget -O phpunit https://phar.phpunit.de/phpunit-4.phar \
- && chmod +x phpunit \
- && cp phpunit /usr/local/php-5.5/bin \
- && mv phpunit /usr/local/php-5.5-zts/bin
-
-# php 5.6
-RUN cd php-src \
- && git checkout PHP-5.6.39 \
- && ./buildconf --force
-RUN cd php-src \
- && ./configure \
- --enable-bcmath \
- --with-gmp \
- --with-openssl \
- --with-zlib \
- --prefix=/usr/local/php-5.6 \
- && make \
- && make install \
- && make clean
-RUN cd php-src \
- && ./configure \
- --enable-maintainer-zts \
- --with-gmp \
- --with-openssl \
- --with-zlib \
- --prefix=/usr/local/php-5.6-zts \
- && make \
- && make install \
- && make clean
-
-RUN wget -O phpunit https://phar.phpunit.de/phpunit-5.phar \
- && chmod +x phpunit \
- && cp phpunit /usr/local/php-5.6/bin \
- && mv phpunit /usr/local/php-5.6-zts/bin
-
# php 7.0
RUN cd php-src \
&& git checkout PHP-7.0.33 \
@@ -122,6 +62,7 @@ RUN cd php-src \
RUN cd php-src \
&& ./configure \
--enable-bcmath \
+ --enable-mbstring \
--with-gmp \
--with-openssl \
--with-zlib \
@@ -132,6 +73,7 @@ RUN cd php-src \
RUN cd php-src \
&& ./configure \
--enable-maintainer-zts \
+ --enable-mbstring \
--with-gmp \
--with-openssl \
--with-zlib \
@@ -152,6 +94,7 @@ RUN cd php-src \
RUN cd php-src \
&& ./configure \
--enable-bcmath \
+ --enable-mbstring \
--with-gmp \
--with-openssl \
--with-zlib \
@@ -162,6 +105,7 @@ RUN cd php-src \
RUN cd php-src \
&& ./configure \
--enable-maintainer-zts \
+ --enable-mbstring \
--with-gmp \
--with-openssl \
--with-zlib \
@@ -170,7 +114,7 @@ RUN cd php-src \
&& make install \
&& make clean
-RUN wget -O phpunit https://phar.phpunit.de/phpunit-7.phar \
+RUN wget -O phpunit https://phar.phpunit.de/phpunit-7.5.0.phar \
&& chmod +x phpunit \
&& cp phpunit /usr/local/php-7.1/bin \
&& mv phpunit /usr/local/php-7.1-zts/bin
@@ -182,6 +126,7 @@ RUN cd php-src \
RUN cd php-src \
&& ./configure \
--enable-bcmath \
+ --enable-mbstring \
--with-gmp \
--with-openssl \
--with-zlib \
@@ -192,6 +137,7 @@ RUN cd php-src \
RUN cd php-src \
&& ./configure \
--enable-maintainer-zts \
+ --enable-mbstring \
--with-gmp \
--with-openssl \
--with-zlib \
@@ -200,7 +146,7 @@ RUN cd php-src \
&& make install \
&& make clean
-RUN wget -O phpunit https://phar.phpunit.de/phpunit-7.phar \
+RUN wget -O phpunit https://phar.phpunit.de/phpunit-7.5.0.phar \
&& chmod +x phpunit \
&& cp phpunit /usr/local/php-7.2/bin \
&& mv phpunit /usr/local/php-7.2-zts/bin
@@ -212,6 +158,7 @@ RUN cd php-src \
RUN cd php-src \
&& ./configure \
--enable-bcmath \
+ --enable-mbstring \
--with-gmp \
--with-openssl \
--with-zlib \
@@ -222,6 +169,7 @@ RUN cd php-src \
RUN cd php-src \
&& ./configure \
--enable-maintainer-zts \
+ --enable-mbstring \
--with-gmp \
--with-openssl \
--with-zlib \
@@ -230,7 +178,7 @@ RUN cd php-src \
&& make install \
&& make clean
-RUN wget -O phpunit https://phar.phpunit.de/phpunit-7.phar \
+RUN wget -O phpunit https://phar.phpunit.de/phpunit-7.5.0.phar \
&& chmod +x phpunit \
&& cp phpunit /usr/local/php-7.3/bin \
&& mv phpunit /usr/local/php-7.3-zts/bin
@@ -253,6 +201,8 @@ RUN cd /var/local/php-src-php-7.4.0 \
&& ./buildconf --force \
&& ./configure \
--enable-bcmath \
+ --enable-mbstring \
+ --disable-mbregex \
--with-gmp \
--with-openssl \
--with-zlib \
@@ -264,6 +214,8 @@ RUN cd /var/local/php-src-php-7.4.0 \
&& ./buildconf --force \
&& ./configure \
--enable-maintainer-zts \
+ --enable-mbstring \
+ --disable-mbregex \
--with-gmp \
--with-openssl \
--with-zlib \
diff --git a/kokoro/linux/dockerfile/test/php80/Dockerfile b/kokoro/linux/dockerfile/test/php80/Dockerfile
index d6c9b4d273..8093eae16c 100644
--- a/kokoro/linux/dockerfile/test/php80/Dockerfile
+++ b/kokoro/linux/dockerfile/test/php80/Dockerfile
@@ -59,7 +59,7 @@ RUN git clone https://github.com/php/php-src
# php 8.0
RUN cd php-src \
- && git checkout php-8.0.0alpha3 \
+ && git checkout php-8.0.0 \
&& ./buildconf --force
RUN cd php-src \
&& ./configure \
diff --git a/kokoro/linux/dockerfile/test/php_32bit/Dockerfile b/kokoro/linux/dockerfile/test/php_32bit/Dockerfile
index b40cb70032..ed2acbef7c 100644
--- a/kokoro/linux/dockerfile/test/php_32bit/Dockerfile
+++ b/kokoro/linux/dockerfile/test/php_32bit/Dockerfile
@@ -53,78 +53,28 @@ RUN mv composer.phar /usr/local/bin/composer
# Download php source code
RUN git clone https://github.com/php/php-src
-# php 5.5
-RUN cd php-src \
- && git checkout PHP-5.5.38 \
- && ./buildconf --force
-RUN cd php-src \
- && ./configure \
- --enable-bcmath \
- --with-openssl \
- --with-zlib \
- --prefix=/usr/local/php-5.5 \
- && make \
- && make install \
- && make clean
-RUN cd php-src \
- && ./configure \
- --enable-maintainer-zts \
- --with-openssl \
- --with-zlib \
- --prefix=/usr/local/php-5.5-zts \
- && make \
- && make install \
- && make clean
-
-RUN wget -O phpunit https://phar.phpunit.de/phpunit-4.phar \
- && chmod +x phpunit \
- && cp phpunit /usr/local/php-5.5/bin \
- && mv phpunit /usr/local/php-5.5-zts/bin
-
-# php 5.6
-RUN cd php-src \
- && git checkout PHP-5.6.39 \
- && ./buildconf --force
-RUN cd php-src \
- && ./configure \
- --enable-bcmath \
- --with-openssl \
- --with-zlib \
- --prefix=/usr/local/php-5.6 \
- && make \
- && make install \
- && make clean
-RUN cd php-src \
- && ./configure \
- --enable-maintainer-zts \
- --with-openssl \
- --with-zlib \
- --prefix=/usr/local/php-5.6-zts \
- && make \
- && make install \
- && make clean
+# php 7.0
+RUN wget https://github.com/php/php-src/archive/php-7.0.33.tar.gz -O /var/local/php-7.0.33.tar.gz
-RUN wget -O phpunit https://phar.phpunit.de/phpunit-5.phar \
- && chmod +x phpunit \
- && cp phpunit /usr/local/php-5.6/bin \
- && mv phpunit /usr/local/php-5.6-zts/bin
+RUN cd /var/local \
+ && tar -zxvf php-7.0.33.tar.gz
-# php 7.0
-RUN cd php-src \
- && git checkout PHP-7.0.33 \
- && ./buildconf --force
-RUN cd php-src \
+RUN cd /var/local/php-src-php-7.0.33 \
+ && ./buildconf --force \
&& ./configure \
--enable-bcmath \
+ --enable-mbstring \
--with-openssl \
--with-zlib \
--prefix=/usr/local/php-7.0 \
&& make \
&& make install \
&& make clean
-RUN cd php-src \
+RUN cd /var/local/php-src-php-7.0.33 \
+ && ./buildconf --force \
&& ./configure \
--enable-maintainer-zts \
+ --enable-mbstring \
--with-openssl \
--with-zlib \
--prefix=/usr/local/php-7.0-zts \
@@ -138,21 +88,27 @@ RUN wget -O phpunit https://phar.phpunit.de/phpunit-6.phar \
&& mv phpunit /usr/local/php-7.0-zts/bin
# php 7.1
-RUN cd php-src \
- && git checkout PHP-7.1.25 \
- && ./buildconf --force
-RUN cd php-src \
+RUN wget https://github.com/php/php-src/archive/php-7.1.25.tar.gz -O /var/local/php-7.1.25.tar.gz
+
+RUN cd /var/local \
+ && tar -zxvf php-7.1.25.tar.gz
+
+RUN cd /var/local/php-src-php-7.1.25 \
+ && ./buildconf --force \
&& ./configure \
--enable-bcmath \
+ --enable-mbstring \
--with-openssl \
--with-zlib \
--prefix=/usr/local/php-7.1 \
&& make \
&& make install \
&& make clean
-RUN cd php-src \
+RUN cd /var/local/php-src-php-7.1.25 \
+ && ./buildconf --force \
&& ./configure \
--enable-maintainer-zts \
+ --enable-mbstring \
--with-openssl \
--with-zlib \
--prefix=/usr/local/php-7.1-zts \
@@ -160,27 +116,33 @@ RUN cd php-src \
&& make install \
&& make clean
-RUN wget -O phpunit https://phar.phpunit.de/phpunit-7.phar \
+RUN wget -O phpunit https://phar.phpunit.de/phpunit-7.5.0.phar \
&& chmod +x phpunit \
&& cp phpunit /usr/local/php-7.1/bin \
&& mv phpunit /usr/local/php-7.1-zts/bin
# php 7.2
-RUN cd php-src \
- && git checkout PHP-7.2.13 \
- && ./buildconf --force
-RUN cd php-src \
+RUN wget https://github.com/php/php-src/archive/php-7.2.13.tar.gz -O /var/local/php-7.2.13.tar.gz
+
+RUN cd /var/local \
+ && tar -zxvf php-7.2.13.tar.gz
+
+RUN cd /var/local/php-src-php-7.2.13 \
+ && ./buildconf --force \
&& ./configure \
--enable-bcmath \
+ --enable-mbstring \
--with-openssl \
--with-zlib \
--prefix=/usr/local/php-7.2 \
&& make \
&& make install \
&& make clean
-RUN cd php-src \
+RUN cd /var/local/php-src-php-7.2.13 \
+ && ./buildconf --force \
&& ./configure \
--enable-maintainer-zts \
+ --enable-mbstring \
--with-openssl \
--with-zlib \
--prefix=/usr/local/php-7.2-zts \
@@ -188,27 +150,33 @@ RUN cd php-src \
&& make install \
&& make clean
-RUN wget -O phpunit https://phar.phpunit.de/phpunit-7.phar \
+RUN wget -O phpunit https://phar.phpunit.de/phpunit-7.5.0.phar \
&& chmod +x phpunit \
&& cp phpunit /usr/local/php-7.2/bin \
&& mv phpunit /usr/local/php-7.2-zts/bin
# php 7.3
-RUN cd php-src \
- && git checkout PHP-7.3.0 \
- && ./buildconf --force
-RUN cd php-src \
+RUN wget https://github.com/php/php-src/archive/php-7.3.0.tar.gz -O /var/local/php-7.3.0.tar.gz
+
+RUN cd /var/local \
+ && tar -zxvf php-7.3.0.tar.gz
+
+RUN cd /var/local/php-src-php-7.3.0 \
+ && ./buildconf --force \
&& ./configure \
--enable-bcmath \
+ --enable-mbstring \
--with-openssl \
--with-zlib \
--prefix=/usr/local/php-7.3 \
&& make \
&& make install \
&& make clean
-RUN cd php-src \
+RUN cd /var/local/php-src-php-7.3.0 \
+ && ./buildconf --force \
&& ./configure \
--enable-maintainer-zts \
+ --enable-mbstring \
--with-openssl \
--with-zlib \
--prefix=/usr/local/php-7.3-zts \
@@ -216,7 +184,7 @@ RUN cd php-src \
&& make install \
&& make clean
-RUN wget -O phpunit https://phar.phpunit.de/phpunit-7.phar \
+RUN wget -O phpunit https://phar.phpunit.de/phpunit-7.5.0.phar \
&& chmod +x phpunit \
&& cp phpunit /usr/local/php-7.3/bin \
&& mv phpunit /usr/local/php-7.3-zts/bin
@@ -239,6 +207,8 @@ RUN cd /var/local/php-src-php-7.4.0 \
&& ./buildconf --force \
&& ./configure \
--enable-bcmath \
+ --enable-mbstring \
+ --disable-mbregex \
--with-openssl \
--with-zlib \
--prefix=/usr/local/php-7.4 \
@@ -249,6 +219,8 @@ RUN cd /var/local/php-src-php-7.4.0 \
&& ./buildconf --force \
&& ./configure \
--enable-maintainer-zts \
+ --enable-mbstring \
+ --disable-mbregex \
--with-openssl \
--with-zlib \
--prefix=/usr/local/php-7.4-zts \
diff --git a/kokoro/linux/dockerfile/test/ruby/Dockerfile b/kokoro/linux/dockerfile/test/ruby/Dockerfile
index 9037da715f..b73bf84095 100644
--- a/kokoro/linux/dockerfile/test/ruby/Dockerfile
+++ b/kokoro/linux/dockerfile/test/ruby/Dockerfile
@@ -26,13 +26,14 @@ RUN apt-get update && apt-get install -y \
RUN gpg --keyserver hkp://keys.gnupg.net --recv-keys \
409B6B1796C275462A1703113804BB82D39DC0E3 \
7D2BAF1CF37B13E2069D6956105BD0E739499BDB
-RUN \curl -sSL https://get.rvm.io | bash -s stable
+RUN \curl -sSL https://get.rvm.io | bash -s master
RUN /bin/bash -l -c "rvm install 2.3.8"
RUN /bin/bash -l -c "rvm install 2.4.5"
RUN /bin/bash -l -c "rvm install 2.5.1"
RUN /bin/bash -l -c "rvm install 2.6.0"
RUN /bin/bash -l -c "rvm install 2.7.0"
+RUN /bin/bash -l -c "rvm install 3.0.0"
RUN /bin/bash -l -c "echo 'gem: --no-ri --no-rdoc' > ~/.gemrc"
RUN /bin/bash -l -c "echo 'export PATH=/usr/local/rvm/bin:$PATH' >> ~/.bashrc"
diff --git a/kokoro/linux/php80/build.sh b/kokoro/linux/php80/build.sh
index 6499b39af8..f17aec104f 100755
--- a/kokoro/linux/php80/build.sh
+++ b/kokoro/linux/php80/build.sh
@@ -11,7 +11,7 @@
cd $(dirname $0)/../../..
export DOCKERHUB_ORGANIZATION=protobuftesting
-export DOCKERFILE_DIR=kokoro/linux/dockerfile/test/php
+export DOCKERFILE_DIR=kokoro/linux/dockerfile/test/php80
export DOCKER_RUN_SCRIPT=kokoro/linux/pull_request_in_docker.sh
export OUTPUT_DIR=testoutput
export TEST_SET="php8.0_all"
diff --git a/kokoro/linux/ruby30/build.sh b/kokoro/linux/ruby30/build.sh
new file mode 100755
index 0000000000..9e44575652
--- /dev/null
+++ b/kokoro/linux/ruby30/build.sh
@@ -0,0 +1,18 @@
+#!/bin/bash
+#
+# This is the top-level script we give to Kokoro as the entry point for
+# running the "pull request" project:
+#
+# This script selects a specific Dockerfile (for building a Docker image) and
+# a script to run inside that image. Then we delegate to the general
+# build_and_run_docker.sh script.
+
+# Change to repo root
+cd $(dirname $0)/../../..
+
+export DOCKERHUB_ORGANIZATION=protobuftesting
+export DOCKERFILE_DIR=kokoro/linux/dockerfile/test/ruby
+export DOCKER_RUN_SCRIPT=kokoro/linux/pull_request_in_docker.sh
+export OUTPUT_DIR=testoutput
+export TEST_SET="ruby30"
+./kokoro/linux/build_and_run_docker.sh
diff --git a/kokoro/linux/ruby30/continuous.cfg b/kokoro/linux/ruby30/continuous.cfg
new file mode 100644
index 0000000000..b03a3352f4
--- /dev/null
+++ b/kokoro/linux/ruby30/continuous.cfg
@@ -0,0 +1,11 @@
+# Config file for running tests in Kokoro
+
+# Location of the build script in repository
+build_file: "protobuf/kokoro/linux/ruby30/build.sh"
+timeout_mins: 120
+
+action {
+ define_artifacts {
+ regex: "**/sponge_log.xml"
+ }
+}
diff --git a/kokoro/linux/ruby30/presubmit.cfg b/kokoro/linux/ruby30/presubmit.cfg
new file mode 100644
index 0000000000..b03a3352f4
--- /dev/null
+++ b/kokoro/linux/ruby30/presubmit.cfg
@@ -0,0 +1,11 @@
+# Config file for running tests in Kokoro
+
+# Location of the build script in repository
+build_file: "protobuf/kokoro/linux/ruby30/build.sh"
+timeout_mins: 120
+
+action {
+ define_artifacts {
+ regex: "**/sponge_log.xml"
+ }
+}
diff --git a/kokoro/macos/prepare_build_macos_rc b/kokoro/macos/prepare_build_macos_rc
index 830e7eee67..d94dd543fd 100755
--- a/kokoro/macos/prepare_build_macos_rc
+++ b/kokoro/macos/prepare_build_macos_rc
@@ -37,10 +37,14 @@ sudo rm -rf \
sudo rm -rf \
/usr/local/bin/2to3* \
/usr/local/bin/idle3* \
+ /usr/local/bin/pip3 \
/usr/local/bin/pydoc3* \
/usr/local/bin/python3* \
/usr/local/bin/pyvenv*
+git -C /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core fetch --unshallow
+git -C /usr/local/Homebrew/Library/Taps/homebrew/homebrew-cask fetch --unshallow
+
brew update
brew upgrade
@@ -76,5 +80,5 @@ if [[ "${KOKORO_INSTALL_RVM:-}" == "yes" ]] ; then
curl -sSL https://rvm.io/mpapis.asc | gpg --import -
curl -sSL https://rvm.io/pkuczynski.asc | gpg --import -
- curl -sSL https://get.rvm.io | bash -s stable --ruby
+ curl -sSL https://get.rvm.io | bash -s master --ruby
fi
diff --git a/kokoro/macos/ruby30/build.sh b/kokoro/macos/ruby30/build.sh
new file mode 100755
index 0000000000..6b9bfb3215
--- /dev/null
+++ b/kokoro/macos/ruby30/build.sh
@@ -0,0 +1,13 @@
+#!/bin/bash
+#
+# Build file to set up and run tests
+
+# Change to repo root
+cd $(dirname $0)/../../..
+
+# Prepare worker environment to run tests
+KOKORO_INSTALL_RUBY=yes
+KOKORO_INSTALL_RVM=yes
+source kokoro/macos/prepare_build_macos_rc
+
+./tests.sh ruby30
diff --git a/kokoro/macos/ruby30/continuous.cfg b/kokoro/macos/ruby30/continuous.cfg
new file mode 100644
index 0000000000..d5051170be
--- /dev/null
+++ b/kokoro/macos/ruby30/continuous.cfg
@@ -0,0 +1,5 @@
+# Config file for running tests in Kokoro
+
+# Location of the build script in repository
+build_file: "protobuf/kokoro/macos/ruby30/build.sh"
+timeout_mins: 1440
diff --git a/kokoro/macos/ruby30/presubmit.cfg b/kokoro/macos/ruby30/presubmit.cfg
new file mode 100644
index 0000000000..d5051170be
--- /dev/null
+++ b/kokoro/macos/ruby30/presubmit.cfg
@@ -0,0 +1,5 @@
+# Config file for running tests in Kokoro
+
+# Location of the build script in repository
+build_file: "protobuf/kokoro/macos/ruby30/build.sh"
+timeout_mins: 1440
diff --git a/kokoro/release/ruby/macos/ruby/ruby_build_environment.sh b/kokoro/release/ruby/macos/ruby/ruby_build_environment.sh
index 880c23390c..046b604b40 100755
--- a/kokoro/release/ruby/macos/ruby/ruby_build_environment.sh
+++ b/kokoro/release/ruby/macos/ruby/ruby_build_environment.sh
@@ -21,13 +21,13 @@ rm -rf ~/.rake-compiler
CROSS_RUBY=$(mktemp tmpfile.XXXXXXXX)
-curl https://raw.githubusercontent.com/rake-compiler/rake-compiler/v1.1.0/tasks/bin/cross-ruby.rake > "$CROSS_RUBY"
+curl https://raw.githubusercontent.com/rake-compiler/rake-compiler/72184e51779b6a3b9b8580b036a052fdc3181ced/tasks/bin/cross-ruby.rake > "$CROSS_RUBY"
# See https://github.com/grpc/grpc/issues/12161 for verconf.h patch details
patch "$CROSS_RUBY" << EOF
---- cross-ruby.rake 2018-04-10 11:32:16.000000000 -0700
-+++ patched 2018-04-10 11:40:25.000000000 -0700
-@@ -141,8 +141,10 @@
+--- cross-ruby.rake 2020-12-11 11:17:53.000000000 +0900
++++ patched 2020-12-11 11:18:52.000000000 +0900
+@@ -111,10 +111,12 @@
"--host=#{MINGW_HOST}",
"--target=#{MINGW_TARGET}",
"--build=#{RUBY_BUILD}",
@@ -36,10 +36,13 @@ patch "$CROSS_RUBY" << EOF
+ '--disable-shared',
'--disable-install-doc',
+ '--without-gmp',
- '--with-ext='
+ '--with-ext=',
+- 'LDFLAGS=-pipe -s',
++ 'LDFLAGS=-pipe',
]
-@@ -159,6 +161,7 @@
+ # Force Winsock2 for Ruby 1.8, 1.9 defaults to it
+@@ -130,6 +132,7 @@
# make
file "#{build_dir}/ruby.exe" => ["#{build_dir}/Makefile"] do |t|
chdir File.dirname(t.prerequisites.first) do
@@ -55,7 +58,7 @@ set +x # rvm commands are very verbose
rvm use 2.7.0
set -x
ruby --version | grep 'ruby 2.7.0'
-for v in 2.7.0 ; do
+for v in 3.0.0 2.7.0 ; do
ccache -c
rake -f "$CROSS_RUBY" cross-ruby VERSION="$v" HOST=x86_64-darwin11 MAKE="$MAKE"
done
diff --git a/m4/ax_pthread.m4 b/m4/ax_pthread.m4
index d218d1af73..1598d077ff 100644
--- a/m4/ax_pthread.m4
+++ b/m4/ax_pthread.m4
@@ -1,5 +1,5 @@
# ===========================================================================
-# http://www.gnu.org/software/autoconf-archive/ax_pthread.html
+# https://www.gnu.org/software/autoconf-archive/ax_pthread.html
# ===========================================================================
#
# SYNOPSIS
@@ -55,6 +55,7 @@
#
# Copyright (c) 2008 Steven G. Johnson
# Copyright (c) 2011 Daniel Richard G.
+# Copyright (c) 2019 Marc Stevens
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
@@ -67,7 +68,7 @@
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along
-# with this program. If not, see .
+# with this program. If not, see .
#
# As a special exception, the respective Autoconf Macro's copyright owner
# gives unlimited permission to copy, distribute and modify the configure
@@ -82,7 +83,7 @@
# modified version of the Autoconf Macro, you may extend this special
# exception to the GPL to apply to your modified version as well.
-#serial 22
+#serial 27
AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD])
AC_DEFUN([AX_PTHREAD], [
@@ -100,22 +101,22 @@ ax_pthread_ok=no
# etcetera environment variables, and if threads linking works using
# them:
if test "x$PTHREAD_CFLAGS$PTHREAD_LIBS" != "x"; then
- ax_pthread_save_CC="$CC"
- ax_pthread_save_CFLAGS="$CFLAGS"
- ax_pthread_save_LIBS="$LIBS"
- AS_IF([test "x$PTHREAD_CC" != "x"], [CC="$PTHREAD_CC"])
- CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
- LIBS="$PTHREAD_LIBS $LIBS"
- AC_MSG_CHECKING([for pthread_join using $CC $PTHREAD_CFLAGS $PTHREAD_LIBS])
- AC_LINK_IFELSE([AC_LANG_CALL([], [pthread_join])], [ax_pthread_ok=yes])
- AC_MSG_RESULT([$ax_pthread_ok])
- if test "x$ax_pthread_ok" = "xno"; then
- PTHREAD_LIBS=""
- PTHREAD_CFLAGS=""
- fi
- CC="$ax_pthread_save_CC"
- CFLAGS="$ax_pthread_save_CFLAGS"
- LIBS="$ax_pthread_save_LIBS"
+ ax_pthread_save_CC="$CC"
+ ax_pthread_save_CFLAGS="$CFLAGS"
+ ax_pthread_save_LIBS="$LIBS"
+ AS_IF([test "x$PTHREAD_CC" != "x"], [CC="$PTHREAD_CC"])
+ CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+ LIBS="$PTHREAD_LIBS $LIBS"
+ AC_MSG_CHECKING([for pthread_join using $CC $PTHREAD_CFLAGS $PTHREAD_LIBS])
+ AC_LINK_IFELSE([AC_LANG_CALL([], [pthread_join])], [ax_pthread_ok=yes])
+ AC_MSG_RESULT([$ax_pthread_ok])
+ if test "x$ax_pthread_ok" = "xno"; then
+ PTHREAD_LIBS=""
+ PTHREAD_CFLAGS=""
+ fi
+ CC="$ax_pthread_save_CC"
+ CFLAGS="$ax_pthread_save_CFLAGS"
+ LIBS="$ax_pthread_save_LIBS"
fi
# We must check for the threads library under a number of different
@@ -123,10 +124,12 @@ fi
# (e.g. DEC) have both -lpthread and -lpthreads, where one of the
# libraries is broken (non-POSIX).
-# Create a list of thread flags to try. Items starting with a "-" are
-# C compiler flags, and other items are library names, except for "none"
-# which indicates that we try without any flags at all, and "pthread-config"
-# which is a program returning the flags for the Pth emulation library.
+# Create a list of thread flags to try. Items with a "," contain both
+# C compiler flags (before ",") and linker flags (after ","). Other items
+# starting with a "-" are C compiler flags, and remaining items are
+# library names, except for "none" which indicates that we try without
+# any flags at all, and "pthread-config" which is a program returning
+# the flags for the Pth emulation library.
ax_pthread_flags="pthreads none -Kthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config"
@@ -152,319 +155,338 @@ ax_pthread_flags="pthreads none -Kthread -pthread -pthreads -mthreads pthread --
case $host_os in
- freebsd*)
+ freebsd*)
- # -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
- # lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
+ # -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
+ # lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
- ax_pthread_flags="-kthread lthread $ax_pthread_flags"
- ;;
+ ax_pthread_flags="-kthread lthread $ax_pthread_flags"
+ ;;
- hpux*)
+ hpux*)
- # From the cc(1) man page: "[-mt] Sets various -D flags to enable
- # multi-threading and also sets -lpthread."
+ # From the cc(1) man page: "[-mt] Sets various -D flags to enable
+ # multi-threading and also sets -lpthread."
- ax_pthread_flags="-mt -pthread pthread $ax_pthread_flags"
- ;;
+ ax_pthread_flags="-mt -pthread pthread $ax_pthread_flags"
+ ;;
- openedition*)
+ openedition*)
- # IBM z/OS requires a feature-test macro to be defined in order to
- # enable POSIX threads at all, so give the user a hint if this is
- # not set. (We don't define these ourselves, as they can affect
- # other portions of the system API in unpredictable ways.)
+ # IBM z/OS requires a feature-test macro to be defined in order to
+ # enable POSIX threads at all, so give the user a hint if this is
+ # not set. (We don't define these ourselves, as they can affect
+ # other portions of the system API in unpredictable ways.)
- AC_EGREP_CPP([AX_PTHREAD_ZOS_MISSING],
- [
-# if !defined(_OPEN_THREADS) && !defined(_UNIX03_THREADS)
- AX_PTHREAD_ZOS_MISSING
-# endif
- ],
- [AC_MSG_WARN([IBM z/OS requires -D_OPEN_THREADS or -D_UNIX03_THREADS to enable pthreads support.])])
- ;;
+ AC_EGREP_CPP([AX_PTHREAD_ZOS_MISSING],
+ [
+# if !defined(_OPEN_THREADS) && !defined(_UNIX03_THREADS)
+ AX_PTHREAD_ZOS_MISSING
+# endif
+ ],
+ [AC_MSG_WARN([IBM z/OS requires -D_OPEN_THREADS or -D_UNIX03_THREADS to enable pthreads support.])])
+ ;;
- solaris*)
+ solaris*)
- # On Solaris (at least, for some versions), libc contains stubbed
- # (non-functional) versions of the pthreads routines, so link-based
- # tests will erroneously succeed. (N.B.: The stubs are missing
- # pthread_cleanup_push, or rather a function called by this macro,
- # so we could check for that, but who knows whether they'll stub
- # that too in a future libc.) So we'll check first for the
- # standard Solaris way of linking pthreads (-mt -lpthread).
+ # On Solaris (at least, for some versions), libc contains stubbed
+ # (non-functional) versions of the pthreads routines, so link-based
+ # tests will erroneously succeed. (N.B.: The stubs are missing
+ # pthread_cleanup_push, or rather a function called by this macro,
+ # so we could check for that, but who knows whether they'll stub
+ # that too in a future libc.) So we'll check first for the
+ # standard Solaris way of linking pthreads (-mt -lpthread).
- ax_pthread_flags="-mt,pthread pthread $ax_pthread_flags"
- ;;
+ ax_pthread_flags="-mt,-lpthread pthread $ax_pthread_flags"
+ ;;
esac
+# Are we compiling with Clang?
+
+AC_CACHE_CHECK([whether $CC is Clang],
+ [ax_cv_PTHREAD_CLANG],
+ [ax_cv_PTHREAD_CLANG=no
+ # Note that Autoconf sets GCC=yes for Clang as well as GCC
+ if test "x$GCC" = "xyes"; then
+ AC_EGREP_CPP([AX_PTHREAD_CC_IS_CLANG],
+ [/* Note: Clang 2.7 lacks __clang_[a-z]+__ */
+# if defined(__clang__) && defined(__llvm__)
+ AX_PTHREAD_CC_IS_CLANG
+# endif
+ ],
+ [ax_cv_PTHREAD_CLANG=yes])
+ fi
+ ])
+ax_pthread_clang="$ax_cv_PTHREAD_CLANG"
+
+
# GCC generally uses -pthread, or -pthreads on some platforms (e.g. SPARC)
+# Note that for GCC and Clang -pthread generally implies -lpthread,
+# except when -nostdlib is passed.
+# This is problematic using libtool to build C++ shared libraries with pthread:
+# [1] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=25460
+# [2] https://bugzilla.redhat.com/show_bug.cgi?id=661333
+# [3] https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=468555
+# To solve this, first try -pthread together with -lpthread for GCC
+
AS_IF([test "x$GCC" = "xyes"],
- [ax_pthread_flags="-pthread -pthreads $ax_pthread_flags"])
+ [ax_pthread_flags="-pthread,-lpthread -pthread -pthreads $ax_pthread_flags"])
+
+# Clang takes -pthread (never supported any other flag), but we'll try with -lpthread first
+
+AS_IF([test "x$ax_pthread_clang" = "xyes"],
+ [ax_pthread_flags="-pthread,-lpthread -pthread"])
+
# The presence of a feature test macro requesting re-entrant function
# definitions is, on some systems, a strong hint that pthreads support is
# correctly enabled
case $host_os in
- darwin* | hpux* | linux* | osf* | solaris*)
- ax_pthread_check_macro="_REENTRANT"
- ;;
+ darwin* | hpux* | linux* | osf* | solaris*)
+ ax_pthread_check_macro="_REENTRANT"
+ ;;
- aix* | freebsd*)
- ax_pthread_check_macro="_THREAD_SAFE"
- ;;
+ aix*)
+ ax_pthread_check_macro="_THREAD_SAFE"
+ ;;
- *)
- ax_pthread_check_macro="--"
- ;;
+ *)
+ ax_pthread_check_macro="--"
+ ;;
esac
AS_IF([test "x$ax_pthread_check_macro" = "x--"],
[ax_pthread_check_cond=0],
[ax_pthread_check_cond="!defined($ax_pthread_check_macro)"])
-# Are we compiling with Clang?
-AC_CACHE_CHECK([whether $CC is Clang],
- [ax_cv_PTHREAD_CLANG],
- [ax_cv_PTHREAD_CLANG=no
- # Note that Autoconf sets GCC=yes for Clang as well as GCC
- if test "x$GCC" = "xyes"; then
- AC_EGREP_CPP([AX_PTHREAD_CC_IS_CLANG],
- [/* Note: Clang 2.7 lacks __clang_[a-z]+__ */
-# if defined(__clang__) && defined(__llvm__)
- AX_PTHREAD_CC_IS_CLANG
-# endif
- ],
- [ax_cv_PTHREAD_CLANG=yes])
- fi
- ])
-ax_pthread_clang="$ax_cv_PTHREAD_CLANG"
+if test "x$ax_pthread_ok" = "xno"; then
+for ax_pthread_try_flag in $ax_pthread_flags; do
+
+ case $ax_pthread_try_flag in
+ none)
+ AC_MSG_CHECKING([whether pthreads work without any flags])
+ ;;
+
+ *,*)
+ PTHREAD_CFLAGS=`echo $ax_pthread_try_flag | sed "s/^\(.*\),\(.*\)$/\1/"`
+ PTHREAD_LIBS=`echo $ax_pthread_try_flag | sed "s/^\(.*\),\(.*\)$/\2/"`
+ AC_MSG_CHECKING([whether pthreads work with "$PTHREAD_CFLAGS" and "$PTHREAD_LIBS"])
+ ;;
+
+ -*)
+ AC_MSG_CHECKING([whether pthreads work with $ax_pthread_try_flag])
+ PTHREAD_CFLAGS="$ax_pthread_try_flag"
+ ;;
+
+ pthread-config)
+ AC_CHECK_PROG([ax_pthread_config], [pthread-config], [yes], [no])
+ AS_IF([test "x$ax_pthread_config" = "xno"], [continue])
+ PTHREAD_CFLAGS="`pthread-config --cflags`"
+ PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`"
+ ;;
+
+ *)
+ AC_MSG_CHECKING([for the pthreads library -l$ax_pthread_try_flag])
+ PTHREAD_LIBS="-l$ax_pthread_try_flag"
+ ;;
+ esac
+
+ ax_pthread_save_CFLAGS="$CFLAGS"
+ ax_pthread_save_LIBS="$LIBS"
+ CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+ LIBS="$PTHREAD_LIBS $LIBS"
+
+ # Check for various functions. We must include pthread.h,
+ # since some functions may be macros. (On the Sequent, we
+ # need a special flag -Kthread to make this header compile.)
+ # We check for pthread_join because it is in -lpthread on IRIX
+ # while pthread_create is in libc. We check for pthread_attr_init
+ # due to DEC craziness with -lpthreads. We check for
+ # pthread_cleanup_push because it is one of the few pthread
+ # functions on Solaris that doesn't have a non-functional libc stub.
+ # We try pthread_create on general principles.
+
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([#include
+# if $ax_pthread_check_cond
+# error "$ax_pthread_check_macro must be defined"
+# endif
+ static void *some_global = NULL;
+ static void routine(void *a)
+ {
+ /* To avoid any unused-parameter or
+ unused-but-set-parameter warning. */
+ some_global = a;
+ }
+ static void *start_routine(void *a) { return a; }],
+ [pthread_t th; pthread_attr_t attr;
+ pthread_create(&th, 0, start_routine, 0);
+ pthread_join(th, 0);
+ pthread_attr_init(&attr);
+ pthread_cleanup_push(routine, 0);
+ pthread_cleanup_pop(0) /* ; */])],
+ [ax_pthread_ok=yes],
+ [])
+
+ CFLAGS="$ax_pthread_save_CFLAGS"
+ LIBS="$ax_pthread_save_LIBS"
+
+ AC_MSG_RESULT([$ax_pthread_ok])
+ AS_IF([test "x$ax_pthread_ok" = "xyes"], [break])
+
+ PTHREAD_LIBS=""
+ PTHREAD_CFLAGS=""
+done
+fi
-ax_pthread_clang_warning=no
# Clang needs special handling, because older versions handle the -pthread
# option in a rather... idiosyncratic way
if test "x$ax_pthread_clang" = "xyes"; then
- # Clang takes -pthread; it has never supported any other flag
-
- # (Note 1: This will need to be revisited if a system that Clang
- # supports has POSIX threads in a separate library. This tends not
- # to be the way of modern systems, but it's conceivable.)
-
- # (Note 2: On some systems, notably Darwin, -pthread is not needed
- # to get POSIX threads support; the API is always present and
- # active. We could reasonably leave PTHREAD_CFLAGS empty. But
- # -pthread does define _REENTRANT, and while the Darwin headers
- # ignore this macro, third-party headers might not.)
-
- PTHREAD_CFLAGS="-pthread"
- PTHREAD_LIBS=
-
- ax_pthread_ok=yes
-
- # However, older versions of Clang make a point of warning the user
- # that, in an invocation where only linking and no compilation is
- # taking place, the -pthread option has no effect ("argument unused
- # during compilation"). They expect -pthread to be passed in only
- # when source code is being compiled.
- #
- # Problem is, this is at odds with the way Automake and most other
- # C build frameworks function, which is that the same flags used in
- # compilation (CFLAGS) are also used in linking. Many systems
- # supported by AX_PTHREAD require exactly this for POSIX threads
- # support, and in fact it is often not straightforward to specify a
- # flag that is used only in the compilation phase and not in
- # linking. Such a scenario is extremely rare in practice.
- #
- # Even though use of the -pthread flag in linking would only print
- # a warning, this can be a nuisance for well-run software projects
- # that build with -Werror. So if the active version of Clang has
- # this misfeature, we search for an option to squash it.
-
- AC_CACHE_CHECK([whether Clang needs flag to prevent "argument unused" warning when linking with -pthread],
- [ax_cv_PTHREAD_CLANG_NO_WARN_FLAG],
- [ax_cv_PTHREAD_CLANG_NO_WARN_FLAG=unknown
- # Create an alternate version of $ac_link that compiles and
- # links in two steps (.c -> .o, .o -> exe) instead of one
- # (.c -> exe), because the warning occurs only in the second
- # step
- ax_pthread_save_ac_link="$ac_link"
- ax_pthread_sed='s/conftest\.\$ac_ext/conftest.$ac_objext/g'
- ax_pthread_link_step=`$as_echo "$ac_link" | sed "$ax_pthread_sed"`
- ax_pthread_2step_ac_link="($ac_compile) && (echo ==== >&5) && ($ax_pthread_link_step)"
- ax_pthread_save_CFLAGS="$CFLAGS"
- for ax_pthread_try in '' -Qunused-arguments -Wno-unused-command-line-argument unknown; do
- AS_IF([test "x$ax_pthread_try" = "xunknown"], [break])
- CFLAGS="-Werror -Wunknown-warning-option $ax_pthread_try -pthread $ax_pthread_save_CFLAGS"
- ac_link="$ax_pthread_save_ac_link"
- AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])],
- [ac_link="$ax_pthread_2step_ac_link"
- AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])],
- [break])
- ])
- done
- ac_link="$ax_pthread_save_ac_link"
- CFLAGS="$ax_pthread_save_CFLAGS"
- AS_IF([test "x$ax_pthread_try" = "x"], [ax_pthread_try=no])
- ax_cv_PTHREAD_CLANG_NO_WARN_FLAG="$ax_pthread_try"
- ])
-
- case "$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG" in
- no | unknown) ;;
- *) PTHREAD_CFLAGS="$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG $PTHREAD_CFLAGS" ;;
- esac
+ # Clang takes -pthread; it has never supported any other flag
+
+ # (Note 1: This will need to be revisited if a system that Clang
+ # supports has POSIX threads in a separate library. This tends not
+ # to be the way of modern systems, but it's conceivable.)
+
+ # (Note 2: On some systems, notably Darwin, -pthread is not needed
+ # to get POSIX threads support; the API is always present and
+ # active. We could reasonably leave PTHREAD_CFLAGS empty. But
+ # -pthread does define _REENTRANT, and while the Darwin headers
+ # ignore this macro, third-party headers might not.)
+
+ # However, older versions of Clang make a point of warning the user
+ # that, in an invocation where only linking and no compilation is
+ # taking place, the -pthread option has no effect ("argument unused
+ # during compilation"). They expect -pthread to be passed in only
+ # when source code is being compiled.
+ #
+ # Problem is, this is at odds with the way Automake and most other
+ # C build frameworks function, which is that the same flags used in
+ # compilation (CFLAGS) are also used in linking. Many systems
+ # supported by AX_PTHREAD require exactly this for POSIX threads
+ # support, and in fact it is often not straightforward to specify a
+ # flag that is used only in the compilation phase and not in
+ # linking. Such a scenario is extremely rare in practice.
+ #
+ # Even though use of the -pthread flag in linking would only print
+ # a warning, this can be a nuisance for well-run software projects
+ # that build with -Werror. So if the active version of Clang has
+ # this misfeature, we search for an option to squash it.
+
+ AC_CACHE_CHECK([whether Clang needs flag to prevent "argument unused" warning when linking with -pthread],
+ [ax_cv_PTHREAD_CLANG_NO_WARN_FLAG],
+ [ax_cv_PTHREAD_CLANG_NO_WARN_FLAG=unknown
+ # Create an alternate version of $ac_link that compiles and
+ # links in two steps (.c -> .o, .o -> exe) instead of one
+ # (.c -> exe), because the warning occurs only in the second
+ # step
+ ax_pthread_save_ac_link="$ac_link"
+ ax_pthread_sed='s/conftest\.\$ac_ext/conftest.$ac_objext/g'
+ ax_pthread_link_step=`$as_echo "$ac_link" | sed "$ax_pthread_sed"`
+ ax_pthread_2step_ac_link="($ac_compile) && (echo ==== >&5) && ($ax_pthread_link_step)"
+ ax_pthread_save_CFLAGS="$CFLAGS"
+ for ax_pthread_try in '' -Qunused-arguments -Wno-unused-command-line-argument unknown; do
+ AS_IF([test "x$ax_pthread_try" = "xunknown"], [break])
+ CFLAGS="-Werror -Wunknown-warning-option $ax_pthread_try -pthread $ax_pthread_save_CFLAGS"
+ ac_link="$ax_pthread_save_ac_link"
+ AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])],
+ [ac_link="$ax_pthread_2step_ac_link"
+ AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])],
+ [break])
+ ])
+ done
+ ac_link="$ax_pthread_save_ac_link"
+ CFLAGS="$ax_pthread_save_CFLAGS"
+ AS_IF([test "x$ax_pthread_try" = "x"], [ax_pthread_try=no])
+ ax_cv_PTHREAD_CLANG_NO_WARN_FLAG="$ax_pthread_try"
+ ])
+
+ case "$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG" in
+ no | unknown) ;;
+ *) PTHREAD_CFLAGS="$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG $PTHREAD_CFLAGS" ;;
+ esac
fi # $ax_pthread_clang = yes
-if test "x$ax_pthread_ok" = "xno"; then
-for ax_pthread_try_flag in $ax_pthread_flags; do
- case $ax_pthread_try_flag in
- none)
- AC_MSG_CHECKING([whether pthreads work without any flags])
- ;;
-
- -mt,pthread)
- AC_MSG_CHECKING([whether pthreads work with -mt -lpthread])
- PTHREAD_CFLAGS="-mt"
- PTHREAD_LIBS="-lpthread"
- ;;
-
- -*)
- AC_MSG_CHECKING([whether pthreads work with $ax_pthread_try_flag])
- PTHREAD_CFLAGS="$ax_pthread_try_flag"
- ;;
-
- pthread-config)
- AC_CHECK_PROG([ax_pthread_config], [pthread-config], [yes], [no])
- AS_IF([test "x$ax_pthread_config" = "xno"], [continue])
- PTHREAD_CFLAGS="`pthread-config --cflags`"
- PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`"
- ;;
-
- *)
- AC_MSG_CHECKING([for the pthreads library -l$ax_pthread_try_flag])
- PTHREAD_LIBS="-l$ax_pthread_try_flag"
- ;;
- esac
-
- ax_pthread_save_CFLAGS="$CFLAGS"
- ax_pthread_save_LIBS="$LIBS"
- CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
- LIBS="$PTHREAD_LIBS $LIBS"
-
- # Check for various functions. We must include pthread.h,
- # since some functions may be macros. (On the Sequent, we
- # need a special flag -Kthread to make this header compile.)
- # We check for pthread_join because it is in -lpthread on IRIX
- # while pthread_create is in libc. We check for pthread_attr_init
- # due to DEC craziness with -lpthreads. We check for
- # pthread_cleanup_push because it is one of the few pthread
- # functions on Solaris that doesn't have a non-functional libc stub.
- # We try pthread_create on general principles.
-
- AC_LINK_IFELSE([AC_LANG_PROGRAM([#include
-# if $ax_pthread_check_cond
-# error "$ax_pthread_check_macro must be defined"
-# endif
- static void routine(void *a) { a = 0; }
- static void *start_routine(void *a) { return a; }],
- [pthread_t th; pthread_attr_t attr;
- pthread_create(&th, 0, start_routine, 0);
- pthread_join(th, 0);
- pthread_attr_init(&attr);
- pthread_cleanup_push(routine, 0);
- pthread_cleanup_pop(0) /* ; */])],
- [ax_pthread_ok=yes],
- [])
-
- CFLAGS="$ax_pthread_save_CFLAGS"
- LIBS="$ax_pthread_save_LIBS"
-
- AC_MSG_RESULT([$ax_pthread_ok])
- AS_IF([test "x$ax_pthread_ok" = "xyes"], [break])
-
- PTHREAD_LIBS=""
- PTHREAD_CFLAGS=""
-done
-fi
# Various other checks:
if test "x$ax_pthread_ok" = "xyes"; then
- ax_pthread_save_CFLAGS="$CFLAGS"
- ax_pthread_save_LIBS="$LIBS"
- CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
- LIBS="$PTHREAD_LIBS $LIBS"
-
- # Detect AIX lossage: JOINABLE attribute is called UNDETACHED.
- AC_CACHE_CHECK([for joinable pthread attribute],
- [ax_cv_PTHREAD_JOINABLE_ATTR],
- [ax_cv_PTHREAD_JOINABLE_ATTR=unknown
- for ax_pthread_attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do
- AC_LINK_IFELSE([AC_LANG_PROGRAM([#include ],
- [int attr = $ax_pthread_attr; return attr /* ; */])],
- [ax_cv_PTHREAD_JOINABLE_ATTR=$ax_pthread_attr; break],
- [])
- done
- ])
- AS_IF([test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xunknown" && \
- test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xPTHREAD_CREATE_JOINABLE" && \
- test "x$ax_pthread_joinable_attr_defined" != "xyes"],
- [AC_DEFINE_UNQUOTED([PTHREAD_CREATE_JOINABLE],
- [$ax_cv_PTHREAD_JOINABLE_ATTR],
- [Define to necessary symbol if this constant
- uses a non-standard name on your system.])
- ax_pthread_joinable_attr_defined=yes
- ])
-
- AC_CACHE_CHECK([whether more special flags are required for pthreads],
- [ax_cv_PTHREAD_SPECIAL_FLAGS],
- [ax_cv_PTHREAD_SPECIAL_FLAGS=no
- case $host_os in
- solaris*)
- ax_cv_PTHREAD_SPECIAL_FLAGS="-D_POSIX_PTHREAD_SEMANTICS"
- ;;
- esac
- ])
- AS_IF([test "x$ax_cv_PTHREAD_SPECIAL_FLAGS" != "xno" && \
- test "x$ax_pthread_special_flags_added" != "xyes"],
- [PTHREAD_CFLAGS="$ax_cv_PTHREAD_SPECIAL_FLAGS $PTHREAD_CFLAGS"
- ax_pthread_special_flags_added=yes])
-
- AC_CACHE_CHECK([for PTHREAD_PRIO_INHERIT],
- [ax_cv_PTHREAD_PRIO_INHERIT],
- [AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]],
- [[int i = PTHREAD_PRIO_INHERIT;]])],
- [ax_cv_PTHREAD_PRIO_INHERIT=yes],
- [ax_cv_PTHREAD_PRIO_INHERIT=no])
- ])
- AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes" && \
- test "x$ax_pthread_prio_inherit_defined" != "xyes"],
- [AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], [1], [Have PTHREAD_PRIO_INHERIT.])
- ax_pthread_prio_inherit_defined=yes
- ])
-
- CFLAGS="$ax_pthread_save_CFLAGS"
- LIBS="$ax_pthread_save_LIBS"
-
- # More AIX lossage: compile with *_r variant
- if test "x$GCC" != "xyes"; then
- case $host_os in
- aix*)
- AS_CASE(["x/$CC"],
- [x*/c89|x*/c89_128|x*/c99|x*/c99_128|x*/cc|x*/cc128|x*/xlc|x*/xlc_v6|x*/xlc128|x*/xlc128_v6],
- [#handle absolute path differently from PATH based program lookup
- AS_CASE(["x$CC"],
- [x/*],
- [AS_IF([AS_EXECUTABLE_P([${CC}_r])],[PTHREAD_CC="${CC}_r"])],
- [AC_CHECK_PROGS([PTHREAD_CC],[${CC}_r],[$CC])])])
- ;;
- esac
- fi
+ ax_pthread_save_CFLAGS="$CFLAGS"
+ ax_pthread_save_LIBS="$LIBS"
+ CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+ LIBS="$PTHREAD_LIBS $LIBS"
+
+ # Detect AIX lossage: JOINABLE attribute is called UNDETACHED.
+ AC_CACHE_CHECK([for joinable pthread attribute],
+ [ax_cv_PTHREAD_JOINABLE_ATTR],
+ [ax_cv_PTHREAD_JOINABLE_ATTR=unknown
+ for ax_pthread_attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([#include ],
+ [int attr = $ax_pthread_attr; return attr /* ; */])],
+ [ax_cv_PTHREAD_JOINABLE_ATTR=$ax_pthread_attr; break],
+ [])
+ done
+ ])
+ AS_IF([test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xunknown" && \
+ test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xPTHREAD_CREATE_JOINABLE" && \
+ test "x$ax_pthread_joinable_attr_defined" != "xyes"],
+ [AC_DEFINE_UNQUOTED([PTHREAD_CREATE_JOINABLE],
+ [$ax_cv_PTHREAD_JOINABLE_ATTR],
+ [Define to necessary symbol if this constant
+ uses a non-standard name on your system.])
+ ax_pthread_joinable_attr_defined=yes
+ ])
+
+ AC_CACHE_CHECK([whether more special flags are required for pthreads],
+ [ax_cv_PTHREAD_SPECIAL_FLAGS],
+ [ax_cv_PTHREAD_SPECIAL_FLAGS=no
+ case $host_os in
+ solaris*)
+ ax_cv_PTHREAD_SPECIAL_FLAGS="-D_POSIX_PTHREAD_SEMANTICS"
+ ;;
+ esac
+ ])
+ AS_IF([test "x$ax_cv_PTHREAD_SPECIAL_FLAGS" != "xno" && \
+ test "x$ax_pthread_special_flags_added" != "xyes"],
+ [PTHREAD_CFLAGS="$ax_cv_PTHREAD_SPECIAL_FLAGS $PTHREAD_CFLAGS"
+ ax_pthread_special_flags_added=yes])
+
+ AC_CACHE_CHECK([for PTHREAD_PRIO_INHERIT],
+ [ax_cv_PTHREAD_PRIO_INHERIT],
+ [AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]],
+ [[int i = PTHREAD_PRIO_INHERIT;
+ return i;]])],
+ [ax_cv_PTHREAD_PRIO_INHERIT=yes],
+ [ax_cv_PTHREAD_PRIO_INHERIT=no])
+ ])
+ AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes" && \
+ test "x$ax_pthread_prio_inherit_defined" != "xyes"],
+ [AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], [1], [Have PTHREAD_PRIO_INHERIT.])
+ ax_pthread_prio_inherit_defined=yes
+ ])
+
+ CFLAGS="$ax_pthread_save_CFLAGS"
+ LIBS="$ax_pthread_save_LIBS"
+
+ # More AIX lossage: compile with *_r variant
+ if test "x$GCC" != "xyes"; then
+ case $host_os in
+ aix*)
+ AS_CASE(["x/$CC"],
+ [x*/c89|x*/c89_128|x*/c99|x*/c99_128|x*/cc|x*/cc128|x*/xlc|x*/xlc_v6|x*/xlc128|x*/xlc128_v6],
+ [#handle absolute path differently from PATH based program lookup
+ AS_CASE(["x$CC"],
+ [x/*],
+ [AS_IF([AS_EXECUTABLE_P([${CC}_r])],[PTHREAD_CC="${CC}_r"])],
+ [AC_CHECK_PROGS([PTHREAD_CC],[${CC}_r],[$CC])])])
+ ;;
+ esac
+ fi
fi
test -n "$PTHREAD_CC" || PTHREAD_CC="$CC"
@@ -475,11 +497,11 @@ AC_SUBST([PTHREAD_CC])
# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:
if test "x$ax_pthread_ok" = "xyes"; then
- ifelse([$1],,[AC_DEFINE([HAVE_PTHREAD],[1],[Define if you have POSIX threads libraries and header files.])],[$1])
- :
+ ifelse([$1],,[AC_DEFINE([HAVE_PTHREAD],[1],[Define if you have POSIX threads libraries and header files.])],[$1])
+ :
else
- ax_pthread_ok=no
- $2
+ ax_pthread_ok=no
+ $2
fi
AC_LANG_POP
])dnl AX_PTHREAD
diff --git a/objectivec/GPBMessage.m b/objectivec/GPBMessage.m
index 20ae9aee98..ee94dee8ed 100644
--- a/objectivec/GPBMessage.m
+++ b/objectivec/GPBMessage.m
@@ -82,7 +82,7 @@ static NSString *const kGPBDataCoderKey = @"GPBData";
GPBExtensionDescriptor *autocreatorExtension_;
// Message can only be mutated from one thread. But some *readonly* operations
- // modifify internal state because they autocreate things. The
+ // modify internal state because they autocreate things. The
// autocreatedExtensionMap_ is one such structure. Access during readonly
// operations is protected via this semaphore.
// NOTE: OSSpinLock may seem like a good fit here but Apple engineers have
diff --git a/php/composer.json b/php/composer.json
index abcc293b2b..28d379bdec 100644
--- a/php/composer.json
+++ b/php/composer.json
@@ -6,10 +6,10 @@
"homepage": "https://developers.google.com/protocol-buffers/",
"license": "BSD-3-Clause",
"require": {
- "php": ">=5.5.0"
+ "php": ">=7.0.0"
},
"require-dev": {
- "phpunit/phpunit": "^5|^4.8.0"
+ "phpunit/phpunit": ">=6.0.0"
},
"autoload": {
"psr-4": {
diff --git a/php/ext/google/protobuf/array.c b/php/ext/google/protobuf/array.c
index 0fa9bf0e5b..e6412c0832 100644
--- a/php/ext/google/protobuf/array.c
+++ b/php/ext/google/protobuf/array.c
@@ -453,9 +453,6 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_offsetSet, 0, 0, 2)
ZEND_ARG_INFO(0, newval)
ZEND_END_ARG_INFO()
-ZEND_BEGIN_ARG_INFO(arginfo_void, 0)
-ZEND_END_ARG_INFO()
-
static zend_function_entry repeated_field_methods[] = {
PHP_ME(RepeatedField, __construct, arginfo_construct, ZEND_ACC_PUBLIC)
PHP_ME(RepeatedField, append, arginfo_append, ZEND_ACC_PUBLIC)
@@ -636,7 +633,11 @@ void Array_ModuleInit() {
h = &RepeatedField_object_handlers;
memcpy(h, &std_object_handlers, sizeof(zend_object_handlers));
h->dtor_obj = RepeatedField_destructor;
+#if PHP_VERSION_ID < 80000
h->compare_objects = RepeatedField_compare_objects;
+#else
+ h->compare = RepeatedField_compare_objects;
+#endif
h->get_properties = RepeatedField_GetProperties;
h->get_property_ptr_ptr = RepeatedField_GetPropertyPtrPtr;
diff --git a/php/ext/google/protobuf/def.c b/php/ext/google/protobuf/def.c
index 3f7590ca44..9accb1da36 100644
--- a/php/ext/google/protobuf/def.c
+++ b/php/ext/google/protobuf/def.c
@@ -103,8 +103,8 @@ PHP_METHOD(EnumValueDescriptor, getNumber) {
}
static zend_function_entry EnumValueDescriptor_methods[] = {
- PHP_ME(EnumValueDescriptor, getName, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(EnumValueDescriptor, getNumber, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(EnumValueDescriptor, getName, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(EnumValueDescriptor, getNumber, arginfo_void, ZEND_ACC_PUBLIC)
ZEND_FE_END
};
@@ -224,9 +224,9 @@ PHP_METHOD(EnumDescriptor, getPublicDescriptor) {
}
static zend_function_entry EnumDescriptor_methods[] = {
- PHP_ME(EnumDescriptor, getPublicDescriptor, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(EnumDescriptor, getValueCount, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(EnumDescriptor, getValue, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(EnumDescriptor, getPublicDescriptor, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(EnumDescriptor, getValueCount, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(EnumDescriptor, getValue, arginfo_void, ZEND_ACC_PUBLIC)
ZEND_FE_END
};
@@ -316,9 +316,9 @@ PHP_METHOD(OneofDescriptor, getFieldCount) {
}
static zend_function_entry OneofDescriptor_methods[] = {
- PHP_ME(OneofDescriptor, getName, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(OneofDescriptor, getField, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(OneofDescriptor, getFieldCount, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(OneofDescriptor, getName, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(OneofDescriptor, getField, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(OneofDescriptor, getFieldCount, arginfo_void, ZEND_ACC_PUBLIC)
ZEND_FE_END
};
@@ -480,13 +480,13 @@ PHP_METHOD(FieldDescriptor, getMessageType) {
}
static zend_function_entry FieldDescriptor_methods[] = {
- PHP_ME(FieldDescriptor, getName, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(FieldDescriptor, getNumber, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(FieldDescriptor, getLabel, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(FieldDescriptor, getType, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(FieldDescriptor, isMap, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(FieldDescriptor, getEnumType, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(FieldDescriptor, getMessageType, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(FieldDescriptor, getName, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(FieldDescriptor, getNumber, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(FieldDescriptor, getLabel, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(FieldDescriptor, getType, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(FieldDescriptor, isMap, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(FieldDescriptor, getEnumType, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(FieldDescriptor, getMessageType, arginfo_void, ZEND_ACC_PUBLIC)
ZEND_FE_END
};
@@ -700,13 +700,13 @@ PHP_METHOD(Descriptor, getClass) {
static zend_function_entry Descriptor_methods[] = {
- PHP_ME(Descriptor, getClass, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(Descriptor, getFullName, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(Descriptor, getField, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(Descriptor, getFieldCount, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(Descriptor, getOneofDecl, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(Descriptor, getOneofDeclCount, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(Descriptor, getPublicDescriptor, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(Descriptor, getClass, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(Descriptor, getFullName, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(Descriptor, getField, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(Descriptor, getFieldCount, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(Descriptor, getOneofDecl, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(Descriptor, getOneofDeclCount, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(Descriptor, getPublicDescriptor, arginfo_void, ZEND_ACC_PUBLIC)
ZEND_FE_END
};
@@ -1000,13 +1000,18 @@ PHP_METHOD(DescriptorPool, internalAddGeneratedFile) {
upb_arena_free(arena);
}
+ZEND_BEGIN_ARG_INFO_EX(arginfo_addgeneratedfile, 0, 0, 2)
+ ZEND_ARG_INFO(0, data)
+ ZEND_ARG_INFO(0, data_len)
+ZEND_END_ARG_INFO()
+
static zend_function_entry DescriptorPool_methods[] = {
- PHP_ME(DescriptorPool, getGeneratedPool, NULL,
+ PHP_ME(DescriptorPool, getGeneratedPool, arginfo_void,
ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
- PHP_ME(DescriptorPool, getDescriptorByClassName, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(DescriptorPool, getDescriptorByProtoName, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(DescriptorPool, getEnumDescriptorByClassName, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(DescriptorPool, internalAddGeneratedFile, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(DescriptorPool, getDescriptorByClassName, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(DescriptorPool, getDescriptorByProtoName, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(DescriptorPool, getEnumDescriptorByClassName, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(DescriptorPool, internalAddGeneratedFile, arginfo_addgeneratedfile, ZEND_ACC_PUBLIC)
ZEND_FE_END
};
@@ -1034,7 +1039,7 @@ PHP_METHOD(InternalDescriptorPool, getGeneratedPool) {
}
static zend_function_entry InternalDescriptorPool_methods[] = {
- PHP_ME(InternalDescriptorPool, getGeneratedPool, NULL,
+ PHP_ME(InternalDescriptorPool, getGeneratedPool, arginfo_void,
ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
ZEND_FE_END
};
diff --git a/php/ext/google/protobuf/map.c b/php/ext/google/protobuf/map.c
index 426d56a4f9..26776e677e 100644
--- a/php/ext/google/protobuf/map.c
+++ b/php/ext/google/protobuf/map.c
@@ -437,9 +437,6 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_offsetSet, 0, 0, 2)
ZEND_ARG_INFO(0, newval)
ZEND_END_ARG_INFO()
-ZEND_BEGIN_ARG_INFO(arginfo_void, 0)
-ZEND_END_ARG_INFO()
-
static zend_function_entry MapField_methods[] = {
PHP_ME(MapField, __construct, arginfo_construct, ZEND_ACC_PUBLIC)
PHP_ME(MapField, offsetExists, arginfo_offsetGet, ZEND_ACC_PUBLIC)
@@ -622,7 +619,11 @@ void Map_ModuleInit() {
h = &MapField_object_handlers;
memcpy(h, &std_object_handlers, sizeof(zend_object_handlers));
h->dtor_obj = MapField_destructor;
+#if PHP_VERSION_ID < 80000
h->compare_objects = MapField_compare_objects;
+#else
+ h->compare = MapField_compare_objects;
+#endif
h->get_properties = Map_GetProperties;
h->get_property_ptr_ptr = Map_GetPropertyPtrPtr;
diff --git a/php/ext/google/protobuf/message.c b/php/ext/google/protobuf/message.c
index f15b8ac1b4..0e61770eef 100644
--- a/php/ext/google/protobuf/message.c
+++ b/php/ext/google/protobuf/message.c
@@ -968,6 +968,10 @@ PHP_METHOD(Message, readOneof) {
(int)field_num);
}
+ if (upb_fielddef_issubmsg(f) && !upb_msg_has(intern->msg, f)) {
+ RETURN_NULL();
+ }
+
{
upb_msgval msgval = upb_msg_get(intern->msg, f);
const Descriptor *subdesc = Descriptor_GetFromFieldDef(f);
@@ -1021,9 +1025,6 @@ PHP_METHOD(Message, writeOneof) {
upb_msg_set(intern->msg, f, msgval, arena);
}
-ZEND_BEGIN_ARG_INFO_EX(arginfo_void, 0, 0, 0)
-ZEND_END_ARG_INFO()
-
ZEND_BEGIN_ARG_INFO_EX(arginfo_mergeFrom, 0, 0, 1)
ZEND_ARG_INFO(0, data)
ZEND_END_ARG_INFO()
@@ -1106,7 +1107,7 @@ PHP_METHOD(google_protobuf_Any, unpack) {
if (!TryStripUrlPrefix(&type_url)) {
zend_throw_exception(
NULL, "Type url needs to be type.googleapis.com/fully-qualified",
- 0 TSRMLS_CC);
+ 0);
return;
}
@@ -1115,7 +1116,7 @@ PHP_METHOD(google_protobuf_Any, unpack) {
if (m == NULL) {
zend_throw_exception(
NULL, "Specified message in any hasn't been added to descriptor pool",
- 0 TSRMLS_CC);
+ 0);
return;
}
@@ -1149,7 +1150,7 @@ PHP_METHOD(google_protobuf_Any, pack) {
const char *full_name;
char *buf;
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &val) ==
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "o", &val) ==
FAILURE) {
return;
}
@@ -1182,7 +1183,7 @@ PHP_METHOD(google_protobuf_Any, is) {
zend_class_entry *klass = NULL;
const upb_msgdef *m;
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "C", &klass) ==
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "C", &klass) ==
FAILURE) {
return;
}
@@ -1209,7 +1210,7 @@ PHP_METHOD(google_protobuf_Timestamp, fromDateTime) {
return;
}
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &datetime,
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &datetime,
date_interface_ce) == FAILURE) {
zend_error(E_USER_ERROR, "Expect DatetimeInterface.");
return;
@@ -1326,7 +1327,11 @@ void Message_ModuleInit() {
memcpy(h, &std_object_handlers, sizeof(zend_object_handlers));
h->dtor_obj = Message_dtor;
+#if PHP_VERSION_ID < 80000
h->compare_objects = Message_compare_objects;
+#else
+ h->compare = Message_compare_objects;
+#endif
h->read_property = Message_read_property;
h->write_property = Message_write_property;
h->has_property = Message_has_property;
diff --git a/php/ext/google/protobuf/protobuf.c b/php/ext/google/protobuf/protobuf.c
index 761eeeb532..dbdd22a8f6 100644
--- a/php/ext/google/protobuf/protobuf.c
+++ b/php/ext/google/protobuf/protobuf.c
@@ -297,6 +297,7 @@ static PHP_MINIT_FUNCTION(protobuf) {
}
static PHP_MSHUTDOWN_FUNCTION(protobuf) {
+ UNREGISTER_INI_ENTRIES();
return SUCCESS;
}
diff --git a/php/ext/google/protobuf/protobuf.h b/php/ext/google/protobuf/protobuf.h
index fe0b5a7147..322567ec70 100644
--- a/php/ext/google/protobuf/protobuf.h
+++ b/php/ext/google/protobuf/protobuf.h
@@ -69,6 +69,13 @@ const zval *get_generated_pool();
#define PROTO_STRLEN_P(obj) ZSTR_LEN(obj)
#endif
+ZEND_BEGIN_ARG_INFO(arginfo_void, 0)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_setter, 0, 0, 1)
+ ZEND_ARG_INFO(0, value)
+ZEND_END_ARG_INFO()
+
#define PHP_PROTOBUF_VERSION "3.14.0"
// ptr -> PHP object cache. This is a weak map that caches lazily-created
diff --git a/php/ext/google/protobuf/wkt.inc b/php/ext/google/protobuf/wkt.inc
index 573ff30c14..401f2e825b 100644
--- a/php/ext/google/protobuf/wkt.inc
+++ b/php/ext/google/protobuf/wkt.inc
@@ -37,7 +37,7 @@ static PHP_METHOD(GPBMetadata_Google_Protobuf_Any, initOnce) {
}
static zend_function_entry GPBMetadata_Google_Protobuf_Any_methods[] = {
- PHP_ME(GPBMetadata_Google_Protobuf_Any, initOnce, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
+ PHP_ME(GPBMetadata_Google_Protobuf_Any, initOnce, arginfo_void, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
ZEND_FE_END
};
@@ -103,15 +103,19 @@ static PHP_METHOD(google_protobuf_Any, setValue) {
RETURN_ZVAL(getThis(), 1, 0);
}
+ZEND_BEGIN_ARG_INFO_EX(arginfo_is, 0, 0, 1)
+ ZEND_ARG_INFO(0, proto)
+ZEND_END_ARG_INFO()
+
static zend_function_entry google_protobuf_Any_phpmethods[] = {
- PHP_ME(google_protobuf_Any, __construct, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Any, getTypeUrl, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Any, setTypeUrl, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Any, getValue, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Any, setValue, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Any, is, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Any, pack, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Any, unpack, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Any, __construct, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Any, getTypeUrl, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Any, setTypeUrl, arginfo_setter, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Any, getValue, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Any, setValue, arginfo_setter, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Any, is, arginfo_is, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Any, pack, arginfo_setter, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Any, unpack, arginfo_void, ZEND_ACC_PUBLIC)
ZEND_FE_END
};
@@ -178,7 +182,7 @@ static PHP_METHOD(GPBMetadata_Google_Protobuf_Api, initOnce) {
}
static zend_function_entry GPBMetadata_Google_Protobuf_Api_methods[] = {
- PHP_ME(GPBMetadata_Google_Protobuf_Api, initOnce, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
+ PHP_ME(GPBMetadata_Google_Protobuf_Api, initOnce, arginfo_void, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
ZEND_FE_END
};
@@ -355,21 +359,21 @@ static PHP_METHOD(google_protobuf_Api, setSyntax) {
}
static zend_function_entry google_protobuf_Api_phpmethods[] = {
- PHP_ME(google_protobuf_Api, __construct, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Api, getName, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Api, setName, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Api, getMethods, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Api, setMethods, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Api, getOptions, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Api, setOptions, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Api, getVersion, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Api, setVersion, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Api, getSourceContext, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Api, setSourceContext, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Api, getMixins, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Api, setMixins, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Api, getSyntax, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Api, setSyntax, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Api, __construct, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Api, getName, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Api, setName, arginfo_setter, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Api, getMethods, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Api, setMethods, arginfo_setter, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Api, getOptions, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Api, setOptions, arginfo_setter, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Api, getVersion, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Api, setVersion, arginfo_setter, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Api, getSourceContext, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Api, setSourceContext, arginfo_setter, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Api, getMixins, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Api, setMixins, arginfo_setter, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Api, getSyntax, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Api, setSyntax, arginfo_setter, ZEND_ACC_PUBLIC)
ZEND_FE_END
};
@@ -549,21 +553,21 @@ static PHP_METHOD(google_protobuf_Method, setSyntax) {
}
static zend_function_entry google_protobuf_Method_phpmethods[] = {
- PHP_ME(google_protobuf_Method, __construct, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Method, getName, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Method, setName, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Method, getRequestTypeUrl, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Method, setRequestTypeUrl, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Method, getRequestStreaming, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Method, setRequestStreaming, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Method, getResponseTypeUrl, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Method, setResponseTypeUrl, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Method, getResponseStreaming, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Method, setResponseStreaming, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Method, getOptions, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Method, setOptions, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Method, getSyntax, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Method, setSyntax, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Method, __construct, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Method, getName, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Method, setName, arginfo_setter, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Method, getRequestTypeUrl, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Method, setRequestTypeUrl, arginfo_setter, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Method, getRequestStreaming, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Method, setRequestStreaming, arginfo_setter, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Method, getResponseTypeUrl, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Method, setResponseTypeUrl, arginfo_setter, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Method, getResponseStreaming, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Method, setResponseStreaming, arginfo_setter, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Method, getOptions, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Method, setOptions, arginfo_setter, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Method, getSyntax, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Method, setSyntax, arginfo_setter, ZEND_ACC_PUBLIC)
ZEND_FE_END
};
@@ -633,11 +637,11 @@ static PHP_METHOD(google_protobuf_Mixin, setRoot) {
}
static zend_function_entry google_protobuf_Mixin_phpmethods[] = {
- PHP_ME(google_protobuf_Mixin, __construct, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Mixin, getName, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Mixin, setName, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Mixin, getRoot, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Mixin, setRoot, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Mixin, __construct, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Mixin, getName, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Mixin, setName, arginfo_setter, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Mixin, getRoot, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Mixin, setRoot, arginfo_setter, ZEND_ACC_PUBLIC)
ZEND_FE_END
};
@@ -681,7 +685,7 @@ static PHP_METHOD(GPBMetadata_Google_Protobuf_Duration, initOnce) {
}
static zend_function_entry GPBMetadata_Google_Protobuf_Duration_methods[] = {
- PHP_ME(GPBMetadata_Google_Protobuf_Duration, initOnce, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
+ PHP_ME(GPBMetadata_Google_Protobuf_Duration, initOnce, arginfo_void, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
ZEND_FE_END
};
@@ -748,11 +752,11 @@ static PHP_METHOD(google_protobuf_Duration, setNanos) {
}
static zend_function_entry google_protobuf_Duration_phpmethods[] = {
- PHP_ME(google_protobuf_Duration, __construct, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Duration, getSeconds, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Duration, setSeconds, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Duration, getNanos, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Duration, setNanos, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Duration, __construct, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Duration, getSeconds, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Duration, setSeconds, arginfo_setter, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Duration, getNanos, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Duration, setNanos, arginfo_setter, ZEND_ACC_PUBLIC)
ZEND_FE_END
};
@@ -794,7 +798,7 @@ static PHP_METHOD(GPBMetadata_Google_Protobuf_GPBEmpty, initOnce) {
}
static zend_function_entry GPBMetadata_Google_Protobuf_GPBEmpty_methods[] = {
- PHP_ME(GPBMetadata_Google_Protobuf_GPBEmpty, initOnce, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
+ PHP_ME(GPBMetadata_Google_Protobuf_GPBEmpty, initOnce, arginfo_void, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
ZEND_FE_END
};
@@ -817,7 +821,7 @@ static PHP_METHOD(google_protobuf_Empty, __construct) {
}
static zend_function_entry google_protobuf_Empty_phpmethods[] = {
- PHP_ME(google_protobuf_Empty, __construct, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Empty, __construct, arginfo_void, ZEND_ACC_PUBLIC)
ZEND_FE_END
};
@@ -860,7 +864,7 @@ static PHP_METHOD(GPBMetadata_Google_Protobuf_FieldMask, initOnce) {
}
static zend_function_entry GPBMetadata_Google_Protobuf_FieldMask_methods[] = {
- PHP_ME(GPBMetadata_Google_Protobuf_FieldMask, initOnce, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
+ PHP_ME(GPBMetadata_Google_Protobuf_FieldMask, initOnce, arginfo_void, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
ZEND_FE_END
};
@@ -905,9 +909,9 @@ static PHP_METHOD(google_protobuf_FieldMask, setPaths) {
}
static zend_function_entry google_protobuf_FieldMask_phpmethods[] = {
- PHP_ME(google_protobuf_FieldMask, __construct, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_FieldMask, getPaths, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_FieldMask, setPaths, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_FieldMask, __construct, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_FieldMask, getPaths, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_FieldMask, setPaths, arginfo_setter, ZEND_ACC_PUBLIC)
ZEND_FE_END
};
@@ -951,7 +955,7 @@ static PHP_METHOD(GPBMetadata_Google_Protobuf_SourceContext, initOnce) {
}
static zend_function_entry GPBMetadata_Google_Protobuf_SourceContext_methods[] = {
- PHP_ME(GPBMetadata_Google_Protobuf_SourceContext, initOnce, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
+ PHP_ME(GPBMetadata_Google_Protobuf_SourceContext, initOnce, arginfo_void, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
ZEND_FE_END
};
@@ -996,9 +1000,9 @@ static PHP_METHOD(google_protobuf_SourceContext, setFileName) {
}
static zend_function_entry google_protobuf_SourceContext_phpmethods[] = {
- PHP_ME(google_protobuf_SourceContext, __construct, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_SourceContext, getFileName, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_SourceContext, setFileName, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_SourceContext, __construct, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_SourceContext, getFileName, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_SourceContext, setFileName, arginfo_setter, ZEND_ACC_PUBLIC)
ZEND_FE_END
};
@@ -1058,7 +1062,7 @@ static PHP_METHOD(GPBMetadata_Google_Protobuf_Struct, initOnce) {
}
static zend_function_entry GPBMetadata_Google_Protobuf_Struct_methods[] = {
- PHP_ME(GPBMetadata_Google_Protobuf_Struct, initOnce, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
+ PHP_ME(GPBMetadata_Google_Protobuf_Struct, initOnce, arginfo_void, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
ZEND_FE_END
};
@@ -1103,9 +1107,9 @@ static PHP_METHOD(google_protobuf_Struct, setFields) {
}
static zend_function_entry google_protobuf_Struct_phpmethods[] = {
- PHP_ME(google_protobuf_Struct, __construct, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Struct, getFields, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Struct, setFields, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Struct, __construct, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Struct, getFields, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Struct, setFields, arginfo_setter, ZEND_ACC_PUBLIC)
ZEND_FE_END
};
@@ -1175,11 +1179,11 @@ static PHP_METHOD(google_protobuf_Struct_FieldsEntry, setValue) {
}
static zend_function_entry google_protobuf_Struct_FieldsEntry_phpmethods[] = {
- PHP_ME(google_protobuf_Struct_FieldsEntry, __construct, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Struct_FieldsEntry, getKey, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Struct_FieldsEntry, setKey, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Struct_FieldsEntry, getValue, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Struct_FieldsEntry, setValue, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Struct_FieldsEntry, __construct, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Struct_FieldsEntry, getKey, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Struct_FieldsEntry, setKey, arginfo_setter, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Struct_FieldsEntry, getValue, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Struct_FieldsEntry, setValue, arginfo_setter, ZEND_ACC_PUBLIC)
ZEND_FE_END
};
@@ -1344,20 +1348,20 @@ static PHP_METHOD(google_protobuf_Value, getKind) {
RETURN_STRING(field ? upb_fielddef_name(field) : "");
}
static zend_function_entry google_protobuf_Value_phpmethods[] = {
- PHP_ME(google_protobuf_Value, __construct, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Value, getNullValue, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Value, setNullValue, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Value, getNumberValue, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Value, setNumberValue, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Value, getStringValue, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Value, setStringValue, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Value, getBoolValue, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Value, setBoolValue, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Value, getStructValue, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Value, setStructValue, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Value, getListValue, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Value, setListValue, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Value, getKind, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Value, __construct, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Value, getNullValue, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Value, setNullValue, arginfo_setter, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Value, getNumberValue, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Value, setNumberValue, arginfo_setter, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Value, getStringValue, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Value, setStringValue, arginfo_setter, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Value, getBoolValue, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Value, setBoolValue, arginfo_setter, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Value, getStructValue, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Value, setStructValue, arginfo_setter, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Value, getListValue, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Value, setListValue, arginfo_setter, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Value, getKind, arginfo_void, ZEND_ACC_PUBLIC)
ZEND_FE_END
};
@@ -1405,9 +1409,9 @@ static PHP_METHOD(google_protobuf_ListValue, setValues) {
}
static zend_function_entry google_protobuf_ListValue_phpmethods[] = {
- PHP_ME(google_protobuf_ListValue, __construct, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_ListValue, getValues, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_ListValue, setValues, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_ListValue, __construct, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_ListValue, getValues, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_ListValue, setValues, arginfo_setter, ZEND_ACC_PUBLIC)
ZEND_FE_END
};
@@ -1433,7 +1437,7 @@ PHP_METHOD(google_protobuf_NullValue, name) {
const upb_enumdef *e = upb_symtab_lookupenum(symtab, "google.protobuf.NullValue");
const char *name;
zend_long value;
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &value) ==
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &value) ==
FAILURE) {
return;
}
@@ -1455,7 +1459,7 @@ PHP_METHOD(google_protobuf_NullValue, value) {
char *name = NULL;
size_t name_len;
int32_t num;
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name,
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &name,
&name_len) == FAILURE) {
return;
}
@@ -1470,8 +1474,8 @@ PHP_METHOD(google_protobuf_NullValue, value) {
}
static zend_function_entry google_protobuf_NullValue_phpmethods[] = {
- PHP_ME(google_protobuf_NullValue, name, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
- PHP_ME(google_protobuf_NullValue, value, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
+ PHP_ME(google_protobuf_NullValue, name, arginfo_void, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
+ PHP_ME(google_protobuf_NullValue, value, arginfo_void, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
ZEND_FE_END
};
@@ -1570,7 +1574,7 @@ static PHP_METHOD(GPBMetadata_Google_Protobuf_Type, initOnce) {
}
static zend_function_entry GPBMetadata_Google_Protobuf_Type_methods[] = {
- PHP_ME(GPBMetadata_Google_Protobuf_Type, initOnce, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
+ PHP_ME(GPBMetadata_Google_Protobuf_Type, initOnce, arginfo_void, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
ZEND_FE_END
};
@@ -1725,19 +1729,19 @@ static PHP_METHOD(google_protobuf_Type, setSyntax) {
}
static zend_function_entry google_protobuf_Type_phpmethods[] = {
- PHP_ME(google_protobuf_Type, __construct, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Type, getName, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Type, setName, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Type, getFields, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Type, setFields, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Type, getOneofs, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Type, setOneofs, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Type, getOptions, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Type, setOptions, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Type, getSourceContext, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Type, setSourceContext, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Type, getSyntax, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Type, setSyntax, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Type, __construct, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Type, getName, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Type, setName, arginfo_setter, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Type, getFields, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Type, setFields, arginfo_setter, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Type, getOneofs, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Type, setOneofs, arginfo_setter, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Type, getOptions, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Type, setOptions, arginfo_setter, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Type, getSourceContext, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Type, setSourceContext, arginfo_setter, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Type, getSyntax, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Type, setSyntax, arginfo_setter, ZEND_ACC_PUBLIC)
ZEND_FE_END
};
@@ -1983,27 +1987,27 @@ static PHP_METHOD(google_protobuf_Field, setDefaultValue) {
}
static zend_function_entry google_protobuf_Field_phpmethods[] = {
- PHP_ME(google_protobuf_Field, __construct, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Field, getKind, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Field, setKind, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Field, getCardinality, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Field, setCardinality, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Field, getNumber, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Field, setNumber, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Field, getName, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Field, setName, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Field, getTypeUrl, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Field, setTypeUrl, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Field, getOneofIndex, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Field, setOneofIndex, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Field, getPacked, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Field, setPacked, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Field, getOptions, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Field, setOptions, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Field, getJsonName, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Field, setJsonName, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Field, getDefaultValue, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Field, setDefaultValue, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Field, __construct, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Field, getKind, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Field, setKind, arginfo_setter, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Field, getCardinality, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Field, setCardinality, arginfo_setter, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Field, getNumber, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Field, setNumber, arginfo_setter, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Field, getName, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Field, setName, arginfo_setter, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Field, getTypeUrl, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Field, setTypeUrl, arginfo_setter, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Field, getOneofIndex, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Field, setOneofIndex, arginfo_setter, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Field, getPacked, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Field, setPacked, arginfo_setter, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Field, getOptions, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Field, setOptions, arginfo_setter, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Field, getJsonName, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Field, setJsonName, arginfo_setter, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Field, getDefaultValue, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Field, setDefaultValue, arginfo_setter, ZEND_ACC_PUBLIC)
ZEND_FE_END
};
@@ -2029,7 +2033,7 @@ PHP_METHOD(google_protobuf_Field_Kind, name) {
const upb_enumdef *e = upb_symtab_lookupenum(symtab, "google.protobuf.Field.Kind");
const char *name;
zend_long value;
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &value) ==
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &value) ==
FAILURE) {
return;
}
@@ -2051,7 +2055,7 @@ PHP_METHOD(google_protobuf_Field_Kind, value) {
char *name = NULL;
size_t name_len;
int32_t num;
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name,
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &name,
&name_len) == FAILURE) {
return;
}
@@ -2066,8 +2070,8 @@ PHP_METHOD(google_protobuf_Field_Kind, value) {
}
static zend_function_entry google_protobuf_Field_Kind_phpmethods[] = {
- PHP_ME(google_protobuf_Field_Kind, name, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
- PHP_ME(google_protobuf_Field_Kind, value, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
+ PHP_ME(google_protobuf_Field_Kind, name, arginfo_void, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
+ PHP_ME(google_protobuf_Field_Kind, value, arginfo_void, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
ZEND_FE_END
};
@@ -2128,7 +2132,7 @@ PHP_METHOD(google_protobuf_Field_Cardinality, name) {
const upb_enumdef *e = upb_symtab_lookupenum(symtab, "google.protobuf.Field.Cardinality");
const char *name;
zend_long value;
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &value) ==
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &value) ==
FAILURE) {
return;
}
@@ -2150,7 +2154,7 @@ PHP_METHOD(google_protobuf_Field_Cardinality, value) {
char *name = NULL;
size_t name_len;
int32_t num;
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name,
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &name,
&name_len) == FAILURE) {
return;
}
@@ -2165,8 +2169,8 @@ PHP_METHOD(google_protobuf_Field_Cardinality, value) {
}
static zend_function_entry google_protobuf_Field_Cardinality_phpmethods[] = {
- PHP_ME(google_protobuf_Field_Cardinality, name, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
- PHP_ME(google_protobuf_Field_Cardinality, value, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
+ PHP_ME(google_protobuf_Field_Cardinality, name, arginfo_void, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
+ PHP_ME(google_protobuf_Field_Cardinality, value, arginfo_void, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
ZEND_FE_END
};
@@ -2307,17 +2311,17 @@ static PHP_METHOD(google_protobuf_Enum, setSyntax) {
}
static zend_function_entry google_protobuf_Enum_phpmethods[] = {
- PHP_ME(google_protobuf_Enum, __construct, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Enum, getName, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Enum, setName, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Enum, getEnumvalue, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Enum, setEnumvalue, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Enum, getOptions, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Enum, setOptions, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Enum, getSourceContext, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Enum, setSourceContext, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Enum, getSyntax, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Enum, setSyntax, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Enum, __construct, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Enum, getName, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Enum, setName, arginfo_setter, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Enum, getEnumvalue, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Enum, setEnumvalue, arginfo_setter, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Enum, getOptions, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Enum, setOptions, arginfo_setter, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Enum, getSourceContext, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Enum, setSourceContext, arginfo_setter, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Enum, getSyntax, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Enum, setSyntax, arginfo_setter, ZEND_ACC_PUBLIC)
ZEND_FE_END
};
@@ -2409,13 +2413,13 @@ static PHP_METHOD(google_protobuf_EnumValue, setOptions) {
}
static zend_function_entry google_protobuf_EnumValue_phpmethods[] = {
- PHP_ME(google_protobuf_EnumValue, __construct, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_EnumValue, getName, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_EnumValue, setName, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_EnumValue, getNumber, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_EnumValue, setNumber, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_EnumValue, getOptions, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_EnumValue, setOptions, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_EnumValue, __construct, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_EnumValue, getName, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_EnumValue, setName, arginfo_setter, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_EnumValue, getNumber, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_EnumValue, setNumber, arginfo_setter, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_EnumValue, getOptions, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_EnumValue, setOptions, arginfo_setter, ZEND_ACC_PUBLIC)
ZEND_FE_END
};
@@ -2485,11 +2489,11 @@ static PHP_METHOD(google_protobuf_Option, setValue) {
}
static zend_function_entry google_protobuf_Option_phpmethods[] = {
- PHP_ME(google_protobuf_Option, __construct, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Option, getName, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Option, setName, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Option, getValue, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Option, setValue, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Option, __construct, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Option, getName, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Option, setName, arginfo_setter, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Option, getValue, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Option, setValue, arginfo_setter, ZEND_ACC_PUBLIC)
ZEND_FE_END
};
@@ -2515,7 +2519,7 @@ PHP_METHOD(google_protobuf_Syntax, name) {
const upb_enumdef *e = upb_symtab_lookupenum(symtab, "google.protobuf.Syntax");
const char *name;
zend_long value;
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &value) ==
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &value) ==
FAILURE) {
return;
}
@@ -2537,7 +2541,7 @@ PHP_METHOD(google_protobuf_Syntax, value) {
char *name = NULL;
size_t name_len;
int32_t num;
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name,
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &name,
&name_len) == FAILURE) {
return;
}
@@ -2552,8 +2556,8 @@ PHP_METHOD(google_protobuf_Syntax, value) {
}
static zend_function_entry google_protobuf_Syntax_phpmethods[] = {
- PHP_ME(google_protobuf_Syntax, name, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
- PHP_ME(google_protobuf_Syntax, value, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
+ PHP_ME(google_protobuf_Syntax, name, arginfo_void, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
+ PHP_ME(google_protobuf_Syntax, value, arginfo_void, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
ZEND_FE_END
};
@@ -2598,7 +2602,7 @@ static PHP_METHOD(GPBMetadata_Google_Protobuf_Timestamp, initOnce) {
}
static zend_function_entry GPBMetadata_Google_Protobuf_Timestamp_methods[] = {
- PHP_ME(GPBMetadata_Google_Protobuf_Timestamp, initOnce, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
+ PHP_ME(GPBMetadata_Google_Protobuf_Timestamp, initOnce, arginfo_void, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
ZEND_FE_END
};
@@ -2664,14 +2668,18 @@ static PHP_METHOD(google_protobuf_Timestamp, setNanos) {
RETURN_ZVAL(getThis(), 1, 0);
}
+ZEND_BEGIN_ARG_INFO_EX(arginfo_timestamp_fromdatetime, 0, 0, 1)
+ ZEND_ARG_INFO(0, datetime)
+ZEND_END_ARG_INFO()
+
static zend_function_entry google_protobuf_Timestamp_phpmethods[] = {
- PHP_ME(google_protobuf_Timestamp, __construct, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Timestamp, getSeconds, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Timestamp, setSeconds, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Timestamp, getNanos, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Timestamp, setNanos, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Timestamp, fromDateTime, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Timestamp, toDateTime, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Timestamp, __construct, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Timestamp, getSeconds, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Timestamp, setSeconds, arginfo_setter, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Timestamp, getNanos, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Timestamp, setNanos, arginfo_setter, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Timestamp, fromDateTime, arginfo_timestamp_fromdatetime, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Timestamp, toDateTime, arginfo_void, ZEND_ACC_PUBLIC)
ZEND_FE_END
};
@@ -2724,7 +2732,7 @@ static PHP_METHOD(GPBMetadata_Google_Protobuf_Wrappers, initOnce) {
}
static zend_function_entry GPBMetadata_Google_Protobuf_Wrappers_methods[] = {
- PHP_ME(GPBMetadata_Google_Protobuf_Wrappers, initOnce, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
+ PHP_ME(GPBMetadata_Google_Protobuf_Wrappers, initOnce, arginfo_void, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
ZEND_FE_END
};
@@ -2769,9 +2777,9 @@ static PHP_METHOD(google_protobuf_DoubleValue, setValue) {
}
static zend_function_entry google_protobuf_DoubleValue_phpmethods[] = {
- PHP_ME(google_protobuf_DoubleValue, __construct, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_DoubleValue, getValue, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_DoubleValue, setValue, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_DoubleValue, __construct, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_DoubleValue, getValue, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_DoubleValue, setValue, arginfo_setter, ZEND_ACC_PUBLIC)
ZEND_FE_END
};
@@ -2819,9 +2827,9 @@ static PHP_METHOD(google_protobuf_FloatValue, setValue) {
}
static zend_function_entry google_protobuf_FloatValue_phpmethods[] = {
- PHP_ME(google_protobuf_FloatValue, __construct, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_FloatValue, getValue, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_FloatValue, setValue, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_FloatValue, __construct, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_FloatValue, getValue, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_FloatValue, setValue, arginfo_setter, ZEND_ACC_PUBLIC)
ZEND_FE_END
};
@@ -2869,9 +2877,9 @@ static PHP_METHOD(google_protobuf_Int64Value, setValue) {
}
static zend_function_entry google_protobuf_Int64Value_phpmethods[] = {
- PHP_ME(google_protobuf_Int64Value, __construct, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Int64Value, getValue, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Int64Value, setValue, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Int64Value, __construct, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Int64Value, getValue, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Int64Value, setValue, arginfo_setter, ZEND_ACC_PUBLIC)
ZEND_FE_END
};
@@ -2919,9 +2927,9 @@ static PHP_METHOD(google_protobuf_UInt64Value, setValue) {
}
static zend_function_entry google_protobuf_UInt64Value_phpmethods[] = {
- PHP_ME(google_protobuf_UInt64Value, __construct, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_UInt64Value, getValue, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_UInt64Value, setValue, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_UInt64Value, __construct, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_UInt64Value, getValue, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_UInt64Value, setValue, arginfo_setter, ZEND_ACC_PUBLIC)
ZEND_FE_END
};
@@ -2969,9 +2977,9 @@ static PHP_METHOD(google_protobuf_Int32Value, setValue) {
}
static zend_function_entry google_protobuf_Int32Value_phpmethods[] = {
- PHP_ME(google_protobuf_Int32Value, __construct, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Int32Value, getValue, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_Int32Value, setValue, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Int32Value, __construct, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Int32Value, getValue, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_Int32Value, setValue, arginfo_setter, ZEND_ACC_PUBLIC)
ZEND_FE_END
};
@@ -3019,9 +3027,9 @@ static PHP_METHOD(google_protobuf_UInt32Value, setValue) {
}
static zend_function_entry google_protobuf_UInt32Value_phpmethods[] = {
- PHP_ME(google_protobuf_UInt32Value, __construct, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_UInt32Value, getValue, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_UInt32Value, setValue, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_UInt32Value, __construct, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_UInt32Value, getValue, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_UInt32Value, setValue, arginfo_setter, ZEND_ACC_PUBLIC)
ZEND_FE_END
};
@@ -3069,9 +3077,9 @@ static PHP_METHOD(google_protobuf_BoolValue, setValue) {
}
static zend_function_entry google_protobuf_BoolValue_phpmethods[] = {
- PHP_ME(google_protobuf_BoolValue, __construct, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_BoolValue, getValue, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_BoolValue, setValue, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_BoolValue, __construct, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_BoolValue, getValue, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_BoolValue, setValue, arginfo_setter, ZEND_ACC_PUBLIC)
ZEND_FE_END
};
@@ -3119,9 +3127,9 @@ static PHP_METHOD(google_protobuf_StringValue, setValue) {
}
static zend_function_entry google_protobuf_StringValue_phpmethods[] = {
- PHP_ME(google_protobuf_StringValue, __construct, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_StringValue, getValue, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_StringValue, setValue, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_StringValue, __construct, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_StringValue, getValue, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_StringValue, setValue, arginfo_setter, ZEND_ACC_PUBLIC)
ZEND_FE_END
};
@@ -3169,9 +3177,9 @@ static PHP_METHOD(google_protobuf_BytesValue, setValue) {
}
static zend_function_entry google_protobuf_BytesValue_phpmethods[] = {
- PHP_ME(google_protobuf_BytesValue, __construct, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_BytesValue, getValue, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(google_protobuf_BytesValue, setValue, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_BytesValue, __construct, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_BytesValue, getValue, arginfo_void, ZEND_ACC_PUBLIC)
+ PHP_ME(google_protobuf_BytesValue, setValue, arginfo_setter, ZEND_ACC_PUBLIC)
ZEND_FE_END
};
diff --git a/php/src/Google/Protobuf/Api.php b/php/src/Google/Protobuf/Api.php
index 773397565c..7cbb30eb42 100644
--- a/php/src/Google/Protobuf/Api.php
+++ b/php/src/Google/Protobuf/Api.php
@@ -271,7 +271,7 @@ class Api extends \Google\Protobuf\Internal\Message
* message.
*
* Generated from protobuf field
.google.protobuf.SourceContext source_context = 5;
- * @return \Google\Protobuf\SourceContext
+ * @return \Google\Protobuf\SourceContext|null
*/
public function getSourceContext()
{
diff --git a/php/src/Google/Protobuf/Enum.php b/php/src/Google/Protobuf/Enum.php
index ed5afc447f..2e0ac9987b 100644
--- a/php/src/Google/Protobuf/Enum.php
+++ b/php/src/Google/Protobuf/Enum.php
@@ -151,7 +151,7 @@ class Enum extends \Google\Protobuf\Internal\Message
* The source context.
*
* Generated from protobuf field .google.protobuf.SourceContext source_context = 4;
- * @return \Google\Protobuf\SourceContext
+ * @return \Google\Protobuf\SourceContext|null
*/
public function getSourceContext()
{
diff --git a/php/src/Google/Protobuf/Internal/DescriptorProto.php b/php/src/Google/Protobuf/Internal/DescriptorProto.php
index e0822d779b..ff308e7eeb 100644
--- a/php/src/Google/Protobuf/Internal/DescriptorProto.php
+++ b/php/src/Google/Protobuf/Internal/DescriptorProto.php
@@ -252,7 +252,7 @@ class DescriptorProto extends \Google\Protobuf\Internal\Message
/**
* Generated from protobuf field optional .google.protobuf.MessageOptions options = 7;
- * @return \Google\Protobuf\Internal\MessageOptions
+ * @return \Google\Protobuf\Internal\MessageOptions|null
*/
public function getOptions()
{
diff --git a/php/src/Google/Protobuf/Internal/DescriptorProto/ExtensionRange.php b/php/src/Google/Protobuf/Internal/DescriptorProto/ExtensionRange.php
index 1594913996..bbe4a6a84f 100644
--- a/php/src/Google/Protobuf/Internal/DescriptorProto/ExtensionRange.php
+++ b/php/src/Google/Protobuf/Internal/DescriptorProto/ExtensionRange.php
@@ -124,7 +124,7 @@ class ExtensionRange extends \Google\Protobuf\Internal\Message
/**
* Generated from protobuf field optional .google.protobuf.ExtensionRangeOptions options = 3;
- * @return \Google\Protobuf\Internal\ExtensionRangeOptions
+ * @return \Google\Protobuf\Internal\ExtensionRangeOptions|null
*/
public function getOptions()
{
diff --git a/php/src/Google/Protobuf/Internal/EnumDescriptorProto.php b/php/src/Google/Protobuf/Internal/EnumDescriptorProto.php
index 85dc246634..b9b6342829 100644
--- a/php/src/Google/Protobuf/Internal/EnumDescriptorProto.php
+++ b/php/src/Google/Protobuf/Internal/EnumDescriptorProto.php
@@ -124,7 +124,7 @@ class EnumDescriptorProto extends \Google\Protobuf\Internal\Message
/**
* Generated from protobuf field optional .google.protobuf.EnumOptions options = 3;
- * @return \Google\Protobuf\Internal\EnumOptions
+ * @return \Google\Protobuf\Internal\EnumOptions|null
*/
public function getOptions()
{
diff --git a/php/src/Google/Protobuf/Internal/EnumValueDescriptorProto.php b/php/src/Google/Protobuf/Internal/EnumValueDescriptorProto.php
index 01097b669d..eff1452eed 100644
--- a/php/src/Google/Protobuf/Internal/EnumValueDescriptorProto.php
+++ b/php/src/Google/Protobuf/Internal/EnumValueDescriptorProto.php
@@ -112,7 +112,7 @@ class EnumValueDescriptorProto extends \Google\Protobuf\Internal\Message
/**
* Generated from protobuf field optional .google.protobuf.EnumValueOptions options = 3;
- * @return \Google\Protobuf\Internal\EnumValueOptions
+ * @return \Google\Protobuf\Internal\EnumValueOptions|null
*/
public function getOptions()
{
diff --git a/php/src/Google/Protobuf/Internal/FieldDescriptorProto.php b/php/src/Google/Protobuf/Internal/FieldDescriptorProto.php
index 5c8823f8dc..94e5fe12ec 100644
--- a/php/src/Google/Protobuf/Internal/FieldDescriptorProto.php
+++ b/php/src/Google/Protobuf/Internal/FieldDescriptorProto.php
@@ -511,7 +511,7 @@ class FieldDescriptorProto extends \Google\Protobuf\Internal\Message
/**
* Generated from protobuf field optional .google.protobuf.FieldOptions options = 8;
- * @return \Google\Protobuf\Internal\FieldOptions
+ * @return \Google\Protobuf\Internal\FieldOptions|null
*/
public function getOptions()
{
diff --git a/php/src/Google/Protobuf/Internal/FileDescriptorProto.php b/php/src/Google/Protobuf/Internal/FileDescriptorProto.php
index 96e2c6a6e7..d96c7a78ec 100644
--- a/php/src/Google/Protobuf/Internal/FileDescriptorProto.php
+++ b/php/src/Google/Protobuf/Internal/FileDescriptorProto.php
@@ -371,7 +371,7 @@ class FileDescriptorProto extends \Google\Protobuf\Internal\Message
/**
* Generated from protobuf field optional .google.protobuf.FileOptions options = 8;
- * @return \Google\Protobuf\Internal\FileOptions
+ * @return \Google\Protobuf\Internal\FileOptions|null
*/
public function getOptions()
{
@@ -408,7 +408,7 @@ class FileDescriptorProto extends \Google\Protobuf\Internal\Message
* development tools.
*
* Generated from protobuf field optional .google.protobuf.SourceCodeInfo source_code_info = 9;
- * @return \Google\Protobuf\Internal\SourceCodeInfo
+ * @return \Google\Protobuf\Internal\SourceCodeInfo|null
*/
public function getSourceCodeInfo()
{
diff --git a/php/src/Google/Protobuf/Internal/GPBUtil.php b/php/src/Google/Protobuf/Internal/GPBUtil.php
index 1900e71ccc..cd65d8b7d4 100644
--- a/php/src/Google/Protobuf/Internal/GPBUtil.php
+++ b/php/src/Google/Protobuf/Internal/GPBUtil.php
@@ -168,7 +168,7 @@ class GPBUtil
public static function checkFloat(&$var)
{
if (is_float($var) || is_numeric($var)) {
- $var = floatval($var);
+ $var = unpack("f", pack("f", $var))[1];
} else {
throw new \Exception("Expect float.");
}
diff --git a/php/src/Google/Protobuf/Internal/MapField.php b/php/src/Google/Protobuf/Internal/MapField.php
index 2c66aa0c19..719fb350bd 100644
--- a/php/src/Google/Protobuf/Internal/MapField.php
+++ b/php/src/Google/Protobuf/Internal/MapField.php
@@ -129,7 +129,7 @@ class MapField implements \ArrayAccess, \IteratorAggregate, \Countable
*
* This will also be called for: $ele = $arr[$key]
*
- * @param object $key The key of the element to be fetched.
+ * @param int|bool|string $key The key of the element to be fetched.
* @return object The stored element at given key.
* @throws \ErrorException Invalid type for index.
* @throws \ErrorException Non-existing index.
diff --git a/php/src/Google/Protobuf/Internal/MethodDescriptorProto.php b/php/src/Google/Protobuf/Internal/MethodDescriptorProto.php
index e2ea8ea6c5..5814f08852 100644
--- a/php/src/Google/Protobuf/Internal/MethodDescriptorProto.php
+++ b/php/src/Google/Protobuf/Internal/MethodDescriptorProto.php
@@ -176,7 +176,7 @@ class MethodDescriptorProto extends \Google\Protobuf\Internal\Message
/**
* Generated from protobuf field optional .google.protobuf.MethodOptions options = 4;
- * @return \Google\Protobuf\Internal\MethodOptions
+ * @return \Google\Protobuf\Internal\MethodOptions|null
*/
public function getOptions()
{
diff --git a/php/src/Google/Protobuf/Internal/OneofDescriptorProto.php b/php/src/Google/Protobuf/Internal/OneofDescriptorProto.php
index 5ae36ce7d5..33cf487a8a 100644
--- a/php/src/Google/Protobuf/Internal/OneofDescriptorProto.php
+++ b/php/src/Google/Protobuf/Internal/OneofDescriptorProto.php
@@ -75,7 +75,7 @@ class OneofDescriptorProto extends \Google\Protobuf\Internal\Message
/**
* Generated from protobuf field optional .google.protobuf.OneofOptions options = 2;
- * @return \Google\Protobuf\Internal\OneofOptions
+ * @return \Google\Protobuf\Internal\OneofOptions|null
*/
public function getOptions()
{
diff --git a/php/src/Google/Protobuf/Internal/ServiceDescriptorProto.php b/php/src/Google/Protobuf/Internal/ServiceDescriptorProto.php
index 9c2cc8fc90..f60561c182 100644
--- a/php/src/Google/Protobuf/Internal/ServiceDescriptorProto.php
+++ b/php/src/Google/Protobuf/Internal/ServiceDescriptorProto.php
@@ -102,7 +102,7 @@ class ServiceDescriptorProto extends \Google\Protobuf\Internal\Message
/**
* Generated from protobuf field optional .google.protobuf.ServiceOptions options = 3;
- * @return \Google\Protobuf\Internal\ServiceOptions
+ * @return \Google\Protobuf\Internal\ServiceOptions|null
*/
public function getOptions()
{
diff --git a/php/src/Google/Protobuf/Option.php b/php/src/Google/Protobuf/Option.php
index 9b2cc6c22c..5166a08db6 100644
--- a/php/src/Google/Protobuf/Option.php
+++ b/php/src/Google/Protobuf/Option.php
@@ -97,7 +97,7 @@ class Option extends \Google\Protobuf\Internal\Message
* value using the google.protobuf.Int32Value type.
*
* Generated from protobuf field .google.protobuf.Any value = 2;
- * @return \Google\Protobuf\Any
+ * @return \Google\Protobuf\Any|null
*/
public function getValue()
{
diff --git a/php/src/Google/Protobuf/Type.php b/php/src/Google/Protobuf/Type.php
index f60686665c..3f28359273 100644
--- a/php/src/Google/Protobuf/Type.php
+++ b/php/src/Google/Protobuf/Type.php
@@ -185,7 +185,7 @@ class Type extends \Google\Protobuf\Internal\Message
* The source context.
*
* Generated from protobuf field .google.protobuf.SourceContext source_context = 5;
- * @return \Google\Protobuf\SourceContext
+ * @return \Google\Protobuf\SourceContext|null
*/
public function getSourceContext()
{
diff --git a/php/src/Google/Protobuf/Value.php b/php/src/Google/Protobuf/Value.php
index 20db3cc3e3..7bebb99884 100644
--- a/php/src/Google/Protobuf/Value.php
+++ b/php/src/Google/Protobuf/Value.php
@@ -174,7 +174,7 @@ class Value extends \Google\Protobuf\Internal\Message
* Represents a structured value.
*
* Generated from protobuf field .google.protobuf.Struct struct_value = 5;
- * @return \Google\Protobuf\Struct
+ * @return \Google\Protobuf\Struct|null
*/
public function getStructValue()
{
@@ -205,7 +205,7 @@ class Value extends \Google\Protobuf\Internal\Message
* Represents a repeated `Value`.
*
* Generated from protobuf field .google.protobuf.ListValue list_value = 6;
- * @return \Google\Protobuf\ListValue
+ * @return \Google\Protobuf\ListValue|null
*/
public function getListValue()
{
diff --git a/php/tests/ArrayTest.php b/php/tests/ArrayTest.php
index d167331364..269d11d3a2 100644
--- a/php/tests/ArrayTest.php
+++ b/php/tests/ArrayTest.php
@@ -1,5 +1,6 @@
assertEquals(1.0, $arr[0], '', MAX_FLOAT_DIFF);
+ $this->assertFloatEquals(1.0, $arr[0], MAX_FLOAT_DIFF);
$arr[] = 1.1;
- $this->assertEquals(1.1, $arr[1], '', MAX_FLOAT_DIFF);
+ $this->assertFloatEquals(1.1, $arr[1], MAX_FLOAT_DIFF);
$arr[] = '2';
- $this->assertEquals(2.0, $arr[2], '', MAX_FLOAT_DIFF);
+ $this->assertFloatEquals(2.0, $arr[2], MAX_FLOAT_DIFF);
$arr[] = '3.1';
- $this->assertEquals(3.1, $arr[3], '', MAX_FLOAT_DIFF);
+ $this->assertFloatEquals(3.1, $arr[3], MAX_FLOAT_DIFF);
$this->assertEquals(4, count($arr));
@@ -315,15 +316,15 @@ class ArrayTest extends \PHPUnit\Framework\TestCase
// Test set.
$arr[0] = 1;
- $this->assertEquals(1.0, $arr[0], '', MAX_FLOAT_DIFF);
+ $this->assertFloatEquals(1.0, $arr[0], MAX_FLOAT_DIFF);
$arr[1] = 1.1;
- $this->assertEquals(1.1, $arr[1], '', MAX_FLOAT_DIFF);
+ $this->assertFloatEquals(1.1, $arr[1], MAX_FLOAT_DIFF);
$arr[2] = '2';
- $this->assertEquals(2.0, $arr[2], '', MAX_FLOAT_DIFF);
+ $this->assertFloatEquals(2.0, $arr[2], MAX_FLOAT_DIFF);
$arr[3] = '3.1';
- $this->assertEquals(3.1, $arr[3], '', MAX_FLOAT_DIFF);
+ $this->assertFloatEquals(3.1, $arr[3], MAX_FLOAT_DIFF);
}
#########################################################
@@ -336,15 +337,15 @@ class ArrayTest extends \PHPUnit\Framework\TestCase
// Test append.
$arr[] = 1;
- $this->assertEquals(1.0, $arr[0], '', MAX_FLOAT_DIFF);
+ $this->assertFloatEquals(1.0, $arr[0], MAX_FLOAT_DIFF);
$arr[] = 1.1;
- $this->assertEquals(1.1, $arr[1], '', MAX_FLOAT_DIFF);
+ $this->assertFloatEquals(1.1, $arr[1], MAX_FLOAT_DIFF);
$arr[] = '2';
- $this->assertEquals(2.0, $arr[2], '', MAX_FLOAT_DIFF);
+ $this->assertFloatEquals(2.0, $arr[2], MAX_FLOAT_DIFF);
$arr[] = '3.1';
- $this->assertEquals(3.1, $arr[3], '', MAX_FLOAT_DIFF);
+ $this->assertFloatEquals(3.1, $arr[3], MAX_FLOAT_DIFF);
$this->assertEquals(4, count($arr));
@@ -355,15 +356,15 @@ class ArrayTest extends \PHPUnit\Framework\TestCase
// Test set.
$arr[0] = 1;
- $this->assertEquals(1.0, $arr[0], '', MAX_FLOAT_DIFF);
+ $this->assertFloatEquals(1.0, $arr[0], MAX_FLOAT_DIFF);
$arr[1] = 1.1;
- $this->assertEquals(1.1, $arr[1], '', MAX_FLOAT_DIFF);
+ $this->assertFloatEquals(1.1, $arr[1], MAX_FLOAT_DIFF);
$arr[2] = '2';
- $this->assertEquals(2.0, $arr[2], '', MAX_FLOAT_DIFF);
+ $this->assertFloatEquals(2.0, $arr[2], MAX_FLOAT_DIFF);
$arr[3] = '3.1';
- $this->assertEquals(3.1, $arr[3], '', MAX_FLOAT_DIFF);
+ $this->assertFloatEquals(3.1, $arr[3], MAX_FLOAT_DIFF);
}
#########################################################
@@ -566,6 +567,8 @@ class ArrayTest extends \PHPUnit\Framework\TestCase
$sub = new Sub(['a' => $sub]);
}
$m->setRepeatedMessage($subs);
+
+ $this->assertTrue(true);
}
#########################################################
diff --git a/php/tests/DescriptorsTest.php b/php/tests/DescriptorsTest.php
index b2c5e0144d..ca7e8f3690 100644
--- a/php/tests/DescriptorsTest.php
+++ b/php/tests/DescriptorsTest.php
@@ -205,22 +205,20 @@ class DescriptorsTest extends TestBase
$this->assertSame(self::GPBTYPE_ENUM, $mapDesc->getField(1)->getType());
}
- /**
- * @expectedException \Exception
- */
public function testFieldDescriptorEnumException()
{
+ $this->expectException(Exception::class);
+
$pool = DescriptorPool::getGeneratedPool();
$desc = $pool->getDescriptorByClassName(get_class(new TestDescriptorsMessage()));
$fieldDesc = $desc->getField(0);
$fieldDesc->getEnumType();
}
- /**
- * @expectedException \Exception
- */
public function testFieldDescriptorMessageException()
{
+ $this->expectException(Exception::class);
+
$pool = DescriptorPool::getGeneratedPool();
$desc = $pool->getDescriptorByClassName(get_class(new TestDescriptorsMessage()));
$fieldDesc = $desc->getField(0);
diff --git a/php/tests/EncodeDecodeTest.php b/php/tests/EncodeDecodeTest.php
index cea1e6a47f..6368a188a4 100644
--- a/php/tests/EncodeDecodeTest.php
+++ b/php/tests/EncodeDecodeTest.php
@@ -212,7 +212,7 @@ class EncodeDecodeTest extends TestBase
public function generateRandomString($length = 10) {
$randomString = str_repeat("+", $length);
for ($i = 0; $i < $length; $i++) {
- $randomString[$i] = rand(0, 255);
+ $randomString[$i] = chr(rand(0, 255));
}
return $randomString;
}
@@ -529,200 +529,178 @@ class EncodeDecodeTest extends TestBase
$this->assertSame("", $data);
}
- /**
- * @expectedException Exception
- */
public function testDecodeInvalidInt32()
{
+ $this->expectException(Exception::class);
+
$m = new TestMessage();
$m->mergeFromString(hex2bin('08'));
}
- /**
- * @expectedException Exception
- */
public function testDecodeInvalidSubMessage()
{
+ $this->expectException(Exception::class);
+
$m = new TestMessage();
$m->mergeFromString(hex2bin('9A010108'));
}
- /**
- * @expectedException Exception
- */
public function testDecodeInvalidInt64()
{
+ $this->expectException(Exception::class);
+
$m = new TestMessage();
$m->mergeFromString(hex2bin('10'));
}
- /**
- * @expectedException Exception
- */
public function testDecodeInvalidUInt32()
{
+ $this->expectException(Exception::class);
+
$m = new TestMessage();
$m->mergeFromString(hex2bin('18'));
}
- /**
- * @expectedException Exception
- */
public function testDecodeInvalidUInt64()
{
+ $this->expectException(Exception::class);
+
$m = new TestMessage();
$m->mergeFromString(hex2bin('20'));
}
- /**
- * @expectedException Exception
- */
public function testDecodeInvalidSInt32()
{
+ $this->expectException(Exception::class);
+
$m = new TestMessage();
$m->mergeFromString(hex2bin('28'));
}
- /**
- * @expectedException Exception
- */
public function testDecodeInvalidSInt64()
{
+ $this->expectException(Exception::class);
+
$m = new TestMessage();
$m->mergeFromString(hex2bin('30'));
}
- /**
- * @expectedException Exception
- */
public function testDecodeInvalidFixed32()
{
+ $this->expectException(Exception::class);
+
$m = new TestMessage();
$m->mergeFromString(hex2bin('3D'));
}
- /**
- * @expectedException Exception
- */
public function testDecodeInvalidFixed64()
{
+ $this->expectException(Exception::class);
+
$m = new TestMessage();
$m->mergeFromString(hex2bin('41'));
}
- /**
- * @expectedException Exception
- */
public function testDecodeInvalidSFixed32()
{
+ $this->expectException(Exception::class);
+
$m = new TestMessage();
$m->mergeFromString(hex2bin('4D'));
}
- /**
- * @expectedException Exception
- */
public function testDecodeInvalidSFixed64()
{
+ $this->expectException(Exception::class);
+
$m = new TestMessage();
$m->mergeFromString(hex2bin('51'));
}
- /**
- * @expectedException Exception
- */
public function testDecodeInvalidFloat()
{
+ $this->expectException(Exception::class);
+
$m = new TestMessage();
$m->mergeFromString(hex2bin('5D'));
}
- /**
- * @expectedException Exception
- */
public function testDecodeInvalidDouble()
{
+ $this->expectException(Exception::class);
+
$m = new TestMessage();
$m->mergeFromString(hex2bin('61'));
}
- /**
- * @expectedException Exception
- */
public function testDecodeInvalidBool()
{
+ $this->expectException(Exception::class);
+
$m = new TestMessage();
$m->mergeFromString(hex2bin('68'));
}
- /**
- * @expectedException Exception
- */
public function testDecodeInvalidStringLengthMiss()
{
+ $this->expectException(Exception::class);
+
$m = new TestMessage();
$m->mergeFromString(hex2bin('72'));
}
- /**
- * @expectedException Exception
- */
public function testDecodeInvalidStringDataMiss()
{
+ $this->expectException(Exception::class);
+
$m = new TestMessage();
$m->mergeFromString(hex2bin('7201'));
}
- /**
- * @expectedException Exception
- */
public function testDecodeInvalidBytesLengthMiss()
{
+ $this->expectException(Exception::class);
+
$m = new TestMessage();
$m->mergeFromString(hex2bin('7A'));
}
- /**
- * @expectedException Exception
- */
public function testDecodeInvalidBytesDataMiss()
{
+ $this->expectException(Exception::class);
+
$m = new TestMessage();
$m->mergeFromString(hex2bin('7A01'));
}
- /**
- * @expectedException Exception
- */
public function testDecodeInvalidEnum()
{
+ $this->expectException(Exception::class);
+
$m = new TestMessage();
$m->mergeFromString(hex2bin('8001'));
}
- /**
- * @expectedException Exception
- */
public function testDecodeInvalidMessageLengthMiss()
{
+ $this->expectException(Exception::class);
+
$m = new TestMessage();
$m->mergeFromString(hex2bin('8A01'));
}
- /**
- * @expectedException Exception
- */
public function testDecodeInvalidMessageDataMiss()
{
+ $this->expectException(Exception::class);
+
$m = new TestMessage();
$m->mergeFromString(hex2bin('8A0101'));
}
- /**
- * @expectedException Exception
- */
public function testDecodeInvalidPackedMessageLength()
{
+ $this->expectException(Exception::class);
+
$m = new TestPackedMessage();
$m->mergeFromString(hex2bin('D205'));
}
@@ -1143,11 +1121,10 @@ class EncodeDecodeTest extends TestBase
$this->assertSame("0801", bin2hex($m1->getAny()->getValue()));
}
- /**
- * @expectedException Exception
- */
public function testDecodeAnyWithUnknownPacked()
{
+ $this->expectException(Exception::class);
+
$m = new TestAny();
$m->mergeFromJsonString(
"{\"any\":" .
diff --git a/php/tests/GeneratedClassTest.php b/php/tests/GeneratedClassTest.php
index 037bd1be9c..f3f74d1d3c 100644
--- a/php/tests/GeneratedClassTest.php
+++ b/php/tests/GeneratedClassTest.php
@@ -260,21 +260,21 @@ class GeneratedClassTest extends TestBase
$this->assertEquals(1, TestEnum::value('ONE'));
}
- /**
- * @expectedException UnexpectedValueException
- * @expectedExceptionMessage Enum Foo\TestEnum has no name defined for value -1
- */
public function testInvalidEnumValueThrowsException()
{
+ $this->expectException(UnexpectedValueException::class);
+ $this->expectExceptionMessage(
+ 'Enum Foo\TestEnum has no name defined for value -1');
+
TestEnum::name(-1);
}
- /**
- * @expectedException UnexpectedValueException
- * @expectedExceptionMessage Enum Foo\TestEnum has no value defined for name DOES_NOT_EXIST
- */
public function testInvalidEnumNameThrowsException()
{
+ $this->expectException(UnexpectedValueException::class);
+ $this->expectExceptionMessage(
+ 'Enum Foo\TestEnum has no value defined for name DOES_NOT_EXIST');
+
TestEnum::value('DOES_NOT_EXIST');
}
@@ -313,17 +313,17 @@ class GeneratedClassTest extends TestBase
// Set integer.
$m->setOptionalFloat(1);
- $this->assertEquals(1.0, $m->getOptionalFloat(), '', MAX_FLOAT_DIFF);
+ $this->assertFloatEquals(1.0, $m->getOptionalFloat(), MAX_FLOAT_DIFF);
// Set float.
$m->setOptionalFloat(1.1);
- $this->assertEquals(1.1, $m->getOptionalFloat(), '', MAX_FLOAT_DIFF);
+ $this->assertFloatEquals(1.1, $m->getOptionalFloat(), MAX_FLOAT_DIFF);
// Set string.
$m->setOptionalFloat('2');
- $this->assertEquals(2.0, $m->getOptionalFloat(), '', MAX_FLOAT_DIFF);
+ $this->assertFloatEquals(2.0, $m->getOptionalFloat(), MAX_FLOAT_DIFF);
$m->setOptionalFloat('3.1');
- $this->assertEquals(3.1, $m->getOptionalFloat(), '', MAX_FLOAT_DIFF);
+ $this->assertFloatEquals(3.1, $m->getOptionalFloat(), MAX_FLOAT_DIFF);
}
#########################################################
@@ -336,17 +336,17 @@ class GeneratedClassTest extends TestBase
// Set integer.
$m->setOptionalDouble(1);
- $this->assertEquals(1.0, $m->getOptionalDouble(), '', MAX_FLOAT_DIFF);
+ $this->assertFloatEquals(1.0, $m->getOptionalDouble(), MAX_FLOAT_DIFF);
// Set float.
$m->setOptionalDouble(1.1);
- $this->assertEquals(1.1, $m->getOptionalDouble(), '', MAX_FLOAT_DIFF);
+ $this->assertFloatEquals(1.1, $m->getOptionalDouble(), MAX_FLOAT_DIFF);
// Set string.
$m->setOptionalDouble('2');
- $this->assertEquals(2.0, $m->getOptionalDouble(), '', MAX_FLOAT_DIFF);
+ $this->assertFloatEquals(2.0, $m->getOptionalDouble(), MAX_FLOAT_DIFF);
$m->setOptionalDouble('3.1');
- $this->assertEquals(3.1, $m->getOptionalDouble(), '', MAX_FLOAT_DIFF);
+ $this->assertFloatEquals(3.1, $m->getOptionalDouble(), MAX_FLOAT_DIFF);
}
#########################################################
@@ -1467,6 +1467,8 @@ class GeneratedClassTest extends TestBase
}
$key = new TestMessage($key);
}
+
+ $this->assertTrue(true);
}
public function testOneofMessageInArrayConstructor()
@@ -1476,6 +1478,8 @@ class GeneratedClassTest extends TestBase
]);
$this->assertSame('oneof_message', $m->getMyOneof());
$this->assertNotNull($m->getOneofMessage());
+
+ $this->assertTrue(true);
}
public function testOneofStringInArrayConstructor()
@@ -1483,6 +1487,8 @@ class GeneratedClassTest extends TestBase
$m = new TestMessage([
'oneof_string' => 'abc',
]);
+
+ $this->assertTrue(true);
}
#########################################################
@@ -1527,6 +1533,8 @@ class GeneratedClassTest extends TestBase
array_walk($values, function (&$value) {});
$m = new TestMessage();
$m->setOptionalString($values[0]);
+
+ $this->assertTrue(true);
}
#########################################################
@@ -1697,11 +1705,10 @@ class GeneratedClassTest extends TestBase
throw new Exception('Intended');
}
- /**
- * @expectedException Exception
- */
public function testNoSegfaultWithError()
{
+ $this->expectException(Exception::class);
+
new TestMessage(['optional_int32' => $this->throwIntendedException()]);
}
@@ -1724,5 +1731,7 @@ class GeneratedClassTest extends TestBase
* The value we are passing to var_dump() appears to be corrupt somehow.
*/
/* var_dump($m); */
+
+ $this->assertTrue(true);
}
}
diff --git a/php/tests/GeneratedPhpdocTest.php b/php/tests/GeneratedPhpdocTest.php
index 526927fc28..de672ac84e 100644
--- a/php/tests/GeneratedPhpdocTest.php
+++ b/php/tests/GeneratedPhpdocTest.php
@@ -13,15 +13,15 @@ class GeneratedPhpdocTest extends TestBase
{
$class = new ReflectionClass('Foo\TestMessage');
$doc = $class->getDocComment();
- $this->assertContains('foo.TestMessage', $doc);
+ $this->assertStringContains('foo.TestMessage', $doc);
}
public function testPhpDocForConstructor()
{
$class = new ReflectionClass('Foo\TestMessage');
$doc = $class->getMethod('__construct')->getDocComment();
- $this->assertContains('@param array $data', $doc);
- $this->assertContains('@type int $optional_int32', $doc);
+ $this->assertStringContains('@param array $data', $doc);
+ $this->assertStringContains('@type int $optional_int32', $doc);
}
/**
@@ -32,7 +32,7 @@ class GeneratedPhpdocTest extends TestBase
$class = new ReflectionClass('Foo\TestMessage');
foreach ($methods as $method) {
$doc = $class->getMethod($method)->getDocComment();
- $this->assertContains($expectedDoc, $doc);
+ $this->assertStringContains($expectedDoc, $doc);
}
}
diff --git a/php/tests/GeneratedServiceTest.php b/php/tests/GeneratedServiceTest.php
index 5407db9a3e..be9234c1ab 100644
--- a/php/tests/GeneratedServiceTest.php
+++ b/php/tests/GeneratedServiceTest.php
@@ -30,10 +30,13 @@ class GeneratedServiceTest extends TestBase
'sayHelloAgain'
];
- public function setUp()
+ /**
+ * Avoid calling setUp, which has void return type (not avalialbe in php7.0).
+ *
+ * @before
+ */
+ public function setUpTest()
{
- parent::setUp();
-
$this->serviceClass = new ReflectionClass('Foo\GreeterInterface');
$this->namespacedServiceClass = new ReflectionClass('Bar\OtherGreeterInterface');
@@ -46,17 +49,20 @@ class GeneratedServiceTest extends TestBase
public function testPhpDocForClass()
{
- $this->assertContains('foo.Greeter', $this->serviceClass->getDocComment());
+ $this->assertStringContains(
+ 'foo.Greeter', $this->serviceClass->getDocComment());
}
public function testPhpDocForNamespacedClass()
{
- $this->assertContains('foo.OtherGreeter', $this->namespacedServiceClass->getDocComment());
+ $this->assertStringContains(
+ 'foo.OtherGreeter', $this->namespacedServiceClass->getDocComment());
}
public function testServiceMethodsAreGenerated()
{
- $this->assertCount(count($this->methodNames), $this->serviceClass->getMethods());
+ $this->assertCount(
+ count($this->methodNames), $this->serviceClass->getMethods());
foreach ($this->methodNames as $methodName) {
$this->assertTrue($this->serviceClass->hasMethod($methodName));
}
@@ -65,20 +71,27 @@ class GeneratedServiceTest extends TestBase
public function testPhpDocForServiceMethod()
{
foreach ($this->methodNames as $methodName) {
- $docComment = $this->serviceClass->getMethod($methodName)->getDocComment();
- $this->assertContains($methodName, $docComment);
- $this->assertContains('@param \Foo\HelloRequest $request', $docComment);
- $this->assertContains('@return \Foo\HelloReply', $docComment);
+ $docComment =
+ $this->serviceClass->getMethod($methodName)->getDocComment();
+ $this->assertStringContains($methodName, $docComment);
+ $this->assertStringContains(
+ '@param \Foo\HelloRequest $request', $docComment);
+ $this->assertStringContains(
+ '@return \Foo\HelloReply', $docComment);
}
}
public function testPhpDocForServiceMethodInNamespacedClass()
{
foreach ($this->methodNames as $methodName) {
- $docComment = $this->namespacedServiceClass->getMethod($methodName)->getDocComment();
- $this->assertContains($methodName, $docComment);
- $this->assertContains('@param \Foo\HelloRequest $request', $docComment);
- $this->assertContains('@return \Foo\HelloReply', $docComment);
+ $docComment =
+ $this->namespacedServiceClass->getMethod(
+ $methodName)->getDocComment();
+ $this->assertStringContains($methodName, $docComment);
+ $this->assertStringContains(
+ '@param \Foo\HelloRequest $request', $docComment);
+ $this->assertStringContains(
+ '@return \Foo\HelloReply', $docComment);
}
}
@@ -90,8 +103,10 @@ class GeneratedServiceTest extends TestBase
$param = $method->getParameters()[0];
$this->assertFalse($param->isOptional());
$this->assertSame('request', $param->getName());
- // ReflectionParameter::getType only exists in PHP 7+, so get the type from __toString
- $this->assertContains('Foo\HelloRequest $request', (string) $param);
+ // ReflectionParameter::getType only exists in PHP 7+, so get the
+ // type from __toString
+ $this->assertStringContains(
+ 'Foo\HelloRequest $request', (string) $param);
}
}
@@ -103,8 +118,10 @@ class GeneratedServiceTest extends TestBase
$param = $method->getParameters()[0];
$this->assertFalse($param->isOptional());
$this->assertSame('request', $param->getName());
- // ReflectionParameter::getType only exists in PHP 7+, so get the type from __toString
- $this->assertContains('Foo\HelloRequest $request', (string) $param);
+ // ReflectionParameter::getType only exists in PHP 7+, so get the
+ // type from __toString
+ $this->assertStringContains(
+ 'Foo\HelloRequest $request', (string) $param);
}
}
}
diff --git a/php/tests/MapFieldTest.php b/php/tests/MapFieldTest.php
index 4ed4b09cff..a96f24fb58 100644
--- a/php/tests/MapFieldTest.php
+++ b/php/tests/MapFieldTest.php
@@ -1,5 +1,6 @@
assertEquals(1.0, $arr[0], '', MAX_FLOAT_DIFF);
+ $this->assertFloatEquals(1.0, $arr[0], MAX_FLOAT_DIFF);
$arr[1] = 1.1;
- $this->assertEquals(1.1, $arr[1], '', MAX_FLOAT_DIFF);
+ $this->assertFloatEquals(1.1, $arr[1], MAX_FLOAT_DIFF);
$arr[2] = '2';
- $this->assertEquals(2.0, $arr[2], '', MAX_FLOAT_DIFF);
+ $this->assertFloatEquals(2.0, $arr[2], MAX_FLOAT_DIFF);
$arr[3] = '3.1';
- $this->assertEquals(3.1, $arr[3], '', MAX_FLOAT_DIFF);
+ $this->assertFloatEquals(3.1, $arr[3], MAX_FLOAT_DIFF);
$this->assertEquals(4, count($arr));
}
@@ -279,15 +280,15 @@ class MapFieldTest extends \PHPUnit\Framework\TestCase {
// Test set.
$arr[0] = 1;
- $this->assertEquals(1.0, $arr[0], '', MAX_FLOAT_DIFF);
+ $this->assertFloatEquals(1.0, $arr[0], MAX_FLOAT_DIFF);
$arr[1] = 1.1;
- $this->assertEquals(1.1, $arr[1], '', MAX_FLOAT_DIFF);
+ $this->assertFloatEquals(1.1, $arr[1], MAX_FLOAT_DIFF);
$arr[2] = '2';
- $this->assertEquals(2.0, $arr[2], '', MAX_FLOAT_DIFF);
+ $this->assertFloatEquals(2.0, $arr[2], MAX_FLOAT_DIFF);
$arr[3] = '3.1';
- $this->assertEquals(3.1, $arr[3], '', MAX_FLOAT_DIFF);
+ $this->assertFloatEquals(3.1, $arr[3], MAX_FLOAT_DIFF);
$this->assertEquals(4, count($arr));
}
@@ -477,6 +478,8 @@ class MapFieldTest extends \PHPUnit\Framework\TestCase {
array_walk($values, function (&$value) {});
$m = new TestMessage();
$m->setMapInt32Message($values);
+
+ $this->assertTrue(true);
}
#########################################################
diff --git a/php/tests/PhpImplementationTest.php b/php/tests/PhpImplementationTest.php
index f9fc1fd5ea..82d0c5aff2 100644
--- a/php/tests/PhpImplementationTest.php
+++ b/php/tests/PhpImplementationTest.php
@@ -20,7 +20,11 @@ use Google\Protobuf\Internal\CodedOutputStream;
*/
class ImplementationTest extends TestBase
{
- public function setUp()
+ /**
+ * Avoid calling setUp, which has void return type (not avalialbe in php7.0).
+ * @before
+ */
+ public function skipTestsForExtension()
{
if (extension_loaded('protobuf')) {
$this->markTestSkipped();
@@ -306,6 +310,8 @@ class ImplementationTest extends TestBase
$m = new TestMessage();
$m->mergeFromString(TestUtil::getGoldenTestMessage());
TestUtil::assertTestMessage($m);
+
+ $this->assertTrue(true);
}
public function testDescriptorDecode()
@@ -525,23 +531,23 @@ class ImplementationTest extends TestBase
$this->assertSame(166, $m->byteSize());
}
- /**
- * @expectedException UnexpectedValueException
- * @expectedExceptionMessage Invalid message property: optionalInt32
- */
public function testArrayConstructorJsonCaseThrowsException()
{
+ $this->expectException(UnexpectedValueException::class);
+ $this->expectExceptionMessage(
+ 'Invalid message property: optionalInt32');
+
$m = new TestMessage([
'optionalInt32' => -42,
]);
}
- /**
- * @expectedException Exception
- * @expectedExceptionMessage Expect Foo\TestMessage\Sub.
- */
public function testArraysForMessagesThrowsException()
{
+ $this->expectException(Exception::class);
+ $this->expectExceptionMessage(
+ 'Expect Foo\TestMessage\Sub.');
+
$m = new TestMessage([
'optional_message' => [
'a' => 33
@@ -568,10 +574,11 @@ class ImplementationTest extends TestBase
/**
* @dataProvider provideArrayConstructorWithNullValuesThrowsException
- * @expectedException Exception
*/
public function testArrayConstructorWithNullValuesThrowsException($requestData)
{
+ $this->expectException(Exception::class);
+
$m = new TestMessage($requestData);
}
diff --git a/php/tests/WellKnownTest.php b/php/tests/WellKnownTest.php
index a148fa4a5b..27b7e1463c 100644
--- a/php/tests/WellKnownTest.php
+++ b/php/tests/WellKnownTest.php
@@ -86,31 +86,28 @@ class WellKnownTest extends TestBase {
$this->assertFalse($any->is(Any::class));
}
- /**
- * @expectedException Exception
- */
public function testAnyUnpackInvalidTypeUrl()
{
+ $this->expectException(Exception::class);
+
$any = new Any();
$any->setTypeUrl("invalid");
$any->unpack();
}
- /**
- * @expectedException Exception
- */
public function testAnyUnpackMessageNotAdded()
{
+ $this->expectException(Exception::class);
+
$any = new Any();
$any->setTypeUrl("type.googleapis.com/MessageNotAdded");
$any->unpack();
}
- /**
- * @expectedException Exception
- */
public function testAnyUnpackDecodeError()
{
+ $this->expectException(Exception::class);
+
$any = new Any();
$any->setTypeUrl("type.googleapis.com/foo.TestMessage");
$any->setValue("abc");
diff --git a/php/tests/WrapperTypeSettersTest.php b/php/tests/WrapperTypeSettersTest.php
index e4bdfcfad3..045fa66ef2 100644
--- a/php/tests/WrapperTypeSettersTest.php
+++ b/php/tests/WrapperTypeSettersTest.php
@@ -148,10 +148,10 @@ class WrapperTypeSettersTest extends TestBase
/**
* @dataProvider invalidSettersDataProvider
- * @expectedException \Exception
*/
public function testInvalidSetters($class, $setter, $value)
{
+ $this->expectException(Exception::class);
(new $class())->$setter($value);
}
@@ -243,6 +243,8 @@ class WrapperTypeSettersTest extends TestBase
}
$this->assertEquals($expectedInnerValue, $actualInnerValue);
}
+
+ $this->assertTrue(true);
}
public function constructorWithRepeatedWrapperTypeDataProvider()
@@ -286,6 +288,8 @@ class WrapperTypeSettersTest extends TestBase
}
$this->assertEquals($expectedInnerValue, $actualInnerValue);
}
+
+ $this->assertTrue(true);
}
public function constructorWithMapWrapperTypeDataProvider()
diff --git a/php/tests/test.sh b/php/tests/test.sh
index 91ea56ec8f..d04f36aa90 100755
--- a/php/tests/test.sh
+++ b/php/tests/test.sh
@@ -11,9 +11,11 @@ PHP_VERSION=$(php -r "echo PHP_VERSION;")
# Each version of PHPUnit supports a fairly narrow range of PHP versions.
case "$PHP_VERSION" in
- 7.0.*|7.1.*|7.2.*)
- # Oddly older than for 5.6. Not sure the reason.
- PHPUNIT=phpunit-5.6.0.phar
+ 7.0.*)
+ PHPUNIT=phpunit-6.phar
+ ;;
+ 7.1.*|7.2.*)
+ PHPUNIT=phpunit-7.5.0.phar
;;
7.3.*|7.4.*)
PHPUNIT=phpunit-8.phar
diff --git a/php/tests/test_base.php b/php/tests/test_base.php
index a4d951bdc5..db884a8f21 100644
--- a/php/tests/test_base.php
+++ b/php/tests/test_base.php
@@ -12,6 +12,30 @@ class TestBase extends \PHPUnit\Framework\TestCase
TestUtil::setTestMessage($m);
}
+ /**
+ * Polyfill for phpunit6.
+ */
+ static public function assertStringContains($needle, $haystack)
+ {
+ if (function_exists('PHPUnit\Framework\assertStringContainsString')) {
+ parent::assertStringContainsString($needle, $haystack);
+ } else {
+ parent::assertContains($needle, $haystack);
+ }
+ }
+
+ /**
+ * Polyfill for phpunit6.
+ */
+ static public function assertFloatEquals($expected, $actual, $delta)
+ {
+ if (function_exists('PHPUnit\Framework\assertEqualsWithDelta')) {
+ parent::assertEqualsWithDelta($expected, $actual, $delta);
+ } else {
+ parent::assertEquals($expected, $actual, '', $delta);
+ }
+ }
+
public function setFields2(TestMessage $m)
{
TestUtil::setTestMessage2($m);
diff --git a/python/google/protobuf/__init__.py b/python/google/protobuf/__init__.py
index 512d64105a..97ac28028b 100644
--- a/python/google/protobuf/__init__.py
+++ b/python/google/protobuf/__init__.py
@@ -30,4 +30,4 @@
# Copyright 2007 Google Inc. All Rights Reserved.
-__version__ = '3.13.0'
+__version__ = '3.14.0'
diff --git a/python/google/protobuf/descriptor.py b/python/google/protobuf/descriptor.py
index 7583ea39f7..190b89536f 100644
--- a/python/google/protobuf/descriptor.py
+++ b/python/google/protobuf/descriptor.py
@@ -287,12 +287,26 @@ class Descriptor(_NestedDescriptorBase):
if _USE_C_DESCRIPTORS:
_C_DESCRIPTOR_CLASS = _message.Descriptor
- def __new__(cls, name, full_name, filename, containing_type, fields,
- nested_types, enum_types, extensions, options=None,
- serialized_options=None,
- is_extendable=True, extension_ranges=None, oneofs=None,
- file=None, serialized_start=None, serialized_end=None, # pylint: disable=redefined-builtin
- syntax=None, create_key=None):
+ def __new__(
+ cls,
+ name=None,
+ full_name=None,
+ filename=None,
+ containing_type=None,
+ fields=None,
+ nested_types=None,
+ enum_types=None,
+ extensions=None,
+ options=None,
+ serialized_options=None,
+ is_extendable=True,
+ extension_ranges=None,
+ oneofs=None,
+ file=None, # pylint: disable=redefined-builtin
+ serialized_start=None,
+ serialized_end=None,
+ syntax=None,
+ create_key=None):
_message.Message._CheckCalledFromGeneratedFile()
return _message.default_pool.FindMessageTypeByName(full_name)
@@ -799,9 +813,18 @@ class ServiceDescriptor(_NestedDescriptorBase):
if _USE_C_DESCRIPTORS:
_C_DESCRIPTOR_CLASS = _message.ServiceDescriptor
- def __new__(cls, name, full_name, index, methods, options=None,
- serialized_options=None, file=None, # pylint: disable=redefined-builtin
- serialized_start=None, serialized_end=None, create_key=None):
+ def __new__(
+ cls,
+ name=None,
+ full_name=None,
+ index=None,
+ methods=None,
+ options=None,
+ serialized_options=None,
+ file=None, # pylint: disable=redefined-builtin
+ serialized_start=None,
+ serialized_end=None,
+ create_key=None):
_message.Message._CheckCalledFromGeneratedFile() # pylint: disable=protected-access
return _message.default_pool.FindServiceByName(full_name)
diff --git a/python/google/protobuf/internal/factory_test1.proto b/python/google/protobuf/internal/factory_test1.proto
index f5bd038331..5e729f5b08 100644
--- a/python/google/protobuf/internal/factory_test1.proto
+++ b/python/google/protobuf/internal/factory_test1.proto
@@ -34,7 +34,6 @@ syntax = "proto2";
package google.protobuf.python.internal;
-
enum Factory1Enum {
FACTORY_1_VALUE_0 = 0;
FACTORY_1_VALUE_1 = 1;
@@ -67,6 +66,5 @@ message Factory1MethodResponse {
service Factory1Service {
// Dummy method for this dummy service.
- rpc Factory1Method(Factory1MethodRequest) returns (Factory1MethodResponse) {
- }
+ rpc Factory1Method(Factory1MethodRequest) returns (Factory1MethodResponse) {}
}
diff --git a/python/google/protobuf/internal/message_factory_test.py b/python/google/protobuf/internal/message_factory_test.py
index 24b79ecc9e..42f91b2365 100755
--- a/python/google/protobuf/internal/message_factory_test.py
+++ b/python/google/protobuf/internal/message_factory_test.py
@@ -106,6 +106,23 @@ class MessageFactoryTest(unittest.TestCase):
'google.protobuf.python.internal.Factory2Message'))
self.assertTrue(cls is cls2)
+ def testCreatePrototypeOverride(self):
+ class MyMessageFactory(message_factory.MessageFactory):
+
+ def CreatePrototype(self, descriptor):
+ cls = super(MyMessageFactory, self).CreatePrototype(descriptor)
+ cls.additional_field = 'Some value'
+ return cls
+
+ db = descriptor_database.DescriptorDatabase()
+ pool = descriptor_pool.DescriptorPool(db)
+ db.Add(self.factory_test1_fd)
+ db.Add(self.factory_test2_fd)
+ factory = MyMessageFactory()
+ cls = factory.GetPrototype(pool.FindMessageTypeByName(
+ 'google.protobuf.python.internal.Factory2Message'))
+ self.assertTrue(hasattr(cls, 'additional_field'))
+
def testGetMessages(self):
# performed twice because multiple calls with the same input must be allowed
for _ in range(2):
diff --git a/python/google/protobuf/internal/unknown_fields_test.py b/python/google/protobuf/internal/unknown_fields_test.py
index 277603d952..d0ac5d9052 100755
--- a/python/google/protobuf/internal/unknown_fields_test.py
+++ b/python/google/protobuf/internal/unknown_fields_test.py
@@ -39,6 +39,7 @@ try:
import unittest2 as unittest #PY26
except ImportError:
import unittest
+import sys
from google.protobuf import map_unittest_pb2
from google.protobuf import unittest_mset_pb2
from google.protobuf import unittest_pb2
@@ -53,6 +54,12 @@ from google.protobuf.internal import type_checkers
from google.protobuf.internal import wire_format
from google.protobuf import descriptor
+try:
+ import tracemalloc # pylint: disable=g-import-not-at-top
+except ImportError:
+ # Requires python 3.4+
+ pass
+
@testing_refleaks.TestCase
class UnknownFieldsTest(unittest.TestCase):
@@ -312,6 +319,26 @@ class UnknownFieldsAccessorsTest(unittest.TestCase):
self.assertIn('UnknownFields does not exist.',
str(context.exception))
+ @unittest.skipIf((sys.version_info.major, sys.version_info.minor) < (3, 4),
+ 'tracemalloc requires python 3.4+')
+ def testUnknownFieldsNoMemoryLeak(self):
+ # Call to UnknownFields must not leak memory
+ nb_leaks = 1234
+
+ def leaking_function():
+ for _ in range(nb_leaks):
+ self.empty_message.UnknownFields()
+
+ tracemalloc.start()
+ snapshot1 = tracemalloc.take_snapshot()
+ leaking_function()
+ snapshot2 = tracemalloc.take_snapshot()
+ top_stats = snapshot2.compare_to(snapshot1, 'lineno')
+ tracemalloc.stop()
+ # There's no easy way to look for a precise leak source.
+ # Rely on a "marker" count value while checking allocated memory.
+ self.assertEqual([], [x for x in top_stats if x.count_diff == nb_leaks])
+
def testSubUnknownFields(self):
message = unittest_pb2.TestAllTypes()
message.optionalgroup.a = 123
diff --git a/python/google/protobuf/message_factory.py b/python/google/protobuf/message_factory.py
index 24a524af4f..7dfaec88e1 100644
--- a/python/google/protobuf/message_factory.py
+++ b/python/google/protobuf/message_factory.py
@@ -64,7 +64,7 @@ class MessageFactory(object):
self._classes = {}
def GetPrototype(self, descriptor):
- """Builds a proto2 message class based on the passed in descriptor.
+ """Obtains a proto2 message class based on the passed in descriptor.
Passing a descriptor with a fully qualified name matching a previous
invocation will cause the same class to be returned.
@@ -76,27 +76,52 @@ class MessageFactory(object):
A class describing the passed in descriptor.
"""
if descriptor not in self._classes:
- descriptor_name = descriptor.name
- if str is bytes: # PY2
- descriptor_name = descriptor.name.encode('ascii', 'ignore')
- result_class = _GENERATED_PROTOCOL_MESSAGE_TYPE(
- descriptor_name,
- (message.Message,),
- {'DESCRIPTOR': descriptor, '__module__': None})
- # pylint: disable=protected-access
- result_class._FACTORY = self
- # If module not set, it wrongly points to message_factory module.
+ result_class = self.CreatePrototype(descriptor)
+ # The assignment to _classes is redundant for the base implementation, but
+ # might avoid confusion in cases where CreatePrototype gets overridden and
+ # does not call the base implementation.
self._classes[descriptor] = result_class
- for field in descriptor.fields:
- if field.message_type:
- self.GetPrototype(field.message_type)
- for extension in result_class.DESCRIPTOR.extensions:
- if extension.containing_type not in self._classes:
- self.GetPrototype(extension.containing_type)
- extended_class = self._classes[extension.containing_type]
- extended_class.RegisterExtension(extension)
+ return result_class
return self._classes[descriptor]
+ def CreatePrototype(self, descriptor):
+ """Builds a proto2 message class based on the passed in descriptor.
+
+ Don't call this function directly, it always creates a new class. Call
+ GetPrototype() instead. This method is meant to be overridden in subblasses
+ to perform additional operations on the newly constructed class.
+
+ Args:
+ descriptor: The descriptor to build from.
+
+ Returns:
+ A class describing the passed in descriptor.
+ """
+ descriptor_name = descriptor.name
+ if str is bytes: # PY2
+ descriptor_name = descriptor.name.encode('ascii', 'ignore')
+ result_class = _GENERATED_PROTOCOL_MESSAGE_TYPE(
+ descriptor_name,
+ (message.Message,),
+ {
+ 'DESCRIPTOR': descriptor,
+ # If module not set, it wrongly points to message_factory module.
+ '__module__': None,
+ })
+ result_class._FACTORY = self # pylint: disable=protected-access
+ # Assign in _classes before doing recursive calls to avoid infinite
+ # recursion.
+ self._classes[descriptor] = result_class
+ for field in descriptor.fields:
+ if field.message_type:
+ self.GetPrototype(field.message_type)
+ for extension in result_class.DESCRIPTOR.extensions:
+ if extension.containing_type not in self._classes:
+ self.GetPrototype(extension.containing_type)
+ extended_class = self._classes[extension.containing_type]
+ extended_class.RegisterExtension(extension)
+ return result_class
+
def GetMessages(self, files):
"""Gets all the messages from a specified file.
diff --git a/python/google/protobuf/proto_api.h b/python/google/protobuf/proto_api.h
index 75ee9795ae..c869bce058 100644
--- a/python/google/protobuf/proto_api.h
+++ b/python/google/protobuf/proto_api.h
@@ -82,6 +82,32 @@ struct PyProto_API {
// to create Python-compatible message.
virtual const DescriptorPool* GetDefaultDescriptorPool() const = 0;
virtual MessageFactory* GetDefaultMessageFactory() const = 0;
+
+ // Allocate a new protocol buffer as a python object for the provided
+ // descriptor. This function works even if no Python module has been imported
+ // for the corresponding protocol buffer class.
+ // The factory is usually null; when provided, it is the MessageFactory which
+ // owns the Python class, and will be used to find and create Extensions for
+ // this message.
+ // When null is returned, a python error has already been set.
+ virtual PyObject* NewMessage(const Descriptor* descriptor,
+ PyObject* py_message_factory) const = 0;
+
+ // Allocate a new protocol buffer where the underlying object is owned by C++.
+ // The factory must currently be null. This function works even if no Python
+ // module has been imported for the corresponding protocol buffer class.
+ // When null is returned, a python error has already been set.
+ //
+ // Since this call returns a python object owned by C++, some operations
+ // are risky, and it must be used carefully. In particular:
+ // * Avoid modifying the returned object from the C++ side while there are
+ // existing python references to it or it's subobjects.
+ // * Avoid using python references to this object or any subobjects after the
+ // C++ object has been freed.
+ // * Calling this with the same C++ pointer will result in multiple distinct
+ // python objects referencing the same C++ object.
+ virtual PyObject* NewMessageOwnedExternally(
+ Message* msg, PyObject* py_message_factory) const = 0;
};
inline const char* PyProtoAPICapsuleName() {
diff --git a/python/google/protobuf/pyext/message.cc b/python/google/protobuf/pyext/message.cc
index 0301e9634d..4e74386e2d 100644
--- a/python/google/protobuf/pyext/message.cc
+++ b/python/google/protobuf/pyext/message.cc
@@ -121,7 +121,7 @@ inline void LowerString(std::string* s) {
if ('A' <= *i && *i <= 'Z') *i += 'a' - 'A';
}
}
-}
+} // namespace
// Finalize the creation of the Message class.
static int AddDescriptors(PyObject* cls, const Descriptor* descriptor) {
@@ -145,7 +145,7 @@ static int AddDescriptors(PyObject* cls, const Descriptor* descriptor) {
PyEnumDescriptor_FromDescriptor(enum_descriptor));
if (enum_type == NULL) {
return -1;
- }
+ }
// Add wrapped enum type to message class.
ScopedPyObjectPtr wrapped(PyObject_CallFunctionObjArgs(
EnumTypeWrapper_class, enum_type.get(), NULL));
@@ -195,8 +195,7 @@ static int AddDescriptors(PyObject* cls, const Descriptor* descriptor) {
return 0;
}
-static PyObject* New(PyTypeObject* type,
- PyObject* args, PyObject* kwargs) {
+static PyObject* New(PyTypeObject* type, PyObject* args, PyObject* kwargs) {
static char *kwlist[] = {"name", "bases", "dict", 0};
PyObject *bases, *dict;
const char* name;
@@ -219,41 +218,20 @@ static PyObject* New(PyTypeObject* type,
}
// Check dict['DESCRIPTOR']
- PyObject* descriptor_or_name = PyDict_GetItem(dict, kDESCRIPTOR);
- if (descriptor_or_name == nullptr) {
+ PyObject* py_descriptor = PyDict_GetItem(dict, kDESCRIPTOR);
+ if (py_descriptor == nullptr) {
PyErr_SetString(PyExc_TypeError, "Message class has no DESCRIPTOR");
- return NULL;
+ return nullptr;
}
-
- Py_ssize_t name_size;
- char* full_name;
- const Descriptor* message_descriptor;
- PyObject* py_descriptor;
-
- if (PyObject_TypeCheck(descriptor_or_name, &PyMessageDescriptor_Type)) {
- py_descriptor = descriptor_or_name;
- message_descriptor = PyMessageDescriptor_AsDescriptor(py_descriptor);
- if (message_descriptor == nullptr) {
- return nullptr;
- }
- } else {
- if (PyString_AsStringAndSize(descriptor_or_name, &full_name, &name_size) <
- 0) {
- return nullptr;
- }
- message_descriptor =
- GetDefaultDescriptorPool()->pool->FindMessageTypeByName(
- StringParam(full_name, name_size));
- if (message_descriptor == nullptr) {
- PyErr_Format(PyExc_KeyError,
- "Can not find message descriptor %s "
- "from pool",
- full_name);
- return nullptr;
- }
- py_descriptor = PyMessageDescriptor_FromDescriptor(message_descriptor);
- // reset the dict['DESCRIPTOR'] to py_descriptor.
- PyDict_SetItem(dict, kDESCRIPTOR, py_descriptor);
+ if (!PyObject_TypeCheck(py_descriptor, &PyMessageDescriptor_Type)) {
+ PyErr_Format(PyExc_TypeError, "Expected a message Descriptor, got %s",
+ py_descriptor->ob_type->tp_name);
+ return nullptr;
+ }
+ const Descriptor* message_descriptor =
+ PyMessageDescriptor_AsDescriptor(py_descriptor);
+ if (message_descriptor == nullptr) {
+ return nullptr;
}
// Messages have no __dict__
@@ -603,15 +581,15 @@ bool VerifyIntegerCastAndRange(PyObject* arg, ValueType value) {
OutOfRangeError(arg);
} // Otherwise propagate existing error.
return false;
- }
- if (PROTOBUF_PREDICT_FALSE(!IsValidNumericCast(value))) {
- OutOfRangeError(arg);
- return false;
- }
+ }
+ if (PROTOBUF_PREDICT_FALSE(!IsValidNumericCast(value))) {
+ OutOfRangeError(arg);
+ return false;
+ }
return true;
}
-template
+template
bool CheckAndGetInteger(PyObject* arg, T* value) {
// The fast path.
#if PY_MAJOR_VERSION < 3
@@ -631,10 +609,10 @@ bool CheckAndGetInteger(PyObject* arg, T* value) {
// an integer and can be used as an ordinal number".
// This definition includes everything that implements numbers.Integral
// and shouldn't cast the net too wide.
- if (PROTOBUF_PREDICT_FALSE(!PyIndex_Check(arg))) {
- FormatTypeError(arg, "int, long");
- return false;
- }
+ if (PROTOBUF_PREDICT_FALSE(!PyIndex_Check(arg))) {
+ FormatTypeError(arg, "int, long");
+ return false;
+ }
// Now we have an integral number so we can safely use PyLong_ functions.
// We need to treat the signed and unsigned cases differently in case arg is
@@ -651,7 +629,7 @@ bool CheckAndGetInteger(PyObject* arg, T* value) {
if (PROTOBUF_PREDICT_FALSE(casted == nullptr)) {
// Propagate existing error.
return false;
- }
+ }
ulong_result = PyLong_AsUnsignedLongLong(casted);
Py_DECREF(casted);
}
@@ -676,7 +654,7 @@ bool CheckAndGetInteger(PyObject* arg, T* value) {
if (PROTOBUF_PREDICT_FALSE(casted == nullptr)) {
// Propagate existing error.
return false;
- }
+ }
long_result = PyLong_AsLongLong(casted);
Py_DECREF(casted);
}
@@ -702,7 +680,7 @@ bool CheckAndGetDouble(PyObject* arg, double* value) {
if (PROTOBUF_PREDICT_FALSE(*value == -1 && PyErr_Occurred())) {
FormatTypeError(arg, "int, long, float");
return false;
- }
+ }
return true;
}
@@ -928,9 +906,9 @@ int AssureWritable(CMessage* self) {
// Toplevel messages are always mutable.
GOOGLE_DCHECK(self->parent);
- if (AssureWritable(self->parent) == -1)
+ if (AssureWritable(self->parent) == -1) {
return -1;
-
+ }
// If this message is part of a oneof, there might be a field to release in
// the parent.
if (MaybeReleaseOverlappingOneofField(self->parent,
@@ -1279,32 +1257,41 @@ CMessage* NewEmptyMessage(CMessageClass* type) {
// The __new__ method of Message classes.
// Creates a new C++ message and takes ownership.
-static PyObject* New(PyTypeObject* cls,
- PyObject* unused_args, PyObject* unused_kwargs) {
- CMessageClass* type = CheckMessageClass(cls);
- if (type == NULL) {
- return NULL;
- }
+static CMessage* NewCMessage(CMessageClass* type) {
// Retrieve the message descriptor and the default instance (=prototype).
const Descriptor* message_descriptor = type->message_descriptor;
- if (message_descriptor == NULL) {
- return NULL;
+ if (message_descriptor == nullptr) {
+ // This would be very unexpected since the CMessageClass has already
+ // been checked.
+ PyErr_Format(PyExc_TypeError,
+ "CMessageClass object '%s' has no descriptor.",
+ Py_TYPE(type)->tp_name);
+ return nullptr;
}
const Message* prototype =
type->py_message_factory->message_factory->GetPrototype(
message_descriptor);
- if (prototype == NULL) {
+ if (prototype == nullptr) {
PyErr_SetString(PyExc_TypeError, message_descriptor->full_name().c_str());
- return NULL;
+ return nullptr;
}
CMessage* self = NewEmptyMessage(type);
- if (self == NULL) {
- return NULL;
+ if (self == nullptr) {
+ return nullptr;
}
self->message = prototype->New();
self->parent = nullptr; // This message owns its data.
- return reinterpret_cast(self);
+ return self;
+}
+
+static PyObject* New(PyTypeObject* cls, PyObject* unused_args,
+ PyObject* unused_kwargs) {
+ CMessageClass* type = CheckMessageClass(cls);
+ if (type == nullptr) {
+ return nullptr;
+ }
+ return reinterpret_cast(NewCMessage(type));
}
// The __init__ method of Message classes.
@@ -2866,28 +2853,57 @@ Message* PyMessage_GetMutableMessagePointer(PyObject* msg) {
return cmsg->message;
}
+PyObject* PyMessage_New(const Descriptor* descriptor,
+ PyObject* py_message_factory) {
+ PyMessageFactory* factory = nullptr;
+ if (py_message_factory == nullptr) {
+ factory = GetDescriptorPool_FromPool(descriptor->file()->pool())
+ ->py_message_factory;
+ } else if (PyObject_TypeCheck(py_message_factory, &PyMessageFactory_Type)) {
+ factory = reinterpret_cast(py_message_factory);
+ } else {
+ PyErr_SetString(PyExc_TypeError, "Expected a MessageFactory");
+ return nullptr;
+ }
+ auto* message_class =
+ message_factory::GetOrCreateMessageClass(factory, descriptor);
+ if (message_class == nullptr) {
+ return nullptr;
+ }
+
+ CMessage* self = cmessage::NewCMessage(message_class);
+ Py_DECREF(message_class);
+ if (self == nullptr) {
+ return nullptr;
+ }
+ return self->AsPyObject();
+}
+
PyObject* PyMessage_NewMessageOwnedExternally(Message* message,
- PyObject* message_factory) {
- if (message_factory) {
+ PyObject* py_message_factory) {
+ if (py_message_factory) {
PyErr_SetString(PyExc_NotImplementedError,
"Default message_factory=NULL is the only supported value");
- return NULL;
+ return nullptr;
}
if (message->GetReflection()->GetMessageFactory() !=
MessageFactory::generated_factory()) {
PyErr_SetString(PyExc_TypeError,
"Message pointer was not created from the default factory");
- return NULL;
+ return nullptr;
}
CMessageClass* message_class = message_factory::GetOrCreateMessageClass(
GetDefaultDescriptorPool()->py_message_factory, message->GetDescriptor());
+ if (message_class == nullptr) {
+ return nullptr;
+ }
CMessage* self = cmessage::NewEmptyMessage(message_class);
- if (self == NULL) {
- return NULL;
- }
Py_DECREF(message_class);
+ if (self == nullptr) {
+ return nullptr;
+ }
self->message = message;
Py_INCREF(Py_None);
self->parent = reinterpret_cast(Py_None);
@@ -2954,9 +2970,9 @@ bool InitProto2MessageModule(PyObject *m) {
return false;
}
- PyModule_AddObject(m, "RepeatedScalarContainer",
- reinterpret_cast(
- &RepeatedScalarContainer_Type));
+ PyModule_AddObject(
+ m, "RepeatedScalarContainer",
+ reinterpret_cast(&RepeatedScalarContainer_Type));
if (PyType_Ready(&RepeatedCompositeContainer_Type) < 0) {
return false;
@@ -2964,8 +2980,7 @@ bool InitProto2MessageModule(PyObject *m) {
PyModule_AddObject(
m, "RepeatedCompositeContainer",
- reinterpret_cast(
- &RepeatedCompositeContainer_Type));
+ reinterpret_cast(&RepeatedCompositeContainer_Type));
// Register them as MutableSequence.
#if PY_MAJOR_VERSION >= 3
@@ -2998,16 +3013,14 @@ bool InitProto2MessageModule(PyObject *m) {
}
PyModule_AddObject(m, "UnknownFieldSet",
- reinterpret_cast(
- &PyUnknownFields_Type));
+ reinterpret_cast(&PyUnknownFields_Type));
if (PyType_Ready(&PyUnknownFieldRef_Type) < 0) {
return false;
}
PyModule_AddObject(m, "UnknownField",
- reinterpret_cast(
- &PyUnknownFieldRef_Type));
+ reinterpret_cast(&PyUnknownFieldRef_Type));
// Initialize Map container types.
if (!InitMapContainers()) {
@@ -3023,9 +3036,8 @@ bool InitProto2MessageModule(PyObject *m) {
if (PyType_Ready(&ExtensionDict_Type) < 0) {
return false;
}
- PyModule_AddObject(
- m, "ExtensionDict",
- reinterpret_cast(&ExtensionDict_Type));
+ PyModule_AddObject(m, "ExtensionDict",
+ reinterpret_cast(&ExtensionDict_Type));
if (PyType_Ready(&ExtensionIterator_Type) < 0) {
return false;
}
@@ -3039,25 +3051,24 @@ bool InitProto2MessageModule(PyObject *m) {
PyModule_AddObject(m, "default_pool",
reinterpret_cast(GetDefaultDescriptorPool()));
- PyModule_AddObject(m, "DescriptorPool", reinterpret_cast(
- &PyDescriptorPool_Type));
-
- PyModule_AddObject(m, "Descriptor", reinterpret_cast(
- &PyMessageDescriptor_Type));
- PyModule_AddObject(m, "FieldDescriptor", reinterpret_cast(
- &PyFieldDescriptor_Type));
- PyModule_AddObject(m, "EnumDescriptor", reinterpret_cast(
- &PyEnumDescriptor_Type));
- PyModule_AddObject(m, "EnumValueDescriptor", reinterpret_cast(
- &PyEnumValueDescriptor_Type));
- PyModule_AddObject(m, "FileDescriptor", reinterpret_cast(
- &PyFileDescriptor_Type));
- PyModule_AddObject(m, "OneofDescriptor", reinterpret_cast(
- &PyOneofDescriptor_Type));
- PyModule_AddObject(m, "ServiceDescriptor", reinterpret_cast(
- &PyServiceDescriptor_Type));
- PyModule_AddObject(m, "MethodDescriptor", reinterpret_cast(
- &PyMethodDescriptor_Type));
+ PyModule_AddObject(m, "DescriptorPool",
+ reinterpret_cast(&PyDescriptorPool_Type));
+ PyModule_AddObject(m, "Descriptor",
+ reinterpret_cast(&PyMessageDescriptor_Type));
+ PyModule_AddObject(m, "FieldDescriptor",
+ reinterpret_cast(&PyFieldDescriptor_Type));
+ PyModule_AddObject(m, "EnumDescriptor",
+ reinterpret_cast(&PyEnumDescriptor_Type));
+ PyModule_AddObject(m, "EnumValueDescriptor",
+ reinterpret_cast(&PyEnumValueDescriptor_Type));
+ PyModule_AddObject(m, "FileDescriptor",
+ reinterpret_cast(&PyFileDescriptor_Type));
+ PyModule_AddObject(m, "OneofDescriptor",
+ reinterpret_cast(&PyOneofDescriptor_Type));
+ PyModule_AddObject(m, "ServiceDescriptor",
+ reinterpret_cast(&PyServiceDescriptor_Type));
+ PyModule_AddObject(m, "MethodDescriptor",
+ reinterpret_cast(&PyMethodDescriptor_Type));
PyObject* enum_type_wrapper = PyImport_ImportModule(
"google.protobuf.internal.enum_type_wrapper");
diff --git a/python/google/protobuf/pyext/message.h b/python/google/protobuf/pyext/message.h
index c5a635da02..a1e8326512 100644
--- a/python/google/protobuf/pyext/message.h
+++ b/python/google/protobuf/pyext/message.h
@@ -282,51 +282,50 @@ PyObject* SetAllowOversizeProtos(PyObject* m, PyObject* arg);
/* Is 64bit */
#define IS_64BIT (SIZEOF_LONG == 8)
-#define FIELD_IS_REPEATED(field_descriptor) \
- ((field_descriptor)->label() == FieldDescriptor::LABEL_REPEATED)
-
-#define GOOGLE_CHECK_GET_INT32(arg, value, err) \
- int32 value; \
- if (!CheckAndGetInteger(arg, &value)) { \
- return err; \
- }
-
-#define GOOGLE_CHECK_GET_INT64(arg, value, err) \
- int64 value; \
- if (!CheckAndGetInteger(arg, &value)) { \
- return err; \
- }
-
-#define GOOGLE_CHECK_GET_UINT32(arg, value, err) \
- uint32 value; \
- if (!CheckAndGetInteger(arg, &value)) { \
- return err; \
- }
-
-#define GOOGLE_CHECK_GET_UINT64(arg, value, err) \
- uint64 value; \
- if (!CheckAndGetInteger(arg, &value)) { \
- return err; \
- }
-
-#define GOOGLE_CHECK_GET_FLOAT(arg, value, err) \
- float value; \
- if (!CheckAndGetFloat(arg, &value)) { \
- return err; \
- } \
-
-#define GOOGLE_CHECK_GET_DOUBLE(arg, value, err) \
- double value; \
- if (!CheckAndGetDouble(arg, &value)) { \
- return err; \
- }
-
-#define GOOGLE_CHECK_GET_BOOL(arg, value, err) \
- bool value; \
- if (!CheckAndGetBool(arg, &value)) { \
- return err; \
- }
+#define FIELD_IS_REPEATED(field_descriptor) \
+ ((field_descriptor)->label() == FieldDescriptor::LABEL_REPEATED)
+#define GOOGLE_CHECK_GET_INT32(arg, value, err) \
+ int32 value; \
+ if (!CheckAndGetInteger(arg, &value)) { \
+ return err; \
+ }
+
+#define GOOGLE_CHECK_GET_INT64(arg, value, err) \
+ int64 value; \
+ if (!CheckAndGetInteger(arg, &value)) { \
+ return err; \
+ }
+
+#define GOOGLE_CHECK_GET_UINT32(arg, value, err) \
+ uint32 value; \
+ if (!CheckAndGetInteger(arg, &value)) { \
+ return err; \
+ }
+
+#define GOOGLE_CHECK_GET_UINT64(arg, value, err) \
+ uint64 value; \
+ if (!CheckAndGetInteger(arg, &value)) { \
+ return err; \
+ }
+
+#define GOOGLE_CHECK_GET_FLOAT(arg, value, err) \
+ float value; \
+ if (!CheckAndGetFloat(arg, &value)) { \
+ return err; \
+ }
+
+#define GOOGLE_CHECK_GET_DOUBLE(arg, value, err) \
+ double value; \
+ if (!CheckAndGetDouble(arg, &value)) { \
+ return err; \
+ }
+
+#define GOOGLE_CHECK_GET_BOOL(arg, value, err) \
+ bool value; \
+ if (!CheckAndGetBool(arg, &value)) { \
+ return err; \
+ }
#define FULL_MODULE_NAME "google.protobuf.pyext._message"
@@ -353,10 +352,12 @@ bool CheckFieldBelongsToMessage(const FieldDescriptor* field_descriptor,
extern PyObject* PickleError_class;
+PyObject* PyMessage_New(const Descriptor* descriptor,
+ PyObject* py_message_factory);
const Message* PyMessage_GetMessagePointer(PyObject* msg);
Message* PyMessage_GetMutableMessagePointer(PyObject* msg);
PyObject* PyMessage_NewMessageOwnedExternally(Message* message,
- PyObject* message_factory);
+ PyObject* py_message_factory);
bool InitProto2MessageModule(PyObject *m);
diff --git a/python/google/protobuf/pyext/message_module.cc b/python/google/protobuf/pyext/message_module.cc
index 63d60b70e7..b5975f76c5 100644
--- a/python/google/protobuf/pyext/message_module.cc
+++ b/python/google/protobuf/pyext/message_module.cc
@@ -30,13 +30,12 @@
#include
+#include
#include
#include
#include
#include
-#include
-
namespace {
// C++ API. Clients get at this via proto_api.h
@@ -55,6 +54,15 @@ struct ApiImplementation : google::protobuf::python::PyProto_API {
return google::protobuf::python::GetDefaultDescriptorPool()
->py_message_factory->message_factory;
}
+ PyObject* NewMessage(const google::protobuf::Descriptor* descriptor,
+ PyObject* py_message_factory) const override {
+ return google::protobuf::python::PyMessage_New(descriptor, py_message_factory);
+ }
+ PyObject* NewMessageOwnedExternally(
+ google::protobuf::Message* msg, PyObject* py_message_factory) const override {
+ return google::protobuf::python::PyMessage_NewMessageOwnedExternally(
+ msg, py_message_factory);
+ }
};
} // namespace
diff --git a/python/google/protobuf/pyext/repeated_composite_container.cc b/python/google/protobuf/pyext/repeated_composite_container.cc
index d934f756ba..cbc0f9f8af 100644
--- a/python/google/protobuf/pyext/repeated_composite_container.cc
+++ b/python/google/protobuf/pyext/repeated_composite_container.cc
@@ -567,7 +567,11 @@ PyTypeObject RepeatedCompositeContainer_Type = {
sizeof(RepeatedCompositeContainer), // tp_basicsize
0, // tp_itemsize
repeated_composite_container::Dealloc, // tp_dealloc
+#if PY_VERSION_HEX >= 0x03080000
+ 0, // tp_vectorcall_offset
+#else
nullptr, // tp_print
+#endif
nullptr, // tp_getattr
nullptr, // tp_setattr
nullptr, // tp_compare
diff --git a/python/google/protobuf/pyext/repeated_scalar_container.cc b/python/google/protobuf/pyext/repeated_scalar_container.cc
index 8c937b7ccf..5a5c4db16e 100644
--- a/python/google/protobuf/pyext/repeated_scalar_container.cc
+++ b/python/google/protobuf/pyext/repeated_scalar_container.cc
@@ -753,7 +753,11 @@ PyTypeObject RepeatedScalarContainer_Type = {
sizeof(RepeatedScalarContainer), // tp_basicsize
0, // tp_itemsize
repeated_scalar_container::Dealloc, // tp_dealloc
+#if PY_VERSION_HEX >= 0x03080000
+ 0, // tp_vectorcall_offset
+#else
nullptr, // tp_print
+#endif
nullptr, // tp_getattr
nullptr, // tp_setattr
nullptr, // tp_compare
diff --git a/python/google/protobuf/pyext/unknown_fields.cc b/python/google/protobuf/pyext/unknown_fields.cc
index 8509213b18..deb86e6916 100644
--- a/python/google/protobuf/pyext/unknown_fields.cc
+++ b/python/google/protobuf/pyext/unknown_fields.cc
@@ -142,6 +142,7 @@ static void Dealloc(PyObject* pself) {
}
Py_CLEAR(self->parent);
self->~PyUnknownFields();
+ Py_TYPE(pself)->tp_free(pself);
}
static PySequenceMethods SqMethods = {
diff --git a/python/google/protobuf/service_reflection.py b/python/google/protobuf/service_reflection.py
index 8590e46b17..75c51ff322 100644
--- a/python/google/protobuf/service_reflection.py
+++ b/python/google/protobuf/service_reflection.py
@@ -38,12 +38,6 @@ compiler at compile-time.
__author__ = 'petar@google.com (Petar Petrov)'
-from google.protobuf.internal import api_implementation
-
-if api_implementation.Type() == 'cpp':
- # pylint: disable=g-import-not-at-top
- from google.protobuf.pyext import _message
-
class GeneratedServiceType(type):
@@ -84,10 +78,6 @@ class GeneratedServiceType(type):
return
descriptor = dictionary[GeneratedServiceType._DESCRIPTOR_KEY]
- if isinstance(descriptor, str):
- descriptor = _message.default_pool.FindServiceByName(descriptor)
- dictionary[GeneratedServiceType._DESCRIPTOR_KEY] = descriptor
-
service_builder = _ServiceBuilder(descriptor)
service_builder.BuildService(cls)
cls.DESCRIPTOR = descriptor
@@ -113,16 +103,13 @@ class GeneratedServiceStubType(GeneratedServiceType):
dictionary[_DESCRIPTOR_KEY] must contain a ServiceDescriptor object
describing this protocol service type.
"""
- descriptor = dictionary.get(cls._DESCRIPTOR_KEY)
- if isinstance(descriptor, str):
- descriptor = _message.default_pool.FindServiceByName(descriptor)
- dictionary[GeneratedServiceStubType._DESCRIPTOR_KEY] = descriptor
super(GeneratedServiceStubType, cls).__init__(name, bases, dictionary)
# Don't do anything if this class doesn't have a descriptor. This happens
# when a service stub is subclassed.
if GeneratedServiceStubType._DESCRIPTOR_KEY not in dictionary:
return
+ descriptor = dictionary[GeneratedServiceStubType._DESCRIPTOR_KEY]
service_stub_builder = _ServiceStubBuilder(descriptor)
service_stub_builder.BuildServiceStub(cls)
diff --git a/python/google/protobuf/text_format.py b/python/google/protobuf/text_format.py
index 9ebe8b46b1..c376c7bac7 100644
--- a/python/google/protobuf/text_format.py
+++ b/python/google/protobuf/text_format.py
@@ -541,7 +541,7 @@ class _Printer(object):
# For groups, use the capitalized name.
out.write(field.message_type.name)
else:
- out.write(field.name)
+ out.write(field.name)
if (self.force_colon or
field.cpp_type != descriptor.FieldDescriptor.CPPTYPE_MESSAGE):
@@ -902,6 +902,8 @@ class _Parser(object):
# pylint: disable=protected-access
field = message.Extensions._FindExtensionByName(name)
# pylint: enable=protected-access
+
+
if not field:
if self.allow_unknown_extension:
field = None
@@ -988,6 +990,7 @@ class _Parser(object):
if not tokenizer.TryConsume(','):
tokenizer.TryConsume(';')
+
def _ConsumeAnyTypeUrl(self, tokenizer):
"""Consumes a google.protobuf.Any type URL and returns the type name."""
# Consume "type.googleapis.com/".
diff --git a/ruby/Rakefile b/ruby/Rakefile
index 2aa7743e20..3e3da055d3 100644
--- a/ruby/Rakefile
+++ b/ruby/Rakefile
@@ -51,6 +51,12 @@ if RUBY_PLATFORM == "java"
system("mvn --batch-mode package")
end
else
+ unless ENV['IN_DOCKER'] == 'true'
+ # We need wyhash in-tree.
+ FileUtils.mkdir_p("ext/google/protobuf_c/third_party/wyhash")
+ FileUtils.cp("../third_party/wyhash/wyhash.h", "ext/google/protobuf_c/third_party/wyhash/wyhash.h")
+ end
+
Rake::ExtensionTask.new("protobuf_c", spec) do |ext|
unless RUBY_PLATFORM =~ /darwin/
# TODO: also set "no_native to true" for mac if possible. As is,
@@ -73,7 +79,7 @@ else
['x86-mingw32', 'x64-mingw32', 'x86_64-linux', 'x86-linux'].each do |plat|
RakeCompilerDock.sh <<-"EOT", platform: plat
bundle && \
- IN_DOCKER=true rake native:#{plat} pkg/#{spec.full_name}-#{plat}.gem RUBY_CC_VERSION=2.7.0:2.6.0:2.5.0:2.4.0:2.3.0
+ IN_DOCKER=true rake native:#{plat} pkg/#{spec.full_name}-#{plat}.gem RUBY_CC_VERSION=3.0.0:2.7.0:2.6.0:2.5.0:2.4.0:2.3.0
EOT
end
end
@@ -81,7 +87,7 @@ else
if RUBY_PLATFORM =~ /darwin/
task 'gem:native' do
system "rake genproto"
- system "rake cross native gem RUBY_CC_VERSION=2.7.0:2.6.0:2.5.1:2.4.0:2.3.0"
+ system "rake cross native gem RUBY_CC_VERSION=3.0.0:2.7.0:2.6.0:2.5.1:2.4.0:2.3.0"
end
else
task 'gem:native' => [:genproto, 'gem:windows']
@@ -98,7 +104,9 @@ genproto_output << "tests/test_ruby_package.rb"
genproto_output << "tests/test_ruby_package_proto2.rb"
genproto_output << "tests/basic_test.rb"
genproto_output << "tests/basic_test_proto2.rb"
+genproto_output << "tests/multi_level_nesting_test.rb"
genproto_output << "tests/wrappers.rb"
+
file "tests/generated_code.rb" => "tests/generated_code.proto" do |file_task|
sh "../src/protoc --ruby_out=. tests/generated_code.proto"
end
@@ -131,6 +139,10 @@ file "tests/basic_test_proto2.rb" => "tests/basic_test_proto2.proto" do |file_ta
sh "../src/protoc -I../src -I. --ruby_out=. tests/basic_test_proto2.proto"
end
+file "tests/multi_level_nesting_test.rb" => "tests/multi_level_nesting_test.proto" do |file_task|
+ sh "../src/protoc -I../src -I. --ruby_out=. tests/multi_level_nesting_test.proto"
+end
+
file "tests/wrappers.rb" => "../src/google/protobuf/wrappers.proto" do |file_task|
sh "../src/protoc -I../src -I. --ruby_out=tests ../src/google/protobuf/wrappers.proto"
end
diff --git a/ruby/compatibility_tests/v3.0.0/tests/basic.rb b/ruby/compatibility_tests/v3.0.0/tests/basic.rb
index bfe68eff44..7228144cb1 100755
--- a/ruby/compatibility_tests/v3.0.0/tests/basic.rb
+++ b/ruby/compatibility_tests/v3.0.0/tests/basic.rb
@@ -1264,10 +1264,10 @@ module BasicTest
m = MapMessage.new(:map_string_int32 => {"a" => 1})
expected = '{"mapStringInt32":{"a":1},"mapStringMsg":{}}'
expected_preserve = '{"map_string_int32":{"a":1},"map_string_msg":{}}'
- assert MapMessage.encode_json(m) == expected
+ assert_equal expected, MapMessage.encode_json(m, :emit_defaults => true)
- json = MapMessage.encode_json(m, :preserve_proto_fieldnames => true)
- assert json == expected_preserve
+ json = MapMessage.encode_json(m, :preserve_proto_fieldnames => true, :emit_defaults => true)
+ assert_equal expected_preserve, json
m2 = MapMessage.decode_json(MapMessage.encode_json(m))
assert m == m2
diff --git a/ruby/ext/google/protobuf_c/convert.c b/ruby/ext/google/protobuf_c/convert.c
new file mode 100644
index 0000000000..bc3e35a5ed
--- /dev/null
+++ b/ruby/ext/google/protobuf_c/convert.c
@@ -0,0 +1,349 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// -----------------------------------------------------------------------------
+// Ruby <-> upb data conversion functions.
+//
+// This file Also contains a few other assorted algorithms on upb_msgval.
+//
+// None of the algorithms in this file require any access to the internal
+// representation of Ruby or upb objects.
+// -----------------------------------------------------------------------------
+
+#include "convert.h"
+
+#include "message.h"
+#include "protobuf.h"
+#include "third_party/wyhash/wyhash.h"
+
+static upb_strview Convert_StringData(VALUE str, upb_arena *arena) {
+ upb_strview ret;
+ if (arena) {
+ char *ptr = upb_arena_malloc(arena, RSTRING_LEN(str));
+ memcpy(ptr, RSTRING_PTR(str), RSTRING_LEN(str));
+ ret.data = ptr;
+ } else {
+ // Data is only needed temporarily (within map lookup).
+ ret.data = RSTRING_PTR(str);
+ }
+ ret.size = RSTRING_LEN(str);
+ return ret;
+}
+
+static bool is_ruby_num(VALUE value) {
+ return (TYPE(value) == T_FLOAT ||
+ TYPE(value) == T_FIXNUM ||
+ TYPE(value) == T_BIGNUM);
+}
+
+static void Convert_CheckInt(const char* name, upb_fieldtype_t type,
+ VALUE val) {
+ if (!is_ruby_num(val)) {
+ rb_raise(cTypeError,
+ "Expected number type for integral field '%s' (given %s).", name,
+ rb_class2name(CLASS_OF(val)));
+ }
+
+ // NUM2{INT,UINT,LL,ULL} macros do the appropriate range checks on upper
+ // bound; we just need to do precision checks (i.e., disallow rounding) and
+ // check for < 0 on unsigned types.
+ if (TYPE(val) == T_FLOAT) {
+ double dbl_val = NUM2DBL(val);
+ if (floor(dbl_val) != dbl_val) {
+ rb_raise(rb_eRangeError,
+ "Non-integral floating point value assigned to integer field "
+ "'%s' (given %s).",
+ name, rb_class2name(CLASS_OF(val)));
+ }
+ }
+ if (type == UPB_TYPE_UINT32 || type == UPB_TYPE_UINT64) {
+ if (NUM2DBL(val) < 0) {
+ rb_raise(
+ rb_eRangeError,
+ "Assigning negative value to unsigned integer field '%s' (given %s).",
+ name, rb_class2name(CLASS_OF(val)));
+ }
+ }
+}
+
+static int32_t Convert_ToEnum(VALUE value, const char* name,
+ const upb_enumdef* e) {
+ int32_t val;
+
+ switch (TYPE(value)) {
+ case T_FLOAT:
+ case T_FIXNUM:
+ case T_BIGNUM:
+ Convert_CheckInt(name, UPB_TYPE_INT32, value);
+ val = NUM2INT(value);
+ break;
+ case T_STRING:
+ if (!upb_enumdef_ntoi(e, RSTRING_PTR(value), RSTRING_LEN(value), &val)) {
+ goto unknownval;
+ }
+ break;
+ case T_SYMBOL:
+ if (!upb_enumdef_ntoiz(e, rb_id2name(SYM2ID(value)), &val)) {
+ goto unknownval;
+ }
+ break;
+ default:
+ rb_raise(cTypeError,
+ "Expected number or symbol type for enum field '%s'.", name);
+ }
+
+ return val;
+
+unknownval:
+ rb_raise(rb_eRangeError, "Unknown symbol value for enum field '%s'.", name);
+}
+
+upb_msgval Convert_RubyToUpb(VALUE value, const char* name, TypeInfo type_info,
+ upb_arena* arena) {
+ upb_msgval ret;
+
+ switch (type_info.type) {
+ case UPB_TYPE_FLOAT:
+ if (!is_ruby_num(value)) {
+ rb_raise(cTypeError, "Expected number type for float field '%s' (given %s).",
+ name, rb_class2name(CLASS_OF(value)));
+ }
+ ret.float_val = NUM2DBL(value);
+ break;
+ case UPB_TYPE_DOUBLE:
+ if (!is_ruby_num(value)) {
+ rb_raise(cTypeError, "Expected number type for double field '%s' (given %s).",
+ name, rb_class2name(CLASS_OF(value)));
+ }
+ ret.double_val = NUM2DBL(value);
+ break;
+ case UPB_TYPE_BOOL: {
+ if (value == Qtrue) {
+ ret.bool_val = 1;
+ } else if (value == Qfalse) {
+ ret.bool_val = 0;
+ } else {
+ rb_raise(cTypeError, "Invalid argument for boolean field '%s' (given %s).",
+ name, rb_class2name(CLASS_OF(value)));
+ }
+ break;
+ }
+ case UPB_TYPE_STRING: {
+ VALUE utf8 = rb_enc_from_encoding(rb_utf8_encoding());
+ if (CLASS_OF(value) == rb_cSymbol) {
+ value = rb_funcall(value, rb_intern("to_s"), 0);
+ } else if (CLASS_OF(value) != rb_cString) {
+ rb_raise(cTypeError, "Invalid argument for string field '%s' (given %s).",
+ name, rb_class2name(CLASS_OF(value)));
+ }
+
+ if (rb_obj_encoding(value) != utf8) {
+ // Note: this will not duplicate underlying string data unless necessary.
+ value = rb_str_encode(value, utf8, 0, Qnil);
+
+ if (rb_enc_str_coderange(value) == ENC_CODERANGE_BROKEN) {
+ rb_raise(rb_eEncodingError, "String is invalid UTF-8");
+ }
+ }
+
+ ret.str_val = Convert_StringData(value, arena);
+ break;
+ }
+ case UPB_TYPE_BYTES: {
+ VALUE bytes = rb_enc_from_encoding(rb_ascii8bit_encoding());
+ if (CLASS_OF(value) != rb_cString) {
+ rb_raise(cTypeError, "Invalid argument for bytes field '%s' (given %s).",
+ name, rb_class2name(CLASS_OF(value)));
+ }
+
+ if (rb_obj_encoding(value) != bytes) {
+ // Note: this will not duplicate underlying string data unless necessary.
+ // TODO(haberman): is this really necessary to get raw bytes?
+ value = rb_str_encode(value, bytes, 0, Qnil);
+ }
+
+ ret.str_val = Convert_StringData(value, arena);
+ break;
+ }
+ case UPB_TYPE_MESSAGE:
+ ret.msg_val =
+ Message_GetUpbMessage(value, type_info.def.msgdef, name, arena);
+ break;
+ case UPB_TYPE_ENUM:
+ ret.int32_val = Convert_ToEnum(value, name, type_info.def.enumdef);
+ break;
+ case UPB_TYPE_INT32:
+ case UPB_TYPE_INT64:
+ case UPB_TYPE_UINT32:
+ case UPB_TYPE_UINT64:
+ Convert_CheckInt(name, type_info.type, value);
+ switch (type_info.type) {
+ case UPB_TYPE_INT32:
+ ret.int32_val = NUM2INT(value);
+ break;
+ case UPB_TYPE_INT64:
+ ret.int64_val = NUM2LL(value);
+ break;
+ case UPB_TYPE_UINT32:
+ ret.uint32_val = NUM2UINT(value);
+ break;
+ case UPB_TYPE_UINT64:
+ ret.uint64_val = NUM2ULL(value);
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+VALUE Convert_UpbToRuby(upb_msgval upb_val, TypeInfo type_info, VALUE arena) {
+ switch (type_info.type) {
+ case UPB_TYPE_FLOAT:
+ return DBL2NUM(upb_val.float_val);
+ case UPB_TYPE_DOUBLE:
+ return DBL2NUM(upb_val.double_val);
+ case UPB_TYPE_BOOL:
+ return upb_val.bool_val ? Qtrue : Qfalse;
+ case UPB_TYPE_INT32:
+ return INT2NUM(upb_val.int32_val);
+ case UPB_TYPE_INT64:
+ return LL2NUM(upb_val.int64_val);
+ case UPB_TYPE_UINT32:
+ return UINT2NUM(upb_val.uint32_val);
+ case UPB_TYPE_UINT64:
+ return ULL2NUM(upb_val.int64_val);
+ case UPB_TYPE_ENUM: {
+ const char* name =
+ upb_enumdef_iton(type_info.def.enumdef, upb_val.int32_val);
+ if (name) {
+ return ID2SYM(rb_intern(name));
+ } else {
+ return INT2NUM(upb_val.int32_val);
+ }
+ }
+ case UPB_TYPE_STRING: {
+ VALUE str_rb = rb_str_new(upb_val.str_val.data, upb_val.str_val.size);
+ rb_enc_associate(str_rb, rb_utf8_encoding());
+ rb_obj_freeze(str_rb);
+ return str_rb;
+ }
+ case UPB_TYPE_BYTES: {
+ VALUE str_rb = rb_str_new(upb_val.str_val.data, upb_val.str_val.size);
+ rb_enc_associate(str_rb, rb_ascii8bit_encoding());
+ rb_obj_freeze(str_rb);
+ return str_rb;
+ }
+ case UPB_TYPE_MESSAGE:
+ return Message_GetRubyWrapper((upb_msg*)upb_val.msg_val,
+ type_info.def.msgdef, arena);
+ default:
+ rb_raise(rb_eRuntimeError, "Convert_UpbToRuby(): Unexpected type %d",
+ (int)type_info.type);
+ }
+}
+
+upb_msgval Msgval_DeepCopy(upb_msgval msgval, TypeInfo type_info,
+ upb_arena* arena) {
+ upb_msgval new_msgval;
+
+ switch (type_info.type) {
+ default:
+ memcpy(&new_msgval, &msgval, sizeof(msgval));
+ break;
+ case UPB_TYPE_STRING:
+ case UPB_TYPE_BYTES: {
+ size_t n = msgval.str_val.size;
+ char *mem = upb_arena_malloc(arena, n);
+ new_msgval.str_val.data = mem;
+ new_msgval.str_val.size = n;
+ memcpy(mem, msgval.str_val.data, n);
+ break;
+ }
+ case UPB_TYPE_MESSAGE:
+ new_msgval.msg_val =
+ Message_deep_copy(msgval.msg_val, type_info.def.msgdef, arena);
+ break;
+ }
+
+ return new_msgval;
+}
+
+bool Msgval_IsEqual(upb_msgval val1, upb_msgval val2, TypeInfo type_info) {
+ switch (type_info.type) {
+ case UPB_TYPE_BOOL:
+ return memcmp(&val1, &val2, 1) == 0;
+ case UPB_TYPE_FLOAT:
+ case UPB_TYPE_INT32:
+ case UPB_TYPE_UINT32:
+ case UPB_TYPE_ENUM:
+ return memcmp(&val1, &val2, 4) == 0;
+ case UPB_TYPE_DOUBLE:
+ case UPB_TYPE_INT64:
+ case UPB_TYPE_UINT64:
+ return memcmp(&val1, &val2, 8) == 0;
+ case UPB_TYPE_STRING:
+ case UPB_TYPE_BYTES:
+ return val1.str_val.size != val2.str_val.size ||
+ memcmp(val1.str_val.data, val2.str_val.data,
+ val1.str_val.size) == 0;
+ case UPB_TYPE_MESSAGE:
+ return Message_Equal(val1.msg_val, val2.msg_val, type_info.def.msgdef);
+ default:
+ rb_raise(rb_eRuntimeError, "Internal error, unexpected type");
+ }
+}
+
+uint64_t Msgval_GetHash(upb_msgval val, TypeInfo type_info, uint64_t seed) {
+ switch (type_info.type) {
+ case UPB_TYPE_BOOL:
+ return wyhash(&val, 1, seed, _wyp);
+ case UPB_TYPE_FLOAT:
+ case UPB_TYPE_INT32:
+ case UPB_TYPE_UINT32:
+ case UPB_TYPE_ENUM:
+ return wyhash(&val, 4, seed, _wyp);
+ case UPB_TYPE_DOUBLE:
+ case UPB_TYPE_INT64:
+ case UPB_TYPE_UINT64:
+ return wyhash(&val, 8, seed, _wyp);
+ case UPB_TYPE_STRING:
+ case UPB_TYPE_BYTES:
+ return wyhash(val.str_val.data, val.str_val.size, seed, _wyp);
+ case UPB_TYPE_MESSAGE:
+ return Message_Hash(val.msg_val, type_info.def.msgdef, seed);
+ default:
+ rb_raise(rb_eRuntimeError, "Internal error, unexpected type");
+ }
+}
diff --git a/ruby/ext/google/protobuf_c/convert.h b/ruby/ext/google/protobuf_c/convert.h
new file mode 100644
index 0000000000..cda18a0547
--- /dev/null
+++ b/ruby/ext/google/protobuf_c/convert.h
@@ -0,0 +1,72 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef RUBY_PROTOBUF_CONVERT_H_
+#define RUBY_PROTOBUF_CONVERT_H_
+
+#include
+
+#include "protobuf.h"
+#include "ruby-upb.h"
+
+// Converts |ruby_val| to a upb_msgval according to |type_info|.
+//
+// The |arena| parameter indicates the lifetime of the container where this
+// value will be assigned. It is used as follows:
+// - If type is string or bytes, the string data will be copied into |arena|.
+// - If type is message, and we need to auto-construct a message due to implicit
+// conversions (eg. Time -> Google::Protobuf::Timestamp), the new message
+// will be created in |arena|.
+// - If type is message and the Ruby value is a message instance, we will fuse
+// the message's arena into |arena|, to ensure that this message outlives the
+// container.
+upb_msgval Convert_RubyToUpb(VALUE ruby_val, const char *name,
+ TypeInfo type_info, upb_arena *arena);
+
+// Converts |upb_val| to a Ruby VALUE according to |type_info|. This may involve
+// creating a Ruby wrapper object.
+//
+// The |arena| parameter indicates the arena that owns the lifetime of
+// |upb_val|. Any Ruby wrapper object that is created will reference |arena|
+// and ensure it outlives the wrapper.
+VALUE Convert_UpbToRuby(upb_msgval upb_val, TypeInfo type_info, VALUE arena);
+
+// Creates a deep copy of |msgval| in |arena|.
+upb_msgval Msgval_DeepCopy(upb_msgval msgval, TypeInfo type_info,
+ upb_arena *arena);
+
+// Returns true if |val1| and |val2| are equal. Their type is given by
+// |type_info|.
+bool Msgval_IsEqual(upb_msgval val1, upb_msgval val2, TypeInfo type_info);
+
+// Returns a hash value for the given upb_msgval.
+uint64_t Msgval_GetHash(upb_msgval val, TypeInfo type_info, uint64_t seed);
+
+#endif // RUBY_PROTOBUF_CONVERT_H_
diff --git a/ruby/ext/google/protobuf_c/defs.c b/ruby/ext/google/protobuf_c/defs.c
index 1a09cc5ffb..6cf8174ccd 100644
--- a/ruby/ext/google/protobuf_c/defs.c
+++ b/ruby/ext/google/protobuf_c/defs.c
@@ -30,8 +30,35 @@
#include
#include
+#include
+
+#include "convert.h"
+#include "message.h"
#include "protobuf.h"
+static VALUE Builder_build(VALUE _self);
+
+static VALUE cMessageBuilderContext;
+static VALUE cOneofBuilderContext;
+static VALUE cEnumBuilderContext;
+static VALUE cBuilder;
+
+// -----------------------------------------------------------------------------
+// Global map from upb {msg,enum}defs to wrapper Descriptor/EnumDescriptor
+// instances.
+// -----------------------------------------------------------------------------
+
+static VALUE get_msgdef_obj(VALUE descriptor_pool, const upb_msgdef* def);
+static VALUE get_enumdef_obj(VALUE descriptor_pool, const upb_enumdef* def);
+static VALUE get_fielddef_obj(VALUE descriptor_pool, const upb_fielddef* def);
+static VALUE get_filedef_obj(VALUE descriptor_pool, const upb_filedef* def);
+static VALUE get_oneofdef_obj(VALUE descriptor_pool, const upb_oneofdef* def);
+
+// A distinct object that is not accessible from Ruby. We use this as a
+// constructor argument to enforce that certain objects cannot be created from
+// Ruby.
+VALUE c_only_cookie = Qnil;
+
// -----------------------------------------------------------------------------
// Common utilities.
// -----------------------------------------------------------------------------
@@ -48,6 +75,10 @@ static VALUE rb_str_maybe_null(const char* s) {
return rb_str_new2(s);
}
+// -----------------------------------------------------------------------------
+// Backward compatibility code.
+// -----------------------------------------------------------------------------
+
static void rewrite_enum_default(const upb_symtab* symtab,
google_protobuf_FileDescriptorProto* file,
google_protobuf_FieldDescriptorProto* field) {
@@ -205,221 +236,70 @@ static void rewrite_nesting(VALUE msg_ent, google_protobuf_DescriptorProto* msg,
}
}
-/* We have to do some relatively complicated logic here for backward
- * compatibility.
- *
- * In descriptor.proto, messages are nested inside other messages if that is
- * what the original .proto file looks like. For example, suppose we have this
- * foo.proto:
- *
- * package foo;
- * message Bar {
- * message Baz {}
- * }
- *
- * The descriptor for this must look like this:
- *
- * file {
- * name: "test.proto"
- * package: "foo"
- * message_type {
- * name: "Bar"
- * nested_type {
- * name: "Baz"
- * }
- * }
- * }
- *
- * However, the Ruby generated code has always generated messages in a flat,
- * non-nested way:
- *
- * Google::Protobuf::DescriptorPool.generated_pool.build do
- * add_message "foo.Bar" do
- * end
- * add_message "foo.Bar.Baz" do
- * end
- * end
- *
- * Here we need to do a translation where we turn this generated code into the
- * above descriptor. We need to infer that "foo" is the package name, and not
- * a message itself.
- *
- * We delegate to Ruby to compute the transformation, for more concice and
- * readable code than we can do in C */
-static void rewrite_names(VALUE _file_builder,
- google_protobuf_FileDescriptorProto* file_proto) {
- FileBuilderContext* file_builder = ruby_to_FileBuilderContext(_file_builder);
- upb_arena *arena = file_builder->arena;
- // Build params (package, msg_names, enum_names).
- VALUE package = Qnil;
- VALUE msg_names = rb_ary_new();
- VALUE enum_names = rb_ary_new();
- size_t msg_count, enum_count, i;
- VALUE new_package, nesting, msg_ents, enum_ents;
- google_protobuf_DescriptorProto** msgs;
- google_protobuf_EnumDescriptorProto** enums;
-
- if (google_protobuf_FileDescriptorProto_has_package(file_proto)) {
- upb_strview package_str =
- google_protobuf_FileDescriptorProto_package(file_proto);
- package = rb_str_new(package_str.data, package_str.size);
- }
-
- msgs = google_protobuf_FileDescriptorProto_mutable_message_type(file_proto,
- &msg_count);
- for (i = 0; i < msg_count; i++) {
- upb_strview name = google_protobuf_DescriptorProto_name(msgs[i]);
- rb_ary_push(msg_names, rb_str_new(name.data, name.size));
- }
-
- enums = google_protobuf_FileDescriptorProto_mutable_enum_type(file_proto,
- &enum_count);
- for (i = 0; i < enum_count; i++) {
- upb_strview name = google_protobuf_EnumDescriptorProto_name(enums[i]);
- rb_ary_push(enum_names, rb_str_new(name.data, name.size));
- }
-
- {
- // Call Ruby code to calculate package name and nesting.
- VALUE args[3] = { package, msg_names, enum_names };
- VALUE internal = rb_eval_string("Google::Protobuf::Internal");
- VALUE ret = rb_funcallv(internal, rb_intern("fixup_descriptor"), 3, args);
-
- new_package = rb_ary_entry(ret, 0);
- nesting = rb_ary_entry(ret, 1);
- }
-
- // Rewrite package and names.
- if (new_package != Qnil) {
- upb_strview new_package_str =
- FileBuilderContext_strdup(_file_builder, new_package);
- google_protobuf_FileDescriptorProto_set_package(file_proto,
- new_package_str);
- }
-
- for (i = 0; i < msg_count; i++) {
- upb_strview name = google_protobuf_DescriptorProto_name(msgs[i]);
- remove_path(&name);
- google_protobuf_DescriptorProto_set_name(msgs[i], name);
- }
-
- for (i = 0; i < enum_count; i++) {
- upb_strview name = google_protobuf_EnumDescriptorProto_name(enums[i]);
- remove_path(&name);
- google_protobuf_EnumDescriptorProto_set_name(enums[i], name);
- }
-
- // Rewrite nesting.
- msg_ents = rb_hash_aref(nesting, ID2SYM(rb_intern("msgs")));
- enum_ents = rb_hash_aref(nesting, ID2SYM(rb_intern("enums")));
-
- Check_Type(msg_ents, T_ARRAY);
- Check_Type(enum_ents, T_ARRAY);
-
- for (i = 0; i < (size_t)RARRAY_LEN(msg_ents); i++) {
- VALUE msg_ent = rb_ary_entry(msg_ents, i);
- VALUE pos = rb_hash_aref(msg_ent, ID2SYM(rb_intern("pos")));
- msgs[i] = msgs[NUM2INT(pos)];
- rewrite_nesting(msg_ent, msgs[i], msgs, enums, arena);
- }
-
- for (i = 0; i < (size_t)RARRAY_LEN(enum_ents); i++) {
- VALUE enum_pos = rb_ary_entry(enum_ents, i);
- enums[i] = enums[NUM2INT(enum_pos)];
- }
-
- google_protobuf_FileDescriptorProto_resize_message_type(
- file_proto, RARRAY_LEN(msg_ents), arena);
- google_protobuf_FileDescriptorProto_resize_enum_type(
- file_proto, RARRAY_LEN(enum_ents), arena);
-}
-
// -----------------------------------------------------------------------------
// DescriptorPool.
// -----------------------------------------------------------------------------
-#define DEFINE_CLASS(name, string_name) \
- VALUE c ## name = Qnil; \
- const rb_data_type_t _ ## name ## _type = { \
- string_name, \
- { name ## _mark, name ## _free, NULL }, \
- }; \
- name* ruby_to_ ## name(VALUE val) { \
- name* ret; \
- TypedData_Get_Struct(val, name, &_ ## name ## _type, ret); \
- return ret; \
- } \
-
-#define DEFINE_SELF(type, var, rb_var) \
- type* var = ruby_to_ ## type(rb_var)
+typedef struct {
+ VALUE def_to_descriptor; // Hash table of def* -> Ruby descriptor.
+ upb_symtab* symtab;
+} DescriptorPool;
+
+VALUE cDescriptorPool = Qnil;
// Global singleton DescriptorPool. The user is free to create others, but this
// is used by generated code.
VALUE generated_pool = Qnil;
-DEFINE_CLASS(DescriptorPool, "Google::Protobuf::DescriptorPool");
-
-void DescriptorPool_mark(void* _self) {
+static void DescriptorPool_mark(void* _self) {
DescriptorPool* self = _self;
rb_gc_mark(self->def_to_descriptor);
}
-void DescriptorPool_free(void* _self) {
+static void DescriptorPool_free(void* _self) {
DescriptorPool* self = _self;
-
upb_symtab_free(self->symtab);
- upb_handlercache_free(self->fill_handler_cache);
- upb_handlercache_free(self->pb_serialize_handler_cache);
- upb_handlercache_free(self->json_serialize_handler_cache);
- upb_handlercache_free(self->json_serialize_handler_preserve_cache);
- upb_pbcodecache_free(self->fill_method_cache);
- upb_json_codecache_free(self->json_fill_method_cache);
-
xfree(self);
}
+static const rb_data_type_t DescriptorPool_type = {
+ "Google::Protobuf::DescriptorPool",
+ {DescriptorPool_mark, DescriptorPool_free, NULL},
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY,
+};
+
+static DescriptorPool* ruby_to_DescriptorPool(VALUE val) {
+ DescriptorPool* ret;
+ TypedData_Get_Struct(val, DescriptorPool, &DescriptorPool_type, ret);
+ return ret;
+}
+
+// Exposed to other modules in defs.h.
+const upb_symtab *DescriptorPool_GetSymtab(VALUE desc_pool_rb) {
+ DescriptorPool *pool = ruby_to_DescriptorPool(desc_pool_rb);
+ return pool->symtab;
+}
+
/*
* call-seq:
* DescriptorPool.new => pool
*
* Creates a new, empty, descriptor pool.
*/
-VALUE DescriptorPool_alloc(VALUE klass) {
+static VALUE DescriptorPool_alloc(VALUE klass) {
DescriptorPool* self = ALLOC(DescriptorPool);
VALUE ret;
self->def_to_descriptor = Qnil;
- ret = TypedData_Wrap_Struct(klass, &_DescriptorPool_type, self);
+ ret = TypedData_Wrap_Struct(klass, &DescriptorPool_type, self);
self->def_to_descriptor = rb_hash_new();
self->symtab = upb_symtab_new();
- self->fill_handler_cache =
- upb_handlercache_new(add_handlers_for_message, (void*)ret);
- self->pb_serialize_handler_cache = upb_pb_encoder_newcache();
- self->json_serialize_handler_cache = upb_json_printer_newcache(false);
- self->json_serialize_handler_preserve_cache =
- upb_json_printer_newcache(true);
- self->fill_method_cache = upb_pbcodecache_new(self->fill_handler_cache);
- self->json_fill_method_cache = upb_json_codecache_new();
+ ObjectCache_Add(self->symtab, ret, _upb_symtab_arena(self->symtab));
return ret;
}
-void DescriptorPool_register(VALUE module) {
- VALUE klass = rb_define_class_under(
- module, "DescriptorPool", rb_cObject);
- rb_define_alloc_func(klass, DescriptorPool_alloc);
- rb_define_method(klass, "build", DescriptorPool_build, -1);
- rb_define_method(klass, "lookup", DescriptorPool_lookup, 1);
- rb_define_singleton_method(klass, "generated_pool",
- DescriptorPool_generated_pool, 0);
- rb_gc_register_address(&cDescriptorPool);
- cDescriptorPool = klass;
-
- rb_gc_register_address(&generated_pool);
- generated_pool = rb_class_new_instance(0, NULL, klass);
-}
-
/*
* call-seq:
* DescriptorPool.build(&block)
@@ -430,7 +310,7 @@ void DescriptorPool_register(VALUE module) {
* Builder#add_enum within the block as appropriate. This is the recommended,
* idiomatic way to define new message and enum types.
*/
-VALUE DescriptorPool_build(int argc, VALUE* argv, VALUE _self) {
+static VALUE DescriptorPool_build(int argc, VALUE* argv, VALUE _self) {
VALUE ctx = rb_class_new_instance(1, &_self, cBuilder);
VALUE block = rb_block_proc();
rb_funcall_with_block(ctx, rb_intern("instance_eval"), 0, NULL, block);
@@ -445,8 +325,8 @@ VALUE DescriptorPool_build(int argc, VALUE* argv, VALUE _self) {
* Finds a Descriptor or EnumDescriptor by name and returns it, or nil if none
* exists with the given name.
*/
-VALUE DescriptorPool_lookup(VALUE _self, VALUE name) {
- DEFINE_SELF(DescriptorPool, self, _self);
+static VALUE DescriptorPool_lookup(VALUE _self, VALUE name) {
+ DescriptorPool* self = ruby_to_DescriptorPool(_self);
const char* name_str = get_str(name);
const upb_msgdef* msgdef;
const upb_enumdef* enumdef;
@@ -473,31 +353,53 @@ VALUE DescriptorPool_lookup(VALUE _self, VALUE name) {
* register types in this pool for convenience so that they do not have to hold
* a reference to a private pool instance.
*/
-VALUE DescriptorPool_generated_pool(VALUE _self) {
+static VALUE DescriptorPool_generated_pool(VALUE _self) {
return generated_pool;
}
+static void DescriptorPool_register(VALUE module) {
+ VALUE klass = rb_define_class_under(
+ module, "DescriptorPool", rb_cObject);
+ rb_define_alloc_func(klass, DescriptorPool_alloc);
+ rb_define_method(klass, "build", DescriptorPool_build, -1);
+ rb_define_method(klass, "lookup", DescriptorPool_lookup, 1);
+ rb_define_singleton_method(klass, "generated_pool",
+ DescriptorPool_generated_pool, 0);
+ rb_gc_register_address(&cDescriptorPool);
+ cDescriptorPool = klass;
+
+ rb_gc_register_address(&generated_pool);
+ generated_pool = rb_class_new_instance(0, NULL, klass);
+}
+
// -----------------------------------------------------------------------------
// Descriptor.
// -----------------------------------------------------------------------------
-DEFINE_CLASS(Descriptor, "Google::Protobuf::Descriptor");
+typedef struct {
+ const upb_msgdef* msgdef;
+ VALUE klass;
+ VALUE descriptor_pool;
+} Descriptor;
+
+VALUE cDescriptor = Qnil;
-void Descriptor_mark(void* _self) {
+static void Descriptor_mark(void* _self) {
Descriptor* self = _self;
rb_gc_mark(self->klass);
rb_gc_mark(self->descriptor_pool);
- if (self->layout && self->layout->empty_template) {
- layout_mark(self->layout, self->layout->empty_template);
- }
}
-void Descriptor_free(void* _self) {
- Descriptor* self = _self;
- if (self->layout) {
- free_layout(self->layout);
- }
- xfree(self);
+static const rb_data_type_t Descriptor_type = {
+ "Google::Protobuf::Descriptor",
+ {Descriptor_mark, RUBY_DEFAULT_FREE, NULL},
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY,
+};
+
+static Descriptor* ruby_to_Descriptor(VALUE val) {
+ Descriptor* ret;
+ TypedData_Get_Struct(val, Descriptor, &Descriptor_type, ret);
+ return ret;
}
/*
@@ -509,42 +411,24 @@ void Descriptor_free(void* _self) {
* it is added to a pool, after which it becomes immutable (as part of a
* finalization process).
*/
-VALUE Descriptor_alloc(VALUE klass) {
+static VALUE Descriptor_alloc(VALUE klass) {
Descriptor* self = ALLOC(Descriptor);
- VALUE ret = TypedData_Wrap_Struct(klass, &_Descriptor_type, self);
+ VALUE ret = TypedData_Wrap_Struct(klass, &Descriptor_type, self);
self->msgdef = NULL;
self->klass = Qnil;
self->descriptor_pool = Qnil;
- self->layout = NULL;
return ret;
}
-void Descriptor_register(VALUE module) {
- VALUE klass = rb_define_class_under(
- module, "Descriptor", rb_cObject);
- rb_define_alloc_func(klass, Descriptor_alloc);
- rb_define_method(klass, "initialize", Descriptor_initialize, 3);
- rb_define_method(klass, "each", Descriptor_each, 0);
- rb_define_method(klass, "lookup", Descriptor_lookup, 1);
- rb_define_method(klass, "each_oneof", Descriptor_each_oneof, 0);
- rb_define_method(klass, "lookup_oneof", Descriptor_lookup_oneof, 1);
- rb_define_method(klass, "msgclass", Descriptor_msgclass, 0);
- rb_define_method(klass, "name", Descriptor_name, 0);
- rb_define_method(klass, "file_descriptor", Descriptor_file_descriptor, 0);
- rb_include_module(klass, rb_mEnumerable);
- rb_gc_register_address(&cDescriptor);
- cDescriptor = klass;
-}
-
/*
* call-seq:
* Descriptor.new(c_only_cookie, ptr) => Descriptor
*
* Creates a descriptor wrapper object. May only be called from C.
*/
-VALUE Descriptor_initialize(VALUE _self, VALUE cookie,
- VALUE descriptor_pool, VALUE ptr) {
- DEFINE_SELF(Descriptor, self, _self);
+static VALUE Descriptor_initialize(VALUE _self, VALUE cookie,
+ VALUE descriptor_pool, VALUE ptr) {
+ Descriptor* self = ruby_to_Descriptor(_self);
if (cookie != c_only_cookie) {
rb_raise(rb_eRuntimeError,
@@ -563,8 +447,8 @@ VALUE Descriptor_initialize(VALUE _self, VALUE cookie,
*
* Returns the FileDescriptor object this message belongs to.
*/
-VALUE Descriptor_file_descriptor(VALUE _self) {
- DEFINE_SELF(Descriptor, self, _self);
+static VALUE Descriptor_file_descriptor(VALUE _self) {
+ Descriptor* self = ruby_to_Descriptor(_self);
return get_filedef_obj(self->descriptor_pool, upb_msgdef_file(self->msgdef));
}
@@ -575,8 +459,8 @@ VALUE Descriptor_file_descriptor(VALUE _self) {
* Returns the name of this message type as a fully-qualified string (e.g.,
* My.Package.MessageType).
*/
-VALUE Descriptor_name(VALUE _self) {
- DEFINE_SELF(Descriptor, self, _self);
+static VALUE Descriptor_name(VALUE _self) {
+ Descriptor* self = ruby_to_Descriptor(_self);
return rb_str_maybe_null(upb_msgdef_fullname(self->msgdef));
}
@@ -586,8 +470,8 @@ VALUE Descriptor_name(VALUE _self) {
*
* Iterates over fields in this message type, yielding to the block on each one.
*/
-VALUE Descriptor_each(VALUE _self) {
- DEFINE_SELF(Descriptor, self, _self);
+static VALUE Descriptor_each(VALUE _self) {
+ Descriptor* self = ruby_to_Descriptor(_self);
upb_msg_field_iter it;
for (upb_msg_field_begin(&it, self->msgdef);
@@ -607,8 +491,8 @@ VALUE Descriptor_each(VALUE _self) {
* Returns the field descriptor for the field with the given name, if present,
* or nil if none.
*/
-VALUE Descriptor_lookup(VALUE _self, VALUE name) {
- DEFINE_SELF(Descriptor, self, _self);
+static VALUE Descriptor_lookup(VALUE _self, VALUE name) {
+ Descriptor* self = ruby_to_Descriptor(_self);
const char* s = get_str(name);
const upb_fielddef* field = upb_msgdef_ntofz(self->msgdef, s);
if (field == NULL) {
@@ -624,8 +508,8 @@ VALUE Descriptor_lookup(VALUE _self, VALUE name) {
* Invokes the given block for each oneof in this message type, passing the
* corresponding OneofDescriptor.
*/
-VALUE Descriptor_each_oneof(VALUE _self) {
- DEFINE_SELF(Descriptor, self, _self);
+static VALUE Descriptor_each_oneof(VALUE _self) {
+ Descriptor* self = ruby_to_Descriptor(_self);
upb_msg_oneof_iter it;
for (upb_msg_oneof_begin(&it, self->msgdef);
@@ -645,8 +529,8 @@ VALUE Descriptor_each_oneof(VALUE _self) {
* Returns the oneof descriptor for the oneof with the given name, if present,
* or nil if none.
*/
-VALUE Descriptor_lookup_oneof(VALUE _self, VALUE name) {
- DEFINE_SELF(Descriptor, self, _self);
+static VALUE Descriptor_lookup_oneof(VALUE _self, VALUE name) {
+ Descriptor* self = ruby_to_Descriptor(_self);
const char* s = get_str(name);
const upb_oneofdef* oneof = upb_msgdef_ntooz(self->msgdef, s);
if (oneof == NULL) {
@@ -661,32 +545,62 @@ VALUE Descriptor_lookup_oneof(VALUE _self, VALUE name) {
*
* Returns the Ruby class created for this message type.
*/
-VALUE Descriptor_msgclass(VALUE _self) {
- DEFINE_SELF(Descriptor, self, _self);
+static VALUE Descriptor_msgclass(VALUE _self) {
+ Descriptor* self = ruby_to_Descriptor(_self);
if (self->klass == Qnil) {
self->klass = build_class_from_descriptor(_self);
}
return self->klass;
}
+static void Descriptor_register(VALUE module) {
+ VALUE klass = rb_define_class_under(
+ module, "Descriptor", rb_cObject);
+ rb_define_alloc_func(klass, Descriptor_alloc);
+ rb_define_method(klass, "initialize", Descriptor_initialize, 3);
+ rb_define_method(klass, "each", Descriptor_each, 0);
+ rb_define_method(klass, "lookup", Descriptor_lookup, 1);
+ rb_define_method(klass, "each_oneof", Descriptor_each_oneof, 0);
+ rb_define_method(klass, "lookup_oneof", Descriptor_lookup_oneof, 1);
+ rb_define_method(klass, "msgclass", Descriptor_msgclass, 0);
+ rb_define_method(klass, "name", Descriptor_name, 0);
+ rb_define_method(klass, "file_descriptor", Descriptor_file_descriptor, 0);
+ rb_include_module(klass, rb_mEnumerable);
+ rb_gc_register_address(&cDescriptor);
+ cDescriptor = klass;
+}
+
// -----------------------------------------------------------------------------
// FileDescriptor.
// -----------------------------------------------------------------------------
-DEFINE_CLASS(FileDescriptor, "Google::Protobuf::FileDescriptor");
+typedef struct {
+ const upb_filedef* filedef;
+ VALUE descriptor_pool; // Owns the upb_filedef.
+} FileDescriptor;
-void FileDescriptor_mark(void* _self) {
+static VALUE cFileDescriptor = Qnil;
+
+static void FileDescriptor_mark(void* _self) {
FileDescriptor* self = _self;
rb_gc_mark(self->descriptor_pool);
}
-void FileDescriptor_free(void* _self) {
- xfree(_self);
+static const rb_data_type_t FileDescriptor_type = {
+ "Google::Protobuf::FileDescriptor",
+ {FileDescriptor_mark, RUBY_DEFAULT_FREE, NULL},
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY,
+};
+
+static FileDescriptor* ruby_to_FileDescriptor(VALUE val) {
+ FileDescriptor* ret;
+ TypedData_Get_Struct(val, FileDescriptor, &FileDescriptor_type, ret);
+ return ret;
}
-VALUE FileDescriptor_alloc(VALUE klass) {
+static VALUE FileDescriptor_alloc(VALUE klass) {
FileDescriptor* self = ALLOC(FileDescriptor);
- VALUE ret = TypedData_Wrap_Struct(klass, &_FileDescriptor_type, self);
+ VALUE ret = TypedData_Wrap_Struct(klass, &FileDescriptor_type, self);
self->descriptor_pool = Qnil;
self->filedef = NULL;
return ret;
@@ -699,9 +613,9 @@ VALUE FileDescriptor_alloc(VALUE klass) {
* Returns a new file descriptor. The syntax must be set before it's passed
* to a builder.
*/
-VALUE FileDescriptor_initialize(VALUE _self, VALUE cookie,
+static VALUE FileDescriptor_initialize(VALUE _self, VALUE cookie,
VALUE descriptor_pool, VALUE ptr) {
- DEFINE_SELF(FileDescriptor, self, _self);
+ FileDescriptor* self = ruby_to_FileDescriptor(_self);
if (cookie != c_only_cookie) {
rb_raise(rb_eRuntimeError,
@@ -714,25 +628,14 @@ VALUE FileDescriptor_initialize(VALUE _self, VALUE cookie,
return Qnil;
}
-void FileDescriptor_register(VALUE module) {
- VALUE klass = rb_define_class_under(
- module, "FileDescriptor", rb_cObject);
- rb_define_alloc_func(klass, FileDescriptor_alloc);
- rb_define_method(klass, "initialize", FileDescriptor_initialize, 3);
- rb_define_method(klass, "name", FileDescriptor_name, 0);
- rb_define_method(klass, "syntax", FileDescriptor_syntax, 0);
- rb_gc_register_address(&cFileDescriptor);
- cFileDescriptor = klass;
-}
-
/*
* call-seq:
* FileDescriptor.name => name
*
* Returns the name of the file.
*/
-VALUE FileDescriptor_name(VALUE _self) {
- DEFINE_SELF(FileDescriptor, self, _self);
+static VALUE FileDescriptor_name(VALUE _self) {
+ FileDescriptor* self = ruby_to_FileDescriptor(_self);
const char* name = upb_filedef_name(self->filedef);
return name == NULL ? Qnil : rb_str_new2(name);
}
@@ -746,8 +649,8 @@ VALUE FileDescriptor_name(VALUE _self) {
* Valid syntax versions are:
* :proto2 or :proto3.
*/
-VALUE FileDescriptor_syntax(VALUE _self) {
- DEFINE_SELF(FileDescriptor, self, _self);
+static VALUE FileDescriptor_syntax(VALUE _self) {
+ FileDescriptor* self = ruby_to_FileDescriptor(_self);
switch (upb_filedef_syntax(self->filedef)) {
case UPB_SYNTAX_PROTO3: return ID2SYM(rb_intern("proto3"));
@@ -756,19 +659,43 @@ VALUE FileDescriptor_syntax(VALUE _self) {
}
}
+static void FileDescriptor_register(VALUE module) {
+ VALUE klass = rb_define_class_under(
+ module, "FileDescriptor", rb_cObject);
+ rb_define_alloc_func(klass, FileDescriptor_alloc);
+ rb_define_method(klass, "initialize", FileDescriptor_initialize, 3);
+ rb_define_method(klass, "name", FileDescriptor_name, 0);
+ rb_define_method(klass, "syntax", FileDescriptor_syntax, 0);
+ rb_gc_register_address(&cFileDescriptor);
+ cFileDescriptor = klass;
+}
+
// -----------------------------------------------------------------------------
// FieldDescriptor.
// -----------------------------------------------------------------------------
-DEFINE_CLASS(FieldDescriptor, "Google::Protobuf::FieldDescriptor");
+typedef struct {
+ const upb_fielddef* fielddef;
+ VALUE descriptor_pool; // Owns the upb_fielddef.
+} FieldDescriptor;
+
+static VALUE cFieldDescriptor = Qnil;
-void FieldDescriptor_mark(void* _self) {
+static void FieldDescriptor_mark(void* _self) {
FieldDescriptor* self = _self;
rb_gc_mark(self->descriptor_pool);
}
-void FieldDescriptor_free(void* _self) {
- xfree(_self);
+static const rb_data_type_t FieldDescriptor_type = {
+ "Google::Protobuf::FieldDescriptor",
+ {FieldDescriptor_mark, RUBY_DEFAULT_FREE, NULL},
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY,
+};
+
+static FieldDescriptor* ruby_to_FieldDescriptor(VALUE val) {
+ FieldDescriptor* ret;
+ TypedData_Get_Struct(val, FieldDescriptor, &FieldDescriptor_type, ret);
+ return ret;
}
/*
@@ -778,42 +705,22 @@ void FieldDescriptor_free(void* _self) {
* Returns a new field descriptor. Its name, type, etc. must be set before it is
* added to a message type.
*/
-VALUE FieldDescriptor_alloc(VALUE klass) {
+static VALUE FieldDescriptor_alloc(VALUE klass) {
FieldDescriptor* self = ALLOC(FieldDescriptor);
- VALUE ret = TypedData_Wrap_Struct(klass, &_FieldDescriptor_type, self);
+ VALUE ret = TypedData_Wrap_Struct(klass, &FieldDescriptor_type, self);
self->fielddef = NULL;
return ret;
}
-void FieldDescriptor_register(VALUE module) {
- VALUE klass = rb_define_class_under(
- module, "FieldDescriptor", rb_cObject);
- rb_define_alloc_func(klass, FieldDescriptor_alloc);
- rb_define_method(klass, "initialize", FieldDescriptor_initialize, 3);
- rb_define_method(klass, "name", FieldDescriptor_name, 0);
- rb_define_method(klass, "type", FieldDescriptor_type, 0);
- rb_define_method(klass, "default", FieldDescriptor_default, 0);
- rb_define_method(klass, "label", FieldDescriptor_label, 0);
- rb_define_method(klass, "number", FieldDescriptor_number, 0);
- rb_define_method(klass, "submsg_name", FieldDescriptor_submsg_name, 0);
- rb_define_method(klass, "subtype", FieldDescriptor_subtype, 0);
- rb_define_method(klass, "has?", FieldDescriptor_has, 1);
- rb_define_method(klass, "clear", FieldDescriptor_clear, 1);
- rb_define_method(klass, "get", FieldDescriptor_get, 1);
- rb_define_method(klass, "set", FieldDescriptor_set, 2);
- rb_gc_register_address(&cFieldDescriptor);
- cFieldDescriptor = klass;
-}
-
/*
* call-seq:
* EnumDescriptor.new(c_only_cookie, pool, ptr) => EnumDescriptor
*
* Creates a descriptor wrapper object. May only be called from C.
*/
-VALUE FieldDescriptor_initialize(VALUE _self, VALUE cookie,
- VALUE descriptor_pool, VALUE ptr) {
- DEFINE_SELF(FieldDescriptor, self, _self);
+static VALUE FieldDescriptor_initialize(VALUE _self, VALUE cookie,
+ VALUE descriptor_pool, VALUE ptr) {
+ FieldDescriptor* self = ruby_to_FieldDescriptor(_self);
if (cookie != c_only_cookie) {
rb_raise(rb_eRuntimeError,
@@ -832,11 +739,12 @@ VALUE FieldDescriptor_initialize(VALUE _self, VALUE cookie,
*
* Returns the name of this field.
*/
-VALUE FieldDescriptor_name(VALUE _self) {
- DEFINE_SELF(FieldDescriptor, self, _self);
+static VALUE FieldDescriptor_name(VALUE _self) {
+ FieldDescriptor* self = ruby_to_FieldDescriptor(_self);
return rb_str_maybe_null(upb_fielddef_name(self->fielddef));
}
+// Non-static, exposed to other .c files.
upb_fieldtype_t ruby_to_fieldtype(VALUE type) {
if (TYPE(type) != T_SYMBOL) {
rb_raise(rb_eArgError, "Expected symbol for field type.");
@@ -865,27 +773,7 @@ upb_fieldtype_t ruby_to_fieldtype(VALUE type) {
return 0;
}
-VALUE fieldtype_to_ruby(upb_fieldtype_t type) {
- switch (type) {
-#define CONVERT(upb, ruby) \
- case UPB_TYPE_ ## upb : return ID2SYM(rb_intern( # ruby ));
- CONVERT(FLOAT, float);
- CONVERT(DOUBLE, double);
- CONVERT(BOOL, bool);
- CONVERT(STRING, string);
- CONVERT(BYTES, bytes);
- CONVERT(MESSAGE, message);
- CONVERT(ENUM, enum);
- CONVERT(INT32, int32);
- CONVERT(INT64, int64);
- CONVERT(UINT32, uint32);
- CONVERT(UINT64, uint64);
-#undef CONVERT
- }
- return Qnil;
-}
-
-upb_descriptortype_t ruby_to_descriptortype(VALUE type) {
+static upb_descriptortype_t ruby_to_descriptortype(VALUE type) {
if (TYPE(type) != T_SYMBOL) {
rb_raise(rb_eArgError, "Expected symbol for field type.");
}
@@ -920,7 +808,7 @@ upb_descriptortype_t ruby_to_descriptortype(VALUE type) {
return 0;
}
-VALUE descriptortype_to_ruby(upb_descriptortype_t type) {
+static VALUE descriptortype_to_ruby(upb_descriptortype_t type) {
switch (type) {
#define CONVERT(upb, ruby) \
case UPB_DESCRIPTOR_TYPE_ ## upb : return ID2SYM(rb_intern( # ruby ));
@@ -947,29 +835,6 @@ VALUE descriptortype_to_ruby(upb_descriptortype_t type) {
return Qnil;
}
-VALUE ruby_to_label(VALUE label) {
- upb_label_t upb_label;
- bool converted = false;
-
-#define CONVERT(upb, ruby) \
- if (SYM2ID(label) == rb_intern( # ruby )) { \
- upb_label = UPB_LABEL_ ## upb; \
- converted = true; \
- }
-
- CONVERT(OPTIONAL, optional);
- CONVERT(REQUIRED, required);
- CONVERT(REPEATED, repeated);
-
-#undef CONVERT
-
- if (!converted) {
- rb_raise(rb_eArgError, "Unknown field label.");
- }
-
- return upb_label;
-}
-
/*
* call-seq:
* FieldDescriptor.type => type
@@ -980,8 +845,8 @@ VALUE ruby_to_label(VALUE label) {
* :int32, :int64, :uint32, :uint64, :float, :double, :bool, :string,
* :bytes, :message.
*/
-VALUE FieldDescriptor_type(VALUE _self) {
- DEFINE_SELF(FieldDescriptor, self, _self);
+static VALUE FieldDescriptor__type(VALUE _self) {
+ FieldDescriptor* self = ruby_to_FieldDescriptor(_self);
return descriptortype_to_ruby(upb_fielddef_descriptortype(self->fielddef));
}
@@ -991,9 +856,16 @@ VALUE FieldDescriptor_type(VALUE _self) {
*
* Returns this field's default, as a Ruby object, or nil if not yet set.
*/
-VALUE FieldDescriptor_default(VALUE _self) {
- DEFINE_SELF(FieldDescriptor, self, _self);
- return layout_get_default(self->fielddef);
+static VALUE FieldDescriptor_default(VALUE _self) {
+ FieldDescriptor* self = ruby_to_FieldDescriptor(_self);
+ const upb_fielddef *f = self->fielddef;
+ upb_msgval default_val = {0};
+ if (upb_fielddef_issubmsg(f)) {
+ return Qnil;
+ } else if (!upb_fielddef_isseq(f)) {
+ default_val = upb_fielddef_default(f);
+ }
+ return Convert_UpbToRuby(default_val, TypeInfo_get(self->fielddef), Qnil);
}
/*
@@ -1005,8 +877,8 @@ VALUE FieldDescriptor_default(VALUE _self) {
* Valid field labels are:
* :optional, :repeated
*/
-VALUE FieldDescriptor_label(VALUE _self) {
- DEFINE_SELF(FieldDescriptor, self, _self);
+static VALUE FieldDescriptor_label(VALUE _self) {
+ FieldDescriptor* self = ruby_to_FieldDescriptor(_self);
switch (upb_fielddef_label(self->fielddef)) {
#define CONVERT(upb, ruby) \
case UPB_LABEL_ ## upb : return ID2SYM(rb_intern( # ruby ));
@@ -1027,8 +899,8 @@ VALUE FieldDescriptor_label(VALUE _self) {
*
* Returns the tag number for this field.
*/
-VALUE FieldDescriptor_number(VALUE _self) {
- DEFINE_SELF(FieldDescriptor, self, _self);
+static VALUE FieldDescriptor_number(VALUE _self) {
+ FieldDescriptor* self = ruby_to_FieldDescriptor(_self);
return INT2NUM(upb_fielddef_number(self->fielddef));
}
@@ -1041,8 +913,8 @@ VALUE FieldDescriptor_number(VALUE _self) {
* name will be resolved within the context of the pool to which the containing
* message type is added.
*/
-VALUE FieldDescriptor_submsg_name(VALUE _self) {
- DEFINE_SELF(FieldDescriptor, self, _self);
+static VALUE FieldDescriptor_submsg_name(VALUE _self) {
+ FieldDescriptor* self = ruby_to_FieldDescriptor(_self);
switch (upb_fielddef_type(self->fielddef)) {
case UPB_TYPE_ENUM:
return rb_str_new2(
@@ -1064,8 +936,8 @@ VALUE FieldDescriptor_submsg_name(VALUE _self) {
* called *until* the containing message type is added to a pool (and thus
* resolved).
*/
-VALUE FieldDescriptor_subtype(VALUE _self) {
- DEFINE_SELF(FieldDescriptor, self, _self);
+static VALUE FieldDescriptor_subtype(VALUE _self) {
+ FieldDescriptor* self = ruby_to_FieldDescriptor(_self);
switch (upb_fielddef_type(self->fielddef)) {
case UPB_TYPE_ENUM:
return get_enumdef_obj(self->descriptor_pool,
@@ -1085,14 +957,19 @@ VALUE FieldDescriptor_subtype(VALUE _self) {
* Returns the value set for this field on the given message. Raises an
* exception if message is of the wrong type.
*/
-VALUE FieldDescriptor_get(VALUE _self, VALUE msg_rb) {
- DEFINE_SELF(FieldDescriptor, self, _self);
- MessageHeader* msg;
- TypedData_Get_Struct(msg_rb, MessageHeader, &Message_type, msg);
- if (msg->descriptor->msgdef != upb_fielddef_containingtype(self->fielddef)) {
+static VALUE FieldDescriptor_get(VALUE _self, VALUE msg_rb) {
+ FieldDescriptor* self = ruby_to_FieldDescriptor(_self);
+ const upb_msgdef *m;
+ const upb_msgdef *msg = Message_Get(msg_rb, &m);
+ VALUE arena = Message_GetArena(msg_rb);
+ upb_msgval msgval;
+
+ if (m != upb_fielddef_containingtype(self->fielddef)) {
rb_raise(cTypeError, "get method called on wrong message type");
}
- return layout_get(msg->descriptor->layout, Message_data(msg), self->fielddef);
+
+ msgval = upb_msg_get(msg, self->fielddef);
+ return Convert_UpbToRuby(msgval, TypeInfo_get(self->fielddef), arena);
}
/*
@@ -1102,17 +979,18 @@ VALUE FieldDescriptor_get(VALUE _self, VALUE msg_rb) {
* Returns whether the value is set on the given message. Raises an
* exception when calling for fields that do not have presence.
*/
-VALUE FieldDescriptor_has(VALUE _self, VALUE msg_rb) {
- DEFINE_SELF(FieldDescriptor, self, _self);
- MessageHeader* msg;
- TypedData_Get_Struct(msg_rb, MessageHeader, &Message_type, msg);
- if (msg->descriptor->msgdef != upb_fielddef_containingtype(self->fielddef)) {
+static VALUE FieldDescriptor_has(VALUE _self, VALUE msg_rb) {
+ FieldDescriptor* self = ruby_to_FieldDescriptor(_self);
+ const upb_msgdef *m;
+ const upb_msgdef *msg = Message_Get(msg_rb, &m);
+
+ if (m != upb_fielddef_containingtype(self->fielddef)) {
rb_raise(cTypeError, "has method called on wrong message type");
} else if (!upb_fielddef_haspresence(self->fielddef)) {
rb_raise(rb_eArgError, "does not track presence");
}
- return layout_has(msg->descriptor->layout, Message_data(msg), self->fielddef);
+ return upb_msg_has(msg, self->fielddef) ? Qtrue : Qfalse;
}
/*
@@ -1121,15 +999,16 @@ VALUE FieldDescriptor_has(VALUE _self, VALUE msg_rb) {
*
* Clears the field from the message if it's set.
*/
-VALUE FieldDescriptor_clear(VALUE _self, VALUE msg_rb) {
- DEFINE_SELF(FieldDescriptor, self, _self);
- MessageHeader* msg;
- TypedData_Get_Struct(msg_rb, MessageHeader, &Message_type, msg);
- if (msg->descriptor->msgdef != upb_fielddef_containingtype(self->fielddef)) {
+static VALUE FieldDescriptor_clear(VALUE _self, VALUE msg_rb) {
+ FieldDescriptor* self = ruby_to_FieldDescriptor(_self);
+ const upb_msgdef *m;
+ upb_msgdef *msg = Message_GetMutable(msg_rb, &m);
+
+ if (m != upb_fielddef_containingtype(self->fielddef)) {
rb_raise(cTypeError, "has method called on wrong message type");
}
- layout_clear(msg->descriptor->layout, Message_data(msg), self->fielddef);
+ upb_msg_clearfield(msg, self->fielddef);
return Qnil;
}
@@ -1141,30 +1020,69 @@ VALUE FieldDescriptor_clear(VALUE _self, VALUE msg_rb) {
* message. Raises an exception if message is of the wrong type. Performs the
* ordinary type-checks for field setting.
*/
-VALUE FieldDescriptor_set(VALUE _self, VALUE msg_rb, VALUE value) {
- DEFINE_SELF(FieldDescriptor, self, _self);
- MessageHeader* msg;
- TypedData_Get_Struct(msg_rb, MessageHeader, &Message_type, msg);
- if (msg->descriptor->msgdef != upb_fielddef_containingtype(self->fielddef)) {
+static VALUE FieldDescriptor_set(VALUE _self, VALUE msg_rb, VALUE value) {
+ FieldDescriptor* self = ruby_to_FieldDescriptor(_self);
+ const upb_msgdef *m;
+ upb_msgdef *msg = Message_GetMutable(msg_rb, &m);
+ upb_arena *arena = Arena_get(Message_GetArena(msg_rb));
+ upb_msgval msgval;
+
+ if (m != upb_fielddef_containingtype(self->fielddef)) {
rb_raise(cTypeError, "set method called on wrong message type");
}
- layout_set(msg->descriptor->layout, Message_data(msg), self->fielddef, value);
+
+ msgval = Convert_RubyToUpb(value, upb_fielddef_name(self->fielddef),
+ TypeInfo_get(self->fielddef), arena);
+ upb_msg_set(msg, self->fielddef, msgval, arena);
return Qnil;
}
+static void FieldDescriptor_register(VALUE module) {
+ VALUE klass = rb_define_class_under(
+ module, "FieldDescriptor", rb_cObject);
+ rb_define_alloc_func(klass, FieldDescriptor_alloc);
+ rb_define_method(klass, "initialize", FieldDescriptor_initialize, 3);
+ rb_define_method(klass, "name", FieldDescriptor_name, 0);
+ rb_define_method(klass, "type", FieldDescriptor__type, 0);
+ rb_define_method(klass, "default", FieldDescriptor_default, 0);
+ rb_define_method(klass, "label", FieldDescriptor_label, 0);
+ rb_define_method(klass, "number", FieldDescriptor_number, 0);
+ rb_define_method(klass, "submsg_name", FieldDescriptor_submsg_name, 0);
+ rb_define_method(klass, "subtype", FieldDescriptor_subtype, 0);
+ rb_define_method(klass, "has?", FieldDescriptor_has, 1);
+ rb_define_method(klass, "clear", FieldDescriptor_clear, 1);
+ rb_define_method(klass, "get", FieldDescriptor_get, 1);
+ rb_define_method(klass, "set", FieldDescriptor_set, 2);
+ rb_gc_register_address(&cFieldDescriptor);
+ cFieldDescriptor = klass;
+}
+
// -----------------------------------------------------------------------------
// OneofDescriptor.
// -----------------------------------------------------------------------------
-DEFINE_CLASS(OneofDescriptor, "Google::Protobuf::OneofDescriptor");
+typedef struct {
+ const upb_oneofdef* oneofdef;
+ VALUE descriptor_pool; // Owns the upb_oneofdef.
+} OneofDescriptor;
+
+static VALUE cOneofDescriptor = Qnil;
-void OneofDescriptor_mark(void* _self) {
+static void OneofDescriptor_mark(void* _self) {
OneofDescriptor* self = _self;
rb_gc_mark(self->descriptor_pool);
}
-void OneofDescriptor_free(void* _self) {
- xfree(_self);
+static const rb_data_type_t OneofDescriptor_type = {
+ "Google::Protobuf::OneofDescriptor",
+ {OneofDescriptor_mark, RUBY_DEFAULT_FREE, NULL},
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY,
+};
+
+static OneofDescriptor* ruby_to_OneofDescriptor(VALUE val) {
+ OneofDescriptor* ret;
+ TypedData_Get_Struct(val, OneofDescriptor, &OneofDescriptor_type, ret);
+ return ret;
}
/*
@@ -1174,35 +1092,23 @@ void OneofDescriptor_free(void* _self) {
* Creates a new, empty, oneof descriptor. The oneof may only be modified prior
* to being added to a message descriptor which is subsequently added to a pool.
*/
-VALUE OneofDescriptor_alloc(VALUE klass) {
+static VALUE OneofDescriptor_alloc(VALUE klass) {
OneofDescriptor* self = ALLOC(OneofDescriptor);
- VALUE ret = TypedData_Wrap_Struct(klass, &_OneofDescriptor_type, self);
+ VALUE ret = TypedData_Wrap_Struct(klass, &OneofDescriptor_type, self);
self->oneofdef = NULL;
self->descriptor_pool = Qnil;
return ret;
}
-void OneofDescriptor_register(VALUE module) {
- VALUE klass = rb_define_class_under(
- module, "OneofDescriptor", rb_cObject);
- rb_define_alloc_func(klass, OneofDescriptor_alloc);
- rb_define_method(klass, "initialize", OneofDescriptor_initialize, 3);
- rb_define_method(klass, "name", OneofDescriptor_name, 0);
- rb_define_method(klass, "each", OneofDescriptor_each, 0);
- rb_include_module(klass, rb_mEnumerable);
- rb_gc_register_address(&cOneofDescriptor);
- cOneofDescriptor = klass;
-}
-
/*
* call-seq:
* OneofDescriptor.new(c_only_cookie, pool, ptr) => OneofDescriptor
*
* Creates a descriptor wrapper object. May only be called from C.
*/
-VALUE OneofDescriptor_initialize(VALUE _self, VALUE cookie,
+static VALUE OneofDescriptor_initialize(VALUE _self, VALUE cookie,
VALUE descriptor_pool, VALUE ptr) {
- DEFINE_SELF(OneofDescriptor, self, _self);
+ OneofDescriptor* self = ruby_to_OneofDescriptor(_self);
if (cookie != c_only_cookie) {
rb_raise(rb_eRuntimeError,
@@ -1221,8 +1127,8 @@ VALUE OneofDescriptor_initialize(VALUE _self, VALUE cookie,
*
* Returns the name of this oneof.
*/
-VALUE OneofDescriptor_name(VALUE _self) {
- DEFINE_SELF(OneofDescriptor, self, _self);
+static VALUE OneofDescriptor_name(VALUE _self) {
+ OneofDescriptor* self = ruby_to_OneofDescriptor(_self);
return rb_str_maybe_null(upb_oneofdef_name(self->oneofdef));
}
@@ -1232,8 +1138,8 @@ VALUE OneofDescriptor_name(VALUE _self) {
*
* Iterates through fields in this oneof, yielding to the block on each one.
*/
-VALUE OneofDescriptor_each(VALUE _self) {
- DEFINE_SELF(OneofDescriptor, self, _self);
+static VALUE OneofDescriptor_each(VALUE _self) {
+ OneofDescriptor* self = ruby_to_OneofDescriptor(_self);
upb_oneof_iter it;
for (upb_oneof_begin(&it, self->oneofdef);
!upb_oneof_done(&it);
@@ -1245,40 +1151,72 @@ VALUE OneofDescriptor_each(VALUE _self) {
return Qnil;
}
+static void OneofDescriptor_register(VALUE module) {
+ VALUE klass = rb_define_class_under(
+ module, "OneofDescriptor", rb_cObject);
+ rb_define_alloc_func(klass, OneofDescriptor_alloc);
+ rb_define_method(klass, "initialize", OneofDescriptor_initialize, 3);
+ rb_define_method(klass, "name", OneofDescriptor_name, 0);
+ rb_define_method(klass, "each", OneofDescriptor_each, 0);
+ rb_include_module(klass, rb_mEnumerable);
+ rb_gc_register_address(&cOneofDescriptor);
+ cOneofDescriptor = klass;
+}
+
// -----------------------------------------------------------------------------
// EnumDescriptor.
// -----------------------------------------------------------------------------
-DEFINE_CLASS(EnumDescriptor, "Google::Protobuf::EnumDescriptor");
+typedef struct {
+ const upb_enumdef* enumdef;
+ VALUE module; // begins as nil
+ VALUE descriptor_pool; // Owns the upb_enumdef.
+} EnumDescriptor;
+
+static VALUE cEnumDescriptor = Qnil;
-void EnumDescriptor_mark(void* _self) {
+static void EnumDescriptor_mark(void* _self) {
EnumDescriptor* self = _self;
rb_gc_mark(self->module);
rb_gc_mark(self->descriptor_pool);
}
-void EnumDescriptor_free(void* _self) {
- xfree(_self);
+static const rb_data_type_t EnumDescriptor_type = {
+ "Google::Protobuf::EnumDescriptor",
+ {EnumDescriptor_mark, RUBY_DEFAULT_FREE, NULL},
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY,
+};
+
+static EnumDescriptor* ruby_to_EnumDescriptor(VALUE val) {
+ EnumDescriptor* ret;
+ TypedData_Get_Struct(val, EnumDescriptor, &EnumDescriptor_type, ret);
+ return ret;
}
-VALUE EnumDescriptor_alloc(VALUE klass) {
+static VALUE EnumDescriptor_alloc(VALUE klass) {
EnumDescriptor* self = ALLOC(EnumDescriptor);
- VALUE ret = TypedData_Wrap_Struct(klass, &_EnumDescriptor_type, self);
+ VALUE ret = TypedData_Wrap_Struct(klass, &EnumDescriptor_type, self);
self->enumdef = NULL;
self->module = Qnil;
self->descriptor_pool = Qnil;
return ret;
}
+// Exposed to other modules in defs.h.
+const upb_enumdef *EnumDescriptor_GetEnumDef(VALUE enum_desc_rb) {
+ EnumDescriptor *desc = ruby_to_EnumDescriptor(enum_desc_rb);
+ return desc->enumdef;
+}
+
/*
* call-seq:
* EnumDescriptor.new(c_only_cookie, ptr) => EnumDescriptor
*
* Creates a descriptor wrapper object. May only be called from C.
*/
-VALUE EnumDescriptor_initialize(VALUE _self, VALUE cookie,
- VALUE descriptor_pool, VALUE ptr) {
- DEFINE_SELF(EnumDescriptor, self, _self);
+static VALUE EnumDescriptor_initialize(VALUE _self, VALUE cookie,
+ VALUE descriptor_pool, VALUE ptr) {
+ EnumDescriptor* self = ruby_to_EnumDescriptor(_self);
if (cookie != c_only_cookie) {
rb_raise(rb_eRuntimeError,
@@ -1291,30 +1229,14 @@ VALUE EnumDescriptor_initialize(VALUE _self, VALUE cookie,
return Qnil;
}
-void EnumDescriptor_register(VALUE module) {
- VALUE klass = rb_define_class_under(
- module, "EnumDescriptor", rb_cObject);
- rb_define_alloc_func(klass, EnumDescriptor_alloc);
- rb_define_method(klass, "initialize", EnumDescriptor_initialize, 3);
- rb_define_method(klass, "name", EnumDescriptor_name, 0);
- rb_define_method(klass, "lookup_name", EnumDescriptor_lookup_name, 1);
- rb_define_method(klass, "lookup_value", EnumDescriptor_lookup_value, 1);
- rb_define_method(klass, "each", EnumDescriptor_each, 0);
- rb_define_method(klass, "enummodule", EnumDescriptor_enummodule, 0);
- rb_define_method(klass, "file_descriptor", EnumDescriptor_file_descriptor, 0);
- rb_include_module(klass, rb_mEnumerable);
- rb_gc_register_address(&cEnumDescriptor);
- cEnumDescriptor = klass;
-}
-
/*
* call-seq:
* EnumDescriptor.file_descriptor
*
* Returns the FileDescriptor object this enum belongs to.
*/
-VALUE EnumDescriptor_file_descriptor(VALUE _self) {
- DEFINE_SELF(EnumDescriptor, self, _self);
+static VALUE EnumDescriptor_file_descriptor(VALUE _self) {
+ EnumDescriptor* self = ruby_to_EnumDescriptor(_self);
return get_filedef_obj(self->descriptor_pool,
upb_enumdef_file(self->enumdef));
}
@@ -1325,8 +1247,8 @@ VALUE EnumDescriptor_file_descriptor(VALUE _self) {
*
* Returns the name of this enum type.
*/
-VALUE EnumDescriptor_name(VALUE _self) {
- DEFINE_SELF(EnumDescriptor, self, _self);
+static VALUE EnumDescriptor_name(VALUE _self) {
+ EnumDescriptor* self = ruby_to_EnumDescriptor(_self);
return rb_str_maybe_null(upb_enumdef_fullname(self->enumdef));
}
@@ -1337,8 +1259,8 @@ VALUE EnumDescriptor_name(VALUE _self) {
* Returns the numeric value corresponding to the given key name (as a Ruby
* symbol), or nil if none.
*/
-VALUE EnumDescriptor_lookup_name(VALUE _self, VALUE name) {
- DEFINE_SELF(EnumDescriptor, self, _self);
+static VALUE EnumDescriptor_lookup_name(VALUE _self, VALUE name) {
+ EnumDescriptor* self = ruby_to_EnumDescriptor(_self);
const char* name_str= rb_id2name(SYM2ID(name));
int32_t val = 0;
if (upb_enumdef_ntoiz(self->enumdef, name_str, &val)) {
@@ -1355,8 +1277,8 @@ VALUE EnumDescriptor_lookup_name(VALUE _self, VALUE name) {
* Returns the key name (as a Ruby symbol) corresponding to the integer value,
* or nil if none.
*/
-VALUE EnumDescriptor_lookup_value(VALUE _self, VALUE number) {
- DEFINE_SELF(EnumDescriptor, self, _self);
+static VALUE EnumDescriptor_lookup_value(VALUE _self, VALUE number) {
+ EnumDescriptor* self = ruby_to_EnumDescriptor(_self);
int32_t val = NUM2INT(number);
const char* name = upb_enumdef_iton(self->enumdef, val);
if (name != NULL) {
@@ -1373,8 +1295,8 @@ VALUE EnumDescriptor_lookup_value(VALUE _self, VALUE number) {
* Iterates over key => value mappings in this enum's definition, yielding to
* the block with (key, value) arguments for each one.
*/
-VALUE EnumDescriptor_each(VALUE _self) {
- DEFINE_SELF(EnumDescriptor, self, _self);
+static VALUE EnumDescriptor_each(VALUE _self) {
+ EnumDescriptor* self = ruby_to_EnumDescriptor(_self);
upb_enum_iter it;
for (upb_enum_begin(&it, self->enumdef);
@@ -1394,53 +1316,365 @@ VALUE EnumDescriptor_each(VALUE _self) {
*
* Returns the Ruby module corresponding to this enum type.
*/
-VALUE EnumDescriptor_enummodule(VALUE _self) {
- DEFINE_SELF(EnumDescriptor, self, _self);
+static VALUE EnumDescriptor_enummodule(VALUE _self) {
+ EnumDescriptor* self = ruby_to_EnumDescriptor(_self);
if (self->module == Qnil) {
self->module = build_module_from_enumdesc(_self);
}
return self->module;
}
+static void EnumDescriptor_register(VALUE module) {
+ VALUE klass = rb_define_class_under(
+ module, "EnumDescriptor", rb_cObject);
+ rb_define_alloc_func(klass, EnumDescriptor_alloc);
+ rb_define_method(klass, "initialize", EnumDescriptor_initialize, 3);
+ rb_define_method(klass, "name", EnumDescriptor_name, 0);
+ rb_define_method(klass, "lookup_name", EnumDescriptor_lookup_name, 1);
+ rb_define_method(klass, "lookup_value", EnumDescriptor_lookup_value, 1);
+ rb_define_method(klass, "each", EnumDescriptor_each, 0);
+ rb_define_method(klass, "enummodule", EnumDescriptor_enummodule, 0);
+ rb_define_method(klass, "file_descriptor", EnumDescriptor_file_descriptor, 0);
+ rb_include_module(klass, rb_mEnumerable);
+ rb_gc_register_address(&cEnumDescriptor);
+ cEnumDescriptor = klass;
+}
+
+// -----------------------------------------------------------------------------
+// FileBuilderContext.
+// -----------------------------------------------------------------------------
+
+typedef struct {
+ upb_arena *arena;
+ google_protobuf_FileDescriptorProto* file_proto;
+ VALUE descriptor_pool;
+} FileBuilderContext;
+
+static VALUE cFileBuilderContext = Qnil;
+
+static void FileBuilderContext_mark(void* _self) {
+ FileBuilderContext* self = _self;
+ rb_gc_mark(self->descriptor_pool);
+}
+
+static void FileBuilderContext_free(void* _self) {
+ FileBuilderContext* self = _self;
+ upb_arena_free(self->arena);
+ xfree(self);
+}
+
+static const rb_data_type_t FileBuilderContext_type = {
+ "Google::Protobuf::Internal::FileBuilderContext",
+ {FileBuilderContext_mark, FileBuilderContext_free, NULL},
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY,
+};
+
+static FileBuilderContext* ruby_to_FileBuilderContext(VALUE val) {
+ FileBuilderContext* ret;
+ TypedData_Get_Struct(val, FileBuilderContext, &FileBuilderContext_type, ret);
+ return ret;
+}
+
+static upb_strview FileBuilderContext_strdup2(VALUE _self, const char *str) {
+ FileBuilderContext* self = ruby_to_FileBuilderContext(_self);
+ upb_strview ret;
+ char *data;
+
+ ret.size = strlen(str);
+ data = upb_malloc(upb_arena_alloc(self->arena), ret.size + 1);
+ ret.data = data;
+ memcpy(data, str, ret.size);
+ /* Null-terminate required by rewrite_enum_defaults() above. */
+ data[ret.size] = '\0';
+ return ret;
+}
+
+static upb_strview FileBuilderContext_strdup(VALUE _self, VALUE rb_str) {
+ return FileBuilderContext_strdup2(_self, get_str(rb_str));
+}
+
+static upb_strview FileBuilderContext_strdup_sym(VALUE _self, VALUE rb_sym) {
+ Check_Type(rb_sym, T_SYMBOL);
+ return FileBuilderContext_strdup(_self, rb_id2str(SYM2ID(rb_sym)));
+}
+
+static VALUE FileBuilderContext_alloc(VALUE klass) {
+ FileBuilderContext* self = ALLOC(FileBuilderContext);
+ VALUE ret = TypedData_Wrap_Struct(klass, &FileBuilderContext_type, self);
+ self->arena = upb_arena_new();
+ self->file_proto = google_protobuf_FileDescriptorProto_new(self->arena);
+ self->descriptor_pool = Qnil;
+ return ret;
+}
+
+/*
+ * call-seq:
+ * FileBuilderContext.new(descriptor_pool) => context
+ *
+ * Create a new file builder context for the given file descriptor and
+ * builder context. This class is intended to serve as a DSL context to be used
+ * with #instance_eval.
+ */
+static VALUE FileBuilderContext_initialize(VALUE _self, VALUE descriptor_pool,
+ VALUE name, VALUE options) {
+ FileBuilderContext* self = ruby_to_FileBuilderContext(_self);
+ self->descriptor_pool = descriptor_pool;
+
+ google_protobuf_FileDescriptorProto_set_name(
+ self->file_proto, FileBuilderContext_strdup(_self, name));
+
+ // Default syntax for Ruby is proto3.
+ google_protobuf_FileDescriptorProto_set_syntax(
+ self->file_proto,
+ FileBuilderContext_strdup(_self, rb_str_new2("proto3")));
+
+ if (options != Qnil) {
+ VALUE syntax;
+
+ Check_Type(options, T_HASH);
+ syntax = rb_hash_lookup2(options, ID2SYM(rb_intern("syntax")), Qnil);
+
+ if (syntax != Qnil) {
+ VALUE syntax_str;
+
+ Check_Type(syntax, T_SYMBOL);
+ syntax_str = rb_id2str(SYM2ID(syntax));
+ google_protobuf_FileDescriptorProto_set_syntax(
+ self->file_proto, FileBuilderContext_strdup(_self, syntax_str));
+ }
+ }
+
+ return Qnil;
+}
+
+static void MessageBuilderContext_add_synthetic_oneofs(VALUE _self);
+
+/*
+ * call-seq:
+ * FileBuilderContext.add_message(name, &block)
+ *
+ * Creates a new, empty descriptor with the given name, and invokes the block in
+ * the context of a MessageBuilderContext on that descriptor. The block can then
+ * call, e.g., MessageBuilderContext#optional and MessageBuilderContext#repeated
+ * methods to define the message fields.
+ *
+ * This is the recommended, idiomatic way to build message definitions.
+ */
+static VALUE FileBuilderContext_add_message(VALUE _self, VALUE name) {
+ VALUE args[2] = { _self, name };
+ VALUE ctx = rb_class_new_instance(2, args, cMessageBuilderContext);
+ VALUE block = rb_block_proc();
+ rb_funcall_with_block(ctx, rb_intern("instance_eval"), 0, NULL, block);
+ MessageBuilderContext_add_synthetic_oneofs(ctx);
+ return Qnil;
+}
+
+/* We have to do some relatively complicated logic here for backward
+ * compatibility.
+ *
+ * In descriptor.proto, messages are nested inside other messages if that is
+ * what the original .proto file looks like. For example, suppose we have this
+ * foo.proto:
+ *
+ * package foo;
+ * message Bar {
+ * message Baz {}
+ * }
+ *
+ * The descriptor for this must look like this:
+ *
+ * file {
+ * name: "test.proto"
+ * package: "foo"
+ * message_type {
+ * name: "Bar"
+ * nested_type {
+ * name: "Baz"
+ * }
+ * }
+ * }
+ *
+ * However, the Ruby generated code has always generated messages in a flat,
+ * non-nested way:
+ *
+ * Google::Protobuf::DescriptorPool.generated_pool.build do
+ * add_message "foo.Bar" do
+ * end
+ * add_message "foo.Bar.Baz" do
+ * end
+ * end
+ *
+ * Here we need to do a translation where we turn this generated code into the
+ * above descriptor. We need to infer that "foo" is the package name, and not
+ * a message itself.
+ *
+ * We delegate to Ruby to compute the transformation, for more concice and
+ * readable code than we can do in C */
+static void rewrite_names(VALUE _file_builder,
+ google_protobuf_FileDescriptorProto* file_proto) {
+ FileBuilderContext* file_builder = ruby_to_FileBuilderContext(_file_builder);
+ upb_arena *arena = file_builder->arena;
+ // Build params (package, msg_names, enum_names).
+ VALUE package = Qnil;
+ VALUE msg_names = rb_ary_new();
+ VALUE enum_names = rb_ary_new();
+ size_t msg_count, enum_count, i;
+ VALUE new_package, nesting, msg_ents, enum_ents;
+ google_protobuf_DescriptorProto** msgs;
+ google_protobuf_EnumDescriptorProto** enums;
+
+ if (google_protobuf_FileDescriptorProto_has_package(file_proto)) {
+ upb_strview package_str =
+ google_protobuf_FileDescriptorProto_package(file_proto);
+ package = rb_str_new(package_str.data, package_str.size);
+ }
+
+ msgs = google_protobuf_FileDescriptorProto_mutable_message_type(file_proto,
+ &msg_count);
+ for (i = 0; i < msg_count; i++) {
+ upb_strview name = google_protobuf_DescriptorProto_name(msgs[i]);
+ rb_ary_push(msg_names, rb_str_new(name.data, name.size));
+ }
+
+ enums = google_protobuf_FileDescriptorProto_mutable_enum_type(file_proto,
+ &enum_count);
+ for (i = 0; i < enum_count; i++) {
+ upb_strview name = google_protobuf_EnumDescriptorProto_name(enums[i]);
+ rb_ary_push(enum_names, rb_str_new(name.data, name.size));
+ }
+
+ {
+ // Call Ruby code to calculate package name and nesting.
+ VALUE args[3] = { package, msg_names, enum_names };
+ VALUE internal = rb_eval_string("Google::Protobuf::Internal");
+ VALUE ret = rb_funcallv(internal, rb_intern("fixup_descriptor"), 3, args);
+
+ new_package = rb_ary_entry(ret, 0);
+ nesting = rb_ary_entry(ret, 1);
+ }
+
+ // Rewrite package and names.
+ if (new_package != Qnil) {
+ upb_strview new_package_str =
+ FileBuilderContext_strdup(_file_builder, new_package);
+ google_protobuf_FileDescriptorProto_set_package(file_proto,
+ new_package_str);
+ }
+
+ for (i = 0; i < msg_count; i++) {
+ upb_strview name = google_protobuf_DescriptorProto_name(msgs[i]);
+ remove_path(&name);
+ google_protobuf_DescriptorProto_set_name(msgs[i], name);
+ }
+
+ for (i = 0; i < enum_count; i++) {
+ upb_strview name = google_protobuf_EnumDescriptorProto_name(enums[i]);
+ remove_path(&name);
+ google_protobuf_EnumDescriptorProto_set_name(enums[i], name);
+ }
+
+ // Rewrite nesting.
+ msg_ents = rb_hash_aref(nesting, ID2SYM(rb_intern("msgs")));
+ enum_ents = rb_hash_aref(nesting, ID2SYM(rb_intern("enums")));
+
+ Check_Type(msg_ents, T_ARRAY);
+ Check_Type(enum_ents, T_ARRAY);
+
+ for (i = 0; i < (size_t)RARRAY_LEN(msg_ents); i++) {
+ VALUE msg_ent = rb_ary_entry(msg_ents, i);
+ VALUE pos = rb_hash_aref(msg_ent, ID2SYM(rb_intern("pos")));
+ msgs[i] = msgs[NUM2INT(pos)];
+ rewrite_nesting(msg_ent, msgs[i], msgs, enums, arena);
+ }
+
+ for (i = 0; i < (size_t)RARRAY_LEN(enum_ents); i++) {
+ VALUE enum_pos = rb_ary_entry(enum_ents, i);
+ enums[i] = enums[NUM2INT(enum_pos)];
+ }
+
+ google_protobuf_FileDescriptorProto_resize_message_type(
+ file_proto, RARRAY_LEN(msg_ents), arena);
+ google_protobuf_FileDescriptorProto_resize_enum_type(
+ file_proto, RARRAY_LEN(enum_ents), arena);
+}
+
+/*
+ * call-seq:
+ * FileBuilderContext.add_enum(name, &block)
+ *
+ * Creates a new, empty enum descriptor with the given name, and invokes the
+ * block in the context of an EnumBuilderContext on that descriptor. The block
+ * can then call EnumBuilderContext#add_value to define the enum values.
+ *
+ * This is the recommended, idiomatic way to build enum definitions.
+ */
+static VALUE FileBuilderContext_add_enum(VALUE _self, VALUE name) {
+ VALUE args[2] = { _self, name };
+ VALUE ctx = rb_class_new_instance(2, args, cEnumBuilderContext);
+ VALUE block = rb_block_proc();
+ rb_funcall_with_block(ctx, rb_intern("instance_eval"), 0, NULL, block);
+ return Qnil;
+}
+
+static void FileBuilderContext_build(VALUE _self) {
+ FileBuilderContext* self = ruby_to_FileBuilderContext(_self);
+ DescriptorPool* pool = ruby_to_DescriptorPool(self->descriptor_pool);
+ upb_status status;
+
+ rewrite_enum_defaults(pool->symtab, self->file_proto);
+ rewrite_names(_self, self->file_proto);
+
+ upb_status_clear(&status);
+ if (!upb_symtab_addfile(pool->symtab, self->file_proto, &status)) {
+ rb_raise(cTypeError, "Unable to add defs to DescriptorPool: %s",
+ upb_status_errmsg(&status));
+ }
+}
+
+static void FileBuilderContext_register(VALUE module) {
+ VALUE klass = rb_define_class_under(module, "FileBuilderContext", rb_cObject);
+ rb_define_alloc_func(klass, FileBuilderContext_alloc);
+ rb_define_method(klass, "initialize", FileBuilderContext_initialize, 3);
+ rb_define_method(klass, "add_message", FileBuilderContext_add_message, 1);
+ rb_define_method(klass, "add_enum", FileBuilderContext_add_enum, 1);
+ rb_gc_register_address(&cFileBuilderContext);
+ cFileBuilderContext = klass;
+}
+
// -----------------------------------------------------------------------------
// MessageBuilderContext.
// -----------------------------------------------------------------------------
-DEFINE_CLASS(MessageBuilderContext,
- "Google::Protobuf::Internal::MessageBuilderContext");
+typedef struct {
+ google_protobuf_DescriptorProto* msg_proto;
+ VALUE file_builder;
+} MessageBuilderContext;
+
+static VALUE cMessageBuilderContext = Qnil;
-void MessageBuilderContext_mark(void* _self) {
+static void MessageBuilderContext_mark(void* _self) {
MessageBuilderContext* self = _self;
rb_gc_mark(self->file_builder);
}
-void MessageBuilderContext_free(void* _self) {
- MessageBuilderContext* self = _self;
- xfree(self);
-}
+static const rb_data_type_t MessageBuilderContext_type = {
+ "Google::Protobuf::Internal::MessageBuilderContext",
+ {MessageBuilderContext_mark, RUBY_DEFAULT_FREE, NULL},
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY,
+};
-VALUE MessageBuilderContext_alloc(VALUE klass) {
- MessageBuilderContext* self = ALLOC(MessageBuilderContext);
- VALUE ret = TypedData_Wrap_Struct(
- klass, &_MessageBuilderContext_type, self);
- self->file_builder = Qnil;
+static MessageBuilderContext* ruby_to_MessageBuilderContext(VALUE val) {
+ MessageBuilderContext* ret;
+ TypedData_Get_Struct(val, MessageBuilderContext, &MessageBuilderContext_type,
+ ret);
return ret;
}
-void MessageBuilderContext_register(VALUE module) {
- VALUE klass = rb_define_class_under(
- module, "MessageBuilderContext", rb_cObject);
- rb_define_alloc_func(klass, MessageBuilderContext_alloc);
- rb_define_method(klass, "initialize",
- MessageBuilderContext_initialize, 2);
- rb_define_method(klass, "optional", MessageBuilderContext_optional, -1);
- rb_define_method(klass, "proto3_optional", MessageBuilderContext_proto3_optional, -1);
- rb_define_method(klass, "required", MessageBuilderContext_required, -1);
- rb_define_method(klass, "repeated", MessageBuilderContext_repeated, -1);
- rb_define_method(klass, "map", MessageBuilderContext_map, -1);
- rb_define_method(klass, "oneof", MessageBuilderContext_oneof, 1);
- rb_gc_register_address(&cMessageBuilderContext);
- cMessageBuilderContext = klass;
+static VALUE MessageBuilderContext_alloc(VALUE klass) {
+ MessageBuilderContext* self = ALLOC(MessageBuilderContext);
+ VALUE ret = TypedData_Wrap_Struct(klass, &MessageBuilderContext_type, self);
+ self->file_builder = Qnil;
+ return ret;
}
/*
@@ -1451,10 +1685,9 @@ void MessageBuilderContext_register(VALUE module) {
* builder context. This class is intended to serve as a DSL context to be used
* with #instance_eval.
*/
-VALUE MessageBuilderContext_initialize(VALUE _self,
- VALUE _file_builder,
- VALUE name) {
- DEFINE_SELF(MessageBuilderContext, self, _self);
+static VALUE MessageBuilderContext_initialize(VALUE _self, VALUE _file_builder,
+ VALUE name) {
+ MessageBuilderContext* self = ruby_to_MessageBuilderContext(_self);
FileBuilderContext* file_builder = ruby_to_FileBuilderContext(_file_builder);
google_protobuf_FileDescriptorProto* file_proto = file_builder->file_proto;
@@ -1472,7 +1705,7 @@ static void msgdef_add_field(VALUE msgbuilder_rb, upb_label_t label, VALUE name,
VALUE type, VALUE number, VALUE type_class,
VALUE options, int oneof_index,
bool proto3_optional) {
- DEFINE_SELF(MessageBuilderContext, self, msgbuilder_rb);
+ MessageBuilderContext* self = ruby_to_MessageBuilderContext(msgbuilder_rb);
FileBuilderContext* file_context =
ruby_to_FileBuilderContext(self->file_builder);
google_protobuf_FieldDescriptorProto* field_proto;
@@ -1527,9 +1760,16 @@ static void msgdef_add_field(VALUE msgbuilder_rb, upb_label_t label, VALUE name,
}
}
+#if RUBY_API_VERSION_CODE >= 20700
+static VALUE make_mapentry(VALUE _message_builder, VALUE types, int argc,
+ const VALUE* argv, VALUE blockarg) {
+ (void)blockarg;
+#else
static VALUE make_mapentry(VALUE _message_builder, VALUE types, int argc,
VALUE* argv) {
- DEFINE_SELF(MessageBuilderContext, message_builder, _message_builder);
+#endif
+ MessageBuilderContext* message_builder =
+ ruby_to_MessageBuilderContext(_message_builder);
VALUE type_class = rb_ary_entry(types, 2);
FileBuilderContext* file_context =
ruby_to_FileBuilderContext(message_builder->file_builder);
@@ -1596,8 +1836,8 @@ VALUE MessageBuilderContext_optional(int argc, VALUE* argv, VALUE _self) {
* FieldDescriptor#type=) and the type_class must be a string, if present (as
* accepted by FieldDescriptor#submsg_name=).
*/
-VALUE MessageBuilderContext_proto3_optional(int argc, VALUE* argv,
- VALUE _self) {
+static VALUE MessageBuilderContext_proto3_optional(int argc, VALUE* argv,
+ VALUE _self) {
VALUE name, type, number;
VALUE type_class, options = Qnil;
@@ -1630,7 +1870,8 @@ VALUE MessageBuilderContext_proto3_optional(int argc, VALUE* argv,
* completeness. Any attempt to add a message type with required fields to a
* pool will currently result in an error.
*/
-VALUE MessageBuilderContext_required(int argc, VALUE* argv, VALUE _self) {
+static VALUE MessageBuilderContext_required(int argc, VALUE* argv,
+ VALUE _self) {
VALUE name, type, number;
VALUE type_class, options = Qnil;
@@ -1658,7 +1899,8 @@ VALUE MessageBuilderContext_required(int argc, VALUE* argv, VALUE _self) {
* symbol (as accepted by FieldDescriptor#type=) and the type_class must be a
* string, if present (as accepted by FieldDescriptor#submsg_name=).
*/
-VALUE MessageBuilderContext_repeated(int argc, VALUE* argv, VALUE _self) {
+static VALUE MessageBuilderContext_repeated(int argc, VALUE* argv,
+ VALUE _self) {
VALUE name, type, number, type_class;
if (argc < 3) {
@@ -1687,8 +1929,8 @@ VALUE MessageBuilderContext_repeated(int argc, VALUE* argv, VALUE _self) {
* type_class must be a string, if present (as accepted by
* FieldDescriptor#submsg_name=).
*/
-VALUE MessageBuilderContext_map(int argc, VALUE* argv, VALUE _self) {
- DEFINE_SELF(MessageBuilderContext, self, _self);
+static VALUE MessageBuilderContext_map(int argc, VALUE* argv, VALUE _self) {
+ MessageBuilderContext* self = ruby_to_MessageBuilderContext(_self);
VALUE name, key_type, value_type, number, type_class;
VALUE mapentry_desc_name;
FileBuilderContext* file_builder;
@@ -1717,14 +1959,6 @@ VALUE MessageBuilderContext_map(int argc, VALUE* argv, VALUE _self) {
file_builder = ruby_to_FileBuilderContext(self->file_builder);
- // TODO(haberman): remove this restriction, maps are supported in proto2.
- if (upb_strview_eql(
- google_protobuf_FileDescriptorProto_syntax(file_builder->file_proto),
- upb_strview_makez("proto2"))) {
- rb_raise(rb_eArgError,
- "Cannot add a native map field using proto2 syntax.");
- }
-
// Create a new message descriptor for the map entry message, and create a
// repeated submessage field here with that type.
msg_name = google_protobuf_DescriptorProto_name(self->msg_proto);
@@ -1768,8 +2002,8 @@ VALUE MessageBuilderContext_map(int argc, VALUE* argv, VALUE _self) {
*
* This is the recommended, idiomatic way to build oneof definitions.
*/
-VALUE MessageBuilderContext_oneof(VALUE _self, VALUE name) {
- DEFINE_SELF(MessageBuilderContext, self, _self);
+static VALUE MessageBuilderContext_oneof(VALUE _self, VALUE name) {
+ MessageBuilderContext* self = ruby_to_MessageBuilderContext(_self);
size_t oneof_count;
FileBuilderContext* file_context =
ruby_to_FileBuilderContext(self->file_builder);
@@ -1795,8 +2029,8 @@ VALUE MessageBuilderContext_oneof(VALUE _self, VALUE name) {
return Qnil;
}
-void MessageBuilderContext_add_synthetic_oneofs(VALUE _self) {
- DEFINE_SELF(MessageBuilderContext, self, _self);
+static void MessageBuilderContext_add_synthetic_oneofs(VALUE _self) {
+ MessageBuilderContext* self = ruby_to_MessageBuilderContext(_self);
FileBuilderContext* file_context =
ruby_to_FileBuilderContext(self->file_builder);
size_t field_count, oneof_count;
@@ -1845,42 +2079,59 @@ void MessageBuilderContext_add_synthetic_oneofs(VALUE _self) {
}
}
+static void MessageBuilderContext_register(VALUE module) {
+ VALUE klass = rb_define_class_under(
+ module, "MessageBuilderContext", rb_cObject);
+ rb_define_alloc_func(klass, MessageBuilderContext_alloc);
+ rb_define_method(klass, "initialize",
+ MessageBuilderContext_initialize, 2);
+ rb_define_method(klass, "optional", MessageBuilderContext_optional, -1);
+ rb_define_method(klass, "proto3_optional", MessageBuilderContext_proto3_optional, -1);
+ rb_define_method(klass, "required", MessageBuilderContext_required, -1);
+ rb_define_method(klass, "repeated", MessageBuilderContext_repeated, -1);
+ rb_define_method(klass, "map", MessageBuilderContext_map, -1);
+ rb_define_method(klass, "oneof", MessageBuilderContext_oneof, 1);
+ rb_gc_register_address(&cMessageBuilderContext);
+ cMessageBuilderContext = klass;
+}
+
// -----------------------------------------------------------------------------
// OneofBuilderContext.
// -----------------------------------------------------------------------------
-DEFINE_CLASS(OneofBuilderContext,
- "Google::Protobuf::Internal::OneofBuilderContext");
+typedef struct {
+ int oneof_index;
+ VALUE message_builder;
+} OneofBuilderContext;
+
+static VALUE cOneofBuilderContext = Qnil;
void OneofBuilderContext_mark(void* _self) {
OneofBuilderContext* self = _self;
rb_gc_mark(self->message_builder);
}
-void OneofBuilderContext_free(void* _self) {
- xfree(_self);
+static const rb_data_type_t OneofBuilderContext_type = {
+ "Google::Protobuf::Internal::OneofBuilderContext",
+ {OneofBuilderContext_mark, RUBY_DEFAULT_FREE, NULL},
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY,
+};
+
+static OneofBuilderContext* ruby_to_OneofBuilderContext(VALUE val) {
+ OneofBuilderContext* ret;
+ TypedData_Get_Struct(val, OneofBuilderContext, &OneofBuilderContext_type,
+ ret);
+ return ret;
}
-VALUE OneofBuilderContext_alloc(VALUE klass) {
+static VALUE OneofBuilderContext_alloc(VALUE klass) {
OneofBuilderContext* self = ALLOC(OneofBuilderContext);
- VALUE ret = TypedData_Wrap_Struct(
- klass, &_OneofBuilderContext_type, self);
+ VALUE ret = TypedData_Wrap_Struct(klass, &OneofBuilderContext_type, self);
self->oneof_index = 0;
self->message_builder = Qnil;
return ret;
}
-void OneofBuilderContext_register(VALUE module) {
- VALUE klass = rb_define_class_under(
- module, "OneofBuilderContext", rb_cObject);
- rb_define_alloc_func(klass, OneofBuilderContext_alloc);
- rb_define_method(klass, "initialize",
- OneofBuilderContext_initialize, 2);
- rb_define_method(klass, "optional", OneofBuilderContext_optional, -1);
- rb_gc_register_address(&cOneofBuilderContext);
- cOneofBuilderContext = klass;
-}
-
/*
* call-seq:
* OneofBuilderContext.new(oneof_index, message_builder) => context
@@ -1889,10 +2140,9 @@ void OneofBuilderContext_register(VALUE module) {
* builder context. This class is intended to serve as a DSL context to be used
* with #instance_eval.
*/
-VALUE OneofBuilderContext_initialize(VALUE _self,
- VALUE oneof_index,
- VALUE message_builder) {
- DEFINE_SELF(OneofBuilderContext, self, _self);
+static VALUE OneofBuilderContext_initialize(VALUE _self, VALUE oneof_index,
+ VALUE message_builder) {
+ OneofBuilderContext* self = ruby_to_OneofBuilderContext(_self);
self->oneof_index = NUM2INT(oneof_index);
self->message_builder = message_builder;
return Qnil;
@@ -1908,8 +2158,8 @@ VALUE OneofBuilderContext_initialize(VALUE _self,
* (as accepted by FieldDescriptor#type=) and the type_class must be a string,
* if present (as accepted by FieldDescriptor#submsg_name=).
*/
-VALUE OneofBuilderContext_optional(int argc, VALUE* argv, VALUE _self) {
- DEFINE_SELF(OneofBuilderContext, self, _self);
+static VALUE OneofBuilderContext_optional(int argc, VALUE* argv, VALUE _self) {
+ OneofBuilderContext* self = ruby_to_OneofBuilderContext(_self);
VALUE name, type, number;
VALUE type_class, options = Qnil;
@@ -1921,41 +2171,53 @@ VALUE OneofBuilderContext_optional(int argc, VALUE* argv, VALUE _self) {
return Qnil;
}
+static void OneofBuilderContext_register(VALUE module) {
+ VALUE klass = rb_define_class_under(
+ module, "OneofBuilderContext", rb_cObject);
+ rb_define_alloc_func(klass, OneofBuilderContext_alloc);
+ rb_define_method(klass, "initialize",
+ OneofBuilderContext_initialize, 2);
+ rb_define_method(klass, "optional", OneofBuilderContext_optional, -1);
+ rb_gc_register_address(&cOneofBuilderContext);
+ cOneofBuilderContext = klass;
+}
+
// -----------------------------------------------------------------------------
// EnumBuilderContext.
// -----------------------------------------------------------------------------
-DEFINE_CLASS(EnumBuilderContext,
- "Google::Protobuf::Internal::EnumBuilderContext");
+typedef struct {
+ google_protobuf_EnumDescriptorProto* enum_proto;
+ VALUE file_builder;
+} EnumBuilderContext;
+
+static VALUE cEnumBuilderContext = Qnil;
void EnumBuilderContext_mark(void* _self) {
EnumBuilderContext* self = _self;
rb_gc_mark(self->file_builder);
}
-void EnumBuilderContext_free(void* _self) {
- xfree(_self);
+static const rb_data_type_t EnumBuilderContext_type = {
+ "Google::Protobuf::Internal::EnumBuilderContext",
+ {EnumBuilderContext_mark, RUBY_DEFAULT_FREE, NULL},
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY,
+};
+
+static EnumBuilderContext* ruby_to_EnumBuilderContext(VALUE val) {
+ EnumBuilderContext* ret;
+ TypedData_Get_Struct(val, EnumBuilderContext, &EnumBuilderContext_type, ret);
+ return ret;
}
-VALUE EnumBuilderContext_alloc(VALUE klass) {
+static VALUE EnumBuilderContext_alloc(VALUE klass) {
EnumBuilderContext* self = ALLOC(EnumBuilderContext);
- VALUE ret = TypedData_Wrap_Struct(
- klass, &_EnumBuilderContext_type, self);
+ VALUE ret = TypedData_Wrap_Struct(klass, &EnumBuilderContext_type, self);
self->enum_proto = NULL;
self->file_builder = Qnil;
return ret;
}
-void EnumBuilderContext_register(VALUE module) {
- VALUE klass = rb_define_class_under(
- module, "EnumBuilderContext", rb_cObject);
- rb_define_alloc_func(klass, EnumBuilderContext_alloc);
- rb_define_method(klass, "initialize", EnumBuilderContext_initialize, 2);
- rb_define_method(klass, "value", EnumBuilderContext_value, 2);
- rb_gc_register_address(&cEnumBuilderContext);
- cEnumBuilderContext = klass;
-}
-
/*
* call-seq:
* EnumBuilderContext.new(file_builder) => context
@@ -1963,9 +2225,9 @@ void EnumBuilderContext_register(VALUE module) {
* Create a new builder context around the given enum descriptor. This class is
* intended to serve as a DSL context to be used with #instance_eval.
*/
-VALUE EnumBuilderContext_initialize(VALUE _self, VALUE _file_builder,
- VALUE name) {
- DEFINE_SELF(EnumBuilderContext, self, _self);
+static VALUE EnumBuilderContext_initialize(VALUE _self, VALUE _file_builder,
+ VALUE name) {
+ EnumBuilderContext* self = ruby_to_EnumBuilderContext(_self);
FileBuilderContext* file_builder = ruby_to_FileBuilderContext(_file_builder);
google_protobuf_FileDescriptorProto* file_proto = file_builder->file_proto;
@@ -1986,8 +2248,8 @@ VALUE EnumBuilderContext_initialize(VALUE _self, VALUE _file_builder,
* Adds the given name => number mapping to the enum type. Name must be a Ruby
* symbol.
*/
-VALUE EnumBuilderContext_value(VALUE _self, VALUE name, VALUE number) {
- DEFINE_SELF(EnumBuilderContext, self, _self);
+static VALUE EnumBuilderContext_value(VALUE _self, VALUE name, VALUE number) {
+ EnumBuilderContext* self = ruby_to_EnumBuilderContext(_self);
FileBuilderContext* file_builder =
ruby_to_FileBuilderContext(self->file_builder);
google_protobuf_EnumValueDescriptorProto* enum_value;
@@ -2003,196 +2265,53 @@ VALUE EnumBuilderContext_value(VALUE _self, VALUE name, VALUE number) {
return Qnil;
}
-
-// -----------------------------------------------------------------------------
-// FileBuilderContext.
-// -----------------------------------------------------------------------------
-
-DEFINE_CLASS(FileBuilderContext,
- "Google::Protobuf::Internal::FileBuilderContext");
-
-void FileBuilderContext_mark(void* _self) {
- FileBuilderContext* self = _self;
- rb_gc_mark(self->descriptor_pool);
-}
-
-void FileBuilderContext_free(void* _self) {
- FileBuilderContext* self = _self;
- upb_arena_free(self->arena);
- xfree(self);
-}
-
-upb_strview FileBuilderContext_strdup2(VALUE _self, const char *str) {
- DEFINE_SELF(FileBuilderContext, self, _self);
- upb_strview ret;
- char *data;
-
- ret.size = strlen(str);
- data = upb_malloc(upb_arena_alloc(self->arena), ret.size + 1);
- ret.data = data;
- memcpy(data, str, ret.size);
- /* Null-terminate required by rewrite_enum_defaults() above. */
- data[ret.size] = '\0';
- return ret;
-}
-
-upb_strview FileBuilderContext_strdup(VALUE _self, VALUE rb_str) {
- return FileBuilderContext_strdup2(_self, get_str(rb_str));
-}
-
-upb_strview FileBuilderContext_strdup_sym(VALUE _self, VALUE rb_sym) {
- Check_Type(rb_sym, T_SYMBOL);
- return FileBuilderContext_strdup(_self, rb_id2str(SYM2ID(rb_sym)));
-}
-
-VALUE FileBuilderContext_alloc(VALUE klass) {
- FileBuilderContext* self = ALLOC(FileBuilderContext);
- VALUE ret = TypedData_Wrap_Struct(klass, &_FileBuilderContext_type, self);
- self->arena = upb_arena_new();
- self->file_proto = google_protobuf_FileDescriptorProto_new(self->arena);
- self->descriptor_pool = Qnil;
- return ret;
-}
-
-void FileBuilderContext_register(VALUE module) {
- VALUE klass = rb_define_class_under(module, "FileBuilderContext", rb_cObject);
- rb_define_alloc_func(klass, FileBuilderContext_alloc);
- rb_define_method(klass, "initialize", FileBuilderContext_initialize, 3);
- rb_define_method(klass, "add_message", FileBuilderContext_add_message, 1);
- rb_define_method(klass, "add_enum", FileBuilderContext_add_enum, 1);
- rb_gc_register_address(&cFileBuilderContext);
- cFileBuilderContext = klass;
-}
-
-/*
- * call-seq:
- * FileBuilderContext.new(descriptor_pool) => context
- *
- * Create a new file builder context for the given file descriptor and
- * builder context. This class is intended to serve as a DSL context to be used
- * with #instance_eval.
- */
-VALUE FileBuilderContext_initialize(VALUE _self, VALUE descriptor_pool,
- VALUE name, VALUE options) {
- DEFINE_SELF(FileBuilderContext, self, _self);
- self->descriptor_pool = descriptor_pool;
-
- google_protobuf_FileDescriptorProto_set_name(
- self->file_proto, FileBuilderContext_strdup(_self, name));
-
- // Default syntax for Ruby is proto3.
- google_protobuf_FileDescriptorProto_set_syntax(
- self->file_proto,
- FileBuilderContext_strdup(_self, rb_str_new2("proto3")));
-
- if (options != Qnil) {
- VALUE syntax;
-
- Check_Type(options, T_HASH);
- syntax = rb_hash_lookup2(options, ID2SYM(rb_intern("syntax")), Qnil);
-
- if (syntax != Qnil) {
- VALUE syntax_str;
-
- Check_Type(syntax, T_SYMBOL);
- syntax_str = rb_id2str(SYM2ID(syntax));
- google_protobuf_FileDescriptorProto_set_syntax(
- self->file_proto, FileBuilderContext_strdup(_self, syntax_str));
- }
- }
-
- return Qnil;
-}
-
-/*
- * call-seq:
- * FileBuilderContext.add_message(name, &block)
- *
- * Creates a new, empty descriptor with the given name, and invokes the block in
- * the context of a MessageBuilderContext on that descriptor. The block can then
- * call, e.g., MessageBuilderContext#optional and MessageBuilderContext#repeated
- * methods to define the message fields.
- *
- * This is the recommended, idiomatic way to build message definitions.
- */
-VALUE FileBuilderContext_add_message(VALUE _self, VALUE name) {
- VALUE args[2] = { _self, name };
- VALUE ctx = rb_class_new_instance(2, args, cMessageBuilderContext);
- VALUE block = rb_block_proc();
- rb_funcall_with_block(ctx, rb_intern("instance_eval"), 0, NULL, block);
- MessageBuilderContext_add_synthetic_oneofs(ctx);
- return Qnil;
-}
-
-/*
- * call-seq:
- * FileBuilderContext.add_enum(name, &block)
- *
- * Creates a new, empty enum descriptor with the given name, and invokes the
- * block in the context of an EnumBuilderContext on that descriptor. The block
- * can then call EnumBuilderContext#add_value to define the enum values.
- *
- * This is the recommended, idiomatic way to build enum definitions.
- */
-VALUE FileBuilderContext_add_enum(VALUE _self, VALUE name) {
- VALUE args[2] = { _self, name };
- VALUE ctx = rb_class_new_instance(2, args, cEnumBuilderContext);
- VALUE block = rb_block_proc();
- rb_funcall_with_block(ctx, rb_intern("instance_eval"), 0, NULL, block);
- return Qnil;
-}
-
-void FileBuilderContext_build(VALUE _self) {
- DEFINE_SELF(FileBuilderContext, self, _self);
- DescriptorPool* pool = ruby_to_DescriptorPool(self->descriptor_pool);
- upb_status status;
-
- rewrite_enum_defaults(pool->symtab, self->file_proto);
- rewrite_names(_self, self->file_proto);
-
- upb_status_clear(&status);
- if (!upb_symtab_addfile(pool->symtab, self->file_proto, &status)) {
- rb_raise(cTypeError, "Unable to add defs to DescriptorPool: %s",
- upb_status_errmsg(&status));
- }
+static void EnumBuilderContext_register(VALUE module) {
+ VALUE klass = rb_define_class_under(
+ module, "EnumBuilderContext", rb_cObject);
+ rb_define_alloc_func(klass, EnumBuilderContext_alloc);
+ rb_define_method(klass, "initialize", EnumBuilderContext_initialize, 2);
+ rb_define_method(klass, "value", EnumBuilderContext_value, 2);
+ rb_gc_register_address(&cEnumBuilderContext);
+ cEnumBuilderContext = klass;
}
// -----------------------------------------------------------------------------
// Builder.
// -----------------------------------------------------------------------------
-DEFINE_CLASS(Builder, "Google::Protobuf::Internal::Builder");
+typedef struct {
+ VALUE descriptor_pool;
+ VALUE default_file_builder;
+} Builder;
-void Builder_mark(void* _self) {
+static VALUE cBuilder = Qnil;
+
+static void Builder_mark(void* _self) {
Builder* self = _self;
rb_gc_mark(self->descriptor_pool);
rb_gc_mark(self->default_file_builder);
}
-void Builder_free(void* _self) {
- xfree(_self);
+static const rb_data_type_t Builder_type = {
+ "Google::Protobuf::Internal::Builder",
+ {Builder_mark, RUBY_DEFAULT_FREE, NULL},
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY,
+};
+
+static Builder* ruby_to_Builder(VALUE val) {
+ Builder* ret;
+ TypedData_Get_Struct(val, Builder, &Builder_type, ret);
+ return ret;
}
-VALUE Builder_alloc(VALUE klass) {
+static VALUE Builder_alloc(VALUE klass) {
Builder* self = ALLOC(Builder);
- VALUE ret = TypedData_Wrap_Struct(
- klass, &_Builder_type, self);
+ VALUE ret = TypedData_Wrap_Struct(klass, &Builder_type, self);
self->descriptor_pool = Qnil;
self->default_file_builder = Qnil;
return ret;
}
-void Builder_register(VALUE module) {
- VALUE klass = rb_define_class_under(module, "Builder", rb_cObject);
- rb_define_alloc_func(klass, Builder_alloc);
- rb_define_method(klass, "initialize", Builder_initialize, 1);
- rb_define_method(klass, "add_file", Builder_add_file, -1);
- rb_define_method(klass, "add_message", Builder_add_message, 1);
- rb_define_method(klass, "add_enum", Builder_add_enum, 1);
- rb_gc_register_address(&cBuilder);
- cBuilder = klass;
-}
-
/*
* call-seq:
* Builder.new(descriptor_pool) => builder
@@ -2201,8 +2320,8 @@ void Builder_register(VALUE module) {
* descriptors and atomically register them into a pool in a way that allows for
* (co)recursive type references.
*/
-VALUE Builder_initialize(VALUE _self, VALUE pool) {
- DEFINE_SELF(Builder, self, _self);
+static VALUE Builder_initialize(VALUE _self, VALUE pool) {
+ Builder* self = ruby_to_Builder(_self);
self->descriptor_pool = pool;
self->default_file_builder = Qnil; // Created lazily if needed.
return Qnil;
@@ -2219,8 +2338,8 @@ VALUE Builder_initialize(VALUE _self, VALUE pool) {
*
* This is the recommended, idiomatic way to build file descriptors.
*/
-VALUE Builder_add_file(int argc, VALUE* argv, VALUE _self) {
- DEFINE_SELF(Builder, self, _self);
+static VALUE Builder_add_file(int argc, VALUE* argv, VALUE _self) {
+ Builder* self = ruby_to_Builder(_self);
VALUE name, options;
VALUE ctx;
VALUE block;
@@ -2240,7 +2359,7 @@ VALUE Builder_add_file(int argc, VALUE* argv, VALUE _self) {
}
static VALUE Builder_get_default_file(VALUE _self) {
- DEFINE_SELF(Builder, self, _self);
+ Builder* self = ruby_to_Builder(_self);
/* Lazily create only if legacy builder-level methods are called. */
if (self->default_file_builder == Qnil) {
@@ -2264,7 +2383,7 @@ static VALUE Builder_get_default_file(VALUE _self) {
* files generated by protoc which don't add messages within "add_file" block.
* Descriptors created this way get assigned to a default empty FileDescriptor.
*/
-VALUE Builder_add_message(VALUE _self, VALUE name) {
+static VALUE Builder_add_message(VALUE _self, VALUE name) {
VALUE file_builder = Builder_get_default_file(_self);
rb_funcall_with_block(file_builder, rb_intern("add_message"), 1, &name,
rb_block_proc());
@@ -2283,7 +2402,7 @@ VALUE Builder_add_message(VALUE _self, VALUE name) {
* Enum descriptors created this way get assigned to a default empty
* FileDescriptor.
*/
-VALUE Builder_add_enum(VALUE _self, VALUE name) {
+static VALUE Builder_add_enum(VALUE _self, VALUE name) {
VALUE file_builder = Builder_get_default_file(_self);
rb_funcall_with_block(file_builder, rb_intern("add_enum"), 1, &name,
rb_block_proc());
@@ -2292,8 +2411,8 @@ VALUE Builder_add_enum(VALUE _self, VALUE name) {
/* This method is hidden from Ruby, and only called directly from
* DescriptorPool_build(). */
-VALUE Builder_build(VALUE _self) {
- DEFINE_SELF(Builder, self, _self);
+static VALUE Builder_build(VALUE _self) {
+ Builder* self = ruby_to_Builder(_self);
if (self->default_file_builder != Qnil) {
FileBuilderContext_build(self->default_file_builder);
@@ -2303,8 +2422,19 @@ VALUE Builder_build(VALUE _self) {
return Qnil;
}
+static void Builder_register(VALUE module) {
+ VALUE klass = rb_define_class_under(module, "Builder", rb_cObject);
+ rb_define_alloc_func(klass, Builder_alloc);
+ rb_define_method(klass, "initialize", Builder_initialize, 1);
+ rb_define_method(klass, "add_file", Builder_add_file, -1);
+ rb_define_method(klass, "add_message", Builder_add_message, 1);
+ rb_define_method(klass, "add_enum", Builder_add_enum, 1);
+ rb_gc_register_address(&cBuilder);
+ cBuilder = klass;
+}
+
static VALUE get_def_obj(VALUE _descriptor_pool, const void* ptr, VALUE klass) {
- DEFINE_SELF(DescriptorPool, descriptor_pool, _descriptor_pool);
+ DescriptorPool* descriptor_pool = ruby_to_DescriptorPool(_descriptor_pool);
VALUE key = ULL2NUM((intptr_t)ptr);
VALUE def;
@@ -2319,48 +2449,111 @@ static VALUE get_def_obj(VALUE _descriptor_pool, const void* ptr, VALUE klass) {
VALUE args[3] = { c_only_cookie, _descriptor_pool, key };
def = rb_class_new_instance(3, args, klass);
rb_hash_aset(descriptor_pool->def_to_descriptor, key, def);
-
- // For message defs, we now eagerly get/create descriptors for all
- // submessages. We will need these anyway to parse or serialize this
- // message type. But more importantly, we must do this now so that
- // add_handlers_for_message() (which calls get_msgdef_obj()) does *not*
- // need to create a Ruby object or insert into a Ruby Hash. We need to
- // avoid triggering GC, which can switch Ruby threads and re-enter our
- // C extension from a different thread. This wreaks havoc on our state
- // if we were in the middle of building handlers.
- if (klass == cDescriptor) {
- const upb_msgdef *m = ptr;
- upb_msg_field_iter it;
- for (upb_msg_field_begin(&it, m);
- !upb_msg_field_done(&it);
- upb_msg_field_next(&it)) {
- const upb_fielddef* f = upb_msg_iter_field(&it);
- if (upb_fielddef_issubmsg(f)) {
- get_msgdef_obj(_descriptor_pool, upb_fielddef_msgsubdef(f));
- }
- }
- }
}
return def;
}
-VALUE get_msgdef_obj(VALUE descriptor_pool, const upb_msgdef* def) {
+static VALUE get_msgdef_obj(VALUE descriptor_pool, const upb_msgdef* def) {
return get_def_obj(descriptor_pool, def, cDescriptor);
}
-VALUE get_enumdef_obj(VALUE descriptor_pool, const upb_enumdef* def) {
+static VALUE get_enumdef_obj(VALUE descriptor_pool, const upb_enumdef* def) {
return get_def_obj(descriptor_pool, def, cEnumDescriptor);
}
-VALUE get_fielddef_obj(VALUE descriptor_pool, const upb_fielddef* def) {
+static VALUE get_fielddef_obj(VALUE descriptor_pool, const upb_fielddef* def) {
return get_def_obj(descriptor_pool, def, cFieldDescriptor);
}
-VALUE get_filedef_obj(VALUE descriptor_pool, const upb_filedef* def) {
+static VALUE get_filedef_obj(VALUE descriptor_pool, const upb_filedef* def) {
return get_def_obj(descriptor_pool, def, cFileDescriptor);
}
-VALUE get_oneofdef_obj(VALUE descriptor_pool, const upb_oneofdef* def) {
+static VALUE get_oneofdef_obj(VALUE descriptor_pool, const upb_oneofdef* def) {
return get_def_obj(descriptor_pool, def, cOneofDescriptor);
}
+
+// -----------------------------------------------------------------------------
+// Shared functions
+// -----------------------------------------------------------------------------
+
+// Functions exposed to other modules in defs.h.
+
+VALUE Descriptor_DefToClass(const upb_msgdef *m) {
+ const upb_symtab *symtab = upb_filedef_symtab(upb_msgdef_file(m));
+ VALUE pool = ObjectCache_Get(symtab);
+ PBRUBY_ASSERT(pool != Qnil);
+ VALUE desc_rb = get_msgdef_obj(pool, m);
+ const Descriptor* desc = ruby_to_Descriptor(desc_rb);
+ return desc->klass;
+}
+
+const upb_msgdef *Descriptor_GetMsgDef(VALUE desc_rb) {
+ const Descriptor* desc = ruby_to_Descriptor(desc_rb);
+ return desc->msgdef;
+}
+
+VALUE TypeInfo_InitArg(int argc, VALUE *argv, int skip_arg) {
+ if (argc > skip_arg) {
+ if (argc > 1 + skip_arg) {
+ rb_raise(rb_eArgError, "Expected a maximum of %d arguments.", skip_arg + 1);
+ }
+ return argv[skip_arg];
+ } else {
+ return Qnil;
+ }
+}
+
+TypeInfo TypeInfo_FromClass(int argc, VALUE* argv, int skip_arg,
+ VALUE* type_class, VALUE* init_arg) {
+ TypeInfo ret = {ruby_to_fieldtype(argv[skip_arg])};
+
+ if (ret.type == UPB_TYPE_MESSAGE || ret.type == UPB_TYPE_ENUM) {
+ *init_arg = TypeInfo_InitArg(argc, argv, skip_arg + 2);
+
+ if (argc < 2 + skip_arg) {
+ rb_raise(rb_eArgError, "Expected at least %d arguments for message/enum.",
+ 2 + skip_arg);
+ }
+
+ VALUE klass = argv[1 + skip_arg];
+ VALUE desc = MessageOrEnum_GetDescriptor(klass);
+ *type_class = klass;
+
+ if (desc == Qnil) {
+ rb_raise(rb_eArgError,
+ "Type class has no descriptor. Please pass a "
+ "class or enum as returned by the DescriptorPool.");
+ }
+
+ if (ret.type == UPB_TYPE_MESSAGE) {
+ ret.def.msgdef = ruby_to_Descriptor(desc)->msgdef;
+ Message_CheckClass(klass);
+ } else {
+ PBRUBY_ASSERT(ret.type == UPB_TYPE_ENUM);
+ ret.def.enumdef = ruby_to_EnumDescriptor(desc)->enumdef;
+ }
+ } else {
+ *init_arg = TypeInfo_InitArg(argc, argv, skip_arg + 1);
+ }
+
+ return ret;
+}
+
+void Defs_register(VALUE module) {
+ DescriptorPool_register(module);
+ Descriptor_register(module);
+ FileDescriptor_register(module);
+ FieldDescriptor_register(module);
+ OneofDescriptor_register(module);
+ EnumDescriptor_register(module);
+ FileBuilderContext_register(module);
+ MessageBuilderContext_register(module);
+ OneofBuilderContext_register(module);
+ EnumBuilderContext_register(module);
+ Builder_register(module);
+
+ rb_gc_register_address(&c_only_cookie);
+ c_only_cookie = rb_class_new_instance(0, NULL, rb_cObject);
+}
diff --git a/ruby/ext/google/protobuf_c/defs.h b/ruby/ext/google/protobuf_c/defs.h
new file mode 100644
index 0000000000..97a94bb7b5
--- /dev/null
+++ b/ruby/ext/google/protobuf_c/defs.h
@@ -0,0 +1,107 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef RUBY_PROTOBUF_DEFS_H_
+#define RUBY_PROTOBUF_DEFS_H_
+
+#include
+
+#include "protobuf.h"
+#include "ruby-upb.h"
+
+// -----------------------------------------------------------------------------
+// TypeInfo
+// -----------------------------------------------------------------------------
+
+// This bundles a upb_fieldtype_t and msgdef/enumdef when appropriate. This is
+// convenient for functions that need type information but cannot necessarily
+// assume a upb_fielddef will be available.
+//
+// For example, Google::Protobuf::Map and Google::Protobuf::RepeatedField can
+// be constructed with type information alone:
+//
+// # RepeatedField will internally store the type information in a TypeInfo.
+// Google::Protobuf::RepeatedField.new(:message, FooMessage)
+
+typedef struct {
+ upb_fieldtype_t type;
+ union {
+ const upb_msgdef* msgdef; // When type == UPB_TYPE_MESSAGE
+ const upb_enumdef* enumdef; // When type == UPB_TYPE_ENUM
+ } def;
+} TypeInfo;
+
+static inline TypeInfo TypeInfo_get(const upb_fielddef *f) {
+ TypeInfo ret = {upb_fielddef_type(f), {NULL}};
+ switch (ret.type) {
+ case UPB_TYPE_MESSAGE:
+ ret.def.msgdef = upb_fielddef_msgsubdef(f);
+ break;
+ case UPB_TYPE_ENUM:
+ ret.def.enumdef = upb_fielddef_enumsubdef(f);
+ break;
+ default:
+ break;
+ }
+ return ret;
+}
+
+TypeInfo TypeInfo_FromClass(int argc, VALUE* argv, int skip_arg,
+ VALUE* type_class, VALUE* init_arg);
+
+static inline TypeInfo TypeInfo_from_type(upb_fieldtype_t type) {
+ TypeInfo ret = {type};
+ assert(type != UPB_TYPE_MESSAGE && type != UPB_TYPE_ENUM);
+ return ret;
+}
+
+// -----------------------------------------------------------------------------
+// Other utilities
+// -----------------------------------------------------------------------------
+
+VALUE Descriptor_DefToClass(const upb_msgdef *m);
+
+// Returns the underlying msgdef, enumdef, or symtab (respectively) for the
+// given Descriptor, EnumDescriptor, or DescriptorPool Ruby object.
+const upb_enumdef *EnumDescriptor_GetEnumDef(VALUE enum_desc_rb);
+const upb_symtab *DescriptorPool_GetSymtab(VALUE desc_pool_rb);
+const upb_msgdef *Descriptor_GetMsgDef(VALUE desc_rb);
+
+// Returns a upb field type for the given Ruby symbol
+// (eg. :float => UPB_TYPE_FLOAT).
+upb_fieldtype_t ruby_to_fieldtype(VALUE type);
+
+// The singleton generated pool (a DescriptorPool object).
+extern VALUE generated_pool;
+
+// Call at startup to register all types in this module.
+void Defs_register(VALUE module);
+
+#endif // RUBY_PROTOBUF_DEFS_H_
diff --git a/ruby/ext/google/protobuf_c/encode_decode.c b/ruby/ext/google/protobuf_c/encode_decode.c
deleted file mode 100644
index a58a5d2f84..0000000000
--- a/ruby/ext/google/protobuf_c/encode_decode.c
+++ /dev/null
@@ -1,1795 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2014 Google Inc. All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#include "protobuf.h"
-
-VALUE initialize_rb_class_with_no_args(VALUE klass) {
- return rb_funcall(klass, rb_intern("new"), 0);
-}
-
-// This function is equivalent to rb_str_cat(), but unlike the real
-// rb_str_cat(), it doesn't leak memory in some versions of Ruby.
-// For more information, see:
-// https://bugs.ruby-lang.org/issues/11328
-VALUE noleak_rb_str_cat(VALUE rb_str, const char *str, long len) {
- char *p;
- size_t oldlen = RSTRING_LEN(rb_str);
- rb_str_modify_expand(rb_str, len);
- p = RSTRING_PTR(rb_str);
- memcpy(p + oldlen, str, len);
- rb_str_set_len(rb_str, oldlen + len);
- return rb_str;
-}
-
-bool is_wrapper(const upb_msgdef* m) {
- switch (upb_msgdef_wellknowntype(m)) {
- case UPB_WELLKNOWN_DOUBLEVALUE:
- case UPB_WELLKNOWN_FLOATVALUE:
- case UPB_WELLKNOWN_INT64VALUE:
- case UPB_WELLKNOWN_UINT64VALUE:
- case UPB_WELLKNOWN_INT32VALUE:
- case UPB_WELLKNOWN_UINT32VALUE:
- case UPB_WELLKNOWN_STRINGVALUE:
- case UPB_WELLKNOWN_BYTESVALUE:
- case UPB_WELLKNOWN_BOOLVALUE:
- return true;
- default:
- return false;
- }
-}
-
-// The code below also comes from upb's prototype Ruby binding, developed by
-// haberman@.
-
-/* stringsink *****************************************************************/
-
-static void *stringsink_start(void *_sink, const void *hd, size_t size_hint) {
- stringsink *sink = _sink;
- sink->len = 0;
- return sink;
-}
-
-static size_t stringsink_string(void *_sink, const void *hd, const char *ptr,
- size_t len, const upb_bufhandle *handle) {
- stringsink *sink = _sink;
- size_t new_size = sink->size;
-
- UPB_UNUSED(hd);
- UPB_UNUSED(handle);
-
- while (sink->len + len > new_size) {
- new_size *= 2;
- }
-
- if (new_size != sink->size) {
- sink->ptr = realloc(sink->ptr, new_size);
- sink->size = new_size;
- }
-
- memcpy(sink->ptr + sink->len, ptr, len);
- sink->len += len;
-
- return len;
-}
-
-void stringsink_init(stringsink *sink) {
- upb_byteshandler_init(&sink->handler);
- upb_byteshandler_setstartstr(&sink->handler, stringsink_start, NULL);
- upb_byteshandler_setstring(&sink->handler, stringsink_string, NULL);
-
- upb_bytessink_reset(&sink->sink, &sink->handler, sink);
-
- sink->size = 32;
- sink->ptr = malloc(sink->size);
- sink->len = 0;
-}
-
-void stringsink_uninit(stringsink *sink) {
- free(sink->ptr);
-}
-
-// -----------------------------------------------------------------------------
-// Parsing.
-// -----------------------------------------------------------------------------
-
-#define DEREF(msg, ofs, type) *(type*)(((uint8_t *)msg) + ofs)
-
-typedef struct {
- size_t ofs;
- int32_t hasbit;
-} field_handlerdata_t;
-
-// Creates a handlerdata that contains the offset and the hasbit for the field
-static const void* newhandlerdata(upb_handlers* h, uint32_t ofs, int32_t hasbit) {
- field_handlerdata_t *hd = ALLOC(field_handlerdata_t);
- hd->ofs = ofs;
- hd->hasbit = hasbit;
- upb_handlers_addcleanup(h, hd, xfree);
- return hd;
-}
-
-typedef struct {
- size_t ofs;
- int32_t hasbit;
- upb_fieldtype_t wrapped_type; // Only for wrappers.
- VALUE subklass;
-} submsg_handlerdata_t;
-
-// Creates a handlerdata that contains offset and submessage type information.
-static const void *newsubmsghandlerdata(upb_handlers* h,
- const upb_fielddef *f,
- uint32_t ofs,
- int32_t hasbit,
- VALUE subklass) {
- submsg_handlerdata_t *hd = ALLOC(submsg_handlerdata_t);
- const upb_msgdef *subm = upb_fielddef_msgsubdef(f);
- hd->ofs = ofs;
- hd->hasbit = hasbit;
- hd->subklass = subklass;
- upb_handlers_addcleanup(h, hd, xfree);
- if (is_wrapper(subm)) {
- const upb_fielddef *value_f = upb_msgdef_itof(subm, 1);
- hd->wrapped_type = upb_fielddef_type(value_f);
- }
- return hd;
-}
-
-typedef struct {
- size_t ofs; // union data slot
- size_t case_ofs; // oneof_case field
- uint32_t oneof_case_num; // oneof-case number to place in oneof_case field
- VALUE subklass;
-} oneof_handlerdata_t;
-
-static const void *newoneofhandlerdata(upb_handlers *h,
- uint32_t ofs,
- uint32_t case_ofs,
- const upb_fielddef *f,
- const Descriptor* desc) {
- oneof_handlerdata_t *hd = ALLOC(oneof_handlerdata_t);
- hd->ofs = ofs;
- hd->case_ofs = case_ofs;
- // We reuse the field tag number as a oneof union discriminant tag. Note that
- // we don't expose these numbers to the user, so the only requirement is that
- // we have some unique ID for each union case/possibility. The field tag
- // numbers are already present and are easy to use so there's no reason to
- // create a separate ID space. In addition, using the field tag number here
- // lets us easily look up the field in the oneof accessor.
- hd->oneof_case_num = upb_fielddef_number(f);
- if (is_value_field(f)) {
- hd->oneof_case_num |= ONEOF_CASE_MASK;
- }
- hd->subklass = field_type_class(desc->layout, f);
- upb_handlers_addcleanup(h, hd, xfree);
- return hd;
-}
-
-// A handler that starts a repeated field. Gets the Repeated*Field instance for
-// this field (such an instance always exists even in an empty message).
-static void *startseq_handler(void* closure, const void* hd) {
- MessageHeader* msg = closure;
- const size_t *ofs = hd;
- return (void*)DEREF(msg, *ofs, VALUE);
-}
-
-// Handlers that append primitive values to a repeated field.
-#define DEFINE_APPEND_HANDLER(type, ctype) \
- static bool append##type##_handler(void *closure, const void *hd, \
- ctype val) { \
- VALUE ary = (VALUE)closure; \
- RepeatedField_push_native(ary, &val); \
- return true; \
- }
-
-DEFINE_APPEND_HANDLER(bool, bool)
-DEFINE_APPEND_HANDLER(int32, int32_t)
-DEFINE_APPEND_HANDLER(uint32, uint32_t)
-DEFINE_APPEND_HANDLER(float, float)
-DEFINE_APPEND_HANDLER(int64, int64_t)
-DEFINE_APPEND_HANDLER(uint64, uint64_t)
-DEFINE_APPEND_HANDLER(double, double)
-
-// Appends a string to a repeated field.
-static void* appendstr_handler(void *closure,
- const void *hd,
- size_t size_hint) {
- VALUE ary = (VALUE)closure;
- VALUE str = rb_str_new2("");
- rb_enc_associate(str, kRubyStringUtf8Encoding);
- RepeatedField_push_native(ary, &str);
- return (void*)str;
-}
-
-static void set_hasbit(void *closure, int32_t hasbit) {
- if (hasbit > 0) {
- uint8_t* storage = closure;
- storage[hasbit/8] |= 1 << (hasbit % 8);
- }
-}
-
-// Appends a 'bytes' string to a repeated field.
-static void* appendbytes_handler(void *closure,
- const void *hd,
- size_t size_hint) {
- VALUE ary = (VALUE)closure;
- VALUE str = rb_str_new2("");
- rb_enc_associate(str, kRubyString8bitEncoding);
- RepeatedField_push_native(ary, &str);
- return (void*)str;
-}
-
-// Sets a non-repeated string field in a message.
-static void* str_handler(void *closure,
- const void *hd,
- size_t size_hint) {
- MessageHeader* msg = closure;
- const field_handlerdata_t *fieldhandler = hd;
-
- VALUE str = rb_str_new2("");
- rb_enc_associate(str, kRubyStringUtf8Encoding);
- DEREF(msg, fieldhandler->ofs, VALUE) = str;
- set_hasbit(closure, fieldhandler->hasbit);
- return (void*)str;
-}
-
-// Sets a non-repeated 'bytes' field in a message.
-static void* bytes_handler(void *closure,
- const void *hd,
- size_t size_hint) {
- MessageHeader* msg = closure;
- const field_handlerdata_t *fieldhandler = hd;
-
- VALUE str = rb_str_new2("");
- rb_enc_associate(str, kRubyString8bitEncoding);
- DEREF(msg, fieldhandler->ofs, VALUE) = str;
- set_hasbit(closure, fieldhandler->hasbit);
- return (void*)str;
-}
-
-static size_t stringdata_handler(void* closure, const void* hd,
- const char* str, size_t len,
- const upb_bufhandle* handle) {
- VALUE rb_str = (VALUE)closure;
- noleak_rb_str_cat(rb_str, str, len);
- return len;
-}
-
-static bool stringdata_end_handler(void* closure, const void* hd) {
- VALUE rb_str = (VALUE)closure;
- rb_obj_freeze(rb_str);
- return true;
-}
-
-static bool appendstring_end_handler(void* closure, const void* hd) {
- VALUE rb_str = (VALUE)closure;
- rb_obj_freeze(rb_str);
- return true;
-}
-
-// Appends a submessage to a repeated field (a regular Ruby array for now).
-static void *appendsubmsg_handler(void *closure, const void *hd) {
- VALUE ary = (VALUE)closure;
- const submsg_handlerdata_t *submsgdata = hd;
- MessageHeader* submsg;
-
- VALUE submsg_rb = initialize_rb_class_with_no_args(submsgdata->subklass);
- RepeatedField_push(ary, submsg_rb);
-
- TypedData_Get_Struct(submsg_rb, MessageHeader, &Message_type, submsg);
- return submsg;
-}
-
-// Appends a wrapper to a repeated field (a regular Ruby array for now).
-static void *appendwrapper_handler(void *closure, const void *hd) {
- VALUE ary = (VALUE)closure;
- int size = RepeatedField_size(ary);
- (void)hd;
-
- RepeatedField_push(ary, Qnil);
-
- return RepeatedField_index_native(ary, size);
-}
-
-// Sets a non-repeated submessage field in a message.
-static void *submsg_handler(void *closure, const void *hd) {
- MessageHeader* msg = closure;
- const submsg_handlerdata_t* submsgdata = hd;
- VALUE submsg_rb;
- MessageHeader* submsg;
-
- if (DEREF(msg, submsgdata->ofs, VALUE) == Qnil) {
- DEREF(msg, submsgdata->ofs, VALUE) =
- initialize_rb_class_with_no_args(submsgdata->subklass);
- }
-
- set_hasbit(closure, submsgdata->hasbit);
-
- submsg_rb = DEREF(msg, submsgdata->ofs, VALUE);
- TypedData_Get_Struct(submsg_rb, MessageHeader, &Message_type, submsg);
-
- return submsg;
-}
-
-static void* startwrapper(void* closure, const void* hd) {
- const submsg_handlerdata_t* submsgdata = hd;
- char* msg = closure;
- VALUE* field = (VALUE*)(msg + submsgdata->ofs);
-
- set_hasbit(closure, submsgdata->hasbit);
-
- switch (submsgdata->wrapped_type) {
- case UPB_TYPE_FLOAT:
- case UPB_TYPE_DOUBLE:
- *field = DBL2NUM(0);
- break;
- case UPB_TYPE_BOOL:
- *field = Qfalse;
- break;
- case UPB_TYPE_STRING:
- *field = get_frozen_string(NULL, 0, false);
- break;
- case UPB_TYPE_BYTES:
- *field = get_frozen_string(NULL, 0, true);
- break;
- case UPB_TYPE_ENUM:
- case UPB_TYPE_INT32:
- case UPB_TYPE_INT64:
- case UPB_TYPE_UINT32:
- case UPB_TYPE_UINT64:
- *field = INT2NUM(0);
- break;
- case UPB_TYPE_MESSAGE:
- rb_raise(rb_eRuntimeError,
- "Internal logic error with well-known types.");
- }
-
- return field;
-}
-
-// Handler data for startmap/endmap handlers.
-typedef struct {
- size_t ofs;
- upb_fieldtype_t key_field_type;
- upb_fieldtype_t value_field_type;
- VALUE subklass;
-} map_handlerdata_t;
-
-// Temporary frame for map parsing: at the beginning of a map entry message, a
-// submsg handler allocates a frame to hold (i) a reference to the Map object
-// into which this message will be inserted and (ii) storage slots to
-// temporarily hold the key and value for this map entry until the end of the
-// submessage. When the submessage ends, another handler is called to insert the
-// value into the map.
-typedef struct {
- VALUE map;
- const map_handlerdata_t* handlerdata;
- char key_storage[NATIVE_SLOT_MAX_SIZE];
- char value_storage[NATIVE_SLOT_MAX_SIZE];
-} map_parse_frame_t;
-
-static void MapParseFrame_mark(void* _self) {
- map_parse_frame_t* frame = _self;
-
- // This shouldn't strictly be necessary since this should be rooted by the
- // message itself, but it can't hurt.
- rb_gc_mark(frame->map);
-
- native_slot_mark(frame->handlerdata->key_field_type, &frame->key_storage);
- native_slot_mark(frame->handlerdata->value_field_type, &frame->value_storage);
-}
-
-void MapParseFrame_free(void* self) {
- xfree(self);
-}
-
-rb_data_type_t MapParseFrame_type = {
- "MapParseFrame",
- { MapParseFrame_mark, MapParseFrame_free, NULL },
-};
-
-// Handler to begin a map entry: allocates a temporary frame. This is the
-// 'startsubmsg' handler on the msgdef that contains the map field.
-static void *startmap_handler(void *closure, const void *hd) {
- MessageHeader* msg = closure;
- const map_handlerdata_t* mapdata = hd;
- map_parse_frame_t* frame = ALLOC(map_parse_frame_t);
- VALUE map_rb = DEREF(msg, mapdata->ofs, VALUE);
-
- frame->handlerdata = mapdata;
- frame->map = map_rb;
- native_slot_init(mapdata->key_field_type, &frame->key_storage);
- native_slot_init(mapdata->value_field_type, &frame->value_storage);
-
- Map_set_frame(map_rb,
- TypedData_Wrap_Struct(rb_cObject, &MapParseFrame_type, frame));
-
- return frame;
-}
-
-static bool endmap_handler(void *closure, const void *hd) {
- map_parse_frame_t* frame = closure;
- Map_set_frame(frame->map, Qnil);
- return true;
-}
-
-// Handler to end a map entry: inserts the value defined during the message into
-// the map. This is the 'endmsg' handler on the map entry msgdef.
-static bool endmapentry_handler(void* closure, const void* hd, upb_status* s) {
- map_parse_frame_t* frame = closure;
- const map_handlerdata_t* mapdata = hd;
-
- VALUE key = native_slot_get(
- mapdata->key_field_type, Qnil,
- &frame->key_storage);
-
- VALUE value = native_slot_get(
- mapdata->value_field_type, mapdata->subklass,
- &frame->value_storage);
-
- Map_index_set(frame->map, key, value);
-
- return true;
-}
-
-// Allocates a new map_handlerdata_t given the map entry message definition. If
-// the offset of the field within the parent message is also given, that is
-// added to the handler data as well. Note that this is called *twice* per map
-// field: once in the parent message handler setup when setting the startsubmsg
-// handler and once in the map entry message handler setup when setting the
-// key/value and endmsg handlers. The reason is that there is no easy way to
-// pass the handlerdata down to the sub-message handler setup.
-static map_handlerdata_t* new_map_handlerdata(
- size_t ofs,
- const upb_msgdef* mapentry_def,
- const Descriptor* desc) {
- const upb_fielddef* key_field;
- const upb_fielddef* value_field;
- map_handlerdata_t* hd = ALLOC(map_handlerdata_t);
- hd->ofs = ofs;
- key_field = upb_msgdef_itof(mapentry_def, MAP_KEY_FIELD);
- assert(key_field != NULL);
- hd->key_field_type = upb_fielddef_type(key_field);
- value_field = upb_msgdef_itof(mapentry_def, MAP_VALUE_FIELD);
- assert(value_field != NULL);
- hd->value_field_type = upb_fielddef_type(value_field);
- hd->subklass = field_type_class(desc->layout, value_field);
-
- return hd;
-}
-
-// Handlers that set primitive values in oneofs.
-#define DEFINE_ONEOF_HANDLER(type, ctype) \
- static bool oneof##type##_handler(void *closure, const void *hd, \
- ctype val) { \
- const oneof_handlerdata_t *oneofdata = hd; \
- DEREF(closure, oneofdata->case_ofs, uint32_t) = \
- oneofdata->oneof_case_num; \
- DEREF(closure, oneofdata->ofs, ctype) = val; \
- return true; \
- }
-
-DEFINE_ONEOF_HANDLER(bool, bool)
-DEFINE_ONEOF_HANDLER(int32, int32_t)
-DEFINE_ONEOF_HANDLER(uint32, uint32_t)
-DEFINE_ONEOF_HANDLER(float, float)
-DEFINE_ONEOF_HANDLER(int64, int64_t)
-DEFINE_ONEOF_HANDLER(uint64, uint64_t)
-DEFINE_ONEOF_HANDLER(double, double)
-
-#undef DEFINE_ONEOF_HANDLER
-
-// Handlers for strings in a oneof.
-static void *oneofstr_handler(void *closure,
- const void *hd,
- size_t size_hint) {
- MessageHeader* msg = closure;
- const oneof_handlerdata_t *oneofdata = hd;
- VALUE str = rb_str_new2("");
- rb_enc_associate(str, kRubyStringUtf8Encoding);
- DEREF(msg, oneofdata->case_ofs, uint32_t) =
- oneofdata->oneof_case_num;
- DEREF(msg, oneofdata->ofs, VALUE) = str;
- return (void*)str;
-}
-
-static void *oneofbytes_handler(void *closure,
- const void *hd,
- size_t size_hint) {
- MessageHeader* msg = closure;
- const oneof_handlerdata_t *oneofdata = hd;
- VALUE str = rb_str_new2("");
- rb_enc_associate(str, kRubyString8bitEncoding);
- DEREF(msg, oneofdata->case_ofs, uint32_t) =
- oneofdata->oneof_case_num;
- DEREF(msg, oneofdata->ofs, VALUE) = str;
- return (void*)str;
-}
-
-static bool oneofstring_end_handler(void* closure, const void* hd) {
- VALUE rb_str = rb_str_new2("");
- rb_obj_freeze(rb_str);
- return true;
-}
-
-// Handler for a submessage field in a oneof.
-static void *oneofsubmsg_handler(void *closure,
- const void *hd) {
- MessageHeader* msg = closure;
- const oneof_handlerdata_t *oneofdata = hd;
- uint32_t oldcase = DEREF(msg, oneofdata->case_ofs, uint32_t);
-
- VALUE submsg_rb;
- MessageHeader* submsg;
-
- if (oldcase != oneofdata->oneof_case_num ||
- DEREF(msg, oneofdata->ofs, VALUE) == Qnil) {
- DEREF(msg, oneofdata->ofs, VALUE) =
- initialize_rb_class_with_no_args(oneofdata->subklass);
- }
- // Set the oneof case *after* allocating the new class instance -- otherwise,
- // if the Ruby GC is invoked as part of a call into the VM, it might invoke
- // our mark routines, and our mark routines might see the case value
- // indicating a VALUE is present and expect a valid VALUE. See comment in
- // layout_set() for more detail: basically, the change to the value and the
- // case must be atomic w.r.t. the Ruby VM.
- DEREF(msg, oneofdata->case_ofs, uint32_t) = oneofdata->oneof_case_num;
-
- submsg_rb = DEREF(msg, oneofdata->ofs, VALUE);
- TypedData_Get_Struct(submsg_rb, MessageHeader, &Message_type, submsg);
- return submsg;
-}
-
-static void* oneof_startwrapper(void* closure, const void* hd) {
- char* msg = closure;
- const oneof_handlerdata_t *oneofdata = hd;
-
- DEREF(msg, oneofdata->case_ofs, uint32_t) = oneofdata->oneof_case_num;
-
- return msg + oneofdata->ofs;
-}
-
-// Set up handlers for a repeated field.
-static void add_handlers_for_repeated_field(upb_handlers *h,
- const Descriptor* desc,
- const upb_fielddef *f,
- size_t offset) {
- upb_handlerattr attr = UPB_HANDLERATTR_INIT;
- attr.handler_data = newhandlerdata(h, offset, -1);
- upb_handlers_setstartseq(h, f, startseq_handler, &attr);
-
- switch (upb_fielddef_type(f)) {
-
-#define SET_HANDLER(utype, ltype) \
- case utype: \
- upb_handlers_set##ltype(h, f, append##ltype##_handler, NULL); \
- break;
-
- SET_HANDLER(UPB_TYPE_BOOL, bool);
- SET_HANDLER(UPB_TYPE_INT32, int32);
- SET_HANDLER(UPB_TYPE_UINT32, uint32);
- SET_HANDLER(UPB_TYPE_ENUM, int32);
- SET_HANDLER(UPB_TYPE_FLOAT, float);
- SET_HANDLER(UPB_TYPE_INT64, int64);
- SET_HANDLER(UPB_TYPE_UINT64, uint64);
- SET_HANDLER(UPB_TYPE_DOUBLE, double);
-
-#undef SET_HANDLER
-
- case UPB_TYPE_STRING:
- case UPB_TYPE_BYTES: {
- bool is_bytes = upb_fielddef_type(f) == UPB_TYPE_BYTES;
- upb_handlers_setstartstr(h, f, is_bytes ?
- appendbytes_handler : appendstr_handler,
- NULL);
- upb_handlers_setstring(h, f, stringdata_handler, NULL);
- upb_handlers_setendstr(h, f, appendstring_end_handler, NULL);
- break;
- }
- case UPB_TYPE_MESSAGE: {
- VALUE subklass = field_type_class(desc->layout, f);
- upb_handlerattr attr = UPB_HANDLERATTR_INIT;
- attr.handler_data = newsubmsghandlerdata(h, f, 0, -1, subklass);
- if (is_wrapper(upb_fielddef_msgsubdef(f))) {
- upb_handlers_setstartsubmsg(h, f, appendwrapper_handler, &attr);
- } else {
- upb_handlers_setstartsubmsg(h, f, appendsubmsg_handler, &attr);
- }
- break;
- }
- }
-}
-
-static bool doublewrapper_handler(void* closure, const void* hd, double val) {
- VALUE* rbval = closure;
- *rbval = DBL2NUM(val);
- return true;
-}
-
-static bool floatwrapper_handler(void* closure, const void* hd, float val) {
- VALUE* rbval = closure;
- *rbval = DBL2NUM(val);
- return true;
-}
-
-static bool int64wrapper_handler(void* closure, const void* hd, int64_t val) {
- VALUE* rbval = closure;
- *rbval = LL2NUM(val);
- return true;
-}
-
-static bool uint64wrapper_handler(void* closure, const void* hd, uint64_t val) {
- VALUE* rbval = closure;
- *rbval = ULL2NUM(val);
- return true;
-}
-
-static bool int32wrapper_handler(void* closure, const void* hd, int32_t val) {
- VALUE* rbval = closure;
- *rbval = INT2NUM(val);
- return true;
-}
-
-static bool uint32wrapper_handler(void* closure, const void* hd, uint32_t val) {
- VALUE* rbval = closure;
- *rbval = UINT2NUM(val);
- return true;
-}
-
-static void* startstringwrapper_handler(void* closure, const void* hd,
- size_t size_hint) {
- VALUE* rbval = closure;
- (void)size_hint;
- *rbval = rb_str_new(NULL, 0);
- rb_enc_associate(*rbval, kRubyStringUtf8Encoding);
- return closure;
-}
-
-static size_t stringwrapper_handler(void* closure, const void* hd,
- const char* ptr, size_t len,
- const upb_bufhandle* handle) {
- VALUE* rbval = closure;
- *rbval = noleak_rb_str_cat(*rbval, ptr, len);
- return len;
-}
-
-static void* startbyteswrapper_handler(void* closure, const void* hd,
- size_t size_hint) {
- VALUE* rbval = closure;
- (void)size_hint;
- *rbval = rb_str_new(NULL, 0);
- rb_enc_associate(*rbval, kRubyString8bitEncoding);
- return closure;
-}
-
-static size_t byteswrapper_handler(void* closure, const void* hd,
- const char* ptr, size_t len,
- const upb_bufhandle* handle) {
- VALUE* rbval = closure;
- *rbval = noleak_rb_str_cat(*rbval, ptr, len);
- return len;
-}
-
-static bool boolwrapper_handler(void* closure, const void* hd, bool val) {
- VALUE* rbval = closure;
- if (val) {
- *rbval = Qtrue;
- } else {
- *rbval = Qfalse;
- }
- return true;
-}
-
-// Set up handlers for a singular field.
-static void add_handlers_for_singular_field(const Descriptor* desc,
- upb_handlers* h,
- const upb_fielddef* f,
- size_t offset, size_t hasbit_off) {
- // The offset we pass to UPB points to the start of the Message,
- // rather than the start of where our data is stored.
- int32_t hasbit = -1;
- if (hasbit_off != MESSAGE_FIELD_NO_HASBIT) {
- hasbit = hasbit_off + sizeof(MessageHeader) * 8;
- }
-
- switch (upb_fielddef_type(f)) {
- case UPB_TYPE_BOOL:
- case UPB_TYPE_INT32:
- case UPB_TYPE_UINT32:
- case UPB_TYPE_ENUM:
- case UPB_TYPE_FLOAT:
- case UPB_TYPE_INT64:
- case UPB_TYPE_UINT64:
- case UPB_TYPE_DOUBLE:
- upb_msg_setscalarhandler(h, f, offset, hasbit);
- break;
- case UPB_TYPE_STRING:
- case UPB_TYPE_BYTES: {
- bool is_bytes = upb_fielddef_type(f) == UPB_TYPE_BYTES;
- upb_handlerattr attr = UPB_HANDLERATTR_INIT;
- attr.handler_data = newhandlerdata(h, offset, hasbit);
- upb_handlers_setstartstr(h, f,
- is_bytes ? bytes_handler : str_handler,
- &attr);
- upb_handlers_setstring(h, f, stringdata_handler, &attr);
- upb_handlers_setendstr(h, f, stringdata_end_handler, &attr);
- break;
- }
- case UPB_TYPE_MESSAGE: {
- upb_handlerattr attr = UPB_HANDLERATTR_INIT;
- attr.handler_data = newsubmsghandlerdata(
- h, f, offset, hasbit, field_type_class(desc->layout, f));
- if (is_wrapper(upb_fielddef_msgsubdef(f))) {
- upb_handlers_setstartsubmsg(h, f, startwrapper, &attr);
- } else {
- upb_handlers_setstartsubmsg(h, f, submsg_handler, &attr);
- }
- }
- }
-}
-
-// Adds handlers to a map field.
-static void add_handlers_for_mapfield(upb_handlers* h,
- const upb_fielddef* fielddef,
- size_t offset,
- const Descriptor* desc) {
- const upb_msgdef* map_msgdef = upb_fielddef_msgsubdef(fielddef);
- map_handlerdata_t* hd = new_map_handlerdata(offset, map_msgdef, desc);
- upb_handlerattr attr = UPB_HANDLERATTR_INIT;
-
- upb_handlers_addcleanup(h, hd, xfree);
- attr.handler_data = hd;
- upb_handlers_setstartsubmsg(h, fielddef, startmap_handler, &attr);
- upb_handlers_setendsubmsg(h, fielddef, endmap_handler, &attr);
-}
-
-// Adds handlers to a map-entry msgdef.
-static void add_handlers_for_mapentry(const upb_msgdef* msgdef, upb_handlers* h,
- const Descriptor* desc) {
- const upb_fielddef* key_field = map_entry_key(msgdef);
- const upb_fielddef* value_field = map_entry_value(msgdef);
- map_handlerdata_t* hd = new_map_handlerdata(0, msgdef, desc);
- upb_handlerattr attr = UPB_HANDLERATTR_INIT;
-
- upb_handlers_addcleanup(h, hd, xfree);
- attr.handler_data = hd;
- upb_handlers_setendmsg(h, endmapentry_handler, &attr);
-
- add_handlers_for_singular_field(
- desc, h, key_field,
- offsetof(map_parse_frame_t, key_storage),
- MESSAGE_FIELD_NO_HASBIT);
- add_handlers_for_singular_field(
- desc, h, value_field,
- offsetof(map_parse_frame_t, value_storage),
- MESSAGE_FIELD_NO_HASBIT);
-}
-
-static void add_handlers_for_wrapper(const upb_msgdef* msgdef,
- upb_handlers* h) {
- const upb_fielddef* f = upb_msgdef_itof(msgdef, 1);
- switch (upb_msgdef_wellknowntype(msgdef)) {
- case UPB_WELLKNOWN_DOUBLEVALUE:
- upb_handlers_setdouble(h, f, doublewrapper_handler, NULL);
- break;
- case UPB_WELLKNOWN_FLOATVALUE:
- upb_handlers_setfloat(h, f, floatwrapper_handler, NULL);
- break;
- case UPB_WELLKNOWN_INT64VALUE:
- upb_handlers_setint64(h, f, int64wrapper_handler, NULL);
- break;
- case UPB_WELLKNOWN_UINT64VALUE:
- upb_handlers_setuint64(h, f, uint64wrapper_handler, NULL);
- break;
- case UPB_WELLKNOWN_INT32VALUE:
- upb_handlers_setint32(h, f, int32wrapper_handler, NULL);
- break;
- case UPB_WELLKNOWN_UINT32VALUE:
- upb_handlers_setuint32(h, f, uint32wrapper_handler, NULL);
- break;
- case UPB_WELLKNOWN_STRINGVALUE:
- upb_handlers_setstartstr(h, f, startstringwrapper_handler, NULL);
- upb_handlers_setstring(h, f, stringwrapper_handler, NULL);
- break;
- case UPB_WELLKNOWN_BYTESVALUE:
- upb_handlers_setstartstr(h, f, startbyteswrapper_handler, NULL);
- upb_handlers_setstring(h, f, byteswrapper_handler, NULL);
- break;
- case UPB_WELLKNOWN_BOOLVALUE:
- upb_handlers_setbool(h, f, boolwrapper_handler, NULL);
- return;
- default:
- rb_raise(rb_eRuntimeError,
- "Internal logic error with well-known types.");
- }
-}
-
-// Set up handlers for a oneof field.
-static void add_handlers_for_oneof_field(upb_handlers *h,
- const upb_fielddef *f,
- size_t offset,
- size_t oneof_case_offset,
- const Descriptor* desc) {
- upb_handlerattr attr = UPB_HANDLERATTR_INIT;
- attr.handler_data =
- newoneofhandlerdata(h, offset, oneof_case_offset, f, desc);
-
- switch (upb_fielddef_type(f)) {
-
-#define SET_HANDLER(utype, ltype) \
- case utype: \
- upb_handlers_set##ltype(h, f, oneof##ltype##_handler, &attr); \
- break;
-
- SET_HANDLER(UPB_TYPE_BOOL, bool);
- SET_HANDLER(UPB_TYPE_INT32, int32);
- SET_HANDLER(UPB_TYPE_UINT32, uint32);
- SET_HANDLER(UPB_TYPE_ENUM, int32);
- SET_HANDLER(UPB_TYPE_FLOAT, float);
- SET_HANDLER(UPB_TYPE_INT64, int64);
- SET_HANDLER(UPB_TYPE_UINT64, uint64);
- SET_HANDLER(UPB_TYPE_DOUBLE, double);
-
-#undef SET_HANDLER
-
- case UPB_TYPE_STRING:
- case UPB_TYPE_BYTES: {
- bool is_bytes = upb_fielddef_type(f) == UPB_TYPE_BYTES;
- upb_handlers_setstartstr(h, f, is_bytes ?
- oneofbytes_handler : oneofstr_handler,
- &attr);
- upb_handlers_setstring(h, f, stringdata_handler, NULL);
- upb_handlers_setendstr(h, f, oneofstring_end_handler, &attr);
- break;
- }
- case UPB_TYPE_MESSAGE: {
- if (is_wrapper(upb_fielddef_msgsubdef(f))) {
- upb_handlers_setstartsubmsg(h, f, oneof_startwrapper, &attr);
- } else {
- upb_handlers_setstartsubmsg(h, f, oneofsubmsg_handler, &attr);
- }
- break;
- }
- }
-}
-
-static bool unknown_field_handler(void* closure, const void* hd,
- const char* buf, size_t size) {
- MessageHeader* msg = (MessageHeader*)closure;
- UPB_UNUSED(hd);
-
- if (msg->unknown_fields == NULL) {
- msg->unknown_fields = malloc(sizeof(stringsink));
- stringsink_init(msg->unknown_fields);
- }
-
- stringsink_string(msg->unknown_fields, NULL, buf, size, NULL);
-
- return true;
-}
-
-size_t get_field_offset(MessageLayout* layout, const upb_fielddef* f) {
- return layout->fields[upb_fielddef_index(f)].offset + sizeof(MessageHeader);
-}
-
-void add_handlers_for_message(const void *closure, upb_handlers *h) {
- const VALUE descriptor_pool = (VALUE)closure;
- const upb_msgdef* msgdef = upb_handlers_msgdef(h);
- Descriptor* desc =
- ruby_to_Descriptor(get_msgdef_obj(descriptor_pool, msgdef));
- upb_msg_field_iter i;
- upb_handlerattr attr = UPB_HANDLERATTR_INIT;
-
- // Ensure layout exists. We may be invoked to create handlers for a given
- // message if we are included as a submsg of another message type before our
- // class is actually built, so to work around this, we just create the layout
- // (and handlers, in the class-building function) on-demand.
- if (desc->layout == NULL) {
- create_layout(desc);
- }
-
- // If this is a mapentry message type, set up a special set of handlers and
- // bail out of the normal (user-defined) message type handling.
- if (upb_msgdef_mapentry(msgdef)) {
- add_handlers_for_mapentry(msgdef, h, desc);
- return;
- }
-
- // If this is a wrapper type, use special handlers and bail.
- if (is_wrapper(msgdef)) {
- add_handlers_for_wrapper(msgdef, h);
- return;
- }
-
- upb_handlers_setunknown(h, unknown_field_handler, &attr);
-
- for (upb_msg_field_begin(&i, desc->msgdef);
- !upb_msg_field_done(&i);
- upb_msg_field_next(&i)) {
- const upb_fielddef *f = upb_msg_iter_field(&i);
- const upb_oneofdef* oneof = upb_fielddef_realcontainingoneof(f);
- size_t offset = get_field_offset(desc->layout, f);
-
- if (oneof) {
- size_t oneof_case_offset =
- desc->layout->oneofs[upb_oneofdef_index(oneof)].case_offset +
- sizeof(MessageHeader);
- add_handlers_for_oneof_field(h, f, offset, oneof_case_offset, desc);
- } else if (is_map_field(f)) {
- add_handlers_for_mapfield(h, f, offset, desc);
- } else if (upb_fielddef_isseq(f)) {
- add_handlers_for_repeated_field(h, desc, f, offset);
- } else {
- add_handlers_for_singular_field(
- desc, h, f, offset,
- desc->layout->fields[upb_fielddef_index(f)].hasbit);
- }
- }
-}
-
-// Constructs the handlers for filling a message's data into an in-memory
-// object.
-const upb_handlers* get_fill_handlers(Descriptor* desc) {
- DescriptorPool* pool = ruby_to_DescriptorPool(desc->descriptor_pool);
- return upb_handlercache_get(pool->fill_handler_cache, desc->msgdef);
-}
-
-static const upb_pbdecodermethod *msgdef_decodermethod(Descriptor* desc) {
- DescriptorPool* pool = ruby_to_DescriptorPool(desc->descriptor_pool);
- return upb_pbcodecache_get(pool->fill_method_cache, desc->msgdef);
-}
-
-static const upb_json_parsermethod *msgdef_jsonparsermethod(Descriptor* desc) {
- DescriptorPool* pool = ruby_to_DescriptorPool(desc->descriptor_pool);
- return upb_json_codecache_get(pool->json_fill_method_cache, desc->msgdef);
-}
-
-static const upb_handlers* msgdef_pb_serialize_handlers(Descriptor* desc) {
- DescriptorPool* pool = ruby_to_DescriptorPool(desc->descriptor_pool);
- return upb_handlercache_get(pool->pb_serialize_handler_cache, desc->msgdef);
-}
-
-static const upb_handlers* msgdef_json_serialize_handlers(
- Descriptor* desc, bool preserve_proto_fieldnames) {
- DescriptorPool* pool = ruby_to_DescriptorPool(desc->descriptor_pool);
- if (preserve_proto_fieldnames) {
- return upb_handlercache_get(pool->json_serialize_handler_preserve_cache,
- desc->msgdef);
- } else {
- return upb_handlercache_get(pool->json_serialize_handler_cache,
- desc->msgdef);
- }
-}
-
-
-// Stack-allocated context during an encode/decode operation. Contains the upb
-// environment and its stack-based allocator, an initial buffer for allocations
-// to avoid malloc() when possible, and a template for Ruby exception messages
-// if any error occurs.
-#define STACK_ENV_STACKBYTES 4096
-typedef struct {
- upb_arena *arena;
- upb_status status;
- const char* ruby_error_template;
- char allocbuf[STACK_ENV_STACKBYTES];
-} stackenv;
-
-static void stackenv_init(stackenv* se, const char* errmsg);
-static void stackenv_uninit(stackenv* se);
-
-static void stackenv_init(stackenv* se, const char* errmsg) {
- se->ruby_error_template = errmsg;
- se->arena =
- upb_arena_init(se->allocbuf, sizeof(se->allocbuf), &upb_alloc_global);
- upb_status_clear(&se->status);
-}
-
-static void stackenv_uninit(stackenv* se) {
- upb_arena_free(se->arena);
-
- if (!upb_ok(&se->status)) {
- // TODO(haberman): have a way to verify that this is actually a parse error,
- // instead of just throwing "parse error" unconditionally.
- VALUE errmsg = rb_str_new2(upb_status_errmsg(&se->status));
- rb_raise(cParseError, se->ruby_error_template, errmsg);
- }
-}
-
-/*
- * call-seq:
- * MessageClass.decode(data) => message
- *
- * Decodes the given data (as a string containing bytes in protocol buffers wire
- * format) under the interpretration given by this message class's definition
- * and returns a message object with the corresponding field values.
- */
-VALUE Message_decode(VALUE klass, VALUE data) {
- VALUE descriptor = rb_ivar_get(klass, descriptor_instancevar_interned);
- Descriptor* desc = ruby_to_Descriptor(descriptor);
- VALUE msgklass = Descriptor_msgclass(descriptor);
- VALUE msg_rb;
- MessageHeader* msg;
-
- if (TYPE(data) != T_STRING) {
- rb_raise(rb_eArgError, "Expected string for binary protobuf data.");
- }
-
- msg_rb = initialize_rb_class_with_no_args(msgklass);
- TypedData_Get_Struct(msg_rb, MessageHeader, &Message_type, msg);
-
- {
- const upb_pbdecodermethod* method = msgdef_decodermethod(desc);
- const upb_handlers* h = upb_pbdecodermethod_desthandlers(method);
- const upb_msgdef* m = upb_handlers_msgdef(h);
- VALUE wrapper = Qnil;
- void* ptr = msg;
- stackenv se;
- upb_sink sink;
- upb_pbdecoder* decoder;
- stackenv_init(&se, "Error occurred during parsing: %" PRIsVALUE);
-
- if (is_wrapper(m)) {
- ptr = &wrapper;
- }
-
- upb_sink_reset(&sink, h, ptr);
- decoder = upb_pbdecoder_create(se.arena, method, sink, &se.status);
- upb_bufsrc_putbuf(RSTRING_PTR(data), RSTRING_LEN(data),
- upb_pbdecoder_input(decoder));
-
- stackenv_uninit(&se);
-
- if (is_wrapper(m)) {
- msg_rb = ruby_wrapper_type(msgklass, wrapper);
- }
- }
-
- return msg_rb;
-}
-
-/*
- * call-seq:
- * MessageClass.decode_json(data, options = {}) => message
- *
- * Decodes the given data (as a string containing bytes in protocol buffers wire
- * format) under the interpretration given by this message class's definition
- * and returns a message object with the corresponding field values.
- *
- * @param options [Hash] options for the decoder
- * ignore_unknown_fields: set true to ignore unknown fields (default is to
- * raise an error)
- */
-VALUE Message_decode_json(int argc, VALUE* argv, VALUE klass) {
- VALUE descriptor = rb_ivar_get(klass, descriptor_instancevar_interned);
- Descriptor* desc = ruby_to_Descriptor(descriptor);
- VALUE msgklass = Descriptor_msgclass(descriptor);
- VALUE msg_rb;
- VALUE data = argv[0];
- VALUE ignore_unknown_fields = Qfalse;
- MessageHeader* msg;
-
- if (argc < 1 || argc > 2) {
- rb_raise(rb_eArgError, "Expected 1 or 2 arguments.");
- }
-
- if (argc == 2) {
- VALUE hash_args = argv[1];
- if (TYPE(hash_args) != T_HASH) {
- rb_raise(rb_eArgError, "Expected hash arguments.");
- }
-
- ignore_unknown_fields = rb_hash_lookup2(
- hash_args, ID2SYM(rb_intern("ignore_unknown_fields")), Qfalse);
- }
-
- if (TYPE(data) != T_STRING) {
- rb_raise(rb_eArgError, "Expected string for JSON data.");
- }
-
- // TODO(cfallin): Check and respect string encoding. If not UTF-8, we need to
- // convert, because string handlers pass data directly to message string
- // fields.
-
- msg_rb = initialize_rb_class_with_no_args(msgklass);
- TypedData_Get_Struct(msg_rb, MessageHeader, &Message_type, msg);
-
- {
- const upb_json_parsermethod* method = msgdef_jsonparsermethod(desc);
- const upb_handlers* h = get_fill_handlers(desc);
- const upb_msgdef* m = upb_handlers_msgdef(h);
- stackenv se;
- upb_sink sink;
- upb_json_parser* parser;
- DescriptorPool* pool = ruby_to_DescriptorPool(generated_pool);
- stackenv_init(&se, "Error occurred during parsing: %" PRIsVALUE);
-
- if (is_wrapper(m)) {
- rb_raise(
- rb_eRuntimeError,
- "Parsing a wrapper type from JSON at the top level does not work.");
- }
-
- upb_sink_reset(&sink, h, msg);
- parser = upb_json_parser_create(se.arena, method, pool->symtab, sink,
- &se.status, RTEST(ignore_unknown_fields));
- upb_bufsrc_putbuf(RSTRING_PTR(data), RSTRING_LEN(data),
- upb_json_parser_input(parser));
-
- stackenv_uninit(&se);
- }
-
- return msg_rb;
-}
-
-// -----------------------------------------------------------------------------
-// Serializing.
-// -----------------------------------------------------------------------------
-
-/* msgvisitor *****************************************************************/
-
-static void putmsg(VALUE msg, const Descriptor* desc, upb_sink sink, int depth,
- bool emit_defaults, bool is_json, bool open_msg);
-
-static upb_selector_t getsel(const upb_fielddef *f, upb_handlertype_t type) {
- upb_selector_t ret;
- bool ok = upb_handlers_getselector(f, type, &ret);
- UPB_ASSERT(ok);
- return ret;
-}
-
-static void putstr(VALUE str, const upb_fielddef *f, upb_sink sink) {
- upb_sink subsink;
-
- if (str == Qnil) return;
-
- assert(BUILTIN_TYPE(str) == RUBY_T_STRING);
-
- // We should be guaranteed that the string has the correct encoding because
- // we ensured this at assignment time and then froze the string.
- if (upb_fielddef_type(f) == UPB_TYPE_STRING) {
- assert(rb_enc_from_index(ENCODING_GET(str)) == kRubyStringUtf8Encoding);
- } else {
- assert(rb_enc_from_index(ENCODING_GET(str)) == kRubyString8bitEncoding);
- }
-
- upb_sink_startstr(sink, getsel(f, UPB_HANDLER_STARTSTR), RSTRING_LEN(str),
- &subsink);
- upb_sink_putstring(subsink, getsel(f, UPB_HANDLER_STRING), RSTRING_PTR(str),
- RSTRING_LEN(str), NULL);
- upb_sink_endstr(sink, getsel(f, UPB_HANDLER_ENDSTR));
-}
-
-static void putsubmsg(VALUE submsg, const upb_fielddef *f, upb_sink sink,
- int depth, bool emit_defaults, bool is_json) {
- upb_sink subsink;
- VALUE descriptor;
- Descriptor* subdesc;
-
- if (submsg == Qnil) return;
-
- descriptor = rb_ivar_get(submsg, descriptor_instancevar_interned);
- subdesc = ruby_to_Descriptor(descriptor);
-
- upb_sink_startsubmsg(sink, getsel(f, UPB_HANDLER_STARTSUBMSG), &subsink);
- putmsg(submsg, subdesc, subsink, depth + 1, emit_defaults, is_json, true);
- upb_sink_endsubmsg(sink, subsink, getsel(f, UPB_HANDLER_ENDSUBMSG));
-}
-
-static void putary(VALUE ary, const upb_fielddef* f, upb_sink sink, int depth,
- bool emit_defaults, bool is_json) {
- upb_sink subsink;
- upb_fieldtype_t type = upb_fielddef_type(f);
- upb_selector_t sel = 0;
- int size;
- int i;
- VALUE type_class = ruby_to_RepeatedField(ary)->field_type_class;
-
- if (ary == Qnil) return;
- if (!emit_defaults && NUM2INT(RepeatedField_length(ary)) == 0) return;
-
- size = NUM2INT(RepeatedField_length(ary));
- if (size == 0 && !emit_defaults) return;
-
- upb_sink_startseq(sink, getsel(f, UPB_HANDLER_STARTSEQ), &subsink);
-
- if (upb_fielddef_isprimitive(f)) {
- sel = getsel(f, upb_handlers_getprimitivehandlertype(f));
- }
-
- for (i = 0; i < size; i++) {
- void* memory = RepeatedField_index_native(ary, i);
- switch (type) {
-#define T(upbtypeconst, upbtype, ctype) \
- case upbtypeconst: \
- upb_sink_put##upbtype(subsink, sel, *((ctype*)memory)); \
- break;
-
- T(UPB_TYPE_FLOAT, float, float)
- T(UPB_TYPE_DOUBLE, double, double)
- T(UPB_TYPE_BOOL, bool, int8_t)
- case UPB_TYPE_ENUM:
- T(UPB_TYPE_INT32, int32, int32_t)
- T(UPB_TYPE_UINT32, uint32, uint32_t)
- T(UPB_TYPE_INT64, int64, int64_t)
- T(UPB_TYPE_UINT64, uint64, uint64_t)
-
- case UPB_TYPE_STRING:
- case UPB_TYPE_BYTES:
- putstr(*((VALUE *)memory), f, subsink);
- break;
- case UPB_TYPE_MESSAGE: {
- VALUE val = native_slot_get(UPB_TYPE_MESSAGE, type_class, memory);
- putsubmsg(val, f, subsink, depth, emit_defaults, is_json);
- break;
- }
-
-#undef T
-
- }
- }
- upb_sink_endseq(sink, getsel(f, UPB_HANDLER_ENDSEQ));
-}
-
-static void put_ruby_value(VALUE value, const upb_fielddef* f, VALUE type_class,
- int depth, upb_sink sink, bool emit_defaults,
- bool is_json) {
- upb_selector_t sel = 0;
-
- if (depth > ENCODE_MAX_NESTING) {
- rb_raise(rb_eRuntimeError,
- "Maximum recursion depth exceeded during encoding.");
- }
-
- if (upb_fielddef_isprimitive(f)) {
- sel = getsel(f, upb_handlers_getprimitivehandlertype(f));
- }
-
- switch (upb_fielddef_type(f)) {
- case UPB_TYPE_INT32:
- upb_sink_putint32(sink, sel, NUM2INT(value));
- break;
- case UPB_TYPE_INT64:
- upb_sink_putint64(sink, sel, NUM2LL(value));
- break;
- case UPB_TYPE_UINT32:
- upb_sink_putuint32(sink, sel, NUM2UINT(value));
- break;
- case UPB_TYPE_UINT64:
- upb_sink_putuint64(sink, sel, NUM2ULL(value));
- break;
- case UPB_TYPE_FLOAT:
- upb_sink_putfloat(sink, sel, NUM2DBL(value));
- break;
- case UPB_TYPE_DOUBLE:
- upb_sink_putdouble(sink, sel, NUM2DBL(value));
- break;
- case UPB_TYPE_ENUM: {
- if (TYPE(value) == T_SYMBOL) {
- value = rb_funcall(type_class, rb_intern("resolve"), 1, value);
- }
- upb_sink_putint32(sink, sel, NUM2INT(value));
- break;
- }
- case UPB_TYPE_BOOL:
- upb_sink_putbool(sink, sel, value == Qtrue);
- break;
- case UPB_TYPE_STRING:
- case UPB_TYPE_BYTES:
- putstr(value, f, sink);
- break;
- case UPB_TYPE_MESSAGE:
- putsubmsg(value, f, sink, depth, emit_defaults, is_json);
- }
-}
-
-static void putmap(VALUE map, const upb_fielddef* f, upb_sink sink, int depth,
- bool emit_defaults, bool is_json) {
- Map* self;
- upb_sink subsink;
- const upb_fielddef* key_field;
- const upb_fielddef* value_field;
- Map_iter it;
-
- if (map == Qnil) return;
- if (!emit_defaults && Map_length(map) == 0) return;
-
- self = ruby_to_Map(map);
-
- upb_sink_startseq(sink, getsel(f, UPB_HANDLER_STARTSEQ), &subsink);
-
- assert(upb_fielddef_type(f) == UPB_TYPE_MESSAGE);
- key_field = map_field_key(f);
- value_field = map_field_value(f);
-
- for (Map_begin(map, &it); !Map_done(&it); Map_next(&it)) {
- VALUE key = Map_iter_key(&it);
- VALUE value = Map_iter_value(&it);
- upb_status status;
-
- upb_sink entry_sink;
- upb_sink_startsubmsg(subsink, getsel(f, UPB_HANDLER_STARTSUBMSG),
- &entry_sink);
- upb_sink_startmsg(entry_sink);
-
- put_ruby_value(key, key_field, Qnil, depth + 1, entry_sink, emit_defaults,
- is_json);
- put_ruby_value(value, value_field, self->value_type_class, depth + 1,
- entry_sink, emit_defaults, is_json);
-
- upb_sink_endmsg(entry_sink, &status);
- upb_sink_endsubmsg(subsink, entry_sink, getsel(f, UPB_HANDLER_ENDSUBMSG));
- }
-
- upb_sink_endseq(sink, getsel(f, UPB_HANDLER_ENDSEQ));
-}
-
-static const upb_handlers* msgdef_json_serialize_handlers(
- Descriptor* desc, bool preserve_proto_fieldnames);
-
-static void putjsonany(VALUE msg_rb, const Descriptor* desc, upb_sink sink,
- int depth, bool emit_defaults) {
- upb_status status;
- MessageHeader* msg = NULL;
- const upb_fielddef* type_field = upb_msgdef_itof(desc->msgdef, UPB_ANY_TYPE);
- const upb_fielddef* value_field = upb_msgdef_itof(desc->msgdef, UPB_ANY_VALUE);
-
- size_t type_url_offset;
- VALUE type_url_str_rb;
- const upb_msgdef *payload_type = NULL;
-
- TypedData_Get_Struct(msg_rb, MessageHeader, &Message_type, msg);
-
- upb_sink_startmsg(sink);
-
- /* Handle type url */
- type_url_offset = desc->layout->fields[upb_fielddef_index(type_field)].offset;
- type_url_str_rb = DEREF(Message_data(msg), type_url_offset, VALUE);
- if (RSTRING_LEN(type_url_str_rb) > 0) {
- putstr(type_url_str_rb, type_field, sink);
- }
-
- {
- const char* type_url_str = RSTRING_PTR(type_url_str_rb);
- size_t type_url_len = RSTRING_LEN(type_url_str_rb);
- DescriptorPool* pool = ruby_to_DescriptorPool(generated_pool);
-
- if (type_url_len <= 20 ||
- strncmp(type_url_str, "type.googleapis.com/", 20) != 0) {
- rb_raise(rb_eRuntimeError, "Invalid type url: %s", type_url_str);
- return;
- }
-
- /* Resolve type url */
- type_url_str += 20;
- type_url_len -= 20;
-
- payload_type = upb_symtab_lookupmsg2(
- pool->symtab, type_url_str, type_url_len);
- if (payload_type == NULL) {
- rb_raise(rb_eRuntimeError, "Unknown type: %s", type_url_str);
- return;
- }
- }
-
- {
- uint32_t value_offset;
- VALUE value_str_rb;
- size_t value_len;
-
- value_offset = desc->layout->fields[upb_fielddef_index(value_field)].offset;
- value_str_rb = DEREF(Message_data(msg), value_offset, VALUE);
- value_len = RSTRING_LEN(value_str_rb);
-
- if (value_len > 0) {
- VALUE payload_desc_rb = get_msgdef_obj(generated_pool, payload_type);
- Descriptor* payload_desc = ruby_to_Descriptor(payload_desc_rb);
- VALUE payload_class = Descriptor_msgclass(payload_desc_rb);
- upb_sink subsink;
- bool is_wellknown;
-
- VALUE payload_msg_rb = Message_decode(payload_class, value_str_rb);
-
- is_wellknown =
- upb_msgdef_wellknowntype(payload_desc->msgdef) !=
- UPB_WELLKNOWN_UNSPECIFIED;
- if (is_wellknown) {
- upb_sink_startstr(sink, getsel(value_field, UPB_HANDLER_STARTSTR), 0,
- &subsink);
- }
-
- subsink.handlers =
- msgdef_json_serialize_handlers(payload_desc, true);
- subsink.closure = sink.closure;
- putmsg(payload_msg_rb, payload_desc, subsink, depth, emit_defaults, true,
- is_wellknown);
- }
- }
-
- upb_sink_endmsg(sink, &status);
-}
-
-static void putjsonlistvalue(
- VALUE msg_rb, const Descriptor* desc,
- upb_sink sink, int depth, bool emit_defaults) {
- upb_status status;
- upb_sink subsink;
- MessageHeader* msg = NULL;
- const upb_fielddef* f = upb_msgdef_itof(desc->msgdef, 1);
- uint32_t offset =
- desc->layout->fields[upb_fielddef_index(f)].offset +
- sizeof(MessageHeader);
- VALUE ary;
-
- TypedData_Get_Struct(msg_rb, MessageHeader, &Message_type, msg);
-
- upb_sink_startmsg(sink);
-
- ary = DEREF(msg, offset, VALUE);
-
- if (ary == Qnil || RepeatedField_size(ary) == 0) {
- upb_sink_startseq(sink, getsel(f, UPB_HANDLER_STARTSEQ), &subsink);
- upb_sink_endseq(sink, getsel(f, UPB_HANDLER_ENDSEQ));
- } else {
- putary(ary, f, sink, depth, emit_defaults, true);
- }
-
- upb_sink_endmsg(sink, &status);
-}
-
-static void putmsg(VALUE msg_rb, const Descriptor* desc,
- upb_sink sink, int depth, bool emit_defaults,
- bool is_json, bool open_msg) {
- MessageHeader* msg;
- upb_msg_field_iter i;
- upb_status status;
- bool json_wrapper = is_wrapper(desc->msgdef) && is_json;
-
- if (is_json &&
- upb_msgdef_wellknowntype(desc->msgdef) == UPB_WELLKNOWN_ANY) {
- putjsonany(msg_rb, desc, sink, depth, emit_defaults);
- return;
- }
-
- if (is_json &&
- upb_msgdef_wellknowntype(desc->msgdef) == UPB_WELLKNOWN_LISTVALUE) {
- putjsonlistvalue(msg_rb, desc, sink, depth, emit_defaults);
- return;
- }
-
- if (open_msg) {
- upb_sink_startmsg(sink);
- }
-
- // Protect against cycles (possible because users may freely reassign message
- // and repeated fields) by imposing a maximum recursion depth.
- if (depth > ENCODE_MAX_NESTING) {
- rb_raise(rb_eRuntimeError,
- "Maximum recursion depth exceeded during encoding.");
- }
-
- TypedData_Get_Struct(msg_rb, MessageHeader, &Message_type, msg);
-
- if (desc != msg->descriptor) {
- rb_raise(rb_eArgError,
- "The type of given msg is '%s', expect '%s'.",
- upb_msgdef_fullname(msg->descriptor->msgdef),
- upb_msgdef_fullname(desc->msgdef));
- }
-
- for (upb_msg_field_begin(&i, desc->msgdef);
- !upb_msg_field_done(&i);
- upb_msg_field_next(&i)) {
- upb_fielddef *f = upb_msg_iter_field(&i);
- const upb_oneofdef* oneof = upb_fielddef_realcontainingoneof(f);
- bool is_matching_oneof = false;
- uint32_t offset =
- desc->layout->fields[upb_fielddef_index(f)].offset +
- sizeof(MessageHeader);
-
- if (oneof) {
- uint32_t oneof_case =
- slot_read_oneof_case(desc->layout, Message_data(msg), oneof);
- // For a oneof, check that this field is actually present -- skip all the
- // below if not.
- if (oneof_case != upb_fielddef_number(f)) {
- continue;
- }
- // Otherwise, fall through to the appropriate singular-field handler
- // below.
- is_matching_oneof = true;
- }
-
- if (is_map_field(f)) {
- VALUE map = DEREF(msg, offset, VALUE);
- if (map != Qnil || emit_defaults) {
- putmap(map, f, sink, depth, emit_defaults, is_json);
- }
- } else if (upb_fielddef_isseq(f)) {
- VALUE ary = DEREF(msg, offset, VALUE);
- if (ary != Qnil) {
- putary(ary, f, sink, depth, emit_defaults, is_json);
- }
- } else if (upb_fielddef_isstring(f)) {
- VALUE str = DEREF(msg, offset, VALUE);
- bool is_default = false;
-
- if (upb_msgdef_syntax(desc->msgdef) == UPB_SYNTAX_PROTO2) {
- is_default = layout_has(desc->layout, Message_data(msg), f) == Qfalse;
- } else if (upb_msgdef_syntax(desc->msgdef) == UPB_SYNTAX_PROTO3) {
- is_default = RSTRING_LEN(str) == 0;
- }
-
- if (is_matching_oneof || emit_defaults || !is_default || json_wrapper) {
- putstr(str, f, sink);
- }
- } else if (upb_fielddef_issubmsg(f)) {
- // OPT: could try to avoid the layout_get() (which will expand lazy
- // wrappers).
- VALUE val = layout_get(desc->layout, Message_data(msg), f);
- putsubmsg(val, f, sink, depth, emit_defaults, is_json);
- } else {
- upb_selector_t sel = getsel(f, upb_handlers_getprimitivehandlertype(f));
-
-#define T(upbtypeconst, upbtype, ctype, default_value) \
- case upbtypeconst: { \
- ctype value = DEREF(msg, offset, ctype); \
- bool is_default = false; \
- if (upb_fielddef_haspresence(f)) { \
- is_default = layout_has(desc->layout, Message_data(msg), f) == Qfalse; \
- } else if (upb_msgdef_syntax(desc->msgdef) == UPB_SYNTAX_PROTO3) { \
- is_default = default_value == value; \
- } \
- if (is_matching_oneof || emit_defaults || !is_default || json_wrapper) { \
- upb_sink_put##upbtype(sink, sel, value); \
- } \
- } break;
-
- switch (upb_fielddef_type(f)) {
- T(UPB_TYPE_FLOAT, float, float, 0.0)
- T(UPB_TYPE_DOUBLE, double, double, 0.0)
- T(UPB_TYPE_BOOL, bool, uint8_t, 0)
- case UPB_TYPE_ENUM:
- T(UPB_TYPE_INT32, int32, int32_t, 0)
- T(UPB_TYPE_UINT32, uint32, uint32_t, 0)
- T(UPB_TYPE_INT64, int64, int64_t, 0)
- T(UPB_TYPE_UINT64, uint64, uint64_t, 0)
-
- case UPB_TYPE_STRING:
- case UPB_TYPE_BYTES:
- case UPB_TYPE_MESSAGE: rb_raise(rb_eRuntimeError, "Internal error.");
- }
-
-#undef T
- }
- }
-
- {
- stringsink* unknown = msg->unknown_fields;
- if (unknown != NULL) {
- upb_sink_putunknown(sink, unknown->ptr, unknown->len);
- }
- }
-
- if (open_msg) {
- upb_sink_endmsg(sink, &status);
- }
-}
-
-/*
- * call-seq:
- * MessageClass.encode(msg) => bytes
- *
- * Encodes the given message object to its serialized form in protocol buffers
- * wire format.
- */
-VALUE Message_encode(VALUE klass, VALUE msg_rb) {
- VALUE descriptor = rb_ivar_get(klass, descriptor_instancevar_interned);
- Descriptor* desc = ruby_to_Descriptor(descriptor);
-
- stringsink sink;
- stringsink_init(&sink);
-
- {
- const upb_handlers* serialize_handlers =
- msgdef_pb_serialize_handlers(desc);
-
- stackenv se;
- upb_pb_encoder* encoder;
- VALUE ret;
-
- stackenv_init(&se, "Error occurred during encoding: %" PRIsVALUE);
- encoder = upb_pb_encoder_create(se.arena, serialize_handlers, sink.sink);
-
- putmsg(msg_rb, desc, upb_pb_encoder_input(encoder), 0, false, false, true);
-
- ret = rb_str_new(sink.ptr, sink.len);
-
- stackenv_uninit(&se);
- stringsink_uninit(&sink);
-
- return ret;
- }
-}
-
-/*
- * call-seq:
- * MessageClass.encode_json(msg, options = {}) => json_string
- *
- * Encodes the given message object into its serialized JSON representation.
- * @param options [Hash] options for the decoder
- * preserve_proto_fieldnames: set true to use original fieldnames (default is to camelCase)
- * emit_defaults: set true to emit 0/false values (default is to omit them)
- */
-VALUE Message_encode_json(int argc, VALUE* argv, VALUE klass) {
- VALUE descriptor = rb_ivar_get(klass, descriptor_instancevar_interned);
- Descriptor* desc = ruby_to_Descriptor(descriptor);
- VALUE msg_rb;
- VALUE preserve_proto_fieldnames = Qfalse;
- VALUE emit_defaults = Qfalse;
- stringsink sink;
-
- if (argc < 1 || argc > 2) {
- rb_raise(rb_eArgError, "Expected 1 or 2 arguments.");
- }
-
- msg_rb = argv[0];
-
- if (argc == 2) {
- VALUE hash_args = argv[1];
- if (TYPE(hash_args) != T_HASH) {
- rb_raise(rb_eArgError, "Expected hash arguments.");
- }
- preserve_proto_fieldnames = rb_hash_lookup2(
- hash_args, ID2SYM(rb_intern("preserve_proto_fieldnames")), Qfalse);
-
- emit_defaults = rb_hash_lookup2(
- hash_args, ID2SYM(rb_intern("emit_defaults")), Qfalse);
- }
-
- stringsink_init(&sink);
-
- {
- const upb_handlers* serialize_handlers =
- msgdef_json_serialize_handlers(desc, RTEST(preserve_proto_fieldnames));
- upb_json_printer* printer;
- stackenv se;
- VALUE ret;
-
- stackenv_init(&se, "Error occurred during encoding: %" PRIsVALUE);
- printer = upb_json_printer_create(se.arena, serialize_handlers, sink.sink);
-
- putmsg(msg_rb, desc, upb_json_printer_input(printer), 0,
- RTEST(emit_defaults), true, true);
-
- ret = rb_enc_str_new(sink.ptr, sink.len, rb_utf8_encoding());
-
- stackenv_uninit(&se);
- stringsink_uninit(&sink);
-
- return ret;
- }
-}
-
-static void discard_unknown(VALUE msg_rb, const Descriptor* desc) {
- MessageHeader* msg;
- upb_msg_field_iter it;
-
- TypedData_Get_Struct(msg_rb, MessageHeader, &Message_type, msg);
-
- {
- stringsink* unknown = msg->unknown_fields;
- if (unknown != NULL) {
- stringsink_uninit(unknown);
- msg->unknown_fields = NULL;
- }
- }
-
- for (upb_msg_field_begin(&it, desc->msgdef);
- !upb_msg_field_done(&it);
- upb_msg_field_next(&it)) {
- upb_fielddef *f = upb_msg_iter_field(&it);
- const upb_oneofdef* oneof = upb_fielddef_realcontainingoneof(f);
- uint32_t offset =
- desc->layout->fields[upb_fielddef_index(f)].offset +
- sizeof(MessageHeader);
-
- if (oneof) {
- uint32_t oneof_case =
- slot_read_oneof_case(desc->layout, Message_data(msg), oneof);
- // For a oneof, check that this field is actually present -- skip all the
- // below if not.
- if (oneof_case != upb_fielddef_number(f)) {
- continue;
- }
- // Otherwise, fall through to the appropriate singular-field handler
- // below.
- }
-
- if (!upb_fielddef_issubmsg(f)) {
- continue;
- }
-
- if (is_map_field(f)) {
- VALUE map;
- Map_iter map_it;
-
- if (!upb_fielddef_issubmsg(map_field_value(f))) continue;
- map = DEREF(msg, offset, VALUE);
- if (map == Qnil) continue;
- for (Map_begin(map, &map_it); !Map_done(&map_it); Map_next(&map_it)) {
- VALUE submsg = Map_iter_value(&map_it);
- VALUE descriptor = rb_ivar_get(submsg, descriptor_instancevar_interned);
- const Descriptor* subdesc = ruby_to_Descriptor(descriptor);
- discard_unknown(submsg, subdesc);
- }
- } else if (upb_fielddef_isseq(f)) {
- VALUE ary = DEREF(msg, offset, VALUE);
- int size;
- int i;
-
- if (ary == Qnil) continue;
- size = NUM2INT(RepeatedField_length(ary));
- for (i = 0; i < size; i++) {
- void* memory = RepeatedField_index_native(ary, i);
- VALUE submsg = *((VALUE *)memory);
- VALUE descriptor = rb_ivar_get(submsg, descriptor_instancevar_interned);
- const Descriptor* subdesc = ruby_to_Descriptor(descriptor);
- discard_unknown(submsg, subdesc);
- }
- } else {
- VALUE submsg = DEREF(msg, offset, VALUE);
- VALUE descriptor;
- const Descriptor* subdesc;
-
- if (submsg == Qnil) continue;
- descriptor = rb_ivar_get(submsg, descriptor_instancevar_interned);
- subdesc = ruby_to_Descriptor(descriptor);
- discard_unknown(submsg, subdesc);
- }
- }
-}
-
-/*
- * call-seq:
- * Google::Protobuf.discard_unknown(msg)
- *
- * Discard unknown fields in the given message object and recursively discard
- * unknown fields in submessages.
- */
-VALUE Google_Protobuf_discard_unknown(VALUE self, VALUE msg_rb) {
- VALUE klass = CLASS_OF(msg_rb);
- VALUE descriptor = rb_ivar_get(klass, descriptor_instancevar_interned);
- Descriptor* desc = ruby_to_Descriptor(descriptor);
- if (klass == cRepeatedField || klass == cMap) {
- rb_raise(rb_eArgError, "Expected proto msg for discard unknown.");
- } else {
- discard_unknown(msg_rb, desc);
- }
- return Qnil;
-}
diff --git a/ruby/ext/google/protobuf_c/extconf.rb b/ruby/ext/google/protobuf_c/extconf.rb
index 80b7985000..ec17787f79 100755
--- a/ruby/ext/google/protobuf_c/extconf.rb
+++ b/ruby/ext/google/protobuf_c/extconf.rb
@@ -3,9 +3,9 @@
require 'mkmf'
if RUBY_PLATFORM =~ /darwin/ || RUBY_PLATFORM =~ /linux/
- $CFLAGS += " -std=gnu90 -O3 -DNDEBUG -Wall -Wdeclaration-after-statement -Wsign-compare"
+ $CFLAGS += " -std=gnu99 -O3 -DNDEBUG -fvisibility=hidden -Wall -Wsign-compare -Wno-declaration-after-statement"
else
- $CFLAGS += " -std=gnu90 -O3 -DNDEBUG"
+ $CFLAGS += " -std=gnu99 -O3 -DNDEBUG"
end
@@ -14,8 +14,7 @@ if RUBY_PLATFORM =~ /linux/
$LDFLAGS += " -Wl,-wrap,memcpy"
end
-$objs = ["protobuf.o", "defs.o", "storage.o", "message.o",
- "repeated_field.o", "map.o", "encode_decode.o", "upb.o",
- "wrap_memcpy.o"]
+$objs = ["protobuf.o", "convert.o", "defs.o", "message.o",
+ "repeated_field.o", "map.o", "ruby-upb.o", "wrap_memcpy.o"]
create_makefile("google/protobuf_c")
diff --git a/ruby/ext/google/protobuf_c/map.c b/ruby/ext/google/protobuf_c/map.c
index 00d23a76fa..9d7d16b529 100644
--- a/ruby/ext/google/protobuf_c/map.c
+++ b/ruby/ext/google/protobuf_c/map.c
@@ -28,170 +28,231 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#include "convert.h"
+#include "defs.h"
+#include "message.h"
#include "protobuf.h"
// -----------------------------------------------------------------------------
-// Basic map operations on top of upb's strtable.
+// Basic map operations on top of upb_map.
//
// Note that we roll our own `Map` container here because, as for
// `RepeatedField`, we want a strongly-typed container. This is so that any user
// errors due to incorrect map key or value types are raised as close as
// possible to the error site, rather than at some deferred point (e.g.,
// serialization).
-//
-// We build our `Map` on top of upb_strtable so that we're able to take
-// advantage of the native_slot storage abstraction, as RepeatedField does.
-// (This is not quite a perfect mapping -- see the key conversions below -- but
-// gives us full support and error-checking for all value types for free.)
// -----------------------------------------------------------------------------
-// Map values are stored using the native_slot abstraction (as with repeated
-// field values), but keys are a bit special. Since we use a strtable, we need
-// to store keys as sequences of bytes such that equality of those bytes maps
-// one-to-one to equality of keys. We store strings directly (i.e., they map to
-// their own bytes) and integers as native integers (using the native_slot
-// abstraction).
-
-// Note that there is another tradeoff here in keeping string keys as native
-// strings rather than Ruby strings: traversing the Map requires conversion to
-// Ruby string values on every traversal, potentially creating more garbage. We
-// should consider ways to cache a Ruby version of the key if this becomes an
-// issue later.
-
-// Forms a key to use with the underlying strtable from a Ruby key value. |buf|
-// must point to TABLE_KEY_BUF_LENGTH bytes of temporary space, used to
-// construct a key byte sequence if needed. |out_key| and |out_length| provide
-// the resulting key data/length.
-#define TABLE_KEY_BUF_LENGTH 8 // sizeof(uint64_t)
-static VALUE table_key(Map* self, VALUE key,
- char* buf,
- const char** out_key,
- size_t* out_length) {
- switch (self->key_type) {
- case UPB_TYPE_BYTES:
- case UPB_TYPE_STRING:
- // Strings: use string content directly.
- if (TYPE(key) == T_SYMBOL) {
- key = rb_id2str(SYM2ID(key));
- }
- Check_Type(key, T_STRING);
- key = native_slot_encode_and_freeze_string(self->key_type, key);
- *out_key = RSTRING_PTR(key);
- *out_length = RSTRING_LEN(key);
- break;
-
- case UPB_TYPE_BOOL:
- case UPB_TYPE_INT32:
- case UPB_TYPE_INT64:
- case UPB_TYPE_UINT32:
- case UPB_TYPE_UINT64:
- native_slot_set("", self->key_type, Qnil, buf, key);
- *out_key = buf;
- *out_length = native_slot_size(self->key_type);
- break;
-
- default:
- // Map constructor should not allow a Map with another key type to be
- // constructed.
- assert(false);
- break;
- }
-
- return key;
-}
-
-static VALUE table_key_to_ruby(Map* self, upb_strview key) {
- switch (self->key_type) {
- case UPB_TYPE_BYTES:
- case UPB_TYPE_STRING: {
- VALUE ret = rb_str_new(key.data, key.size);
- rb_enc_associate(ret,
- (self->key_type == UPB_TYPE_BYTES) ?
- kRubyString8bitEncoding : kRubyStringUtf8Encoding);
- return ret;
- }
-
- case UPB_TYPE_BOOL:
- case UPB_TYPE_INT32:
- case UPB_TYPE_INT64:
- case UPB_TYPE_UINT32:
- case UPB_TYPE_UINT64:
- return native_slot_get(self->key_type, Qnil, key.data);
-
- default:
- assert(false);
- return Qnil;
- }
-}
-
-static void* value_memory(upb_value* v) {
- return (void*)(&v->val);
-}
-
// -----------------------------------------------------------------------------
// Map container type.
// -----------------------------------------------------------------------------
+typedef struct {
+ const upb_map *map; // Can convert to mutable when non-frozen.
+ upb_fieldtype_t key_type;
+ TypeInfo value_type_info;
+ VALUE value_type_class;
+ VALUE arena;
+} Map;
+
+static void Map_mark(void* _self) {
+ Map* self = _self;
+ rb_gc_mark(self->value_type_class);
+ rb_gc_mark(self->arena);
+}
+
const rb_data_type_t Map_type = {
"Google::Protobuf::Map",
- { Map_mark, Map_free, NULL },
+ { Map_mark, RUBY_DEFAULT_FREE, NULL },
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY,
};
VALUE cMap;
-Map* ruby_to_Map(VALUE _self) {
+static Map* ruby_to_Map(VALUE _self) {
Map* self;
TypedData_Get_Struct(_self, Map, &Map_type, self);
return self;
}
-void Map_mark(void* _self) {
- Map* self = _self;
+static VALUE Map_alloc(VALUE klass) {
+ Map* self = ALLOC(Map);
+ self->map = NULL;
+ self->value_type_class = Qnil;
+ self->value_type_info.def.msgdef = NULL;
+ self->arena = Qnil;
+ return TypedData_Wrap_Struct(klass, &Map_type, self);
+}
- rb_gc_mark(self->value_type_class);
- rb_gc_mark(self->parse_frame);
-
- if (self->value_type == UPB_TYPE_STRING ||
- self->value_type == UPB_TYPE_BYTES ||
- self->value_type == UPB_TYPE_MESSAGE) {
- upb_strtable_iter it;
- for (upb_strtable_begin(&it, &self->table);
- !upb_strtable_done(&it);
- upb_strtable_next(&it)) {
- upb_value v = upb_strtable_iter_value(&it);
- void* mem = value_memory(&v);
- native_slot_mark(self->value_type, mem);
+VALUE Map_GetRubyWrapper(upb_map* map, upb_fieldtype_t key_type,
+ TypeInfo value_type, VALUE arena) {
+ PBRUBY_ASSERT(map);
+
+ VALUE val = ObjectCache_Get(map);
+
+ if (val == Qnil) {
+ val = Map_alloc(cMap);
+ Map* self;
+ ObjectCache_Add(map, val, Arena_get(arena));
+ TypedData_Get_Struct(val, Map, &Map_type, self);
+ self->map = map;
+ self->arena = arena;
+ self->key_type = key_type;
+ self->value_type_info = value_type;
+ if (self->value_type_info.type == UPB_TYPE_MESSAGE) {
+ const upb_msgdef *val_m = self->value_type_info.def.msgdef;
+ self->value_type_class = Descriptor_DefToClass(val_m);
}
}
+
+ return val;
}
-void Map_free(void* _self) {
- Map* self = _self;
- upb_strtable_uninit(&self->table);
- xfree(self);
+static VALUE Map_new_this_type(Map *from) {
+ VALUE arena_rb = Arena_new();
+ upb_map* map = upb_map_new(Arena_get(arena_rb), from->key_type,
+ from->value_type_info.type);
+ VALUE ret =
+ Map_GetRubyWrapper(map, from->key_type, from->value_type_info, arena_rb);
+ PBRUBY_ASSERT(ruby_to_Map(ret)->value_type_class == from->value_type_class);
+ return ret;
}
-VALUE Map_alloc(VALUE klass) {
- Map* self = ALLOC(Map);
- memset(self, 0, sizeof(Map));
- self->value_type_class = Qnil;
- return TypedData_Wrap_Struct(klass, &Map_type, self);
+static TypeInfo Map_keyinfo(Map* self) {
+ TypeInfo ret;
+ ret.type = self->key_type;
+ ret.def.msgdef = NULL;
+ return ret;
}
-VALUE Map_set_frame(VALUE map, VALUE val) {
- Map* self = ruby_to_Map(map);
- self->parse_frame = val;
- return val;
+static upb_map *Map_GetMutable(VALUE _self) {
+ rb_check_frozen(_self);
+ return (upb_map*)ruby_to_Map(_self)->map;
}
-static bool needs_typeclass(upb_fieldtype_t type) {
- switch (type) {
- case UPB_TYPE_MESSAGE:
- case UPB_TYPE_ENUM:
- return true;
- default:
- return false;
+VALUE Map_CreateHash(const upb_map* map, upb_fieldtype_t key_type,
+ TypeInfo val_info) {
+ VALUE hash = rb_hash_new();
+ size_t iter = UPB_MAP_BEGIN;
+ TypeInfo key_info = TypeInfo_from_type(key_type);
+
+ if (!map) return hash;
+
+ while (upb_mapiter_next(map, &iter)) {
+ upb_msgval key = upb_mapiter_key(map, iter);
+ upb_msgval val = upb_mapiter_value(map, iter);
+ VALUE key_val = Convert_UpbToRuby(key, key_info, Qnil);
+ VALUE val_val = Scalar_CreateHash(val, val_info);
+ rb_hash_aset(hash, key_val, val_val);
+ }
+
+ return hash;
+}
+
+VALUE Map_deep_copy(VALUE obj) {
+ Map* self = ruby_to_Map(obj);
+ VALUE new_arena_rb = Arena_new();
+ upb_arena *arena = Arena_get(new_arena_rb);
+ upb_map* new_map =
+ upb_map_new(arena, self->key_type, self->value_type_info.type);
+ size_t iter = UPB_MAP_BEGIN;
+ while (upb_mapiter_next(self->map, &iter)) {
+ upb_msgval key = upb_mapiter_key(self->map, iter);
+ upb_msgval val = upb_mapiter_value(self->map, iter);
+ upb_msgval val_copy = Msgval_DeepCopy(val, self->value_type_info, arena);
+ upb_map_set(new_map, key, val_copy, arena);
+ }
+
+ return Map_GetRubyWrapper(new_map, self->key_type, self->value_type_info,
+ new_arena_rb);
+}
+
+const upb_map* Map_GetUpbMap(VALUE val, const upb_fielddef *field) {
+ const upb_fielddef* key_field = map_field_key(field);
+ const upb_fielddef* value_field = map_field_value(field);
+ TypeInfo value_type_info = TypeInfo_get(value_field);
+ Map* self;
+
+ if (!RB_TYPE_P(val, T_DATA) || !RTYPEDDATA_P(val) ||
+ RTYPEDDATA_TYPE(val) != &Map_type) {
+ rb_raise(cTypeError, "Expected Map instance");
+ }
+
+ self = ruby_to_Map(val);
+ if (self->key_type != upb_fielddef_type(key_field)) {
+ rb_raise(cTypeError, "Map key type does not match field's key type");
+ }
+ if (self->value_type_info.type != value_type_info.type) {
+ rb_raise(cTypeError, "Map value type does not match field's value type");
+ }
+ if (self->value_type_info.def.msgdef != value_type_info.def.msgdef) {
+ rb_raise(cTypeError, "Map value type has wrong message/enum class");
+ }
+
+ return self->map;
+}
+
+void Map_Inspect(StringBuilder* b, const upb_map* map, upb_fieldtype_t key_type,
+ TypeInfo val_type) {
+ bool first = true;
+ TypeInfo key_type_info = {key_type};
+ StringBuilder_Printf(b, "{");
+ if (map) {
+ size_t iter = UPB_MAP_BEGIN;
+ while (upb_mapiter_next(map, &iter)) {
+ upb_msgval key = upb_mapiter_key(map, iter);
+ upb_msgval val = upb_mapiter_value(map, iter);
+ if (first) {
+ first = false;
+ } else {
+ StringBuilder_Printf(b, ", ");
+ }
+ StringBuilder_PrintMsgval(b, key, key_type_info);
+ StringBuilder_Printf(b, "=>");
+ StringBuilder_PrintMsgval(b, val, val_type);
+ }
+ }
+ StringBuilder_Printf(b, "}");
+}
+
+static int merge_into_self_callback(VALUE key, VALUE val, VALUE _self) {
+ Map* self = ruby_to_Map(_self);
+ upb_arena *arena = Arena_get(self->arena);
+ upb_msgval key_val = Convert_RubyToUpb(key, "", Map_keyinfo(self), arena);
+ upb_msgval val_val = Convert_RubyToUpb(val, "", self->value_type_info, arena);
+ upb_map_set(Map_GetMutable(_self), key_val, val_val, arena);
+ return ST_CONTINUE;
+}
+
+// Used only internally -- shared by #merge and #initialize.
+static VALUE Map_merge_into_self(VALUE _self, VALUE hashmap) {
+ if (TYPE(hashmap) == T_HASH) {
+ rb_hash_foreach(hashmap, merge_into_self_callback, _self);
+ } else if (RB_TYPE_P(hashmap, T_DATA) && RTYPEDDATA_P(hashmap) &&
+ RTYPEDDATA_TYPE(hashmap) == &Map_type) {
+ Map* self = ruby_to_Map(_self);
+ Map* other = ruby_to_Map(hashmap);
+ upb_arena *arena = Arena_get(self->arena);
+ upb_msg *self_msg = Map_GetMutable(_self);
+ size_t iter = UPB_MAP_BEGIN;
+
+ upb_arena_fuse(arena, Arena_get(other->arena));
+
+ if (self->key_type != other->key_type ||
+ self->value_type_info.type != other->value_type_info.type ||
+ self->value_type_class != other->value_type_class) {
+ rb_raise(rb_eArgError, "Attempt to merge Map with mismatching types");
+ }
+
+ while (upb_mapiter_next(other->map, &iter)) {
+ upb_msgval key = upb_mapiter_key(other->map, iter);
+ upb_msgval val = upb_mapiter_value(other->map, iter);
+ upb_map_set(self_msg, key, val, arena);
+ }
+ } else {
+ rb_raise(rb_eArgError, "Unknown type merging into Map");
}
+ return _self;
}
/*
@@ -224,9 +285,9 @@ static bool needs_typeclass(upb_fieldtype_t type) {
* references to underlying objects will be shared if the value type is a
* message type.
*/
-VALUE Map_init(int argc, VALUE* argv, VALUE _self) {
+static VALUE Map_init(int argc, VALUE* argv, VALUE _self) {
Map* self = ruby_to_Map(_self);
- int init_value_arg;
+ VALUE init_arg;
// We take either two args (:key_type, :value_type), three args (:key_type,
// :value_type, "ValueMessageType"), or four args (the above plus an initial
@@ -236,8 +297,9 @@ VALUE Map_init(int argc, VALUE* argv, VALUE _self) {
}
self->key_type = ruby_to_fieldtype(argv[0]);
- self->value_type = ruby_to_fieldtype(argv[1]);
- self->parse_frame = Qnil;
+ self->value_type_info =
+ TypeInfo_FromClass(argc, argv, 1, &self->value_type_class, &init_arg);
+ self->arena = Arena_new();
// Check that the key type is an allowed type.
switch (self->key_type) {
@@ -254,21 +316,12 @@ VALUE Map_init(int argc, VALUE* argv, VALUE _self) {
rb_raise(rb_eArgError, "Invalid key type for map.");
}
- init_value_arg = 2;
- if (needs_typeclass(self->value_type) && argc > 2) {
- self->value_type_class = argv[2];
- validate_type_class(self->value_type, self->value_type_class);
- init_value_arg = 3;
- }
-
- // Table value type is always UINT64: this ensures enough space to store the
- // native_slot value.
- if (!upb_strtable_init(&self->table, UPB_CTYPE_UINT64)) {
- rb_raise(rb_eRuntimeError, "Could not allocate table.");
- }
+ self->map = upb_map_new(Arena_get(self->arena), self->key_type,
+ self->value_type_info.type);
+ ObjectCache_Add(self->map, _self, Arena_get(self->arena));
- if (argc > init_value_arg) {
- Map_merge_into_self(_self, argv[init_value_arg]);
+ if (init_arg != Qnil) {
+ Map_merge_into_self(_self, init_arg);
}
return Qnil;
@@ -282,22 +335,16 @@ VALUE Map_init(int argc, VALUE* argv, VALUE _self) {
* Note that Map also includes Enumerable; map thus acts like a normal Ruby
* sequence.
*/
-VALUE Map_each(VALUE _self) {
+static VALUE Map_each(VALUE _self) {
Map* self = ruby_to_Map(_self);
-
- upb_strtable_iter it;
- for (upb_strtable_begin(&it, &self->table);
- !upb_strtable_done(&it);
- upb_strtable_next(&it)) {
- VALUE key = table_key_to_ruby(self, upb_strtable_iter_key(&it));
-
- upb_value v = upb_strtable_iter_value(&it);
- void* mem = value_memory(&v);
- VALUE value = native_slot_get(self->value_type,
- self->value_type_class,
- mem);
-
- rb_yield_values(2, key, value);
+ size_t iter = UPB_MAP_BEGIN;
+
+ while (upb_mapiter_next(self->map, &iter)) {
+ upb_msgval key = upb_mapiter_key(self->map, iter);
+ upb_msgval val = upb_mapiter_value(self->map, iter);
+ VALUE key_val = Convert_UpbToRuby(key, Map_keyinfo(self), self->arena);
+ VALUE val_val = Convert_UpbToRuby(val, self->value_type_info, self->arena);
+ rb_yield_values(2, key_val, val_val);
}
return Qnil;
@@ -309,17 +356,15 @@ VALUE Map_each(VALUE _self) {
*
* Returns the list of keys contained in the map, in unspecified order.
*/
-VALUE Map_keys(VALUE _self) {
+static VALUE Map_keys(VALUE _self) {
Map* self = ruby_to_Map(_self);
-
+ size_t iter = UPB_MAP_BEGIN;
VALUE ret = rb_ary_new();
- upb_strtable_iter it;
- for (upb_strtable_begin(&it, &self->table);
- !upb_strtable_done(&it);
- upb_strtable_next(&it)) {
- VALUE key = table_key_to_ruby(self, upb_strtable_iter_key(&it));
- rb_ary_push(ret, key);
+ while (upb_mapiter_next(self->map, &iter)) {
+ upb_msgval key = upb_mapiter_key(self->map, iter);
+ VALUE key_val = Convert_UpbToRuby(key, Map_keyinfo(self), self->arena);
+ rb_ary_push(ret, key_val);
}
return ret;
@@ -331,22 +376,15 @@ VALUE Map_keys(VALUE _self) {
*
* Returns the list of values contained in the map, in unspecified order.
*/
-VALUE Map_values(VALUE _self) {
+static VALUE Map_values(VALUE _self) {
Map* self = ruby_to_Map(_self);
-
+ size_t iter = UPB_MAP_BEGIN;
VALUE ret = rb_ary_new();
- upb_strtable_iter it;
- for (upb_strtable_begin(&it, &self->table);
- !upb_strtable_done(&it);
- upb_strtable_next(&it)) {
-
- upb_value v = upb_strtable_iter_value(&it);
- void* mem = value_memory(&v);
- VALUE value = native_slot_get(self->value_type,
- self->value_type_class,
- mem);
-
- rb_ary_push(ret, value);
+
+ while (upb_mapiter_next(self->map, &iter)) {
+ upb_msgval val = upb_mapiter_value(self->map, iter);
+ VALUE val_val = Convert_UpbToRuby(val, self->value_type_info, self->arena);
+ rb_ary_push(ret, val_val);
}
return ret;
@@ -359,18 +397,13 @@ VALUE Map_values(VALUE _self) {
* Accesses the element at the given key. Throws an exception if the key type is
* incorrect. Returns nil when the key is not present in the map.
*/
-VALUE Map_index(VALUE _self, VALUE key) {
+static VALUE Map_index(VALUE _self, VALUE key) {
Map* self = ruby_to_Map(_self);
+ upb_msgval key_upb = Convert_RubyToUpb(key, "", Map_keyinfo(self), NULL);
+ upb_msgval val;
- char keybuf[TABLE_KEY_BUF_LENGTH];
- const char* keyval = NULL;
- size_t length = 0;
- upb_value v;
- key = table_key(self, key, keybuf, &keyval, &length);
-
- if (upb_strtable_lookup2(&self->table, keyval, length, &v)) {
- void* mem = value_memory(&v);
- return native_slot_get(self->value_type, self->value_type_class, mem);
+ if (upb_map_get(self->map, key_upb, &val)) {
+ return Convert_UpbToRuby(val, self->value_type_info, self->arena);
} else {
return Qnil;
}
@@ -384,33 +417,15 @@ VALUE Map_index(VALUE _self, VALUE key) {
* Throws an exception if the key type is incorrect. Returns the new value that
* was just inserted.
*/
-VALUE Map_index_set(VALUE _self, VALUE key, VALUE value) {
+static VALUE Map_index_set(VALUE _self, VALUE key, VALUE val) {
Map* self = ruby_to_Map(_self);
- char keybuf[TABLE_KEY_BUF_LENGTH];
- const char* keyval = NULL;
- size_t length = 0;
- upb_value v;
- void* mem;
- key = table_key(self, key, keybuf, &keyval, &length);
-
- rb_check_frozen(_self);
+ upb_arena *arena = Arena_get(self->arena);
+ upb_msgval key_upb = Convert_RubyToUpb(key, "", Map_keyinfo(self), NULL);
+ upb_msgval val_upb = Convert_RubyToUpb(val, "", self->value_type_info, arena);
- if (TYPE(value) == T_HASH) {
- VALUE args[1] = { value };
- value = rb_class_new_instance(1, args, self->value_type_class);
- }
-
- mem = value_memory(&v);
- native_slot_set("", self->value_type, self->value_type_class, mem, value);
-
- // Replace any existing value by issuing a 'remove' operation first.
- upb_strtable_remove2(&self->table, keyval, length, NULL);
- if (!upb_strtable_insert2(&self->table, keyval, length, v)) {
- rb_raise(rb_eRuntimeError, "Could not insert into table");
- }
+ upb_map_set(Map_GetMutable(_self), key_upb, val_upb, arena);
- // Ruby hashmap's :[]= method also returns the inserted value.
- return value;
+ return val;
}
/*
@@ -420,15 +435,11 @@ VALUE Map_index_set(VALUE _self, VALUE key, VALUE value) {
* Returns true if the given key is present in the map. Throws an exception if
* the key has the wrong type.
*/
-VALUE Map_has_key(VALUE _self, VALUE key) {
+static VALUE Map_has_key(VALUE _self, VALUE key) {
Map* self = ruby_to_Map(_self);
+ upb_msgval key_upb = Convert_RubyToUpb(key, "", Map_keyinfo(self), NULL);
- char keybuf[TABLE_KEY_BUF_LENGTH];
- const char* keyval = NULL;
- size_t length = 0;
- key = table_key(self, key, keybuf, &keyval, &length);
-
- if (upb_strtable_lookup2(&self->table, keyval, length, NULL)) {
+ if (upb_map_get(self->map, key_upb, NULL)) {
return Qtrue;
} else {
return Qfalse;
@@ -442,22 +453,25 @@ VALUE Map_has_key(VALUE _self, VALUE key) {
* Deletes the value at the given key, if any, returning either the old value or
* nil if none was present. Throws an exception if the key is of the wrong type.
*/
-VALUE Map_delete(VALUE _self, VALUE key) {
+static VALUE Map_delete(VALUE _self, VALUE key) {
Map* self = ruby_to_Map(_self);
- char keybuf[TABLE_KEY_BUF_LENGTH];
- const char* keyval = NULL;
- size_t length = 0;
- upb_value v;
- key = table_key(self, key, keybuf, &keyval, &length);
+ upb_msgval key_upb = Convert_RubyToUpb(key, "", Map_keyinfo(self), NULL);
+ upb_msgval val_upb;
+ VALUE ret;
rb_check_frozen(_self);
- if (upb_strtable_remove2(&self->table, keyval, length, &v)) {
- void* mem = value_memory(&v);
- return native_slot_get(self->value_type, self->value_type_class, mem);
+ // TODO(haberman): make upb_map_delete() also capable of returning the deleted
+ // value.
+ if (upb_map_get(self->map, key_upb, &val_upb)) {
+ ret = Convert_UpbToRuby(val_upb, self->value_type_info, self->arena);
} else {
- return Qnil;
+ ret = Qnil;
}
+
+ upb_map_delete(Map_GetMutable(_self), key_upb);
+
+ return ret;
}
/*
@@ -466,17 +480,8 @@ VALUE Map_delete(VALUE _self, VALUE key) {
*
* Removes all entries from the map.
*/
-VALUE Map_clear(VALUE _self) {
- Map* self = ruby_to_Map(_self);
-
- rb_check_frozen(_self);
-
- // Uninit and reinit the table -- this is faster than iterating and doing a
- // delete-lookup on each key.
- upb_strtable_uninit(&self->table);
- if (!upb_strtable_init(&self->table, UPB_CTYPE_INT64)) {
- rb_raise(rb_eRuntimeError, "Unable to re-initialize table");
- }
+static VALUE Map_clear(VALUE _self) {
+ upb_map_clear(Map_GetMutable(_self));
return Qnil;
}
@@ -486,24 +491,9 @@ VALUE Map_clear(VALUE _self) {
*
* Returns the number of entries (key-value pairs) in the map.
*/
-VALUE Map_length(VALUE _self) {
+static VALUE Map_length(VALUE _self) {
Map* self = ruby_to_Map(_self);
- return ULL2NUM(upb_strtable_count(&self->table));
-}
-
-VALUE Map_new_this_type(VALUE _self) {
- Map* self = ruby_to_Map(_self);
- VALUE new_map = Qnil;
- VALUE key_type = fieldtype_to_ruby(self->key_type);
- VALUE value_type = fieldtype_to_ruby(self->value_type);
- if (self->value_type_class != Qnil) {
- new_map = rb_funcall(CLASS_OF(_self), rb_intern("new"), 3,
- key_type, value_type, self->value_type_class);
- } else {
- new_map = rb_funcall(CLASS_OF(_self), rb_intern("new"), 2,
- key_type, value_type);
- }
- return new_map;
+ return ULL2NUM(upb_map_size(self->map));
}
/*
@@ -513,54 +503,23 @@ VALUE Map_new_this_type(VALUE _self) {
* Duplicates this map with a shallow copy. References to all non-primitive
* element objects (e.g., submessages) are shared.
*/
-VALUE Map_dup(VALUE _self) {
- Map* self = ruby_to_Map(_self);
- VALUE new_map = Map_new_this_type(_self);
- Map* new_self = ruby_to_Map(new_map);
-
- upb_strtable_iter it;
- for (upb_strtable_begin(&it, &self->table);
- !upb_strtable_done(&it);
- upb_strtable_next(&it)) {
- upb_strview k = upb_strtable_iter_key(&it);
- upb_value v = upb_strtable_iter_value(&it);
- void* mem = value_memory(&v);
- upb_value dup;
- void* dup_mem = value_memory(&dup);
- native_slot_dup(self->value_type, dup_mem, mem);
-
- if (!upb_strtable_insert2(&new_self->table, k.data, k.size, dup)) {
- rb_raise(rb_eRuntimeError, "Error inserting value into new table");
- }
- }
-
- return new_map;
-}
-
-// Used by Google::Protobuf.deep_copy but not exposed directly.
-VALUE Map_deep_copy(VALUE _self) {
+static VALUE Map_dup(VALUE _self) {
Map* self = ruby_to_Map(_self);
- VALUE new_map = Map_new_this_type(_self);
- Map* new_self = ruby_to_Map(new_map);
-
- upb_strtable_iter it;
- for (upb_strtable_begin(&it, &self->table);
- !upb_strtable_done(&it);
- upb_strtable_next(&it)) {
- upb_strview k = upb_strtable_iter_key(&it);
- upb_value v = upb_strtable_iter_value(&it);
- void* mem = value_memory(&v);
- upb_value dup;
- void* dup_mem = value_memory(&dup);
- native_slot_deep_copy(self->value_type, self->value_type_class, dup_mem,
- mem);
-
- if (!upb_strtable_insert2(&new_self->table, k.data, k.size, dup)) {
- rb_raise(rb_eRuntimeError, "Error inserting value into new table");
- }
+ VALUE new_map_rb = Map_new_this_type(self);
+ Map* new_self = ruby_to_Map(new_map_rb);
+ size_t iter = UPB_MAP_BEGIN;
+ upb_arena *arena = Arena_get(new_self->arena);
+ upb_map *new_map = Map_GetMutable(new_map_rb);
+
+ upb_arena_fuse(arena, Arena_get(self->arena));
+
+ while (upb_mapiter_next(self->map, &iter)) {
+ upb_msgval key = upb_mapiter_key(self->map, iter);
+ upb_msgval val = upb_mapiter_value(self->map, iter);
+ upb_map_set(new_map, key, val, arena);
}
- return new_map;
+ return new_map_rb;
}
/*
@@ -579,12 +538,11 @@ VALUE Map_deep_copy(VALUE _self) {
VALUE Map_eq(VALUE _self, VALUE _other) {
Map* self = ruby_to_Map(_self);
Map* other;
- upb_strtable_iter it;
// Allow comparisons to Ruby hashmaps by converting to a temporary Map
// instance. Slow, but workable.
if (TYPE(_other) == T_HASH) {
- VALUE other_map = Map_new_this_type(_self);
+ VALUE other_map = Map_new_this_type(self);
Map_merge_into_self(other_map, _other);
_other = other_map;
}
@@ -595,33 +553,27 @@ VALUE Map_eq(VALUE _self, VALUE _other) {
return Qtrue;
}
if (self->key_type != other->key_type ||
- self->value_type != other->value_type ||
+ self->value_type_info.type != other->value_type_info.type ||
self->value_type_class != other->value_type_class) {
return Qfalse;
}
- if (upb_strtable_count(&self->table) != upb_strtable_count(&other->table)) {
+ if (upb_map_size(self->map) != upb_map_size(other->map)) {
return Qfalse;
}
// For each member of self, check that an equal member exists at the same key
// in other.
- for (upb_strtable_begin(&it, &self->table);
- !upb_strtable_done(&it);
- upb_strtable_next(&it)) {
- upb_strview k = upb_strtable_iter_key(&it);
- upb_value v = upb_strtable_iter_value(&it);
- void* mem = value_memory(&v);
- upb_value other_v;
- void* other_mem = value_memory(&other_v);
-
- if (!upb_strtable_lookup2(&other->table, k.data, k.size, &other_v)) {
+ size_t iter = UPB_MAP_BEGIN;
+ while (upb_mapiter_next(self->map, &iter)) {
+ upb_msgval key = upb_mapiter_key(self->map, iter);
+ upb_msgval val = upb_mapiter_value(self->map, iter);
+ upb_msgval other_val;
+ if (!upb_map_get(other->map, key, &other_val)) {
// Not present in other map.
return Qfalse;
}
-
- if (!native_slot_eq(self->value_type, self->value_type_class, mem,
- other_mem)) {
- // Present, but value not equal.
+ if (!Msgval_IsEqual(val, other_val, self->value_type_info)) {
+ // Present but different value.
return Qfalse;
}
}
@@ -629,6 +581,21 @@ VALUE Map_eq(VALUE _self, VALUE _other) {
return Qtrue;
}
+/*
+ * call-seq:
+ * Message.freeze => self
+ *
+ * Freezes the message object. We have to intercept this so we can pin the
+ * Ruby object into memory so we don't forget it's frozen.
+ */
+static VALUE Map_freeze(VALUE _self) {
+ Map* self = ruby_to_Map(_self);
+
+ ObjectCache_Pin(self->map, _self, Arena_get(self->arena));
+ RB_OBJ_FREEZE(_self);
+ return _self;
+}
+
/*
* call-seq:
* Map.hash => hash_value
@@ -637,26 +604,18 @@ VALUE Map_eq(VALUE _self, VALUE _other) {
*/
VALUE Map_hash(VALUE _self) {
Map* self = ruby_to_Map(_self);
-
- st_index_t h = rb_hash_start(0);
- VALUE hash_sym = rb_intern("hash");
-
- upb_strtable_iter it;
- for (upb_strtable_begin(&it, &self->table); !upb_strtable_done(&it);
- upb_strtable_next(&it)) {
- VALUE key = table_key_to_ruby(self, upb_strtable_iter_key(&it));
-
- upb_value v = upb_strtable_iter_value(&it);
- void* mem = value_memory(&v);
- VALUE value = native_slot_get(self->value_type,
- self->value_type_class,
- mem);
-
- h = rb_hash_uint(h, NUM2LONG(rb_funcall(key, hash_sym, 0)));
- h = rb_hash_uint(h, NUM2LONG(rb_funcall(value, hash_sym, 0)));
+ uint64_t hash = 0;
+
+ size_t iter = UPB_MAP_BEGIN;
+ TypeInfo key_info = {self->key_type};
+ while (upb_mapiter_next(self->map, &iter)) {
+ upb_msgval key = upb_mapiter_key(self->map, iter);
+ upb_msgval val = upb_mapiter_value(self->map, iter);
+ hash = Msgval_GetHash(key, key_info, hash);
+ hash = Msgval_GetHash(val, self->value_type_info, hash);
}
- return INT2FIX(h);
+ return LL2NUM(hash);
}
/*
@@ -667,24 +626,7 @@ VALUE Map_hash(VALUE _self) {
*/
VALUE Map_to_h(VALUE _self) {
Map* self = ruby_to_Map(_self);
- VALUE hash = rb_hash_new();
- upb_strtable_iter it;
- for (upb_strtable_begin(&it, &self->table);
- !upb_strtable_done(&it);
- upb_strtable_next(&it)) {
- VALUE key = table_key_to_ruby(self, upb_strtable_iter_key(&it));
- upb_value v = upb_strtable_iter_value(&it);
- void* mem = value_memory(&v);
- VALUE value = native_slot_get(self->value_type,
- self->value_type_class,
- mem);
-
- if (self->value_type == UPB_TYPE_MESSAGE) {
- value = Message_to_h(value);
- }
- rb_hash_aset(hash, key, value);
- }
- return hash;
+ return Map_CreateHash(self->map, self->key_type, self->value_type_info);
}
/*
@@ -698,34 +640,11 @@ VALUE Map_to_h(VALUE _self) {
VALUE Map_inspect(VALUE _self) {
Map* self = ruby_to_Map(_self);
- VALUE str = rb_str_new2("{");
-
- bool first = true;
- VALUE inspect_sym = rb_intern("inspect");
-
- upb_strtable_iter it;
- for (upb_strtable_begin(&it, &self->table); !upb_strtable_done(&it);
- upb_strtable_next(&it)) {
- VALUE key = table_key_to_ruby(self, upb_strtable_iter_key(&it));
-
- upb_value v = upb_strtable_iter_value(&it);
- void* mem = value_memory(&v);
- VALUE value = native_slot_get(self->value_type,
- self->value_type_class,
- mem);
-
- if (!first) {
- str = rb_str_cat2(str, ", ");
- } else {
- first = false;
- }
- str = rb_str_append(str, rb_funcall(key, inspect_sym, 0));
- str = rb_str_cat2(str, "=>");
- str = rb_str_append(str, rb_funcall(value, inspect_sym, 0));
- }
-
- str = rb_str_cat2(str, "}");
- return str;
+ StringBuilder* builder = StringBuilder_New();
+ Map_Inspect(builder, self->map, self->key_type, self->value_type_info);
+ VALUE ret = StringBuilder_ToRubyString(builder);
+ StringBuilder_Free(builder);
+ return ret;
}
/*
@@ -737,79 +656,11 @@ VALUE Map_inspect(VALUE _self) {
* in the new copy of this map. Returns the new copy of this map with merged
* contents.
*/
-VALUE Map_merge(VALUE _self, VALUE hashmap) {
+static VALUE Map_merge(VALUE _self, VALUE hashmap) {
VALUE dupped = Map_dup(_self);
return Map_merge_into_self(dupped, hashmap);
}
-static int merge_into_self_callback(VALUE key, VALUE value, VALUE self) {
- Map_index_set(self, key, value);
- return ST_CONTINUE;
-}
-
-// Used only internally -- shared by #merge and #initialize.
-VALUE Map_merge_into_self(VALUE _self, VALUE hashmap) {
- if (TYPE(hashmap) == T_HASH) {
- rb_hash_foreach(hashmap, merge_into_self_callback, _self);
- } else if (RB_TYPE_P(hashmap, T_DATA) && RTYPEDDATA_P(hashmap) &&
- RTYPEDDATA_TYPE(hashmap) == &Map_type) {
-
- Map* self = ruby_to_Map(_self);
- Map* other = ruby_to_Map(hashmap);
- upb_strtable_iter it;
-
- if (self->key_type != other->key_type ||
- self->value_type != other->value_type ||
- self->value_type_class != other->value_type_class) {
- rb_raise(rb_eArgError, "Attempt to merge Map with mismatching types");
- }
-
- for (upb_strtable_begin(&it, &other->table);
- !upb_strtable_done(&it);
- upb_strtable_next(&it)) {
- upb_strview k = upb_strtable_iter_key(&it);
-
- // Replace any existing value by issuing a 'remove' operation first.
- upb_value v;
- upb_value oldv;
- upb_strtable_remove2(&self->table, k.data, k.size, &oldv);
-
- v = upb_strtable_iter_value(&it);
- upb_strtable_insert2(&self->table, k.data, k.size, v);
- }
- } else {
- rb_raise(rb_eArgError, "Unknown type merging into Map");
- }
- return _self;
-}
-
-// Internal method: map iterator initialization (used for serialization).
-void Map_begin(VALUE _self, Map_iter* iter) {
- Map* self = ruby_to_Map(_self);
- iter->self = self;
- upb_strtable_begin(&iter->it, &self->table);
-}
-
-void Map_next(Map_iter* iter) {
- upb_strtable_next(&iter->it);
-}
-
-bool Map_done(Map_iter* iter) {
- return upb_strtable_done(&iter->it);
-}
-
-VALUE Map_iter_key(Map_iter* iter) {
- return table_key_to_ruby(iter->self, upb_strtable_iter_key(&iter->it));
-}
-
-VALUE Map_iter_value(Map_iter* iter) {
- upb_value v = upb_strtable_iter_value(&iter->it);
- void* mem = value_memory(&v);
- return native_slot_get(iter->self->value_type,
- iter->self->value_type_class,
- mem);
-}
-
void Map_register(VALUE module) {
VALUE klass = rb_define_class_under(module, "Map", rb_cObject);
rb_define_alloc_func(klass, Map_alloc);
@@ -828,6 +679,7 @@ void Map_register(VALUE module) {
rb_define_method(klass, "length", Map_length, 0);
rb_define_method(klass, "dup", Map_dup, 0);
rb_define_method(klass, "==", Map_eq, 1);
+ rb_define_method(klass, "freeze", Map_freeze, 0);
rb_define_method(klass, "hash", Map_hash, 0);
rb_define_method(klass, "to_h", Map_to_h, 0);
rb_define_method(klass, "inspect", Map_inspect, 0);
diff --git a/ruby/ext/google/protobuf_c/map.h b/ruby/ext/google/protobuf_c/map.h
new file mode 100644
index 0000000000..1b840c3da7
--- /dev/null
+++ b/ruby/ext/google/protobuf_c/map.h
@@ -0,0 +1,66 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef RUBY_PROTOBUF_MAP_H_
+#define RUBY_PROTOBUF_MAP_H_
+
+#include
+
+#include "protobuf.h"
+#include "ruby-upb.h"
+
+// Returns a Ruby wrapper object for the given map, which will be created if
+// one does not exist already.
+VALUE Map_GetRubyWrapper(upb_map *map, upb_fieldtype_t key_type,
+ TypeInfo value_type, VALUE arena);
+
+// Gets the underlying upb_map for this Ruby map object, which must have
+// key/value type that match |field|. If this is not a map or the type doesn't
+// match, raises an exception.
+const upb_map *Map_GetUpbMap(VALUE val, const upb_fielddef *field);
+
+// Implements #inspect for this map by appending its contents to |b|.
+void Map_Inspect(StringBuilder *b, const upb_map *map, upb_fieldtype_t key_type,
+ TypeInfo val_type);
+
+// Returns a new Hash object containing the contents of this Map.
+VALUE Map_CreateHash(const upb_map* map, upb_fieldtype_t key_type,
+ TypeInfo val_info);
+
+// Returns a deep copy of this Map object.
+VALUE Map_deep_copy(VALUE obj);
+
+// Ruby class of Google::Protobuf::Map.
+extern VALUE cMap;
+
+// Call at startup to register all types in this module.
+void Map_register(VALUE module);
+
+#endif // RUBY_PROTOBUF_MAP_H_
diff --git a/ruby/ext/google/protobuf_c/message.c b/ruby/ext/google/protobuf_c/message.c
index 0050506d3b..22a21c129e 100644
--- a/ruby/ext/google/protobuf_c/message.c
+++ b/ruby/ext/google/protobuf_c/message.c
@@ -28,49 +28,61 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#include "message.h"
+
+#include "convert.h"
+#include "defs.h"
+#include "map.h"
#include "protobuf.h"
+#include "repeated_field.h"
+#include "third_party/wyhash/wyhash.h"
-// -----------------------------------------------------------------------------
-// Class/module creation from msgdefs and enumdefs, respectively.
-// -----------------------------------------------------------------------------
+static VALUE cParseError = Qnil;
+static ID descriptor_instancevar_interned;
-void* Message_data(void* msg) {
- return ((uint8_t *)msg) + sizeof(MessageHeader);
+static VALUE initialize_rb_class_with_no_args(VALUE klass) {
+ return rb_funcall(klass, rb_intern("new"), 0);
}
-void Message_mark(void* _self) {
- MessageHeader* self = (MessageHeader *)_self;
- layout_mark(self->descriptor->layout, Message_data(self));
+VALUE MessageOrEnum_GetDescriptor(VALUE klass) {
+ return rb_ivar_get(klass, descriptor_instancevar_interned);
}
-void Message_free(void* self) {
- stringsink* unknown = ((MessageHeader *)self)->unknown_fields;
- if (unknown != NULL) {
- stringsink_uninit(unknown);
- free(unknown);
- }
- xfree(self);
+// -----------------------------------------------------------------------------
+// Class/module creation from msgdefs and enumdefs, respectively.
+// -----------------------------------------------------------------------------
+
+typedef struct {
+ VALUE arena;
+ const upb_msg* msg; // Can get as mutable when non-frozen.
+ const upb_msgdef* msgdef; // kept alive by self.class.descriptor reference.
+} Message;
+
+static void Message_mark(void* _self) {
+ Message* self = (Message *)_self;
+ rb_gc_mark(self->arena);
}
-rb_data_type_t Message_type = {
+static rb_data_type_t Message_type = {
"Message",
- { Message_mark, Message_free, NULL },
+ { Message_mark, RUBY_DEFAULT_FREE, NULL },
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY,
};
-VALUE Message_alloc(VALUE klass) {
+static Message* ruby_to_Message(VALUE msg_rb) {
+ Message* msg;
+ TypedData_Get_Struct(msg_rb, Message, &Message_type, msg);
+ return msg;
+}
+
+static VALUE Message_alloc(VALUE klass) {
VALUE descriptor = rb_ivar_get(klass, descriptor_instancevar_interned);
- Descriptor* desc = ruby_to_Descriptor(descriptor);
- MessageHeader* msg;
+ Message* msg = ALLOC(Message);
VALUE ret;
- if (desc->layout == NULL) {
- create_layout(desc);
- }
-
- msg = (void*)ALLOC_N(uint8_t, sizeof(MessageHeader) + desc->layout->size);
- msg->descriptor = desc;
- msg->unknown_fields = NULL;
- memcpy(Message_data(msg), desc->layout->empty_template, desc->layout->size);
+ msg->msgdef = Descriptor_GetMsgDef(descriptor);
+ msg->arena = Qnil;
+ msg->msg = NULL;
ret = TypedData_Wrap_Struct(klass, &Message_type, msg);
rb_ivar_set(ret, descriptor_instancevar_interned, descriptor);
@@ -78,24 +90,92 @@ VALUE Message_alloc(VALUE klass) {
return ret;
}
-static const upb_fielddef* which_oneof_field(MessageHeader* self, const upb_oneofdef* o) {
- uint32_t oneof_case;
- const upb_fielddef* f;
+const upb_msg *Message_Get(VALUE msg_rb, const upb_msgdef **m) {
+ Message* msg = ruby_to_Message(msg_rb);
+ if (m) *m = msg->msgdef;
+ return msg->msg;
+}
+
+upb_msg *Message_GetMutable(VALUE msg_rb, const upb_msgdef **m) {
+ rb_check_frozen(msg_rb);
+ return (upb_msg*)Message_Get(msg_rb, m);
+}
+
+void Message_InitPtr(VALUE self_, upb_msg *msg, VALUE arena) {
+ Message* self = ruby_to_Message(self_);
+ self->msg = msg;
+ self->arena = arena;
+ ObjectCache_Add(msg, self_, Arena_get(arena));
+}
+
+VALUE Message_GetArena(VALUE msg_rb) {
+ Message* msg = ruby_to_Message(msg_rb);
+ return msg->arena;
+}
+
+void Message_CheckClass(VALUE klass) {
+ if (rb_get_alloc_func(klass) != &Message_alloc) {
+ rb_raise(rb_eArgError,
+ "Message class was not returned by the DescriptorPool.");
+ }
+}
+
+VALUE Message_GetRubyWrapper(upb_msg* msg, const upb_msgdef* m, VALUE arena) {
+ if (msg == NULL) return Qnil;
- oneof_case =
- slot_read_oneof_case(self->descriptor->layout, Message_data(self), o);
+ VALUE val = ObjectCache_Get(msg);
- if (oneof_case == ONEOF_CASE_NONE) {
- return NULL;
+ if (val == Qnil) {
+ VALUE klass = Descriptor_DefToClass(m);
+ val = Message_alloc(klass);
+ Message_InitPtr(val, msg, arena);
}
- // oneof_case is a field index, so find that field.
- f = upb_oneofdef_itof(o, oneof_case);
- assert(f != NULL);
+ return val;
+}
+
+void Message_PrintMessage(StringBuilder* b, const upb_msg* msg,
+ const upb_msgdef* m) {
+ bool first = true;
+ int n = upb_msgdef_fieldcount(m);
+ VALUE klass = Descriptor_DefToClass(m);
+ StringBuilder_Printf(b, "<%s: ", rb_class2name(klass));
+
+ for (int i = 0; i < n; i++) {
+ const upb_fielddef* field = upb_msgdef_field(m, i);
+
+ if (upb_fielddef_haspresence(field) && !upb_msg_has(msg, field)) {
+ continue;
+ }
+
+ if (!first) {
+ StringBuilder_Printf(b, ", ");
+ } else {
+ first = false;
+ }
+
+ upb_msgval msgval = upb_msg_get(msg, field);
+
+ StringBuilder_Printf(b, "%s: ", upb_fielddef_name(field));
+
+ if (upb_fielddef_ismap(field)) {
+ const upb_msgdef* entry_m = upb_fielddef_msgsubdef(field);
+ const upb_fielddef* key_f = upb_msgdef_itof(entry_m, 1);
+ const upb_fielddef* val_f = upb_msgdef_itof(entry_m, 2);
+ TypeInfo val_info = TypeInfo_get(val_f);
+ Map_Inspect(b, msgval.map_val, upb_fielddef_type(key_f), val_info);
+ } else if (upb_fielddef_isseq(field)) {
+ RepeatedField_Inspect(b, msgval.array_val, TypeInfo_get(field));
+ } else {
+ StringBuilder_PrintMsgval(b, msgval, TypeInfo_get(field));
+ }
+ }
- return f;
+ StringBuilder_Printf(b, ">");
}
+// Helper functions for #method_missing ////////////////////////////////////////
+
enum {
METHOD_UNKNOWN = 0,
METHOD_GETTER = 1,
@@ -108,153 +188,199 @@ enum {
};
// Check if the field is a well known wrapper type
-bool is_wrapper_type_field(const upb_fielddef* field) {
- const upb_msgdef *m;
- if (upb_fielddef_type(field) != UPB_TYPE_MESSAGE) {
+static bool IsWrapper(const upb_fielddef* f) {
+ return upb_fielddef_issubmsg(f) &&
+ upb_msgdef_iswrapper(upb_fielddef_msgsubdef(f));
+}
+
+static bool Match(const upb_msgdef* m, const char* name, const upb_fielddef** f,
+ const upb_oneofdef** o, const char* prefix,
+ const char* suffix) {
+ size_t sp = strlen(prefix);
+ size_t ss = strlen(suffix);
+ size_t sn = strlen(name);
+
+ if (sn <= sp + ss) return false;
+
+ if (memcmp(name, prefix, sp) != 0 ||
+ memcmp(name + sn - ss, suffix, ss) != 0) {
return false;
}
- m = upb_fielddef_msgsubdef(field);
- switch (upb_msgdef_wellknowntype(m)) {
- case UPB_WELLKNOWN_DOUBLEVALUE:
- case UPB_WELLKNOWN_FLOATVALUE:
- case UPB_WELLKNOWN_INT64VALUE:
- case UPB_WELLKNOWN_UINT64VALUE:
- case UPB_WELLKNOWN_INT32VALUE:
- case UPB_WELLKNOWN_UINT32VALUE:
- case UPB_WELLKNOWN_STRINGVALUE:
- case UPB_WELLKNOWN_BYTESVALUE:
- case UPB_WELLKNOWN_BOOLVALUE:
- return true;
- default:
- return false;
- }
+
+ return upb_msgdef_lookupname(m, name + sp, sn - sp - ss, f, o);
}
-// Get a new Ruby wrapper type and set the initial value
-VALUE ruby_wrapper_type(VALUE type_class, VALUE value) {
- if (value != Qnil) {
- VALUE hash = rb_hash_new();
- rb_hash_aset(hash, rb_str_new2("value"), value);
- {
- VALUE args[1] = {hash};
- return rb_class_new_instance(1, args, type_class);
+static int extract_method_call(VALUE method_name, Message* self,
+ const upb_fielddef** f, const upb_oneofdef** o) {
+ const upb_msgdef* m = self->msgdef;
+ const char* name;
+
+ Check_Type(method_name, T_SYMBOL);
+ name = rb_id2name(SYM2ID(method_name));
+
+ if (Match(m, name, f, o, "", "")) return METHOD_GETTER;
+ if (Match(m, name, f, o, "", "=")) return METHOD_SETTER;
+ if (Match(m, name, f, o, "clear_", "")) return METHOD_CLEAR;
+ if (Match(m, name, f, o, "has_", "?") &&
+ (*o || (*f && upb_fielddef_haspresence(*f)))) {
+ // Disallow oneof hazzers for proto3.
+ // TODO(haberman): remove this test when we are enabling oneof hazzers for
+ // proto3.
+ if (*f && !upb_fielddef_issubmsg(*f) &&
+ upb_fielddef_realcontainingoneof(*f) &&
+ upb_msgdef_syntax(upb_fielddef_containingtype(*f)) !=
+ UPB_SYNTAX_PROTO2) {
+ return METHOD_UNKNOWN;
}
+ return METHOD_PRESENCE;
+ }
+ if (Match(m, name, f, o, "", "_as_value") && *f && !upb_fielddef_isseq(*f) &&
+ IsWrapper(*f)) {
+ return METHOD_WRAPPER_GETTER;
+ }
+ if (Match(m, name, f, o, "", "_as_value=") && *f && !upb_fielddef_isseq(*f) &&
+ IsWrapper(*f)) {
+ return METHOD_WRAPPER_SETTER;
+ }
+ if (Match(m, name, f, o, "", "_const") && *f &&
+ upb_fielddef_type(*f) == UPB_TYPE_ENUM) {
+ return METHOD_ENUM_GETTER;
}
- return Qnil;
-}
-static int extract_method_call(VALUE method_name, MessageHeader* self,
- const upb_fielddef **f, const upb_oneofdef **o) {
- VALUE method_str;
- char* name;
- size_t name_len;
- int accessor_type;
- const upb_oneofdef* test_o;
- const upb_fielddef* test_f;
- bool has_field;
+ return METHOD_UNKNOWN;
+}
- Check_Type(method_name, T_SYMBOL);
+static VALUE Message_oneof_accessor(VALUE _self, const upb_oneofdef* o,
+ int accessor_type) {
+ Message* self = ruby_to_Message(_self);
+ const upb_fielddef* oneof_field = upb_msg_whichoneof(self->msg, o);
- method_str = rb_id2str(SYM2ID(method_name));
- name = RSTRING_PTR(method_str);
- name_len = RSTRING_LEN(method_str);
-
- if (name[name_len - 1] == '=') {
- accessor_type = METHOD_SETTER;
- name_len--;
- // We want to ensure if the proto has something named clear_foo or has_foo?,
- // we don't strip the prefix.
- } else if (strncmp("clear_", name, 6) == 0 &&
- !upb_msgdef_lookupname(self->descriptor->msgdef, name, name_len,
- &test_f, &test_o)) {
- accessor_type = METHOD_CLEAR;
- name = name + 6;
- name_len = name_len - 6;
- } else if (strncmp("has_", name, 4) == 0 && name[name_len - 1] == '?' &&
- !upb_msgdef_lookupname(self->descriptor->msgdef, name, name_len,
- &test_f, &test_o)) {
- accessor_type = METHOD_PRESENCE;
- name = name + 4;
- name_len = name_len - 5;
- } else {
- accessor_type = METHOD_GETTER;
- }
-
- has_field = upb_msgdef_lookupname(self->descriptor->msgdef, name, name_len,
- &test_f, &test_o);
-
- // Look for wrapper type accessor of the form _as_value
- if (!has_field &&
- (accessor_type == METHOD_GETTER || accessor_type == METHOD_SETTER) &&
- name_len > 9 && strncmp(name + name_len - 9, "_as_value", 9) == 0) {
- const upb_oneofdef* test_o_wrapper;
- const upb_fielddef* test_f_wrapper;
- char wrapper_field_name[name_len - 8];
-
- // Find the field name
- strncpy(wrapper_field_name, name, name_len - 9);
- wrapper_field_name[name_len - 9] = '\0';
-
- // Check if field exists and is a wrapper type
- if (upb_msgdef_lookupname(self->descriptor->msgdef, wrapper_field_name,
- name_len - 9, &test_f_wrapper, &test_o_wrapper) &&
- is_wrapper_type_field(test_f_wrapper)) {
- // It does exist!
- has_field = true;
- if (accessor_type == METHOD_SETTER) {
- accessor_type = METHOD_WRAPPER_SETTER;
- } else {
- accessor_type = METHOD_WRAPPER_GETTER;
+ switch (accessor_type) {
+ case METHOD_PRESENCE:
+ return oneof_field == NULL ? Qfalse : Qtrue;
+ case METHOD_CLEAR:
+ if (oneof_field != NULL) {
+ upb_msg_clearfield(Message_GetMutable(_self, NULL), oneof_field);
}
- test_o = test_o_wrapper;
- test_f = test_f_wrapper;
- }
+ return Qnil;
+ case METHOD_GETTER:
+ return oneof_field == NULL
+ ? Qnil
+ : ID2SYM(rb_intern(upb_fielddef_name(oneof_field)));
+ case METHOD_SETTER:
+ rb_raise(rb_eRuntimeError, "Oneof accessors are read-only.");
}
+ rb_raise(rb_eRuntimeError, "Invalid access of oneof field.");
+}
- // Look for enum accessor of the form _const
- if (!has_field && accessor_type == METHOD_GETTER &&
- name_len > 6 && strncmp(name + name_len - 6, "_const", 6) == 0) {
- const upb_oneofdef* test_o_enum;
- const upb_fielddef* test_f_enum;
- char enum_name[name_len - 5];
-
- // Find enum field name
- strncpy(enum_name, name, name_len - 6);
- enum_name[name_len - 6] = '\0';
-
- // Check if enum field exists
- if (upb_msgdef_lookupname(self->descriptor->msgdef, enum_name, name_len - 6,
- &test_f_enum, &test_o_enum) &&
- upb_fielddef_type(test_f_enum) == UPB_TYPE_ENUM) {
- // It does exist!
- has_field = true;
- accessor_type = METHOD_ENUM_GETTER;
- test_o = test_o_enum;
- test_f = test_f_enum;
+static void Message_setfield(upb_msg* msg, const upb_fielddef* f, VALUE val,
+ upb_arena* arena) {
+ upb_msgval msgval;
+ if (upb_fielddef_ismap(f)) {
+ msgval.map_val = Map_GetUpbMap(val, f);
+ } else if (upb_fielddef_isseq(f)) {
+ msgval.array_val = RepeatedField_GetUpbArray(val, f);
+ } else {
+ if (val == Qnil &&
+ (upb_fielddef_issubmsg(f) || upb_fielddef_realcontainingoneof(f))) {
+ upb_msg_clearfield(msg, f);
+ return;
}
+ msgval =
+ Convert_RubyToUpb(val, upb_fielddef_name(f), TypeInfo_get(f), arena);
}
+ upb_msg_set(msg, f, msgval, arena);
+}
- // Verify the name corresponds to a oneof or field in this message.
- if (!has_field) {
- return METHOD_UNKNOWN;
- }
-
- // Method calls like 'has_foo?' are not allowed if field "foo" does not have
- // a hasbit (e.g. repeated fields or non-message type fields for proto3
- // syntax).
- if (accessor_type == METHOD_PRESENCE && test_f != NULL) {
- if (!upb_fielddef_haspresence(test_f)) return METHOD_UNKNOWN;
+static VALUE Message_field_accessor(VALUE _self, const upb_fielddef* f,
+ int accessor_type, int argc, VALUE* argv) {
+ upb_arena *arena = Arena_get(Message_GetArena(_self));
- // TODO(haberman): remove this case, allow for proto3 oneofs.
- if (upb_fielddef_realcontainingoneof(test_f) &&
- upb_filedef_syntax(upb_fielddef_file(test_f)) == UPB_SYNTAX_PROTO3) {
- return METHOD_UNKNOWN;
+ switch (accessor_type) {
+ case METHOD_SETTER:
+ Message_setfield(Message_GetMutable(_self, NULL), f, argv[1], arena);
+ return Qnil;
+ case METHOD_CLEAR:
+ upb_msg_clearfield(Message_GetMutable(_self, NULL), f);
+ return Qnil;
+ case METHOD_PRESENCE:
+ if (!upb_fielddef_haspresence(f)) {
+ rb_raise(rb_eRuntimeError, "Field does not have presence.");
+ }
+ return upb_msg_has(Message_Get(_self, NULL), f);
+ case METHOD_WRAPPER_GETTER: {
+ Message* self = ruby_to_Message(_self);
+ if (upb_msg_has(self->msg, f)) {
+ PBRUBY_ASSERT(upb_fielddef_issubmsg(f) && !upb_fielddef_isseq(f));
+ upb_msgval wrapper = upb_msg_get(self->msg, f);
+ const upb_msgdef *wrapper_m = upb_fielddef_msgsubdef(f);
+ const upb_fielddef *value_f = upb_msgdef_itof(wrapper_m, 1);
+ upb_msgval value = upb_msg_get(wrapper.msg_val, value_f);
+ return Convert_UpbToRuby(value, TypeInfo_get(value_f), self->arena);
+ } else {
+ return Qnil;
+ }
+ }
+ case METHOD_WRAPPER_SETTER: {
+ upb_msg *msg = Message_GetMutable(_self, NULL);
+ if (argv[1] == Qnil) {
+ upb_msg_clearfield(msg, f);
+ } else {
+ const upb_fielddef *val_f = upb_msgdef_itof(upb_fielddef_msgsubdef(f), 1);
+ upb_msgval msgval = Convert_RubyToUpb(argv[1], upb_fielddef_name(f),
+ TypeInfo_get(val_f), arena);
+ upb_msg *wrapper = upb_msg_mutable(msg, f, arena).msg;
+ upb_msg_set(wrapper, val_f, msgval, arena);
+ }
+ return Qnil;
+ }
+ case METHOD_ENUM_GETTER: {
+ upb_msgval msgval = upb_msg_get(Message_Get(_self, NULL), f);
+
+ if (upb_fielddef_label(f) == UPB_LABEL_REPEATED) {
+ // Map repeated fields to a new type with ints
+ VALUE arr = rb_ary_new();
+ size_t i, n = upb_array_size(msgval.array_val);
+ for (i = 0; i < n; i++) {
+ upb_msgval elem = upb_array_get(msgval.array_val, i);
+ rb_ary_push(arr, INT2NUM(elem.int32_val));
+ }
+ return arr;
+ } else {
+ return INT2NUM(msgval.int32_val);
+ }
+ }
+ case METHOD_GETTER: {
+ Message* self = ruby_to_Message(_self);
+ // This is a special-case: upb_msg_mutable() for map & array are logically
+ // const (they will not change what is serialized) but physically
+ // non-const, as they do allocate a repeated field or map. The logical
+ // constness means it's ok to do even if the message is frozen.
+ upb_msg *msg = (upb_msg*)self->msg;
+ if (upb_fielddef_ismap(f)) {
+ upb_map *map = upb_msg_mutable(msg, f, arena).map;
+ const upb_fielddef *key_f = map_field_key(f);
+ const upb_fielddef *val_f = map_field_value(f);
+ upb_fieldtype_t key_type = upb_fielddef_type(key_f);
+ TypeInfo value_type_info = TypeInfo_get(val_f);
+ return Map_GetRubyWrapper(map, key_type, value_type_info, self->arena);
+ } else if (upb_fielddef_isseq(f)) {
+ upb_array *arr = upb_msg_mutable(msg, f, arena).array;
+ return RepeatedField_GetRubyWrapper(arr, TypeInfo_get(f), self->arena);
+ } else if (upb_fielddef_issubmsg(f)) {
+ if (!upb_msg_has(self->msg, f)) return Qnil;
+ upb_msg *submsg = upb_msg_mutable(msg, f, arena).msg;
+ const upb_msgdef *m = upb_fielddef_msgsubdef(f);
+ return Message_GetRubyWrapper(submsg, m, self->arena);
+ } else {
+ upb_msgval msgval = upb_msg_get(self->msg, f);
+ return Convert_UpbToRuby(msgval, TypeInfo_get(f), self->arena);
+ }
+ default:
+ rb_raise(rb_eRuntimeError, "Internal error, no such accessor: %d",
+ accessor_type);
}
}
-
- *o = test_o;
- *f = test_f;
- return accessor_type;
}
/*
@@ -284,111 +410,56 @@ static int extract_method_call(VALUE method_name, MessageHeader* self,
* true if the field 'fieldname' is set in the message object, else false. For
* 'proto3' syntax, calling this for a basic type field will result in an error.
*/
-VALUE Message_method_missing(int argc, VALUE* argv, VALUE _self) {
- MessageHeader* self;
+static VALUE Message_method_missing(int argc, VALUE* argv, VALUE _self) {
+ Message* self = ruby_to_Message(_self);
const upb_oneofdef* o;
const upb_fielddef* f;
int accessor_type;
- TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
if (argc < 1) {
rb_raise(rb_eArgError, "Expected method name as first argument.");
}
accessor_type = extract_method_call(argv[0], self, &f, &o);
- if (accessor_type == METHOD_UNKNOWN || (o == NULL && f == NULL) ) {
- return rb_call_super(argc, argv);
- } else if (accessor_type == METHOD_SETTER || accessor_type == METHOD_WRAPPER_SETTER) {
- if (argc != 2) {
- rb_raise(rb_eArgError, "Expected 2 arguments, received %d", argc);
- }
- rb_check_frozen(_self);
- } else if (argc != 1) {
- rb_raise(rb_eArgError, "Expected 1 argument, received %d", argc);
- }
- // Return which of the oneof fields are set
- if (o != NULL) {
- const upb_fielddef* oneof_field = which_oneof_field(self, o);
-
- if (accessor_type == METHOD_SETTER) {
- rb_raise(rb_eRuntimeError, "Oneof accessors are read-only.");
- }
+ if (accessor_type == METHOD_UNKNOWN) return rb_call_super(argc, argv);
- if (accessor_type == METHOD_PRESENCE) {
- return oneof_field == NULL ? Qfalse : Qtrue;
- } else if (accessor_type == METHOD_CLEAR) {
- if (oneof_field != NULL) {
- layout_clear(self->descriptor->layout, Message_data(self), oneof_field);
+ // Validate argument count.
+ switch (accessor_type) {
+ case METHOD_SETTER:
+ case METHOD_WRAPPER_SETTER:
+ if (argc != 2) {
+ rb_raise(rb_eArgError, "Expected 2 arguments, received %d", argc);
}
- return Qnil;
- } else {
- // METHOD_ACCESSOR
- return oneof_field == NULL ? Qnil :
- ID2SYM(rb_intern(upb_fielddef_name(oneof_field)));
- }
- // Otherwise we're operating on a single proto field
- } else if (accessor_type == METHOD_SETTER) {
- layout_set(self->descriptor->layout, Message_data(self), f, argv[1]);
- return Qnil;
- } else if (accessor_type == METHOD_CLEAR) {
- layout_clear(self->descriptor->layout, Message_data(self), f);
- return Qnil;
- } else if (accessor_type == METHOD_PRESENCE) {
- return layout_has(self->descriptor->layout, Message_data(self), f);
- } else if (accessor_type == METHOD_WRAPPER_GETTER) {
- VALUE value = layout_get(self->descriptor->layout, Message_data(self), f);
- switch (TYPE(value)) {
- case T_DATA:
- return rb_funcall(value, rb_intern("value"), 0);
- case T_NIL:
- return Qnil;
- default:
- return value;
- }
- } else if (accessor_type == METHOD_WRAPPER_SETTER) {
- VALUE wrapper = ruby_wrapper_type(
- field_type_class(self->descriptor->layout, f), argv[1]);
- layout_set(self->descriptor->layout, Message_data(self), f, wrapper);
- return Qnil;
- } else if (accessor_type == METHOD_ENUM_GETTER) {
- VALUE enum_type = field_type_class(self->descriptor->layout, f);
- VALUE method = rb_intern("const_get");
- VALUE raw_value = layout_get(self->descriptor->layout, Message_data(self), f);
-
- // Map repeated fields to a new type with ints
- if (upb_fielddef_label(f) == UPB_LABEL_REPEATED) {
- int array_size = FIX2INT(rb_funcall(raw_value, rb_intern("length"), 0));
- int i;
- VALUE array_args[1] = { ID2SYM(rb_intern("int64")) };
- VALUE array = rb_class_new_instance(1, array_args, CLASS_OF(raw_value));
- for (i = 0; i < array_size; i++) {
- VALUE entry = rb_funcall(enum_type, method, 1, rb_funcall(raw_value,
- rb_intern("at"), 1, INT2NUM(i)));
- rb_funcall(array, rb_intern("push"), 1, entry);
+ rb_check_frozen(_self);
+ break;
+ default:
+ if (argc != 1) {
+ rb_raise(rb_eArgError, "Expected 1 argument, received %d", argc);
}
- return array;
- }
- // Convert the value for singular fields
- return rb_funcall(enum_type, method, 1, raw_value);
+ break;
+ }
+
+ // Dispatch accessor.
+ if (o != NULL) {
+ return Message_oneof_accessor(_self, o, accessor_type);
} else {
- return layout_get(self->descriptor->layout, Message_data(self), f);
+ return Message_field_accessor(_self, f, accessor_type, argc, argv);
}
}
-
-VALUE Message_respond_to_missing(int argc, VALUE* argv, VALUE _self) {
- MessageHeader* self;
+static VALUE Message_respond_to_missing(int argc, VALUE* argv, VALUE _self) {
+ Message* self = ruby_to_Message(_self);
const upb_oneofdef* o;
const upb_fielddef* f;
int accessor_type;
- TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
if (argc < 1) {
rb_raise(rb_eArgError, "Expected method name as first argument.");
}
accessor_type = extract_method_call(argv[0], self, &f, &o);
+
if (accessor_type == METHOD_UNKNOWN) {
return rb_call_super(argc, argv);
} else if (o != NULL) {
@@ -398,17 +469,116 @@ VALUE Message_respond_to_missing(int argc, VALUE* argv, VALUE _self) {
}
}
-VALUE create_submsg_from_hash(const MessageLayout* layout,
- const upb_fielddef* f, VALUE hash) {
- VALUE args[1] = { hash };
- return rb_class_new_instance(1, args, field_type_class(layout, f));
+void Message_InitFromValue(upb_msg* msg, const upb_msgdef* m, VALUE val,
+ upb_arena* arena);
+
+typedef struct {
+ upb_map *map;
+ TypeInfo key_type;
+ TypeInfo val_type;
+ upb_arena *arena;
+} MapInit;
+
+static int Map_initialize_kwarg(VALUE key, VALUE val, VALUE _self) {
+ MapInit *map_init = (MapInit*)_self;
+ upb_msgval k, v;
+ k = Convert_RubyToUpb(key, "", map_init->key_type, NULL);
+
+ if (map_init->val_type.type == UPB_TYPE_MESSAGE && TYPE(val) == T_HASH) {
+ upb_msg *msg = upb_msg_new(map_init->val_type.def.msgdef, map_init->arena);
+ Message_InitFromValue(msg, map_init->val_type.def.msgdef, val,
+ map_init->arena);
+ v.msg_val = msg;
+ } else {
+ v = Convert_RubyToUpb(val, "", map_init->val_type, map_init->arena);
+ }
+ upb_map_set(map_init->map, k, v, map_init->arena);
+ return ST_CONTINUE;
}
-int Message_initialize_kwarg(VALUE key, VALUE val, VALUE _self) {
- MessageHeader* self;
- char *name;
- const upb_fielddef* f;
- TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
+static void Map_InitFromValue(upb_map* map, const upb_fielddef* f, VALUE val,
+ upb_arena* arena) {
+ const upb_msgdef* entry_m = upb_fielddef_msgsubdef(f);
+ const upb_fielddef* key_f = upb_msgdef_itof(entry_m, 1);
+ const upb_fielddef* val_f = upb_msgdef_itof(entry_m, 2);
+ if (TYPE(val) != T_HASH) {
+ rb_raise(rb_eArgError,
+ "Expected Hash object as initializer value for map field '%s' "
+ "(given %s).",
+ upb_fielddef_name(f), rb_class2name(CLASS_OF(val)));
+ }
+ MapInit map_init = {map, TypeInfo_get(key_f), TypeInfo_get(val_f), arena};
+ rb_hash_foreach(val, Map_initialize_kwarg, (VALUE)&map_init);
+}
+
+static upb_msgval MessageValue_FromValue(VALUE val, TypeInfo info,
+ upb_arena* arena) {
+ if (info.type == UPB_TYPE_MESSAGE) {
+ upb_msgval msgval;
+ upb_msg* msg = upb_msg_new(info.def.msgdef, arena);
+ Message_InitFromValue(msg, info.def.msgdef, val, arena);
+ msgval.msg_val = msg;
+ return msgval;
+ } else {
+ return Convert_RubyToUpb(val, "", info, arena);
+ }
+}
+
+static void RepeatedField_InitFromValue(upb_array* arr, const upb_fielddef* f,
+ VALUE val, upb_arena* arena) {
+ TypeInfo type_info = TypeInfo_get(f);
+
+ if (TYPE(val) != T_ARRAY) {
+ rb_raise(rb_eArgError,
+ "Expected array as initializer value for repeated field '%s' (given %s).",
+ upb_fielddef_name(f), rb_class2name(CLASS_OF(val)));
+ }
+
+ for (int i = 0; i < RARRAY_LEN(val); i++) {
+ VALUE entry = rb_ary_entry(val, i);
+ upb_msgval msgval;
+ if (upb_fielddef_issubmsg(f) && TYPE(entry) == T_HASH) {
+ msgval = MessageValue_FromValue(entry, type_info, arena);
+ } else {
+ msgval = Convert_RubyToUpb(entry, upb_fielddef_name(f), type_info, arena);
+ }
+ upb_array_append(arr, msgval, arena);
+ }
+}
+
+static void Message_InitFieldFromValue(upb_msg* msg, const upb_fielddef* f,
+ VALUE val, upb_arena* arena) {
+ if (TYPE(val) == T_NIL) return;
+
+ if (upb_fielddef_ismap(f)) {
+ upb_map *map = upb_msg_mutable(msg, f, arena).map;
+ Map_InitFromValue(map, f, val, arena);
+ } else if (upb_fielddef_label(f) == UPB_LABEL_REPEATED) {
+ upb_array *arr = upb_msg_mutable(msg, f, arena).array;
+ RepeatedField_InitFromValue(arr, f, val, arena);
+ } else if (upb_fielddef_issubmsg(f)) {
+ if (TYPE(val) == T_HASH) {
+ upb_msg *submsg = upb_msg_mutable(msg, f, arena).msg;
+ Message_InitFromValue(submsg, upb_fielddef_msgsubdef(f), val, arena);
+ } else {
+ Message_setfield(msg, f, val, arena);
+ }
+ } else {
+ upb_msgval msgval =
+ Convert_RubyToUpb(val, upb_fielddef_name(f), TypeInfo_get(f), arena);
+ upb_msg_set(msg, f, msgval, arena);
+ }
+}
+
+typedef struct {
+ upb_msg *msg;
+ const upb_msgdef *msgdef;
+ upb_arena *arena;
+} MsgInit;
+
+static int Message_initialize_kwarg(VALUE key, VALUE val, VALUE _self) {
+ MsgInit *msg_init = (MsgInit*)_self;
+ const char *name;
if (TYPE(key) == T_STRING) {
name = RSTRING_PTR(key);
@@ -419,52 +589,26 @@ int Message_initialize_kwarg(VALUE key, VALUE val, VALUE _self) {
"Expected string or symbols as hash keys when initializing proto from hash.");
}
- f = upb_msgdef_ntofz(self->descriptor->msgdef, name);
+ const upb_fielddef* f = upb_msgdef_ntofz(msg_init->msgdef, name);
+
if (f == NULL) {
rb_raise(rb_eArgError,
"Unknown field name '%s' in initialization map entry.", name);
}
- if (TYPE(val) == T_NIL) {
- return 0;
- }
-
- if (is_map_field(f)) {
- VALUE map;
-
- if (TYPE(val) != T_HASH) {
- rb_raise(rb_eArgError,
- "Expected Hash object as initializer value for map field '%s' (given %s).",
- name, rb_class2name(CLASS_OF(val)));
- }
- map = layout_get(self->descriptor->layout, Message_data(self), f);
- Map_merge_into_self(map, val);
- } else if (upb_fielddef_label(f) == UPB_LABEL_REPEATED) {
- VALUE ary;
- int i;
-
- if (TYPE(val) != T_ARRAY) {
- rb_raise(rb_eArgError,
- "Expected array as initializer value for repeated field '%s' (given %s).",
- name, rb_class2name(CLASS_OF(val)));
- }
- ary = layout_get(self->descriptor->layout, Message_data(self), f);
- for (i = 0; i < RARRAY_LEN(val); i++) {
- VALUE entry = rb_ary_entry(val, i);
- if (TYPE(entry) == T_HASH && upb_fielddef_issubmsg(f)) {
- entry = create_submsg_from_hash(self->descriptor->layout, f, entry);
- }
+ Message_InitFieldFromValue(msg_init->msg, f, val, msg_init->arena);
+ return ST_CONTINUE;
+}
- RepeatedField_push(ary, entry);
- }
+void Message_InitFromValue(upb_msg* msg, const upb_msgdef* m, VALUE val,
+ upb_arena* arena) {
+ MsgInit msg_init = {msg, m, arena};
+ if (TYPE(val) == T_HASH) {
+ rb_hash_foreach(val, Message_initialize_kwarg, (VALUE)&msg_init);
} else {
- if (TYPE(val) == T_HASH && upb_fielddef_issubmsg(f)) {
- val = create_submsg_from_hash(self->descriptor->layout, f, val);
- }
-
- layout_set(self->descriptor->layout, Message_data(self), f, val);
+ rb_raise(rb_eArgError, "Expected hash arguments or message, not %s",
+ rb_class2name(CLASS_OF(val)));
}
- return 0;
}
/*
@@ -479,12 +623,13 @@ int Message_initialize_kwarg(VALUE key, VALUE val, VALUE _self) {
* have been added to a pool. The method definitions described here on the
* Message class are provided on each concrete message class.
*/
-VALUE Message_initialize(int argc, VALUE* argv, VALUE _self) {
- MessageHeader* self;
- VALUE hash_args;
- TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
+static VALUE Message_initialize(int argc, VALUE* argv, VALUE _self) {
+ Message* self = ruby_to_Message(_self);
+ VALUE arena_rb = Arena_new();
+ upb_arena *arena = Arena_get(arena_rb);
+ upb_msg *msg = upb_msg_new(self->msgdef, arena);
- layout_init(self->descriptor->layout, Message_data(self));
+ Message_InitPtr(_self, msg, arena_rb);
if (argc == 0) {
return Qnil;
@@ -492,12 +637,7 @@ VALUE Message_initialize(int argc, VALUE* argv, VALUE _self) {
if (argc != 1) {
rb_raise(rb_eArgError, "Expected 0 or 1 arguments.");
}
- hash_args = argv[0];
- if (TYPE(hash_args) != T_HASH) {
- rb_raise(rb_eArgError, "Expected hash arguments.");
- }
-
- rb_hash_foreach(hash_args, Message_initialize_kwarg, _self);
+ Message_InitFromValue((upb_msg*)self->msg, self->msgdef, argv[0], arena);
return Qnil;
}
@@ -507,37 +647,40 @@ VALUE Message_initialize(int argc, VALUE* argv, VALUE _self) {
*
* Performs a shallow copy of this message and returns the new copy.
*/
-VALUE Message_dup(VALUE _self) {
- MessageHeader* self;
- VALUE new_msg;
- MessageHeader* new_msg_self;
- TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
-
- new_msg = rb_class_new_instance(0, NULL, CLASS_OF(_self));
- TypedData_Get_Struct(new_msg, MessageHeader, &Message_type, new_msg_self);
-
- layout_dup(self->descriptor->layout,
- Message_data(new_msg_self),
- Message_data(self));
-
+static VALUE Message_dup(VALUE _self) {
+ Message* self = ruby_to_Message(_self);
+ VALUE new_msg = rb_class_new_instance(0, NULL, CLASS_OF(_self));
+ Message* new_msg_self = ruby_to_Message(new_msg);
+ size_t size = upb_msgdef_layout(self->msgdef)->size;
+
+ // TODO(copy unknown fields?)
+ // TODO(use official upb msg copy function)
+ memcpy((upb_msg*)new_msg_self->msg, self->msg, size);
+ upb_arena_fuse(Arena_get(new_msg_self->arena), Arena_get(self->arena));
return new_msg;
}
-// Internal only; used by Google::Protobuf.deep_copy.
-VALUE Message_deep_copy(VALUE _self) {
- MessageHeader* self;
- MessageHeader* new_msg_self;
- VALUE new_msg;
- TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
+// Support function for Message_eq, and also used by other #eq functions.
+bool Message_Equal(const upb_msg *m1, const upb_msg *m2, const upb_msgdef *m) {
+ if (m1 == m2) return true;
- new_msg = rb_class_new_instance(0, NULL, CLASS_OF(_self));
- TypedData_Get_Struct(new_msg, MessageHeader, &Message_type, new_msg_self);
+ size_t size1, size2;
+ int encode_opts = UPB_ENCODE_SKIPUNKNOWN | UPB_ENCODE_DETERMINISTIC;
+ upb_arena *arena_tmp = upb_arena_new();
+ const upb_msglayout *layout = upb_msgdef_layout(m);
- layout_deep_copy(self->descriptor->layout,
- Message_data(new_msg_self),
- Message_data(self));
+ // Compare deterministically serialized payloads with no unknown fields.
+ char *data1 = upb_encode_ex(m1, layout, encode_opts, arena_tmp, &size1);
+ char *data2 = upb_encode_ex(m2, layout, encode_opts, arena_tmp, &size2);
- return new_msg;
+ if (data1 && data2) {
+ bool ret = (size1 == size2) && (memcmp(data1, data2, size1) == 0);
+ upb_arena_free(arena_tmp);
+ return ret;
+ } else {
+ upb_arena_free(arena_tmp);
+ rb_raise(cParseError, "Error comparing messages");
+ }
}
/*
@@ -549,22 +692,37 @@ VALUE Message_deep_copy(VALUE _self) {
* method's semantics (a more efficient comparison may actually be done if the
* field is of a primitive type).
*/
-VALUE Message_eq(VALUE _self, VALUE _other) {
- MessageHeader* self;
- MessageHeader* other;
+static VALUE Message_eq(VALUE _self, VALUE _other) {
if (TYPE(_self) != TYPE(_other)) {
return Qfalse;
}
- TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
- TypedData_Get_Struct(_other, MessageHeader, &Message_type, other);
- if (self->descriptor != other->descriptor) {
- return Qfalse;
- }
+ Message* self = ruby_to_Message(_self);
+ Message* other = ruby_to_Message(_other);
+
+ return Message_Equal(self->msg, other->msg, self->msgdef)
+ ? Qtrue
+ : Qfalse;
+}
+
+uint64_t Message_Hash(const upb_msg* msg, const upb_msgdef* m, uint64_t seed) {
+ upb_arena *arena = upb_arena_new();
+ const char *data;
+ size_t size;
+
+ // Hash a deterministically serialized payloads with no unknown fields.
+ data = upb_encode_ex(msg, upb_msgdef_layout(m),
+ UPB_ENCODE_SKIPUNKNOWN | UPB_ENCODE_DETERMINISTIC, arena,
+ &size);
- return layout_eq(self->descriptor->layout,
- Message_data(self),
- Message_data(other));
+ if (data) {
+ uint64_t ret = wyhash(data, size, seed, _wyp);
+ upb_arena_free(arena);
+ return ret;
+ } else {
+ upb_arena_free(arena);
+ rb_raise(cParseError, "Error calculating hash");
+ }
}
/*
@@ -573,11 +731,9 @@ VALUE Message_eq(VALUE _self, VALUE _other) {
*
* Returns a hash value that represents this message's field values.
*/
-VALUE Message_hash(VALUE _self) {
- MessageHeader* self;
- TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
-
- return layout_hash(self->descriptor->layout, Message_data(self));
+static VALUE Message_hash(VALUE _self) {
+ Message* self = ruby_to_Message(_self);
+ return INT2FIX(Message_Hash(self->msg, self->msgdef, 0));
}
/*
@@ -588,81 +744,117 @@ VALUE Message_hash(VALUE _self) {
* formatted as "". Each
* field's value is represented according to its own #inspect method.
*/
-VALUE Message_inspect(VALUE _self) {
- MessageHeader* self;
- VALUE str;
- TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
+static VALUE Message_inspect(VALUE _self) {
+ Message* self = ruby_to_Message(_self);
- str = rb_str_new2("<");
- str = rb_str_append(str, rb_str_new2(rb_class2name(CLASS_OF(_self))));
- str = rb_str_cat2(str, ": ");
- str = rb_str_append(str, layout_inspect(
- self->descriptor->layout, Message_data(self)));
- str = rb_str_cat2(str, ">");
- return str;
+ StringBuilder* builder = StringBuilder_New();
+ Message_PrintMessage(builder, self->msg, self->msgdef);
+ VALUE ret = StringBuilder_ToRubyString(builder);
+ StringBuilder_Free(builder);
+ return ret;
}
-/*
- * call-seq:
- * Message.to_h => {}
- *
- * Returns the message as a Ruby Hash object, with keys as symbols.
- */
-VALUE Message_to_h(VALUE _self) {
- MessageHeader* self;
+// Support functions for Message_to_h //////////////////////////////////////////
+
+static VALUE RepeatedField_CreateArray(const upb_array* arr,
+ TypeInfo type_info) {
+ int size = arr ? upb_array_size(arr) : 0;
+ VALUE ary = rb_ary_new2(size);
+
+ for (int i = 0; i < size; i++) {
+ upb_msgval msgval = upb_array_get(arr, i);
+ VALUE val = Scalar_CreateHash(msgval, type_info);
+ rb_ary_push(ary, val);
+ }
+
+ return ary;
+}
+
+static VALUE Message_CreateHash(const upb_msg *msg, const upb_msgdef *m) {
+ if (!msg) return Qnil;
+
VALUE hash = rb_hash_new();
- upb_msg_field_iter it;
+ int n = upb_msgdef_fieldcount(m);
bool is_proto2;
- TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
// We currently have a few behaviors that are specific to proto2.
// This is unfortunate, we should key behaviors off field attributes (like
// whether a field has presence), not proto2 vs. proto3. We should see if we
// can change this without breaking users.
- is_proto2 =
- upb_msgdef_syntax(self->descriptor->msgdef) == UPB_SYNTAX_PROTO2;
+ is_proto2 = upb_msgdef_syntax(m) == UPB_SYNTAX_PROTO2;
- for (upb_msg_field_begin(&it, self->descriptor->msgdef);
- !upb_msg_field_done(&it);
- upb_msg_field_next(&it)) {
- const upb_fielddef* field = upb_msg_iter_field(&it);
+ for (int i = 0; i < n; i++) {
+ const upb_fielddef* field = upb_msgdef_field(m, i);
+ TypeInfo type_info = TypeInfo_get(field);
+ upb_msgval msgval;
VALUE msg_value;
VALUE msg_key;
// Do not include fields that are not present (oneof or optional fields).
if (is_proto2 && upb_fielddef_haspresence(field) &&
- !layout_has(self->descriptor->layout, Message_data(self), field)) {
+ !upb_msg_has(msg, field)) {
continue;
}
- msg_value = layout_get(self->descriptor->layout, Message_data(self), field);
msg_key = ID2SYM(rb_intern(upb_fielddef_name(field)));
- if (is_map_field(field)) {
- msg_value = Map_to_h(msg_value);
- } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
- msg_value = RepeatedField_to_ary(msg_value);
- if (is_proto2 && RARRAY_LEN(msg_value) == 0) {
+ msgval = upb_msg_get(msg, field);
+
+ // Proto2 omits empty map/repeated filds also.
+
+ if (upb_fielddef_ismap(field)) {
+ const upb_msgdef *entry_m = upb_fielddef_msgsubdef(field);
+ const upb_fielddef *key_f = upb_msgdef_itof(entry_m, 1);
+ const upb_fielddef *val_f = upb_msgdef_itof(entry_m, 2);
+ upb_fieldtype_t key_type = upb_fielddef_type(key_f);
+ msg_value = Map_CreateHash(msgval.map_val, key_type, TypeInfo_get(val_f));
+ } else if (upb_fielddef_isseq(field)) {
+ if (is_proto2 &&
+ (!msgval.array_val || upb_array_size(msgval.array_val) == 0)) {
continue;
}
-
- if (upb_fielddef_type(field) == UPB_TYPE_MESSAGE) {
- int i;
- for (i = 0; i < RARRAY_LEN(msg_value); i++) {
- VALUE elem = rb_ary_entry(msg_value, i);
- rb_ary_store(msg_value, i, Message_to_h(elem));
- }
- }
-
- } else if (msg_value != Qnil &&
- upb_fielddef_type(field) == UPB_TYPE_MESSAGE) {
- msg_value = Message_to_h(msg_value);
+ msg_value = RepeatedField_CreateArray(msgval.array_val, type_info);
+ } else {
+ msg_value = Scalar_CreateHash(msgval, type_info);
}
+
rb_hash_aset(hash, msg_key, msg_value);
}
+
return hash;
}
+VALUE Scalar_CreateHash(upb_msgval msgval, TypeInfo type_info) {
+ if (type_info.type == UPB_TYPE_MESSAGE) {
+ return Message_CreateHash(msgval.msg_val, type_info.def.msgdef);
+ } else {
+ return Convert_UpbToRuby(msgval, type_info, Qnil);
+ }
+}
+
+/*
+ * call-seq:
+ * Message.to_h => {}
+ *
+ * Returns the message as a Ruby Hash object, with keys as symbols.
+ */
+static VALUE Message_to_h(VALUE _self) {
+ Message* self = ruby_to_Message(_self);
+ return Message_CreateHash(self->msg, self->msgdef);
+}
+/*
+ * call-seq:
+ * Message.freeze => self
+ *
+ * Freezes the message object. We have to intercept this so we can pin the
+ * Ruby object into memory so we don't forget it's frozen.
+ */
+static VALUE Message_freeze(VALUE _self) {
+ Message* self = ruby_to_Message(_self);
+ ObjectCache_Pin(self->msg, _self, Arena_get(self->arena));
+ RB_OBJ_FREEZE(_self);
+ return _self;
+}
/*
* call-seq:
@@ -671,16 +863,20 @@ VALUE Message_to_h(VALUE _self) {
* Accesses a field's value by field name. The provided field name should be a
* string.
*/
-VALUE Message_index(VALUE _self, VALUE field_name) {
- MessageHeader* self;
+static VALUE Message_index(VALUE _self, VALUE field_name) {
+ Message* self = ruby_to_Message(_self);
const upb_fielddef* field;
- TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
+ upb_msgval val;
+
Check_Type(field_name, T_STRING);
- field = upb_msgdef_ntofz(self->descriptor->msgdef, RSTRING_PTR(field_name));
+ field = upb_msgdef_ntofz(self->msgdef, RSTRING_PTR(field_name));
+
if (field == NULL) {
return Qnil;
}
- return layout_get(self->descriptor->layout, Message_data(self), field);
+
+ val = upb_msg_get(self->msg, field);
+ return Convert_UpbToRuby(val, TypeInfo_get(field), self->arena);
}
/*
@@ -690,19 +886,208 @@ VALUE Message_index(VALUE _self, VALUE field_name) {
* Sets a field's value by field name. The provided field name should be a
* string.
*/
-VALUE Message_index_set(VALUE _self, VALUE field_name, VALUE value) {
- MessageHeader* self;
- const upb_fielddef* field;
- TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
+static VALUE Message_index_set(VALUE _self, VALUE field_name, VALUE value) {
+ Message* self = ruby_to_Message(_self);
+ const upb_fielddef* f;
+ upb_msgval val;
+ upb_arena *arena = Arena_get(self->arena);
+
Check_Type(field_name, T_STRING);
- field = upb_msgdef_ntofz(self->descriptor->msgdef, RSTRING_PTR(field_name));
- if (field == NULL) {
+ f = upb_msgdef_ntofz(self->msgdef, RSTRING_PTR(field_name));
+
+ if (f == NULL) {
rb_raise(rb_eArgError, "Unknown field: %s", RSTRING_PTR(field_name));
}
- layout_set(self->descriptor->layout, Message_data(self), field, value);
+
+ val = Convert_RubyToUpb(value, upb_fielddef_name(f), TypeInfo_get(f), arena);
+ upb_msg_set(Message_GetMutable(_self, NULL), f, val, arena);
+
return Qnil;
}
+/*
+ * call-seq:
+ * MessageClass.decode(data) => message
+ *
+ * Decodes the given data (as a string containing bytes in protocol buffers wire
+ * format) under the interpretration given by this message class's definition
+ * and returns a message object with the corresponding field values.
+ */
+static VALUE Message_decode(VALUE klass, VALUE data) {
+ if (TYPE(data) != T_STRING) {
+ rb_raise(rb_eArgError, "Expected string for binary protobuf data.");
+ }
+
+ VALUE msg_rb = initialize_rb_class_with_no_args(klass);
+ Message* msg = ruby_to_Message(msg_rb);
+
+ if (!upb_decode(RSTRING_PTR(data), RSTRING_LEN(data), (upb_msg*)msg->msg,
+ upb_msgdef_layout(msg->msgdef),
+ Arena_get(msg->arena))) {
+ rb_raise(cParseError, "Error occurred during parsing");
+ }
+
+ return msg_rb;
+}
+
+/*
+ * call-seq:
+ * MessageClass.decode_json(data, options = {}) => message
+ *
+ * Decodes the given data (as a string containing bytes in protocol buffers wire
+ * format) under the interpretration given by this message class's definition
+ * and returns a message object with the corresponding field values.
+ *
+ * @param options [Hash] options for the decoder
+ * ignore_unknown_fields: set true to ignore unknown fields (default is to
+ * raise an error)
+ */
+static VALUE Message_decode_json(int argc, VALUE* argv, VALUE klass) {
+ VALUE data = argv[0];
+ int options = 0;
+ upb_status status;
+
+ // TODO(haberman): use this message's pool instead.
+ const upb_symtab *symtab = DescriptorPool_GetSymtab(generated_pool);
+
+ if (argc < 1 || argc > 2) {
+ rb_raise(rb_eArgError, "Expected 1 or 2 arguments.");
+ }
+
+ if (argc == 2) {
+ VALUE hash_args = argv[1];
+ if (TYPE(hash_args) != T_HASH) {
+ rb_raise(rb_eArgError, "Expected hash arguments.");
+ }
+
+ if (RTEST(rb_hash_lookup2( hash_args, ID2SYM(rb_intern("ignore_unknown_fields")), Qfalse))) {
+ options |= UPB_JSONDEC_IGNOREUNKNOWN;
+ }
+ }
+
+ if (TYPE(data) != T_STRING) {
+ rb_raise(rb_eArgError, "Expected string for JSON data.");
+ }
+
+ // TODO(cfallin): Check and respect string encoding. If not UTF-8, we need to
+ // convert, because string handlers pass data directly to message string
+ // fields.
+
+ VALUE msg_rb = initialize_rb_class_with_no_args(klass);
+ Message* msg = ruby_to_Message(msg_rb);
+
+ // We don't allow users to decode a wrapper type directly.
+ if (upb_msgdef_iswrapper(msg->msgdef)) {
+ rb_raise(rb_eRuntimeError, "Cannot parse a wrapper directly.");
+ }
+
+ upb_status_clear(&status);
+ if (!upb_json_decode(RSTRING_PTR(data), RSTRING_LEN(data), (upb_msg*)msg->msg,
+ msg->msgdef, symtab, options,
+ Arena_get(msg->arena), &status)) {
+ rb_raise(cParseError, "Error occurred during parsing: %s",
+ upb_status_errmsg(&status));
+ }
+
+ return msg_rb;
+}
+
+/*
+ * call-seq:
+ * MessageClass.encode(msg) => bytes
+ *
+ * Encodes the given message object to its serialized form in protocol buffers
+ * wire format.
+ */
+static VALUE Message_encode(VALUE klass, VALUE msg_rb) {
+ Message* msg = ruby_to_Message(msg_rb);
+ upb_arena *arena = upb_arena_new();
+ const char *data;
+ size_t size;
+
+ if (CLASS_OF(msg_rb) != klass) {
+ rb_raise(rb_eArgError, "Message of wrong type.");
+ }
+
+ data = upb_encode(msg->msg, upb_msgdef_layout(msg->msgdef), arena,
+ &size);
+
+ if (data) {
+ VALUE ret = rb_str_new(data, size);
+ rb_enc_associate(ret, rb_ascii8bit_encoding());
+ upb_arena_free(arena);
+ return ret;
+ } else {
+ upb_arena_free(arena);
+ rb_raise(rb_eRuntimeError, "Exceeded maximum depth (possibly cycle)");
+ }
+}
+
+/*
+ * call-seq:
+ * MessageClass.encode_json(msg, options = {}) => json_string
+ *
+ * Encodes the given message object into its serialized JSON representation.
+ * @param options [Hash] options for the decoder
+ * preserve_proto_fieldnames: set true to use original fieldnames (default is to camelCase)
+ * emit_defaults: set true to emit 0/false values (default is to omit them)
+ */
+static VALUE Message_encode_json(int argc, VALUE* argv, VALUE klass) {
+ Message* msg = ruby_to_Message(argv[0]);
+ int options = 0;
+ char buf[1024];
+ size_t size;
+ upb_status status;
+
+ // TODO(haberman): use this message's pool instead.
+ const upb_symtab *symtab = DescriptorPool_GetSymtab(generated_pool);
+
+ if (argc < 1 || argc > 2) {
+ rb_raise(rb_eArgError, "Expected 1 or 2 arguments.");
+ }
+
+ if (argc == 2) {
+ VALUE hash_args = argv[1];
+ if (TYPE(hash_args) != T_HASH) {
+ rb_raise(rb_eArgError, "Expected hash arguments.");
+ }
+
+ if (RTEST(rb_hash_lookup2(hash_args,
+ ID2SYM(rb_intern("preserve_proto_fieldnames")),
+ Qfalse))) {
+ options |= UPB_JSONENC_PROTONAMES;
+ }
+
+ if (RTEST(rb_hash_lookup2(hash_args, ID2SYM(rb_intern("emit_defaults")),
+ Qfalse))) {
+ options |= UPB_JSONENC_EMITDEFAULTS;
+ }
+ }
+
+ upb_status_clear(&status);
+ size = upb_json_encode(msg->msg, msg->msgdef, symtab, options, buf,
+ sizeof(buf), &status);
+
+ if (!upb_ok(&status)) {
+ rb_raise(cParseError, "Error occurred during encoding: %s",
+ upb_status_errmsg(&status));
+ }
+
+ VALUE ret;
+ if (size >= sizeof(buf)) {
+ char* buf2 = malloc(size + 1);
+ upb_json_encode(msg->msg, msg->msgdef, symtab, options, buf2, size + 1,
+ &status);
+ ret = rb_str_new(buf2, size);
+ free(buf2);
+ } else {
+ ret = rb_str_new(buf, size);
+ }
+
+ rb_enc_associate(ret, rb_utf8_encoding());
+ return ret;
+}
+
/*
* call-seq:
* Message.descriptor => descriptor
@@ -710,16 +1095,15 @@ VALUE Message_index_set(VALUE _self, VALUE field_name, VALUE value) {
* Class method that returns the Descriptor instance corresponding to this
* message class's type.
*/
-VALUE Message_descriptor(VALUE klass) {
+static VALUE Message_descriptor(VALUE klass) {
return rb_ivar_get(klass, descriptor_instancevar_interned);
}
VALUE build_class_from_descriptor(VALUE descriptor) {
- Descriptor* desc = ruby_to_Descriptor(descriptor);
const char *name;
VALUE klass;
- name = upb_msgdef_fullname(desc->msgdef);
+ name = upb_msgdef_fullname(Descriptor_GetMsgDef(descriptor));
if (name == NULL) {
rb_raise(rb_eRuntimeError, "Descriptor does not have assigned name.");
}
@@ -746,6 +1130,7 @@ VALUE build_class_from_descriptor(VALUE descriptor) {
rb_define_method(klass, "clone", Message_dup, 0);
rb_define_method(klass, "==", Message_eq, 1);
rb_define_method(klass, "eql?", Message_eq, 1);
+ rb_define_method(klass, "freeze", Message_freeze, 0);
rb_define_method(klass, "hash", Message_hash, 0);
rb_define_method(klass, "to_h", Message_to_h, 0);
rb_define_method(klass, "inspect", Message_inspect, 0);
@@ -768,12 +1153,12 @@ VALUE build_class_from_descriptor(VALUE descriptor) {
* This module method, provided on each generated enum module, looks up an enum
* value by number and returns its name as a Ruby symbol, or nil if not found.
*/
-VALUE enum_lookup(VALUE self, VALUE number) {
+static VALUE enum_lookup(VALUE self, VALUE number) {
int32_t num = NUM2INT(number);
VALUE desc = rb_ivar_get(self, descriptor_instancevar_interned);
- EnumDescriptor* enumdesc = ruby_to_EnumDescriptor(desc);
+ const upb_enumdef *e = EnumDescriptor_GetEnumDef(desc);
- const char* name = upb_enumdef_iton(enumdesc->enumdef, num);
+ const char* name = upb_enumdef_iton(e, num);
if (name == NULL) {
return Qnil;
} else {
@@ -788,13 +1173,13 @@ VALUE enum_lookup(VALUE self, VALUE number) {
* This module method, provided on each generated enum module, looks up an enum
* value by name (as a Ruby symbol) and returns its name, or nil if not found.
*/
-VALUE enum_resolve(VALUE self, VALUE sym) {
+static VALUE enum_resolve(VALUE self, VALUE sym) {
const char* name = rb_id2name(SYM2ID(sym));
VALUE desc = rb_ivar_get(self, descriptor_instancevar_interned);
- EnumDescriptor* enumdesc = ruby_to_EnumDescriptor(desc);
+ const upb_enumdef *e = EnumDescriptor_GetEnumDef(desc);
int32_t num = 0;
- bool found = upb_enumdef_ntoiz(enumdesc->enumdef, name, &num);
+ bool found = upb_enumdef_ntoiz(e, name, &num);
if (!found) {
return Qnil;
} else {
@@ -809,17 +1194,16 @@ VALUE enum_resolve(VALUE self, VALUE sym) {
* This module method, provided on each generated enum module, returns the
* EnumDescriptor corresponding to this enum type.
*/
-VALUE enum_descriptor(VALUE self) {
+static VALUE enum_descriptor(VALUE self) {
return rb_ivar_get(self, descriptor_instancevar_interned);
}
VALUE build_module_from_enumdesc(VALUE _enumdesc) {
- EnumDescriptor* enumdesc = ruby_to_EnumDescriptor(_enumdesc);
- VALUE mod = rb_define_module_id(
- rb_intern(upb_enumdef_fullname(enumdesc->enumdef)));
+ const upb_enumdef *e = EnumDescriptor_GetEnumDef(_enumdesc);
+ VALUE mod = rb_define_module_id(rb_intern(upb_enumdef_fullname(e)));
upb_enum_iter it;
- for (upb_enum_begin(&it, enumdesc->enumdef);
+ for (upb_enum_begin(&it, e);
!upb_enum_done(&it);
upb_enum_next(&it)) {
const char* name = upb_enum_iter_name(&it);
@@ -840,20 +1224,92 @@ VALUE build_module_from_enumdesc(VALUE _enumdesc) {
return mod;
}
-/*
- * call-seq:
- * Google::Protobuf.deep_copy(obj) => copy_of_obj
- *
- * Performs a deep copy of a RepeatedField instance, a Map instance, or a
- * message object, recursively copying its members.
- */
-VALUE Google_Protobuf_deep_copy(VALUE self, VALUE obj) {
- VALUE klass = CLASS_OF(obj);
- if (klass == cRepeatedField) {
- return RepeatedField_deep_copy(obj);
- } else if (klass == cMap) {
- return Map_deep_copy(obj);
- } else {
- return Message_deep_copy(obj);
+// Internal only; used by Google::Protobuf.deep_copy.
+upb_msg* Message_deep_copy(const upb_msg* msg, const upb_msgdef* m,
+ upb_arena *arena) {
+ // Serialize and parse.
+ upb_arena *tmp_arena = upb_arena_new();
+ const upb_msglayout *layout = upb_msgdef_layout(m);
+ size_t size;
+
+ char* data = upb_encode_ex(msg, layout, 0, tmp_arena, &size);
+ upb_msg* new_msg = upb_msg_new(m, arena);
+
+ if (!data || !upb_decode(data, size, new_msg, layout, arena)) {
+ upb_arena_free(tmp_arena);
+ rb_raise(cParseError, "Error occurred copying proto");
}
+
+ upb_arena_free(tmp_arena);
+ return new_msg;
+}
+
+const upb_msg* Message_GetUpbMessage(VALUE value, const upb_msgdef* m,
+ const char* name, upb_arena* arena) {
+ if (value == Qnil) return NULL;
+
+ VALUE klass = CLASS_OF(value);
+ VALUE desc_rb = rb_ivar_get(klass, descriptor_instancevar_interned);
+ const upb_msgdef* val_m =
+ desc_rb == Qnil ? NULL : Descriptor_GetMsgDef(desc_rb);
+
+ if (val_m != m) {
+ // Check for possible implicit conversions
+ // TODO: hash conversion?
+
+ switch (upb_msgdef_wellknowntype(m)) {
+ case UPB_WELLKNOWN_TIMESTAMP: {
+ // Time -> Google::Protobuf::Timestamp
+ upb_msg *msg = upb_msg_new(m, arena);
+ upb_msgval sec, nsec;
+ struct timespec time;
+ const upb_fielddef *sec_f = upb_msgdef_itof(m, 1);
+ const upb_fielddef *nsec_f = upb_msgdef_itof(m, 2);
+
+ if (!rb_obj_is_kind_of(value, rb_cTime)) goto badtype;
+
+ time = rb_time_timespec(value);
+ sec.int64_val = time.tv_sec;
+ nsec.int32_val = time.tv_nsec;
+ upb_msg_set(msg, sec_f, sec, arena);
+ upb_msg_set(msg, nsec_f, nsec, arena);
+ return msg;
+ }
+ case UPB_WELLKNOWN_DURATION: {
+ // Numeric -> Google::Protobuf::Duration
+ upb_msg *msg = upb_msg_new(m, arena);
+ upb_msgval sec, nsec;
+ const upb_fielddef *sec_f = upb_msgdef_itof(m, 1);
+ const upb_fielddef *nsec_f = upb_msgdef_itof(m, 2);
+
+ if (!rb_obj_is_kind_of(value, rb_cNumeric)) goto badtype;
+
+ sec.int64_val = NUM2LL(value);
+ nsec.int32_val = (NUM2DBL(value) - NUM2LL(value)) * 1000000000;
+ upb_msg_set(msg, sec_f, sec, arena);
+ upb_msg_set(msg, nsec_f, nsec, arena);
+ return msg;
+ }
+ default:
+ badtype:
+ rb_raise(cTypeError,
+ "Invalid type %s to assign to submessage field '%s'.",
+ rb_class2name(CLASS_OF(value)), name);
+ }
+
+ }
+
+ Message* self = ruby_to_Message(value);
+ upb_arena_fuse(arena, Arena_get(self->arena));
+
+ return self->msg;
+}
+
+void Message_register(VALUE protobuf) {
+ cParseError = rb_const_get(protobuf, rb_intern("ParseError"));
+
+ // Ruby-interned string: "descriptor". We use this identifier to store an
+ // instance variable on message classes we create in order to link them back
+ // to their descriptors.
+ descriptor_instancevar_interned = rb_intern("descriptor");
}
diff --git a/ruby/ext/google/protobuf_c/message.h b/ruby/ext/google/protobuf_c/message.h
new file mode 100644
index 0000000000..551f41f96d
--- /dev/null
+++ b/ruby/ext/google/protobuf_c/message.h
@@ -0,0 +1,98 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef RUBY_PROTOBUF_MESSAGE_H_
+#define RUBY_PROTOBUF_MESSAGE_H_
+
+#include
+
+#include "protobuf.h"
+#include "ruby-upb.h"
+
+// Gets the underlying upb_msg* and upb_msgdef for the given Ruby message
+// wrapper. Requires that |value| is indeed a message object.
+const upb_msg *Message_Get(VALUE value, const upb_msgdef **m);
+
+// Like Message_Get(), but checks that the object is not frozen and returns a
+// mutable pointer.
+upb_msg *Message_GetMutable(VALUE value, const upb_msgdef **m);
+
+// Returns the Arena object for this message.
+VALUE Message_GetArena(VALUE value);
+
+// Converts |value| into a upb_msg value of the expected upb_msgdef type,
+// raising an error if this is not possible. Used when assigning |value| to a
+// field of another message, which means the message must be of a particular
+// type.
+//
+// This will perform automatic conversions in some cases (for example, Time ->
+// Google::Protobuf::Timestamp). If any new message is created, it will be
+// created on |arena|, and any existing message will have its arena fused with
+// |arena|.
+const upb_msg* Message_GetUpbMessage(VALUE value, const upb_msgdef* m,
+ const char* name, upb_arena* arena);
+
+// Gets or constructs a Ruby wrapper object for the given message. The wrapper
+// object will reference |arena| and ensure that it outlives this object.
+VALUE Message_GetRubyWrapper(upb_msg* msg, const upb_msgdef* m, VALUE arena);
+
+// Implements #inspect for this message, printing the text to |b|.
+void Message_PrintMessage(StringBuilder* b, const upb_msg* msg,
+ const upb_msgdef* m);
+
+// Returns a hash value for the given message.
+uint64_t Message_Hash(const upb_msg *msg, const upb_msgdef *m, uint64_t seed);
+
+// Returns a deep copy of the given message.
+upb_msg* Message_deep_copy(const upb_msg* msg, const upb_msgdef* m,
+ upb_arena *arena);
+
+// Returns true if these two messages are equal.
+bool Message_Equal(const upb_msg *m1, const upb_msg *m2, const upb_msgdef *m);
+
+// Checks that this Ruby object is a message, and raises an exception if not.
+void Message_CheckClass(VALUE klass);
+
+// Returns a new Hash object containing the contents of this message.
+VALUE Scalar_CreateHash(upb_msgval val, TypeInfo type_info);
+
+// Creates a message class or enum module for this descriptor, respectively.
+VALUE build_class_from_descriptor(VALUE descriptor);
+VALUE build_module_from_enumdesc(VALUE _enumdesc);
+
+// Returns the Descriptor/EnumDescriptor for the given message class or enum
+// module, respectively. Returns nil if this is not a message class or enum
+// module.
+VALUE MessageOrEnum_GetDescriptor(VALUE klass);
+
+// Call at startup to register all types in this module.
+void Message_register(VALUE protobuf);
+
+#endif // RUBY_PROTOBUF_MESSAGE_H_
diff --git a/ruby/ext/google/protobuf_c/protobuf.c b/ruby/ext/google/protobuf_c/protobuf.c
index 60c1e2a281..737cd284b8 100644
--- a/ruby/ext/google/protobuf_c/protobuf.c
+++ b/ruby/ext/google/protobuf_c/protobuf.c
@@ -30,62 +30,342 @@
#include "protobuf.h"
+#include
+
+#include "defs.h"
+#include "map.h"
+#include "message.h"
+#include "repeated_field.h"
+
VALUE cError;
-VALUE cParseError;
VALUE cTypeError;
-VALUE c_only_cookie = Qnil;
-static VALUE cached_empty_string = Qnil;
-static VALUE cached_empty_bytes = Qnil;
+const upb_fielddef* map_field_key(const upb_fielddef* field) {
+ const upb_msgdef *entry = upb_fielddef_msgsubdef(field);
+ return upb_msgdef_itof(entry, 1);
+}
+
+const upb_fielddef* map_field_value(const upb_fielddef* field) {
+ const upb_msgdef *entry = upb_fielddef_msgsubdef(field);
+ return upb_msgdef_itof(entry, 2);
+}
-static VALUE create_frozen_string(const char* str, size_t size, bool binary) {
- VALUE str_rb = rb_str_new(str, size);
+// -----------------------------------------------------------------------------
+// StringBuilder, for inspect
+// -----------------------------------------------------------------------------
+
+struct StringBuilder {
+ size_t size;
+ size_t cap;
+ char *data;
+};
+
+typedef struct StringBuilder StringBuilder;
+
+static size_t StringBuilder_SizeOf(size_t cap) {
+ return sizeof(StringBuilder) + cap;
+}
+
+StringBuilder* StringBuilder_New() {
+ const size_t cap = 128;
+ StringBuilder* builder = malloc(sizeof(*builder));
+ builder->size = 0;
+ builder->cap = cap;
+ builder->data = malloc(builder->cap);
+ return builder;
+}
+
+void StringBuilder_Free(StringBuilder* b) {
+ free(b->data);
+ free(b);
+}
+
+void StringBuilder_Printf(StringBuilder* b, const char *fmt, ...) {
+ size_t have = b->cap - b->size;
+ size_t n;
+ va_list args;
+
+ va_start(args, fmt);
+ n = vsnprintf(&b->data[b->size], have, fmt, args);
+ va_end(args);
+
+ if (have <= n) {
+ while (have <= n) {
+ b->cap *= 2;
+ have = b->cap - b->size;
+ }
+ b->data = realloc(b->data, StringBuilder_SizeOf(b->cap));
+ va_start(args, fmt);
+ n = vsnprintf(&b->data[b->size], have, fmt, args);
+ va_end(args);
+ PBRUBY_ASSERT(n < have);
+ }
+
+ b->size += n;
+}
- rb_enc_associate(str_rb,
- binary ? kRubyString8bitEncoding : kRubyStringUtf8Encoding);
- rb_obj_freeze(str_rb);
- return str_rb;
+VALUE StringBuilder_ToRubyString(StringBuilder* b) {
+ VALUE ret = rb_str_new(b->data, b->size);
+ rb_enc_associate(ret, rb_utf8_encoding());
+ return ret;
}
-VALUE get_frozen_string(const char* str, size_t size, bool binary) {
- if (size == 0) {
- return binary ? cached_empty_bytes : cached_empty_string;
+static void StringBuilder_PrintEnum(StringBuilder* b, int32_t val,
+ const upb_enumdef* e) {
+ const char *name = upb_enumdef_iton(e, val);
+ if (name) {
+ StringBuilder_Printf(b, ":%s", name);
} else {
- // It is harder to memoize non-empty strings. The obvious approach would be
- // to use a Ruby hash keyed by string as memo table, but looking up in such a table
- // requires constructing a string (the very thing we're trying to avoid).
- //
- // Since few fields have defaults, we will just optimize the empty string
- // case for now.
- return create_frozen_string(str, size, binary);
+ StringBuilder_Printf(b, "%" PRId32, val);
+ }
+}
+
+void StringBuilder_PrintMsgval(StringBuilder* b, upb_msgval val,
+ TypeInfo info) {
+ switch (info.type) {
+ case UPB_TYPE_BOOL:
+ StringBuilder_Printf(b, "%s", val.bool_val ? "true" : "false");
+ break;
+ case UPB_TYPE_FLOAT: {
+ VALUE str = rb_inspect(DBL2NUM(val.float_val));
+ StringBuilder_Printf(b, "%s", RSTRING_PTR(str));
+ break;
+ }
+ case UPB_TYPE_DOUBLE: {
+ VALUE str = rb_inspect(DBL2NUM(val.double_val));
+ StringBuilder_Printf(b, "%s", RSTRING_PTR(str));
+ break;
+ }
+ case UPB_TYPE_INT32:
+ StringBuilder_Printf(b, "%" PRId32, val.int32_val);
+ break;
+ case UPB_TYPE_UINT32:
+ StringBuilder_Printf(b, "%" PRIu32, val.uint32_val);
+ break;
+ case UPB_TYPE_INT64:
+ StringBuilder_Printf(b, "%" PRId64, val.int64_val);
+ break;
+ case UPB_TYPE_UINT64:
+ StringBuilder_Printf(b, "%" PRIu64, val.uint64_val);
+ break;
+ case UPB_TYPE_STRING:
+ StringBuilder_Printf(b, "\"%.*s\"", (int)val.str_val.size, val.str_val.data);
+ break;
+ case UPB_TYPE_BYTES:
+ StringBuilder_Printf(b, "\"%.*s\"", (int)val.str_val.size, val.str_val.data);
+ break;
+ case UPB_TYPE_ENUM:
+ StringBuilder_PrintEnum(b, val.int32_val, info.def.enumdef);
+ break;
+ case UPB_TYPE_MESSAGE:
+ Message_PrintMessage(b, val.msg_val, info.def.msgdef);
+ break;
}
}
// -----------------------------------------------------------------------------
-// Utilities.
+// Arena
// -----------------------------------------------------------------------------
-// Raises a Ruby error if |status| is not OK, using its error message.
-void check_upb_status(const upb_status* status, const char* msg) {
- if (!upb_ok(status)) {
- rb_raise(rb_eRuntimeError, "%s: %s\n", msg, upb_status_errmsg(status));
- }
+void Arena_free(void* data) { upb_arena_free(data); }
+
+static VALUE cArena;
+
+const rb_data_type_t Arena_type = {
+ "Google::Protobuf::Internal::Arena",
+ { NULL, Arena_free, NULL },
+};
+
+static VALUE Arena_alloc(VALUE klass) {
+ upb_arena *arena = upb_arena_new();
+ return TypedData_Wrap_Struct(klass, &Arena_type, arena);
+}
+
+upb_arena *Arena_get(VALUE _arena) {
+ upb_arena *arena;
+ TypedData_Get_Struct(_arena, upb_arena, &Arena_type, arena);
+ return arena;
+}
+
+VALUE Arena_new() {
+ return Arena_alloc(cArena);
+}
+
+void Arena_register(VALUE module) {
+ VALUE internal = rb_define_module_under(module, "Internal");
+ VALUE klass = rb_define_class_under(internal, "Arena", rb_cObject);
+ rb_define_alloc_func(klass, Arena_alloc);
+ rb_gc_register_address(&cArena);
+ cArena = klass;
}
-// String encodings: we look these up once, at load time, and then cache them
-// here.
-rb_encoding* kRubyStringUtf8Encoding;
-rb_encoding* kRubyStringASCIIEncoding;
-rb_encoding* kRubyString8bitEncoding;
+// -----------------------------------------------------------------------------
+// Object Cache
+// -----------------------------------------------------------------------------
-// Ruby-interned string: "descriptor". We use this identifier to store an
-// instance variable on message classes we create in order to link them back to
-// their descriptors.
+// A pointer -> Ruby Object cache that keeps references to Ruby wrapper
+// objects. This allows us to look up any Ruby wrapper object by the address
+// of the object it is wrapping. That way we can avoid ever creating two
+// different wrapper objects for the same C object, which saves memory and
+// preserves object identity.
//
-// We intern this once at module load time then use the interned identifier at
-// runtime in order to avoid the cost of repeatedly interning in hot paths.
-const char* kDescriptorInstanceVar = "descriptor";
-ID descriptor_instancevar_interned;
+// We use Hash and/or WeakMap for the cache. WeakMap is faster overall
+// (probably due to removal being integrated with GC) but doesn't work for Ruby
+// <2.7 (see note below). We need Hash for Ruby <2.7 and for cases where we
+// need to GC-root the object (notably when the object has been frozen).
+
+#if RUBY_API_VERSION_CODE >= 20700
+#define USE_WEAK_MAP 1
+#else
+#define USE_WEAK_MAP 0
+#endif
+
+static VALUE ObjectCache_GetKey(const void* key) {
+ char buf[sizeof(key)];
+ memcpy(&buf, &key, sizeof(key));
+ intptr_t key_int = (intptr_t)key;
+ PBRUBY_ASSERT((key_int & 3) == 0);
+ return LL2NUM(key_int >> 2);
+}
+
+// Strong object cache, uses regular Hash and GC-roots objects.
+// - For Ruby <2.7, used for all objects.
+// - For Ruby >=2.7, used only for frozen objects, so we preserve the "frozen"
+// bit (since this information is not preserved at the upb level).
+
+VALUE strong_obj_cache = Qnil;
+
+static void StrongObjectCache_Init() {
+ rb_gc_register_address(&strong_obj_cache);
+ strong_obj_cache = rb_hash_new();
+}
+
+static void StrongObjectCache_Remove(void* key) {
+ VALUE key_rb = ObjectCache_GetKey(key);
+ PBRUBY_ASSERT(rb_hash_lookup(strong_obj_cache, key_rb) != Qnil);
+ rb_hash_delete(strong_obj_cache, key_rb);
+}
+
+static VALUE StrongObjectCache_Get(const void* key) {
+ VALUE key_rb = ObjectCache_GetKey(key);
+ return rb_hash_lookup(strong_obj_cache, key_rb);
+}
+
+static void StrongObjectCache_Add(const void* key, VALUE val,
+ upb_arena* arena) {
+ PBRUBY_ASSERT(StrongObjectCache_Get(key) == Qnil);
+ VALUE key_rb = ObjectCache_GetKey(key);
+ rb_hash_aset(strong_obj_cache, key_rb, val);
+ upb_arena_addcleanup(arena, (void*)key, StrongObjectCache_Remove);
+}
+
+// Weak object cache. This speeds up the test suite significantly, so we
+// presume it speeds up real code also. However we can only use it in Ruby
+// >=2.7 due to:
+// https://bugs.ruby-lang.org/issues/16035
+
+#if USE_WEAK_MAP
+
+VALUE weak_obj_cache = Qnil;
+
+static void WeakObjectCache_Init() {
+ rb_gc_register_address(&weak_obj_cache);
+ VALUE klass = rb_eval_string("ObjectSpace::WeakMap");
+ weak_obj_cache = rb_class_new_instance(0, NULL, klass);
+}
+
+static VALUE WeakObjectCache_Get(const void* key) {
+ VALUE key_rb = ObjectCache_GetKey(key);
+ VALUE ret = rb_funcall(weak_obj_cache, rb_intern("[]"), 1, key_rb);
+ return ret;
+}
+
+static void WeakObjectCache_Add(const void* key, VALUE val) {
+ PBRUBY_ASSERT(WeakObjectCache_Get(key) == Qnil);
+ VALUE key_rb = ObjectCache_GetKey(key);
+ rb_funcall(weak_obj_cache, rb_intern("[]="), 2, key_rb, val);
+ PBRUBY_ASSERT(WeakObjectCache_Get(key) == val);
+}
+
+#endif
+
+// Public ObjectCache API.
+
+static void ObjectCache_Init() {
+ StrongObjectCache_Init();
+#if USE_WEAK_MAP
+ WeakObjectCache_Init();
+#endif
+}
+
+void ObjectCache_Add(const void* key, VALUE val, upb_arena *arena) {
+#if USE_WEAK_MAP
+ (void)arena;
+ WeakObjectCache_Add(key, val);
+#else
+ StrongObjectCache_Add(key, val, arena);
+#endif
+}
+
+// Returns the cached object for this key, if any. Otherwise returns Qnil.
+VALUE ObjectCache_Get(const void* key) {
+#if USE_WEAK_MAP
+ return WeakObjectCache_Get(key);
+#else
+ return StrongObjectCache_Get(key);
+#endif
+}
+
+void ObjectCache_Pin(const void* key, VALUE val, upb_arena *arena) {
+#if USE_WEAK_MAP
+ PBRUBY_ASSERT(WeakObjectCache_Get(key) == val);
+ // This will GC-root the object, but we'll still use the weak map for
+ // actual lookup.
+ StrongObjectCache_Add(key, val, arena);
+#else
+ // Value is already pinned, nothing to do.
+#endif
+}
+
+/*
+ * call-seq:
+ * Google::Protobuf.discard_unknown(msg)
+ *
+ * Discard unknown fields in the given message object and recursively discard
+ * unknown fields in submessages.
+ */
+static VALUE Google_Protobuf_discard_unknown(VALUE self, VALUE msg_rb) {
+ const upb_msgdef *m;
+ upb_msg *msg = Message_GetMutable(msg_rb, &m);
+ if (!upb_msg_discardunknown(msg, m, 128)) {
+ rb_raise(rb_eRuntimeError, "Messages nested too deeply.");
+ }
+
+ return Qnil;
+}
+
+/*
+ * call-seq:
+ * Google::Protobuf.deep_copy(obj) => copy_of_obj
+ *
+ * Performs a deep copy of a RepeatedField instance, a Map instance, or a
+ * message object, recursively copying its members.
+ */
+VALUE Google_Protobuf_deep_copy(VALUE self, VALUE obj) {
+ VALUE klass = CLASS_OF(obj);
+ if (klass == cRepeatedField) {
+ return RepeatedField_deep_copy(obj);
+ } else if (klass == cMap) {
+ return Map_deep_copy(obj);
+ } else {
+ VALUE new_arena_rb = Arena_new();
+ upb_arena *new_arena = Arena_get(new_arena_rb);
+ const upb_msgdef *m;
+ const upb_msg *msg = Message_Get(obj, &m);
+ upb_msg* new_msg = Message_deep_copy(msg, m, new_arena);
+ return Message_GetRubyWrapper(new_msg, m, new_arena_rb);
+ }
+}
// -----------------------------------------------------------------------------
// Initialization/entry point.
@@ -93,44 +373,24 @@ ID descriptor_instancevar_interned;
// This must be named "Init_protobuf_c" because the Ruby module is named
// "protobuf_c" -- the VM looks for this symbol in our .so.
+__attribute__ ((visibility ("default")))
void Init_protobuf_c() {
+ ObjectCache_Init();
+
VALUE google = rb_define_module("Google");
VALUE protobuf = rb_define_module_under(google, "Protobuf");
- VALUE internal = rb_define_module_under(protobuf, "Internal");
-
- descriptor_instancevar_interned = rb_intern(kDescriptorInstanceVar);
- DescriptorPool_register(protobuf);
- Descriptor_register(protobuf);
- FileDescriptor_register(protobuf);
- FieldDescriptor_register(protobuf);
- OneofDescriptor_register(protobuf);
- EnumDescriptor_register(protobuf);
- MessageBuilderContext_register(internal);
- OneofBuilderContext_register(internal);
- EnumBuilderContext_register(internal);
- FileBuilderContext_register(internal);
- Builder_register(internal);
+
+ Arena_register(protobuf);
+ Defs_register(protobuf);
RepeatedField_register(protobuf);
Map_register(protobuf);
+ Message_register(protobuf);
cError = rb_const_get(protobuf, rb_intern("Error"));
- cParseError = rb_const_get(protobuf, rb_intern("ParseError"));
cTypeError = rb_const_get(protobuf, rb_intern("TypeError"));
rb_define_singleton_method(protobuf, "discard_unknown",
Google_Protobuf_discard_unknown, 1);
rb_define_singleton_method(protobuf, "deep_copy",
Google_Protobuf_deep_copy, 1);
-
- kRubyStringUtf8Encoding = rb_utf8_encoding();
- kRubyStringASCIIEncoding = rb_usascii_encoding();
- kRubyString8bitEncoding = rb_ascii8bit_encoding();
-
- rb_gc_register_address(&c_only_cookie);
- c_only_cookie = rb_class_new_instance(0, NULL, rb_cObject);
-
- rb_gc_register_address(&cached_empty_string);
- rb_gc_register_address(&cached_empty_bytes);
- cached_empty_string = create_frozen_string("", 0, false);
- cached_empty_bytes = create_frozen_string("", 0, true);
}
diff --git a/ruby/ext/google/protobuf_c/protobuf.h b/ruby/ext/google/protobuf_c/protobuf.h
index 0ec78fc4fb..90fb0a2093 100644
--- a/ruby/ext/google/protobuf_c/protobuf.h
+++ b/ruby/ext/google/protobuf_c/protobuf.h
@@ -35,631 +35,76 @@
#include
#include
-#include "upb.h"
-
-// Forward decls.
-struct DescriptorPool;
-struct Descriptor;
-struct FileDescriptor;
-struct FieldDescriptor;
-struct EnumDescriptor;
-struct MessageLayout;
-struct MessageField;
-struct MessageHeader;
-struct MessageBuilderContext;
-struct EnumBuilderContext;
-struct FileBuilderContext;
-struct Builder;
-
-typedef struct DescriptorPool DescriptorPool;
-typedef struct Descriptor Descriptor;
-typedef struct FileDescriptor FileDescriptor;
-typedef struct FieldDescriptor FieldDescriptor;
-typedef struct OneofDescriptor OneofDescriptor;
-typedef struct EnumDescriptor EnumDescriptor;
-typedef struct MessageLayout MessageLayout;
-typedef struct MessageField MessageField;
-typedef struct MessageOneof MessageOneof;
-typedef struct MessageHeader MessageHeader;
-typedef struct MessageBuilderContext MessageBuilderContext;
-typedef struct OneofBuilderContext OneofBuilderContext;
-typedef struct EnumBuilderContext EnumBuilderContext;
-typedef struct FileBuilderContext FileBuilderContext;
-typedef struct Builder Builder;
-
-/*
- It can be a bit confusing how the C structs defined below and the Ruby
- objects interact and hold references to each other. First, a few principles:
-
- - Ruby's "TypedData" abstraction lets a Ruby VALUE hold a pointer to a C
- struct (or arbitrary memory chunk), own it, and free it when collected.
- Thus, each struct below will have a corresponding Ruby object
- wrapping/owning it.
-
- - To get back from an underlying upb {msg,enum}def to the Ruby object, we
- keep a global hashmap, accessed by get_def_obj/add_def_obj below.
-
- The in-memory structure is then something like:
-
- Ruby | upb
- |
- DescriptorPool ------------|-----------> upb_symtab____________________
- | | (message types) \
- | v \
- Descriptor ---------------|-----------> upb_msgdef (enum types)|
- |--> msgclass | | ^ |
- | (dynamically built) | | | (submsg fields) |
- |--> MessageLayout | | | /
- |--------------------------|> decoder method| | /
- \--------------------------|> serialize | | /
- | handlers v | /
- FieldDescriptor -----------|-----------> upb_fielddef /
- | | /
- | v (enum fields) /
- EnumDescriptor ------------|-----------> upb_enumdef <----------'
- |
- |
- ^ | \___/
- `---------------|-----------------' (get_def_obj map)
- */
-
-// -----------------------------------------------------------------------------
-// Ruby class structure definitions.
-// -----------------------------------------------------------------------------
-
-struct DescriptorPool {
- VALUE def_to_descriptor; // Hash table of def* -> Ruby descriptor.
- upb_symtab* symtab;
- upb_handlercache* fill_handler_cache;
- upb_handlercache* pb_serialize_handler_cache;
- upb_handlercache* json_serialize_handler_cache;
- upb_handlercache* json_serialize_handler_preserve_cache;
- upb_pbcodecache* fill_method_cache;
- upb_json_codecache* json_fill_method_cache;
-};
-
-struct Descriptor {
- const upb_msgdef* msgdef;
- MessageLayout* layout;
- VALUE klass;
- VALUE descriptor_pool;
-};
-
-struct FileDescriptor {
- const upb_filedef* filedef;
- VALUE descriptor_pool; // Owns the upb_filedef.
-};
-
-struct FieldDescriptor {
- const upb_fielddef* fielddef;
- VALUE descriptor_pool; // Owns the upb_fielddef.
-};
-
-struct OneofDescriptor {
- const upb_oneofdef* oneofdef;
- VALUE descriptor_pool; // Owns the upb_oneofdef.
-};
-
-struct EnumDescriptor {
- const upb_enumdef* enumdef;
- VALUE module; // begins as nil
- VALUE descriptor_pool; // Owns the upb_enumdef.
-};
-
-struct MessageBuilderContext {
- google_protobuf_DescriptorProto* msg_proto;
- VALUE file_builder;
-};
-
-struct OneofBuilderContext {
- int oneof_index;
- VALUE message_builder;
-};
-
-struct EnumBuilderContext {
- google_protobuf_EnumDescriptorProto* enum_proto;
- VALUE file_builder;
-};
-
-struct FileBuilderContext {
- upb_arena *arena;
- google_protobuf_FileDescriptorProto* file_proto;
- VALUE descriptor_pool;
-};
-
-struct Builder {
- VALUE descriptor_pool;
- VALUE default_file_builder;
-};
-
-extern VALUE cDescriptorPool;
-extern VALUE cDescriptor;
-extern VALUE cFileDescriptor;
-extern VALUE cFieldDescriptor;
-extern VALUE cEnumDescriptor;
-extern VALUE cMessageBuilderContext;
-extern VALUE cOneofBuilderContext;
-extern VALUE cEnumBuilderContext;
-extern VALUE cFileBuilderContext;
-extern VALUE cBuilder;
-
-extern VALUE cError;
-extern VALUE cParseError;
-extern VALUE cTypeError;
-
-// We forward-declare all of the Ruby method implementations here because we
-// sometimes call the methods directly across .c files, rather than going
-// through Ruby's method dispatching (e.g. during message parse). It's cleaner
-// to keep the list of object methods together than to split them between
-// static-in-file definitions and header declarations.
-
-void DescriptorPool_mark(void* _self);
-void DescriptorPool_free(void* _self);
-VALUE DescriptorPool_alloc(VALUE klass);
-void DescriptorPool_register(VALUE module);
-DescriptorPool* ruby_to_DescriptorPool(VALUE value);
-VALUE DescriptorPool_build(int argc, VALUE* argv, VALUE _self);
-VALUE DescriptorPool_lookup(VALUE _self, VALUE name);
-VALUE DescriptorPool_generated_pool(VALUE _self);
-
-extern VALUE generated_pool;
-
-void Descriptor_mark(void* _self);
-void Descriptor_free(void* _self);
-VALUE Descriptor_alloc(VALUE klass);
-void Descriptor_register(VALUE module);
-Descriptor* ruby_to_Descriptor(VALUE value);
-VALUE Descriptor_initialize(VALUE _self, VALUE cookie, VALUE descriptor_pool,
- VALUE ptr);
-VALUE Descriptor_name(VALUE _self);
-VALUE Descriptor_each(VALUE _self);
-VALUE Descriptor_lookup(VALUE _self, VALUE name);
-VALUE Descriptor_each_oneof(VALUE _self);
-VALUE Descriptor_lookup_oneof(VALUE _self, VALUE name);
-VALUE Descriptor_msgclass(VALUE _self);
-VALUE Descriptor_file_descriptor(VALUE _self);
-extern const rb_data_type_t _Descriptor_type;
-
-void FileDescriptor_mark(void* _self);
-void FileDescriptor_free(void* _self);
-VALUE FileDescriptor_alloc(VALUE klass);
-void FileDescriptor_register(VALUE module);
-FileDescriptor* ruby_to_FileDescriptor(VALUE value);
-VALUE FileDescriptor_initialize(VALUE _self, VALUE cookie,
- VALUE descriptor_pool, VALUE ptr);
-VALUE FileDescriptor_name(VALUE _self);
-VALUE FileDescriptor_syntax(VALUE _self);
-
-void FieldDescriptor_mark(void* _self);
-void FieldDescriptor_free(void* _self);
-VALUE FieldDescriptor_alloc(VALUE klass);
-void FieldDescriptor_register(VALUE module);
-FieldDescriptor* ruby_to_FieldDescriptor(VALUE value);
-VALUE FieldDescriptor_initialize(VALUE _self, VALUE cookie,
- VALUE descriptor_pool, VALUE ptr);
-VALUE FieldDescriptor_name(VALUE _self);
-VALUE FieldDescriptor_type(VALUE _self);
-VALUE FieldDescriptor_default(VALUE _self);
-VALUE FieldDescriptor_label(VALUE _self);
-VALUE FieldDescriptor_number(VALUE _self);
-VALUE FieldDescriptor_submsg_name(VALUE _self);
-VALUE FieldDescriptor_subtype(VALUE _self);
-VALUE FieldDescriptor_has(VALUE _self, VALUE msg_rb);
-VALUE FieldDescriptor_clear(VALUE _self, VALUE msg_rb);
-VALUE FieldDescriptor_get(VALUE _self, VALUE msg_rb);
-VALUE FieldDescriptor_set(VALUE _self, VALUE msg_rb, VALUE value);
-upb_fieldtype_t ruby_to_fieldtype(VALUE type);
-VALUE fieldtype_to_ruby(upb_fieldtype_t type);
-
-void OneofDescriptor_mark(void* _self);
-void OneofDescriptor_free(void* _self);
-VALUE OneofDescriptor_alloc(VALUE klass);
-void OneofDescriptor_register(VALUE module);
-OneofDescriptor* ruby_to_OneofDescriptor(VALUE value);
-VALUE OneofDescriptor_initialize(VALUE _self, VALUE cookie,
- VALUE descriptor_pool, VALUE ptr);
-VALUE OneofDescriptor_name(VALUE _self);
-VALUE OneofDescriptor_each(VALUE _self);
-
-void EnumDescriptor_mark(void* _self);
-void EnumDescriptor_free(void* _self);
-VALUE EnumDescriptor_alloc(VALUE klass);
-VALUE EnumDescriptor_initialize(VALUE _self, VALUE cookie,
- VALUE descriptor_pool, VALUE ptr);
-void EnumDescriptor_register(VALUE module);
-EnumDescriptor* ruby_to_EnumDescriptor(VALUE value);
-VALUE EnumDescriptor_file_descriptor(VALUE _self);
-VALUE EnumDescriptor_name(VALUE _self);
-VALUE EnumDescriptor_lookup_name(VALUE _self, VALUE name);
-VALUE EnumDescriptor_lookup_value(VALUE _self, VALUE number);
-VALUE EnumDescriptor_each(VALUE _self);
-VALUE EnumDescriptor_enummodule(VALUE _self);
-extern const rb_data_type_t _EnumDescriptor_type;
-
-void MessageBuilderContext_mark(void* _self);
-void MessageBuilderContext_free(void* _self);
-VALUE MessageBuilderContext_alloc(VALUE klass);
-void MessageBuilderContext_register(VALUE module);
-MessageBuilderContext* ruby_to_MessageBuilderContext(VALUE value);
-VALUE MessageBuilderContext_initialize(VALUE _self,
- VALUE _file_builder,
- VALUE name);
-VALUE MessageBuilderContext_optional(int argc, VALUE* argv, VALUE _self);
-VALUE MessageBuilderContext_proto3_optional(int argc, VALUE* argv, VALUE _self);
-VALUE MessageBuilderContext_required(int argc, VALUE* argv, VALUE _self);
-VALUE MessageBuilderContext_repeated(int argc, VALUE* argv, VALUE _self);
-VALUE MessageBuilderContext_map(int argc, VALUE* argv, VALUE _self);
-VALUE MessageBuilderContext_oneof(VALUE _self, VALUE name);
-
-void OneofBuilderContext_mark(void* _self);
-void OneofBuilderContext_free(void* _self);
-VALUE OneofBuilderContext_alloc(VALUE klass);
-void OneofBuilderContext_register(VALUE module);
-OneofBuilderContext* ruby_to_OneofBuilderContext(VALUE value);
-VALUE OneofBuilderContext_initialize(VALUE _self,
- VALUE descriptor,
- VALUE builder);
-VALUE OneofBuilderContext_optional(int argc, VALUE* argv, VALUE _self);
-
-void EnumBuilderContext_mark(void* _self);
-void EnumBuilderContext_free(void* _self);
-VALUE EnumBuilderContext_alloc(VALUE klass);
-void EnumBuilderContext_register(VALUE module);
-EnumBuilderContext* ruby_to_EnumBuilderContext(VALUE value);
-VALUE EnumBuilderContext_initialize(VALUE _self, VALUE _file_builder,
- VALUE name);
-VALUE EnumBuilderContext_value(VALUE _self, VALUE name, VALUE number);
-
-void FileBuilderContext_mark(void* _self);
-void FileBuilderContext_free(void* _self);
-VALUE FileBuilderContext_alloc(VALUE klass);
-void FileBuilderContext_register(VALUE module);
-FileBuilderContext* ruby_to_FileBuilderContext(VALUE _self);
-upb_strview FileBuilderContext_strdup(VALUE _self, VALUE rb_str);
-upb_strview FileBuilderContext_strdup_name(VALUE _self, VALUE rb_str);
-upb_strview FileBuilderContext_strdup_sym(VALUE _self, VALUE rb_sym);
-VALUE FileBuilderContext_initialize(VALUE _self, VALUE descriptor_pool,
- VALUE name, VALUE options);
-VALUE FileBuilderContext_add_message(VALUE _self, VALUE name);
-VALUE FileBuilderContext_add_enum(VALUE _self, VALUE name);
-VALUE FileBuilderContext_pending_descriptors(VALUE _self);
-
-void Builder_mark(void* _self);
-void Builder_free(void* _self);
-VALUE Builder_alloc(VALUE klass);
-void Builder_register(VALUE module);
-Builder* ruby_to_Builder(VALUE value);
-VALUE Builder_build(VALUE _self);
-VALUE Builder_initialize(VALUE _self, VALUE descriptor_pool);
-VALUE Builder_add_file(int argc, VALUE *argv, VALUE _self);
-VALUE Builder_add_message(VALUE _self, VALUE name);
-VALUE Builder_add_enum(VALUE _self, VALUE name);
-VALUE Builder_finalize_to_pool(VALUE _self, VALUE pool_rb);
-
-// -----------------------------------------------------------------------------
-// Native slot storage abstraction.
-// -----------------------------------------------------------------------------
-
-#define NATIVE_SLOT_MAX_SIZE sizeof(uint64_t)
-
-size_t native_slot_size(upb_fieldtype_t type);
-void native_slot_set(const char* name,
- upb_fieldtype_t type,
- VALUE type_class,
- void* memory,
- VALUE value);
-// Atomically (with respect to Ruby VM calls) either update the value and set a
-// oneof case, or do neither. If |case_memory| is null, then no case value is
-// set.
-void native_slot_set_value_and_case(const char* name,
- upb_fieldtype_t type,
- VALUE type_class,
- void* memory,
- VALUE value,
- uint32_t* case_memory,
- uint32_t case_number);
-VALUE native_slot_get(upb_fieldtype_t type,
- VALUE type_class,
- const void* memory);
-void native_slot_init(upb_fieldtype_t type, void* memory);
-void native_slot_mark(upb_fieldtype_t type, void* memory);
-void native_slot_dup(upb_fieldtype_t type, void* to, void* from);
-void native_slot_deep_copy(upb_fieldtype_t type, VALUE type_class, void* to,
- void* from);
-bool native_slot_eq(upb_fieldtype_t type, VALUE type_class, void* mem1,
- void* mem2);
-
-VALUE native_slot_encode_and_freeze_string(upb_fieldtype_t type, VALUE value);
-void native_slot_check_int_range_precision(const char* name, upb_fieldtype_t type, VALUE value);
-uint32_t slot_read_oneof_case(MessageLayout* layout, const void* storage,
- const upb_oneofdef* oneof);
-bool is_value_field(const upb_fielddef* f);
-
-extern rb_encoding* kRubyStringUtf8Encoding;
-extern rb_encoding* kRubyStringASCIIEncoding;
-extern rb_encoding* kRubyString8bitEncoding;
-
-VALUE field_type_class(const MessageLayout* layout, const upb_fielddef* field);
-
-#define MAP_KEY_FIELD 1
-#define MAP_VALUE_FIELD 2
-
-// Oneof case slot value to indicate that no oneof case is set. The value `0` is
-// safe because field numbers are used as case identifiers, and no field can
-// have a number of 0.
-#define ONEOF_CASE_NONE 0
+#include "ruby-upb.h"
+#include "defs.h"
// These operate on a map field (i.e., a repeated field of submessages whose
// submessage type is a map-entry msgdef).
-bool is_map_field(const upb_fielddef* field);
const upb_fielddef* map_field_key(const upb_fielddef* field);
const upb_fielddef* map_field_value(const upb_fielddef* field);
-// These operate on a map-entry msgdef.
-const upb_fielddef* map_entry_key(const upb_msgdef* msgdef);
-const upb_fielddef* map_entry_value(const upb_msgdef* msgdef);
-
-// -----------------------------------------------------------------------------
-// Repeated field container type.
-// -----------------------------------------------------------------------------
-
-typedef struct {
- upb_fieldtype_t field_type;
- VALUE field_type_class;
- void* elements;
- int size;
- int capacity;
-} RepeatedField;
-
-void RepeatedField_mark(void* self);
-void RepeatedField_free(void* self);
-VALUE RepeatedField_alloc(VALUE klass);
-VALUE RepeatedField_init(int argc, VALUE* argv, VALUE self);
-void RepeatedField_register(VALUE module);
-
-extern const rb_data_type_t RepeatedField_type;
-extern VALUE cRepeatedField;
-
-RepeatedField* ruby_to_RepeatedField(VALUE value);
-
-VALUE RepeatedField_new_this_type(VALUE _self);
-VALUE RepeatedField_each(VALUE _self);
-VALUE RepeatedField_index(int argc, VALUE* argv, VALUE _self);
-void* RepeatedField_index_native(VALUE _self, int index);
-int RepeatedField_size(VALUE _self);
-VALUE RepeatedField_index_set(VALUE _self, VALUE _index, VALUE val);
-void RepeatedField_reserve(RepeatedField* self, int new_size);
-VALUE RepeatedField_push(VALUE _self, VALUE val);
-void RepeatedField_push_native(VALUE _self, void* data);
-VALUE RepeatedField_pop_one(VALUE _self);
-VALUE RepeatedField_insert(int argc, VALUE* argv, VALUE _self);
-VALUE RepeatedField_replace(VALUE _self, VALUE list);
-VALUE RepeatedField_clear(VALUE _self);
-VALUE RepeatedField_length(VALUE _self);
-VALUE RepeatedField_dup(VALUE _self);
-VALUE RepeatedField_deep_copy(VALUE _self);
-VALUE RepeatedField_to_ary(VALUE _self);
-VALUE RepeatedField_eq(VALUE _self, VALUE _other);
-VALUE RepeatedField_hash(VALUE _self);
-VALUE RepeatedField_inspect(VALUE _self);
-VALUE RepeatedField_plus(VALUE _self, VALUE list);
-
-// Defined in repeated_field.c; also used by Map.
-void validate_type_class(upb_fieldtype_t type, VALUE klass);
-
// -----------------------------------------------------------------------------
-// Map container type.
+// Arena
// -----------------------------------------------------------------------------
-typedef struct {
- upb_fieldtype_t key_type;
- upb_fieldtype_t value_type;
- VALUE value_type_class;
- VALUE parse_frame;
- upb_strtable table;
-} Map;
-
-void Map_mark(void* self);
-void Map_free(void* self);
-VALUE Map_alloc(VALUE klass);
-VALUE Map_init(int argc, VALUE* argv, VALUE self);
-void Map_register(VALUE module);
-VALUE Map_set_frame(VALUE self, VALUE val);
-
-extern const rb_data_type_t Map_type;
-extern VALUE cMap;
-
-Map* ruby_to_Map(VALUE value);
-
-VALUE Map_new_this_type(VALUE _self);
-VALUE Map_each(VALUE _self);
-VALUE Map_keys(VALUE _self);
-VALUE Map_values(VALUE _self);
-VALUE Map_index(VALUE _self, VALUE key);
-VALUE Map_index_set(VALUE _self, VALUE key, VALUE value);
-VALUE Map_has_key(VALUE _self, VALUE key);
-VALUE Map_delete(VALUE _self, VALUE key);
-VALUE Map_clear(VALUE _self);
-VALUE Map_length(VALUE _self);
-VALUE Map_dup(VALUE _self);
-VALUE Map_deep_copy(VALUE _self);
-VALUE Map_eq(VALUE _self, VALUE _other);
-VALUE Map_hash(VALUE _self);
-VALUE Map_to_h(VALUE _self);
-VALUE Map_inspect(VALUE _self);
-VALUE Map_merge(VALUE _self, VALUE hashmap);
-VALUE Map_merge_into_self(VALUE _self, VALUE hashmap);
+// A Ruby object that wraps an underlying upb_arena. Any objects that are
+// allocated from this arena should reference the Arena in rb_gc_mark(), to
+// ensure that the object's underlying memory outlives any Ruby object that can
+// reach it.
-typedef struct {
- Map* self;
- upb_strtable_iter it;
-} Map_iter;
-
-void Map_begin(VALUE _self, Map_iter* iter);
-void Map_next(Map_iter* iter);
-bool Map_done(Map_iter* iter);
-VALUE Map_iter_key(Map_iter* iter);
-VALUE Map_iter_value(Map_iter* iter);
+VALUE Arena_new();
+upb_arena *Arena_get(VALUE arena);
// -----------------------------------------------------------------------------
-// Message layout / storage.
+// ObjectCache
// -----------------------------------------------------------------------------
-#define MESSAGE_FIELD_NO_HASBIT ((uint32_t)-1)
-
-struct MessageField {
- uint32_t offset;
- uint32_t hasbit;
-};
-
-struct MessageOneof {
- uint32_t offset;
- uint32_t case_offset;
-};
-
-// MessageLayout is owned by the enclosing Descriptor, which must outlive us.
-struct MessageLayout {
- const Descriptor* desc;
- const upb_msgdef* msgdef;
- void* empty_template; // Can memcpy() onto a layout to clear it.
- MessageField* fields;
- MessageOneof* oneofs;
- uint32_t size;
- uint32_t value_offset;
- int value_count;
- int repeated_count;
- int map_count;
-};
-
-#define ONEOF_CASE_MASK 0x80000000
-
-void create_layout(Descriptor* desc);
-void free_layout(MessageLayout* layout);
-bool field_contains_hasbit(MessageLayout* layout,
- const upb_fielddef* field);
-VALUE layout_get_default(const upb_fielddef* field);
-VALUE layout_get(MessageLayout* layout,
- const void* storage,
- const upb_fielddef* field);
-void layout_set(MessageLayout* layout,
- void* storage,
- const upb_fielddef* field,
- VALUE val);
-VALUE layout_has(MessageLayout* layout,
- const void* storage,
- const upb_fielddef* field);
-void layout_clear(MessageLayout* layout,
- const void* storage,
- const upb_fielddef* field);
-void layout_init(MessageLayout* layout, void* storage);
-void layout_mark(MessageLayout* layout, void* storage);
-void layout_dup(MessageLayout* layout, void* to, void* from);
-void layout_deep_copy(MessageLayout* layout, void* to, void* from);
-VALUE layout_eq(MessageLayout* layout, void* msg1, void* msg2);
-VALUE layout_hash(MessageLayout* layout, void* storage);
-VALUE layout_inspect(MessageLayout* layout, void* storage);
-
-bool is_wrapper_type_field(const upb_fielddef* field);
-VALUE ruby_wrapper_type(VALUE type_class, VALUE value);
+// Global object cache from upb array/map/message/symtab to wrapper object.
+//
+// This is a conceptually "weak" cache, in that it does not prevent "val" from
+// being collected (though in Ruby <2.7 is it effectively strong, due to
+// implementation limitations).
+
+// Adds an entry to the cache. The "arena" parameter must give the arena that
+// "key" was allocated from. In Ruby <2.7.0, it will be used to remove the key
+// from the cache when the arena is destroyed.
+void ObjectCache_Add(const void* key, VALUE val, upb_arena *arena);
+
+// Returns the cached object for this key, if any. Otherwise returns Qnil.
+VALUE ObjectCache_Get(const void* key);
+
+// Pins the previously added object so it is GC-rooted. This turns the
+// reference to "val" from weak to strong. We use this to guarantee that the
+// "frozen" bit on the object will be remembered, even if the user drops their
+// reference to this precise object.
+//
+// The "arena" parameter must give the arena that "key" was allocated from.
+void ObjectCache_Pin(const void* key, VALUE val, upb_arena *arena);
// -----------------------------------------------------------------------------
-// Message class creation.
+// StringBuilder, for inspect
// -----------------------------------------------------------------------------
-// This should probably be factored into a common upb component.
-
-typedef struct {
- upb_byteshandler handler;
- upb_bytessink sink;
- char *ptr;
- size_t len, size;
-} stringsink;
-
-void stringsink_uninit(stringsink *sink);
-
-struct MessageHeader {
- Descriptor* descriptor; // kept alive by self.class.descriptor reference.
- stringsink* unknown_fields; // store unknown fields in decoding.
- // Data comes after this.
-};
-
-extern rb_data_type_t Message_type;
-
-VALUE build_class_from_descriptor(VALUE descriptor);
-void* Message_data(void* msg);
-void Message_mark(void* self);
-void Message_free(void* self);
-VALUE Message_alloc(VALUE klass);
-VALUE Message_method_missing(int argc, VALUE* argv, VALUE _self);
-VALUE Message_initialize(int argc, VALUE* argv, VALUE _self);
-VALUE Message_dup(VALUE _self);
-VALUE Message_deep_copy(VALUE _self);
-VALUE Message_eq(VALUE _self, VALUE _other);
-VALUE Message_hash(VALUE _self);
-VALUE Message_inspect(VALUE _self);
-VALUE Message_to_h(VALUE _self);
-VALUE Message_index(VALUE _self, VALUE field_name);
-VALUE Message_index_set(VALUE _self, VALUE field_name, VALUE value);
-VALUE Message_descriptor(VALUE klass);
-VALUE Message_decode(VALUE klass, VALUE data);
-VALUE Message_encode(VALUE klass, VALUE msg_rb);
-VALUE Message_decode_json(int argc, VALUE* argv, VALUE klass);
-VALUE Message_encode_json(int argc, VALUE* argv, VALUE klass);
-
-VALUE Google_Protobuf_discard_unknown(VALUE self, VALUE msg_rb);
-VALUE Google_Protobuf_deep_copy(VALUE self, VALUE obj);
-
-VALUE build_module_from_enumdesc(VALUE _enumdesc);
-VALUE enum_lookup(VALUE self, VALUE number);
-VALUE enum_resolve(VALUE self, VALUE sym);
-VALUE enum_descriptor(VALUE self);
+struct StringBuilder;
+typedef struct StringBuilder StringBuilder;
-const upb_pbdecodermethod *new_fillmsg_decodermethod(
- Descriptor* descriptor, const void *owner);
-void add_handlers_for_message(const void *closure, upb_handlers *h);
+StringBuilder* StringBuilder_New();
+void StringBuilder_Free(StringBuilder* b);
+void StringBuilder_Printf(StringBuilder* b, const char *fmt, ...);
+VALUE StringBuilder_ToRubyString(StringBuilder* b);
-// Maximum depth allowed during encoding, to avoid stack overflows due to
-// cycles.
-#define ENCODE_MAX_NESTING 63
-
-// -----------------------------------------------------------------------------
-// A cache of frozen string objects to use as field defaults.
-// -----------------------------------------------------------------------------
-VALUE get_frozen_string(const char* data, size_t size, bool binary);
-
-// -----------------------------------------------------------------------------
-// Global map from upb {msg,enum}defs to wrapper Descriptor/EnumDescriptor
-// instances.
-// -----------------------------------------------------------------------------
-VALUE get_msgdef_obj(VALUE descriptor_pool, const upb_msgdef* def);
-VALUE get_enumdef_obj(VALUE descriptor_pool, const upb_enumdef* def);
-VALUE get_fielddef_obj(VALUE descriptor_pool, const upb_fielddef* def);
-VALUE get_filedef_obj(VALUE descriptor_pool, const upb_filedef* def);
-VALUE get_oneofdef_obj(VALUE descriptor_pool, const upb_oneofdef* def);
+void StringBuilder_PrintMsgval(StringBuilder* b, upb_msgval val, TypeInfo info);
// -----------------------------------------------------------------------------
// Utilities.
// -----------------------------------------------------------------------------
-void check_upb_status(const upb_status* status, const char* msg);
-
-#define CHECK_UPB(code, msg) do { \
- upb_status status = UPB_STATUS_INIT; \
- code; \
- check_upb_status(&status, msg); \
-} while (0)
-
-extern ID descriptor_instancevar_interned;
-
-// A distinct object that is not accessible from Ruby. We use this as a
-// constructor argument to enforce that certain objects cannot be created from
-// Ruby.
-extern VALUE c_only_cookie;
+extern VALUE cTypeError;
#ifdef NDEBUG
-#define UPB_ASSERT(expr) do {} while (false && (expr))
+#define PBRUBY_ASSERT(expr) do {} while (false && (expr))
#else
-#define UPB_ASSERT(expr) assert(expr)
+#define PBRUBY_ASSERT(expr) assert(expr)
#endif
#define UPB_UNUSED(var) (void)var
diff --git a/ruby/ext/google/protobuf_c/repeated_field.c b/ruby/ext/google/protobuf_c/repeated_field.c
index e3afb282b8..65ca3c6647 100644
--- a/ruby/ext/google/protobuf_c/repeated_field.c
+++ b/ruby/ext/google/protobuf_c/repeated_field.c
@@ -28,49 +28,162 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#include "repeated_field.h"
+
+#include "convert.h"
+#include "defs.h"
+#include "message.h"
#include "protobuf.h"
+#include "third_party/wyhash/wyhash.h"
// -----------------------------------------------------------------------------
// Repeated field container type.
// -----------------------------------------------------------------------------
+typedef struct {
+ const upb_array *array; // Can get as mutable when non-frozen.
+ TypeInfo type_info;
+ VALUE type_class; // To GC-root the msgdef/enumdef in type_info.
+ VALUE arena; // To GC-root the upb_array.
+} RepeatedField;
+
+VALUE cRepeatedField;
+
+static void RepeatedField_mark(void* _self) {
+ RepeatedField* self = (RepeatedField*)_self;
+ rb_gc_mark(self->type_class);
+ rb_gc_mark(self->arena);
+}
+
const rb_data_type_t RepeatedField_type = {
"Google::Protobuf::RepeatedField",
- { RepeatedField_mark, RepeatedField_free, NULL },
+ { RepeatedField_mark, RUBY_DEFAULT_FREE, NULL },
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY,
};
-VALUE cRepeatedField;
-
-RepeatedField* ruby_to_RepeatedField(VALUE _self) {
+static RepeatedField* ruby_to_RepeatedField(VALUE _self) {
RepeatedField* self;
TypedData_Get_Struct(_self, RepeatedField, &RepeatedField_type, self);
return self;
}
-void* RepeatedField_memoryat(RepeatedField* self, int index, int element_size) {
- return ((uint8_t *)self->elements) + index * element_size;
+static upb_array *RepeatedField_GetMutable(VALUE _self) {
+ rb_check_frozen(_self);
+ return (upb_array*)ruby_to_RepeatedField(_self)->array;
+}
+
+VALUE RepeatedField_alloc(VALUE klass) {
+ RepeatedField* self = ALLOC(RepeatedField);
+ self->arena = Qnil;
+ self->type_class = Qnil;
+ self->array = NULL;
+ return TypedData_Wrap_Struct(klass, &RepeatedField_type, self);
+}
+
+VALUE RepeatedField_GetRubyWrapper(upb_array* array, TypeInfo type_info,
+ VALUE arena) {
+ PBRUBY_ASSERT(array);
+ VALUE val = ObjectCache_Get(array);
+
+ if (val == Qnil) {
+ val = RepeatedField_alloc(cRepeatedField);
+ RepeatedField* self;
+ ObjectCache_Add(array, val, Arena_get(arena));
+ TypedData_Get_Struct(val, RepeatedField, &RepeatedField_type, self);
+ self->array = array;
+ self->arena = arena;
+ self->type_info = type_info;
+ if (self->type_info.type == UPB_TYPE_MESSAGE) {
+ self->type_class = Descriptor_DefToClass(type_info.def.msgdef);
+ }
+ }
+
+ PBRUBY_ASSERT(ruby_to_RepeatedField(val)->type_info.type == type_info.type);
+ PBRUBY_ASSERT(ruby_to_RepeatedField(val)->type_info.def.msgdef ==
+ type_info.def.msgdef);
+ return val;
+}
+
+static VALUE RepeatedField_new_this_type(RepeatedField* from) {
+ VALUE arena_rb = Arena_new();
+ upb_array *array = upb_array_new(Arena_get(arena_rb), from->type_info.type);
+ VALUE ret = RepeatedField_GetRubyWrapper(array, from->type_info, arena_rb);
+ PBRUBY_ASSERT(ruby_to_RepeatedField(ret)->type_class == from->type_class);
+ return ret;
+}
+
+void RepeatedField_Inspect(StringBuilder* b, const upb_array* array,
+ TypeInfo info) {
+ bool first = true;
+ StringBuilder_Printf(b, "[");
+ size_t n = array ? upb_array_size(array) : 0;
+ for (size_t i = 0; i < n; i++) {
+ if (first) {
+ first = false;
+ } else {
+ StringBuilder_Printf(b, ", ");
+ }
+ StringBuilder_PrintMsgval(b, upb_array_get(array, i), info);
+ }
+ StringBuilder_Printf(b, "]");
+}
+
+VALUE RepeatedField_deep_copy(VALUE _self) {
+ RepeatedField* self = ruby_to_RepeatedField(_self);
+ VALUE new_rptfield = RepeatedField_new_this_type(self);
+ RepeatedField* new_self = ruby_to_RepeatedField(new_rptfield);
+ VALUE arena_rb = new_self->arena;
+ upb_array *new_array = RepeatedField_GetMutable(new_rptfield);
+ upb_arena *arena = Arena_get(arena_rb);
+ size_t elements = upb_array_size(self->array);
+
+ upb_array_resize(new_array, elements, arena);
+
+ size_t size = upb_array_size(self->array);
+ for (size_t i = 0; i < size; i++) {
+ upb_msgval msgval = upb_array_get(self->array, i);
+ upb_msgval copy = Msgval_DeepCopy(msgval, self->type_info, arena);
+ upb_array_set(new_array, i, copy);
+ }
+
+ return new_rptfield;
+}
+
+const upb_array* RepeatedField_GetUpbArray(VALUE val, const upb_fielddef *field) {
+ RepeatedField* self;
+ TypeInfo type_info = TypeInfo_get(field);
+
+ if (!RB_TYPE_P(val, T_DATA) || !RTYPEDDATA_P(val) ||
+ RTYPEDDATA_TYPE(val) != &RepeatedField_type) {
+ rb_raise(cTypeError, "Expected repeated field array");
+ }
+
+ self = ruby_to_RepeatedField(val);
+ if (self->type_info.type != type_info.type) {
+ rb_raise(cTypeError, "Repeated field array has wrong element type");
+ }
+
+ if (self->type_info.def.msgdef != type_info.def.msgdef) {
+ rb_raise(cTypeError, "Repeated field array has wrong message/enum class");
+ }
+
+ return self->array;
}
static int index_position(VALUE _index, RepeatedField* repeated_field) {
int index = NUM2INT(_index);
- if (index < 0 && repeated_field->size > 0) {
- index = repeated_field->size + index;
- }
+ if (index < 0) index += upb_array_size(repeated_field->array);
return index;
}
-VALUE RepeatedField_subarray(VALUE _self, long beg, long len) {
- RepeatedField* self = ruby_to_RepeatedField(_self);
- int element_size = native_slot_size(self->field_type);
- upb_fieldtype_t field_type = self->field_type;
- VALUE field_type_class = self->field_type_class;
- size_t off = beg * element_size;
- VALUE ary = rb_ary_new2(len);
- int i;
+static VALUE RepeatedField_subarray(RepeatedField* self, long beg, long len) {
+ size_t size = upb_array_size(self->array);
+ VALUE ary = rb_ary_new2(size);
+ long i;
- for (i = beg; i < beg + len; i++, off += element_size) {
- void* mem = ((uint8_t *)self->elements) + off;
- VALUE elem = native_slot_get(field_type, field_type_class, mem);
+ for (i = beg; i < beg + len; i++) {
+ upb_msgval msgval = upb_array_get(self->array, i);
+ VALUE elem = Convert_UpbToRuby(msgval, self->type_info, self->arena);
rb_ary_push(ary, elem);
}
return ary;
@@ -84,17 +197,14 @@ VALUE RepeatedField_subarray(VALUE _self, long beg, long len) {
* also includes Enumerable; combined with this method, the repeated field thus
* acts like an ordinary Ruby sequence.
*/
-VALUE RepeatedField_each(VALUE _self) {
+static VALUE RepeatedField_each(VALUE _self) {
RepeatedField* self = ruby_to_RepeatedField(_self);
- upb_fieldtype_t field_type = self->field_type;
- VALUE field_type_class = self->field_type_class;
- int element_size = native_slot_size(field_type);
- size_t off = 0;
+ int size = upb_array_size(self->array);
int i;
- for (i = 0; i < self->size; i++, off += element_size) {
- void* memory = (void *) (((uint8_t *)self->elements) + off);
- VALUE val = native_slot_get(field_type, field_type_class, memory);
+ for (i = 0; i < size; i++) {
+ upb_msgval msgval = upb_array_get(self->array, i);
+ VALUE val = Convert_UpbToRuby(msgval, self->type_info, self->arena);
rb_yield(val);
}
return _self;
@@ -107,11 +217,9 @@ VALUE RepeatedField_each(VALUE _self) {
*
* Accesses the element at the given index. Returns nil on out-of-bounds
*/
-VALUE RepeatedField_index(int argc, VALUE* argv, VALUE _self) {
+static VALUE RepeatedField_index(int argc, VALUE* argv, VALUE _self) {
RepeatedField* self = ruby_to_RepeatedField(_self);
- int element_size = native_slot_size(self->field_type);
- upb_fieldtype_t field_type = self->field_type;
- VALUE field_type_class = self->field_type_class;
+ long size = upb_array_size(self->array);
VALUE arg = argv[0];
long beg, len;
@@ -119,35 +227,36 @@ VALUE RepeatedField_index(int argc, VALUE* argv, VALUE _self) {
if (argc == 1){
if (FIXNUM_P(arg)) {
/* standard case */
- void* memory;
+ upb_msgval msgval;
int index = index_position(argv[0], self);
- if (index < 0 || index >= self->size) {
+ if (index < 0 || (size_t)index >= upb_array_size(self->array)) {
return Qnil;
}
- memory = RepeatedField_memoryat(self, index, element_size);
- return native_slot_get(field_type, field_type_class, memory);
- }else{
+ msgval = upb_array_get(self->array, index);
+ return Convert_UpbToRuby(msgval, self->type_info, self->arena);
+ } else {
/* check if idx is Range */
- switch (rb_range_beg_len(arg, &beg, &len, self->size, 0)) {
+ switch (rb_range_beg_len(arg, &beg, &len, size, 0)) {
case Qfalse:
break;
case Qnil:
return Qnil;
default:
- return RepeatedField_subarray(_self, beg, len);
+ return RepeatedField_subarray(self, beg, len);
}
}
}
+
/* assume 2 arguments */
beg = NUM2LONG(argv[0]);
len = NUM2LONG(argv[1]);
if (beg < 0) {
- beg += self->size;
+ beg += size;
}
- if (beg >= self->size) {
+ if (beg >= size) {
return Qnil;
}
- return RepeatedField_subarray(_self, beg, len);
+ return RepeatedField_subarray(self, beg, len);
}
/*
@@ -157,128 +266,88 @@ VALUE RepeatedField_index(int argc, VALUE* argv, VALUE _self) {
* Sets the element at the given index. On out-of-bounds assignments, extends
* the array and fills the hole (if any) with default values.
*/
-VALUE RepeatedField_index_set(VALUE _self, VALUE _index, VALUE val) {
+static VALUE RepeatedField_index_set(VALUE _self, VALUE _index, VALUE val) {
RepeatedField* self = ruby_to_RepeatedField(_self);
- upb_fieldtype_t field_type = self->field_type;
- VALUE field_type_class = self->field_type_class;
- int element_size = native_slot_size(field_type);
- void* memory;
+ int size = upb_array_size(self->array);
+ upb_array *array = RepeatedField_GetMutable(_self);
+ upb_arena *arena = Arena_get(self->arena);
+ upb_msgval msgval = Convert_RubyToUpb(val, "", self->type_info, arena);
int index = index_position(_index, self);
if (index < 0 || index >= (INT_MAX - 1)) {
return Qnil;
}
- if (index >= self->size) {
- upb_fieldtype_t field_type = self->field_type;
- int element_size = native_slot_size(field_type);
- int i;
- RepeatedField_reserve(self, index + 1);
- for (i = self->size; i <= index; i++) {
- void* elem = RepeatedField_memoryat(self, i, element_size);
- native_slot_init(field_type, elem);
+ if (index >= size) {
+ upb_array_resize(array, index + 1, arena);
+ upb_msgval fill;
+ memset(&fill, 0, sizeof(fill));
+ for (int i = size; i < index; i++) {
+ // Fill default values.
+ // TODO(haberman): should this happen at the upb level?
+ upb_array_set(array, i, fill);
}
- self->size = index + 1;
}
- memory = RepeatedField_memoryat(self, index, element_size);
- native_slot_set("", field_type, field_type_class, memory, val);
+ upb_array_set(array, index, msgval);
return Qnil;
}
-static int kInitialSize = 8;
-
-void RepeatedField_reserve(RepeatedField* self, int new_size) {
- void* old_elems = self->elements;
- int elem_size = native_slot_size(self->field_type);
- if (new_size <= self->capacity) {
- return;
- }
- if (self->capacity == 0) {
- self->capacity = kInitialSize;
- }
- while (self->capacity < new_size) {
- self->capacity *= 2;
- }
- self->elements = ALLOC_N(uint8_t, elem_size * self->capacity);
- if (old_elems != NULL) {
- memcpy(self->elements, old_elems, self->size * elem_size);
- xfree(old_elems);
- }
-}
-
/*
* call-seq:
- * RepeatedField.push(value)
+ * RepeatedField.push(value, ...)
*
* Adds a new element to the repeated field.
*/
-VALUE RepeatedField_push(VALUE _self, VALUE val) {
+static VALUE RepeatedField_push_vararg(int argc, VALUE* argv, VALUE _self) {
RepeatedField* self = ruby_to_RepeatedField(_self);
- upb_fieldtype_t field_type = self->field_type;
- int element_size = native_slot_size(field_type);
- void* memory;
-
- RepeatedField_reserve(self, self->size + 1);
- memory = (void *) (((uint8_t *)self->elements) + self->size * element_size);
- native_slot_set("", field_type, self->field_type_class, memory, val);
- // native_slot_set may raise an error; bump size only after set.
- self->size++;
- return _self;
-}
-
-VALUE RepeatedField_push_vararg(VALUE _self, VALUE args) {
+ upb_arena *arena = Arena_get(self->arena);
+ upb_array *array = RepeatedField_GetMutable(_self);
int i;
- for (i = 0; i < RARRAY_LEN(args); i++) {
- RepeatedField_push(_self, rb_ary_entry(args, i));
+
+ for (i = 0; i < argc; i++) {
+ upb_msgval msgval = Convert_RubyToUpb(argv[i], "", self->type_info, arena);
+ upb_array_append(array, msgval, arena);
}
+
return _self;
}
-// Used by parsing handlers.
-void RepeatedField_push_native(VALUE _self, void* data) {
+/*
+ * call-seq:
+ * RepeatedField.<<(value)
+ *
+ * Adds a new element to the repeated field.
+ */
+static VALUE RepeatedField_push(VALUE _self, VALUE val) {
RepeatedField* self = ruby_to_RepeatedField(_self);
- upb_fieldtype_t field_type = self->field_type;
- int element_size = native_slot_size(field_type);
- void* memory;
-
- RepeatedField_reserve(self, self->size + 1);
- memory = (void *) (((uint8_t *)self->elements) + self->size * element_size);
- memcpy(memory, data, element_size);
- self->size++;
-}
+ upb_arena *arena = Arena_get(self->arena);
+ upb_array *array = RepeatedField_GetMutable(_self);
-void* RepeatedField_index_native(VALUE _self, int index) {
- RepeatedField* self = ruby_to_RepeatedField(_self);
- upb_fieldtype_t field_type = self->field_type;
- int element_size = native_slot_size(field_type);
- return RepeatedField_memoryat(self, index, element_size);
-}
+ upb_msgval msgval = Convert_RubyToUpb(val, "", self->type_info, arena);
+ upb_array_append(array, msgval, arena);
-int RepeatedField_size(VALUE _self) {
- RepeatedField* self = ruby_to_RepeatedField(_self);
- return self->size;
+ return _self;
}
/*
* Private ruby method, used by RepeatedField.pop
*/
-VALUE RepeatedField_pop_one(VALUE _self) {
+static VALUE RepeatedField_pop_one(VALUE _self) {
RepeatedField* self = ruby_to_RepeatedField(_self);
- upb_fieldtype_t field_type = self->field_type;
- VALUE field_type_class = self->field_type_class;
- int element_size = native_slot_size(field_type);
- int index;
- void* memory;
+ size_t size = upb_array_size(self->array);
+ upb_array *array = RepeatedField_GetMutable(_self);
+ upb_msgval last;
VALUE ret;
- if (self->size == 0) {
+ if (size == 0) {
return Qnil;
}
- index = self->size - 1;
- memory = RepeatedField_memoryat(self, index, element_size);
- ret = native_slot_get(field_type, field_type_class, memory);
- self->size--;
+
+ last = upb_array_get(self->array, size - 1);
+ ret = Convert_UpbToRuby(last, self->type_info, self->arena);
+
+ upb_array_resize(array, size - 1, Arena_get(self->arena));
return ret;
}
@@ -288,15 +357,18 @@ VALUE RepeatedField_pop_one(VALUE _self) {
*
* Replaces the contents of the repeated field with the given list of elements.
*/
-VALUE RepeatedField_replace(VALUE _self, VALUE list) {
+static VALUE RepeatedField_replace(VALUE _self, VALUE list) {
RepeatedField* self = ruby_to_RepeatedField(_self);
+ upb_array *array = RepeatedField_GetMutable(_self);
int i;
Check_Type(list, T_ARRAY);
- self->size = 0;
+ upb_array_resize(array, 0, Arena_get(self->arena));
+
for (i = 0; i < RARRAY_LEN(list); i++) {
RepeatedField_push(_self, rb_ary_entry(list, i));
}
+
return list;
}
@@ -306,9 +378,10 @@ VALUE RepeatedField_replace(VALUE _self, VALUE list) {
*
* Clears (removes all elements from) this repeated field.
*/
-VALUE RepeatedField_clear(VALUE _self) {
+static VALUE RepeatedField_clear(VALUE _self) {
RepeatedField* self = ruby_to_RepeatedField(_self);
- self->size = 0;
+ upb_array *array = RepeatedField_GetMutable(_self);
+ upb_array_resize(array, 0, Arena_get(self->arena));
return _self;
}
@@ -318,23 +391,9 @@ VALUE RepeatedField_clear(VALUE _self) {
*
* Returns the length of this repeated field.
*/
-VALUE RepeatedField_length(VALUE _self) {
- RepeatedField* self = ruby_to_RepeatedField(_self);
- return INT2NUM(self->size);
-}
-
-VALUE RepeatedField_new_this_type(VALUE _self) {
+static VALUE RepeatedField_length(VALUE _self) {
RepeatedField* self = ruby_to_RepeatedField(_self);
- VALUE new_rptfield = Qnil;
- VALUE element_type = fieldtype_to_ruby(self->field_type);
- if (self->field_type_class != Qnil) {
- new_rptfield = rb_funcall(CLASS_OF(_self), rb_intern("new"), 2,
- element_type, self->field_type_class);
- } else {
- new_rptfield = rb_funcall(CLASS_OF(_self), rb_intern("new"), 1,
- element_type);
- }
- return new_rptfield;
+ return INT2NUM(upb_array_size(self->array));
}
/*
@@ -344,42 +403,20 @@ VALUE RepeatedField_new_this_type(VALUE _self) {
* Duplicates this repeated field with a shallow copy. References to all
* non-primitive element objects (e.g., submessages) are shared.
*/
-VALUE RepeatedField_dup(VALUE _self) {
+static VALUE RepeatedField_dup(VALUE _self) {
RepeatedField* self = ruby_to_RepeatedField(_self);
- VALUE new_rptfield = RepeatedField_new_this_type(_self);
+ VALUE new_rptfield = RepeatedField_new_this_type(self);
RepeatedField* new_rptfield_self = ruby_to_RepeatedField(new_rptfield);
- upb_fieldtype_t field_type = self->field_type;
- size_t elem_size = native_slot_size(field_type);
- size_t off = 0;
+ upb_array *new_array = RepeatedField_GetMutable(new_rptfield);
+ upb_arena* arena = Arena_get(new_rptfield_self->arena);
+ int size = upb_array_size(self->array);
int i;
- RepeatedField_reserve(new_rptfield_self, self->size);
- for (i = 0; i < self->size; i++, off += elem_size) {
- void* to_mem = (uint8_t *)new_rptfield_self->elements + off;
- void* from_mem = (uint8_t *)self->elements + off;
- native_slot_dup(field_type, to_mem, from_mem);
- new_rptfield_self->size++;
- }
-
- return new_rptfield;
-}
+ upb_arena_fuse(arena, Arena_get(self->arena));
-// Internal only: used by Google::Protobuf.deep_copy.
-VALUE RepeatedField_deep_copy(VALUE _self) {
- RepeatedField* self = ruby_to_RepeatedField(_self);
- VALUE new_rptfield = RepeatedField_new_this_type(_self);
- RepeatedField* new_rptfield_self = ruby_to_RepeatedField(new_rptfield);
- upb_fieldtype_t field_type = self->field_type;
- size_t elem_size = native_slot_size(field_type);
- size_t off = 0;
- int i;
-
- RepeatedField_reserve(new_rptfield_self, self->size);
- for (i = 0; i < self->size; i++, off += elem_size) {
- void* to_mem = (uint8_t *)new_rptfield_self->elements + off;
- void* from_mem = (uint8_t *)self->elements + off;
- native_slot_deep_copy(field_type, self->field_type_class, to_mem, from_mem);
- new_rptfield_self->size++;
+ for (i = 0; i < size; i++) {
+ upb_msgval msgval = upb_array_get(self->array, i);
+ upb_array_append(new_array, msgval, arena);
}
return new_rptfield;
@@ -394,17 +431,16 @@ VALUE RepeatedField_deep_copy(VALUE _self) {
*/
VALUE RepeatedField_to_ary(VALUE _self) {
RepeatedField* self = ruby_to_RepeatedField(_self);
- upb_fieldtype_t field_type = self->field_type;
- size_t elem_size = native_slot_size(field_type);
- size_t off = 0;
- VALUE ary = rb_ary_new2(self->size);
+ int size = upb_array_size(self->array);
+ VALUE ary = rb_ary_new2(size);
int i;
- for (i = 0; i < self->size; i++, off += elem_size) {
- void* mem = ((uint8_t *)self->elements) + off;
- VALUE elem = native_slot_get(field_type, self->field_type_class, mem);
- rb_ary_push(ary, elem);
+ for (i = 0; i < size; i++) {
+ upb_msgval msgval = upb_array_get(self->array, i);
+ VALUE val = Convert_UpbToRuby(msgval, self->type_info, self->arena);
+ rb_ary_push(ary, val);
}
+
return ary;
}
@@ -436,28 +472,38 @@ VALUE RepeatedField_eq(VALUE _self, VALUE _other) {
self = ruby_to_RepeatedField(_self);
other = ruby_to_RepeatedField(_other);
- if (self->field_type != other->field_type ||
- self->field_type_class != other->field_type_class ||
- self->size != other->size) {
+ size_t n = upb_array_size(self->array);
+
+ if (self->type_info.type != other->type_info.type ||
+ self->type_class != other->type_class ||
+ upb_array_size(other->array) != n) {
return Qfalse;
}
- {
- upb_fieldtype_t field_type = self->field_type;
- size_t elem_size = native_slot_size(field_type);
- size_t off = 0;
- int i;
-
- for (i = 0; i < self->size; i++, off += elem_size) {
- void* self_mem = ((uint8_t *)self->elements) + off;
- void* other_mem = ((uint8_t *)other->elements) + off;
- if (!native_slot_eq(field_type, self->field_type_class, self_mem,
- other_mem)) {
- return Qfalse;
- }
+ for (size_t i = 0; i < n; i++) {
+ upb_msgval val1 = upb_array_get(self->array, i);
+ upb_msgval val2 = upb_array_get(other->array, i);
+ if (!Msgval_IsEqual(val1, val2, self->type_info)) {
+ return Qfalse;
}
- return Qtrue;
}
+
+ return Qtrue;
+}
+
+/*
+ * call-seq:
+ * RepeatedField.freeze => self
+ *
+ * Freezes the repeated field. We have to intercept this so we can pin the Ruby
+ * object into memory so we don't forget it's frozen.
+ */
+static VALUE RepeatedField_freeze(VALUE _self) {
+ RepeatedField* self = ruby_to_RepeatedField(_self);
+
+ ObjectCache_Pin(self->array, _self, Arena_get(self->arena));
+ RB_OBJ_FREEZE(_self);
+ return _self;
}
/*
@@ -468,22 +514,15 @@ VALUE RepeatedField_eq(VALUE _self, VALUE _other) {
*/
VALUE RepeatedField_hash(VALUE _self) {
RepeatedField* self = ruby_to_RepeatedField(_self);
- st_index_t h = rb_hash_start(0);
- VALUE hash_sym = rb_intern("hash");
- upb_fieldtype_t field_type = self->field_type;
- VALUE field_type_class = self->field_type_class;
- size_t elem_size = native_slot_size(field_type);
- size_t off = 0;
- int i;
+ uint64_t hash = 0;
+ size_t n = upb_array_size(self->array);
- for (i = 0; i < self->size; i++, off += elem_size) {
- void* mem = ((uint8_t *)self->elements) + off;
- VALUE elem = native_slot_get(field_type, field_type_class, mem);
- h = rb_hash_uint(h, NUM2LONG(rb_funcall(elem, hash_sym, 0)));
+ for (size_t i = 0; i < n; i++) {
+ upb_msgval val = upb_array_get(self->array, i);
+ hash = Msgval_GetHash(val, self->type_info, hash);
}
- h = rb_hash_end(h);
- return INT2FIX(h);
+ return LL2NUM(hash);
}
/*
@@ -495,34 +534,39 @@ VALUE RepeatedField_hash(VALUE _self) {
* be either another repeated field or a Ruby array.
*/
VALUE RepeatedField_plus(VALUE _self, VALUE list) {
- VALUE dupped = RepeatedField_dup(_self);
+ VALUE dupped_ = RepeatedField_dup(_self);
if (TYPE(list) == T_ARRAY) {
int i;
for (i = 0; i < RARRAY_LEN(list); i++) {
VALUE elem = rb_ary_entry(list, i);
- RepeatedField_push(dupped, elem);
+ RepeatedField_push(dupped_, elem);
}
} else if (RB_TYPE_P(list, T_DATA) && RTYPEDDATA_P(list) &&
RTYPEDDATA_TYPE(list) == &RepeatedField_type) {
RepeatedField* self = ruby_to_RepeatedField(_self);
RepeatedField* list_rptfield = ruby_to_RepeatedField(list);
+ RepeatedField* dupped = ruby_to_RepeatedField(dupped_);
+ upb_array *dupped_array = RepeatedField_GetMutable(dupped_);
+ upb_arena* arena = Arena_get(dupped->arena);
+ int size = upb_array_size(list_rptfield->array);
int i;
- if (self->field_type != list_rptfield->field_type ||
- self->field_type_class != list_rptfield->field_type_class) {
+ if (self->type_info.type != list_rptfield->type_info.type ||
+ self->type_class != list_rptfield->type_class) {
rb_raise(rb_eArgError,
"Attempt to append RepeatedField with different element type.");
}
- for (i = 0; i < list_rptfield->size; i++) {
- void* mem = RepeatedField_index_native(list, i);
- RepeatedField_push_native(dupped, mem);
+
+ for (i = 0; i < size; i++) {
+ upb_msgval msgval = upb_array_get(list_rptfield->array, i);
+ upb_array_append(dupped_array, msgval, arena);
}
} else {
rb_raise(rb_eArgError, "Unknown type appending to RepeatedField");
}
- return dupped;
+ return dupped_;
}
/*
@@ -541,116 +585,41 @@ VALUE RepeatedField_concat(VALUE _self, VALUE list) {
return _self;
}
-
-void validate_type_class(upb_fieldtype_t type, VALUE klass) {
- if (rb_ivar_get(klass, descriptor_instancevar_interned) == Qnil) {
- rb_raise(rb_eArgError,
- "Type class has no descriptor. Please pass a "
- "class or enum as returned by the DescriptorPool.");
- }
- if (type == UPB_TYPE_MESSAGE) {
- VALUE desc = rb_ivar_get(klass, descriptor_instancevar_interned);
- if (!RB_TYPE_P(desc, T_DATA) || !RTYPEDDATA_P(desc) ||
- RTYPEDDATA_TYPE(desc) != &_Descriptor_type) {
- rb_raise(rb_eArgError, "Descriptor has an incorrect type.");
- }
- if (rb_get_alloc_func(klass) != &Message_alloc) {
- rb_raise(rb_eArgError,
- "Message class was not returned by the DescriptorPool.");
- }
- } else if (type == UPB_TYPE_ENUM) {
- VALUE enumdesc = rb_ivar_get(klass, descriptor_instancevar_interned);
- if (!RB_TYPE_P(enumdesc, T_DATA) || !RTYPEDDATA_P(enumdesc) ||
- RTYPEDDATA_TYPE(enumdesc) != &_EnumDescriptor_type) {
- rb_raise(rb_eArgError, "Descriptor has an incorrect type.");
- }
- }
-}
-
-void RepeatedField_init_args(int argc, VALUE* argv,
- VALUE _self) {
+/*
+ * call-seq:
+ * RepeatedField.new(type, type_class = nil, initial_elems = [])
+ *
+ * Creates a new repeated field. The provided type must be a Ruby symbol, and
+ * can take on the same values as those accepted by FieldDescriptor#type=. If
+ * the type is :message or :enum, type_class must be non-nil, and must be the
+ * Ruby class or module returned by Descriptor#msgclass or
+ * EnumDescriptor#enummodule, respectively. An initial list of elements may also
+ * be provided.
+ */
+VALUE RepeatedField_init(int argc, VALUE* argv, VALUE _self) {
RepeatedField* self = ruby_to_RepeatedField(_self);
+ upb_arena *arena;
VALUE ary = Qnil;
+
+ self->arena = Arena_new();
+ arena = Arena_get(self->arena);
+
if (argc < 1) {
rb_raise(rb_eArgError, "Expected at least 1 argument.");
}
- self->field_type = ruby_to_fieldtype(argv[0]);
- if (self->field_type == UPB_TYPE_MESSAGE ||
- self->field_type == UPB_TYPE_ENUM) {
- if (argc < 2) {
- rb_raise(rb_eArgError, "Expected at least 2 arguments for message/enum.");
- }
- self->field_type_class = argv[1];
- if (argc > 2) {
- ary = argv[2];
- }
- validate_type_class(self->field_type, self->field_type_class);
- } else {
- if (argc > 2) {
- rb_raise(rb_eArgError, "Too many arguments: expected 1 or 2.");
- }
- if (argc > 1) {
- ary = argv[1];
- }
- }
+ self->type_info = TypeInfo_FromClass(argc, argv, 0, &self->type_class, &ary);
+ self->array = upb_array_new(arena, self->type_info.type);
+ ObjectCache_Add(self->array, _self, arena);
if (ary != Qnil) {
- int i;
-
if (!RB_TYPE_P(ary, T_ARRAY)) {
rb_raise(rb_eArgError, "Expected array as initialize argument");
}
- for (i = 0; i < RARRAY_LEN(ary); i++) {
+ for (int i = 0; i < RARRAY_LEN(ary); i++) {
RepeatedField_push(_self, rb_ary_entry(ary, i));
}
}
-}
-
-// Mark, free, alloc, init and class setup functions.
-
-void RepeatedField_mark(void* _self) {
- RepeatedField* self = (RepeatedField*)_self;
- upb_fieldtype_t field_type = self->field_type;
- int element_size = native_slot_size(field_type);
- int i;
-
- rb_gc_mark(self->field_type_class);
- for (i = 0; i < self->size; i++) {
- void* memory = (((uint8_t *)self->elements) + i * element_size);
- native_slot_mark(self->field_type, memory);
- }
-}
-
-void RepeatedField_free(void* _self) {
- RepeatedField* self = (RepeatedField*)_self;
- xfree(self->elements);
- xfree(self);
-}
-
-/*
- * call-seq:
- * RepeatedField.new(type, type_class = nil, initial_elems = [])
- *
- * Creates a new repeated field. The provided type must be a Ruby symbol, and
- * can take on the same values as those accepted by FieldDescriptor#type=. If
- * the type is :message or :enum, type_class must be non-nil, and must be the
- * Ruby class or module returned by Descriptor#msgclass or
- * EnumDescriptor#enummodule, respectively. An initial list of elements may also
- * be provided.
- */
-VALUE RepeatedField_alloc(VALUE klass) {
- RepeatedField* self = ALLOC(RepeatedField);
- self->elements = NULL;
- self->size = 0;
- self->capacity = 0;
- self->field_type = -1;
- self->field_type_class = Qnil;
- return TypedData_Wrap_Struct(klass, &RepeatedField_type, self);
-}
-
-VALUE RepeatedField_init(int argc, VALUE* argv, VALUE self) {
- RepeatedField_init_args(argc, argv, self);
return Qnil;
}
@@ -667,7 +636,7 @@ void RepeatedField_register(VALUE module) {
rb_define_method(klass, "[]", RepeatedField_index, -1);
rb_define_method(klass, "at", RepeatedField_index, -1);
rb_define_method(klass, "[]=", RepeatedField_index_set, 2);
- rb_define_method(klass, "push", RepeatedField_push_vararg, -2);
+ rb_define_method(klass, "push", RepeatedField_push_vararg, -1);
rb_define_method(klass, "<<", RepeatedField_push, 1);
rb_define_private_method(klass, "pop_one", RepeatedField_pop_one, 0);
rb_define_method(klass, "replace", RepeatedField_replace, 1);
@@ -679,6 +648,7 @@ void RepeatedField_register(VALUE module) {
rb_define_method(klass, "clone", RepeatedField_dup, 0);
rb_define_method(klass, "==", RepeatedField_eq, 1);
rb_define_method(klass, "to_ary", RepeatedField_to_ary, 0);
+ rb_define_method(klass, "freeze", RepeatedField_freeze, 0);
rb_define_method(klass, "hash", RepeatedField_hash, 0);
rb_define_method(klass, "+", RepeatedField_plus, 1);
rb_define_method(klass, "concat", RepeatedField_concat, 1);
diff --git a/ruby/ext/google/protobuf_c/repeated_field.h b/ruby/ext/google/protobuf_c/repeated_field.h
new file mode 100644
index 0000000000..5a5959dd83
--- /dev/null
+++ b/ruby/ext/google/protobuf_c/repeated_field.h
@@ -0,0 +1,62 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef RUBY_PROTOBUF_REPEATED_FIELD_H_
+#define RUBY_PROTOBUF_REPEATED_FIELD_H_
+
+#include
+
+#include "protobuf.h"
+#include "ruby-upb.h"
+
+// Returns a Ruby wrapper object for the given upb_array, which will be created
+// if one does not exist already.
+VALUE RepeatedField_GetRubyWrapper(upb_array* msg, TypeInfo type_info,
+ VALUE arena);
+
+// Gets the underlying upb_array for this Ruby RepeatedField object, which must
+// have a type that matches |f|. If this is not a repeated field or the type
+// doesn't match, raises an exception.
+const upb_array* RepeatedField_GetUpbArray(VALUE value, const upb_fielddef* f);
+
+// Implements #inspect for this repeated field by appending its contents to |b|.
+void RepeatedField_Inspect(StringBuilder* b, const upb_array* array,
+ TypeInfo info);
+
+// Returns a deep copy of this RepeatedField object.
+VALUE RepeatedField_deep_copy(VALUE obj);
+
+// Ruby class of Google::Protobuf::RepeatedField.
+extern VALUE cRepeatedField;
+
+// Call at startup to register all types in this module.
+void RepeatedField_register(VALUE module);
+
+#endif // RUBY_PROTOBUF_REPEATED_FIELD_H_
diff --git a/ruby/ext/google/protobuf_c/ruby-upb.c b/ruby/ext/google/protobuf_c/ruby-upb.c
new file mode 100755
index 0000000000..9c048da98b
--- /dev/null
+++ b/ruby/ext/google/protobuf_c/ruby-upb.c
@@ -0,0 +1,8913 @@
+/* Amalgamated source file */
+#include "ruby-upb.h"
+/*
+* This is where we define macros used across upb.
+*
+* All of these macros are undef'd in port_undef.inc to avoid leaking them to
+* users.
+*
+* The correct usage is:
+*
+* #include "upb/foobar.h"
+* #include "upb/baz.h"
+*
+* // MUST be last included header.
+* #include "upb/port_def.inc"
+*
+* // Code for this file.
+* // <...>
+*
+* // Can be omitted for .c files, required for .h.
+* #include "upb/port_undef.inc"
+*
+* This file is private and must not be included by users!
+*/
+
+#if !((defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || \
+ (defined(__cplusplus) && __cplusplus >= 201103L) || \
+ (defined(_MSC_VER) && _MSC_VER >= 1900))
+#error upb requires C99 or C++11 or MSVC >= 2015.
+#endif
+
+#include
+#include
+
+#if UINTPTR_MAX == 0xffffffff
+#define UPB_SIZE(size32, size64) size32
+#else
+#define UPB_SIZE(size32, size64) size64
+#endif
+
+/* If we always read/write as a consistent type to each address, this shouldn't
+ * violate aliasing.
+ */
+#define UPB_PTR_AT(msg, ofs, type) ((type*)((char*)(msg) + (ofs)))
+
+#define UPB_READ_ONEOF(msg, fieldtype, offset, case_offset, case_val, default) \
+ *UPB_PTR_AT(msg, case_offset, int) == case_val \
+ ? *UPB_PTR_AT(msg, offset, fieldtype) \
+ : default
+
+#define UPB_WRITE_ONEOF(msg, fieldtype, offset, value, case_offset, case_val) \
+ *UPB_PTR_AT(msg, case_offset, int) = case_val; \
+ *UPB_PTR_AT(msg, offset, fieldtype) = value;
+
+#define UPB_MAPTYPE_STRING 0
+
+/* UPB_INLINE: inline if possible, emit standalone code if required. */
+#ifdef __cplusplus
+#define UPB_INLINE inline
+#elif defined (__GNUC__) || defined(__clang__)
+#define UPB_INLINE static __inline__
+#else
+#define UPB_INLINE static
+#endif
+
+#define UPB_ALIGN_UP(size, align) (((size) + (align) - 1) / (align) * (align))
+#define UPB_ALIGN_DOWN(size, align) ((size) / (align) * (align))
+#define UPB_ALIGN_MALLOC(size) UPB_ALIGN_UP(size, 16)
+#define UPB_ALIGN_OF(type) offsetof (struct { char c; type member; }, member)
+
+/* Hints to the compiler about likely/unlikely branches. */
+#if defined (__GNUC__) || defined(__clang__)
+#define UPB_LIKELY(x) __builtin_expect((x),1)
+#define UPB_UNLIKELY(x) __builtin_expect((x),0)
+#else
+#define UPB_LIKELY(x) (x)
+#define UPB_UNLIKELY(x) (x)
+#endif
+
+/* Macros for function attributes on compilers that support them. */
+#ifdef __GNUC__
+#define UPB_FORCEINLINE __inline__ __attribute__((always_inline))
+#define UPB_NOINLINE __attribute__((noinline))
+#define UPB_NORETURN __attribute__((__noreturn__))
+#define UPB_PRINTF(str, first_vararg) __attribute__((format (printf, str, first_vararg)))
+#elif defined(_MSC_VER)
+#define UPB_NOINLINE
+#define UPB_FORCEINLINE
+#define UPB_NORETURN __declspec(noreturn)
+#define UPB_PRINTF(str, first_vararg)
+#else /* !defined(__GNUC__) */
+#define UPB_FORCEINLINE
+#define UPB_NOINLINE
+#define UPB_NORETURN
+#define UPB_PRINTF(str, first_vararg)
+#endif
+
+#define UPB_MAX(x, y) ((x) > (y) ? (x) : (y))
+#define UPB_MIN(x, y) ((x) < (y) ? (x) : (y))
+
+#define UPB_UNUSED(var) (void)var
+
+/* UPB_ASSUME(): in release mode, we tell the compiler to assume this is true.
+ */
+#ifdef NDEBUG
+#ifdef __GNUC__
+#define UPB_ASSUME(expr) if (!(expr)) __builtin_unreachable()
+#elif defined _MSC_VER
+#define UPB_ASSUME(expr) if (!(expr)) __assume(0)
+#else
+#define UPB_ASSUME(expr) do {} while (false && (expr))
+#endif
+#else
+#define UPB_ASSUME(expr) assert(expr)
+#endif
+
+/* UPB_ASSERT(): in release mode, we use the expression without letting it be
+ * evaluated. This prevents "unused variable" warnings. */
+#ifdef NDEBUG
+#define UPB_ASSERT(expr) do {} while (false && (expr))
+#else
+#define UPB_ASSERT(expr) assert(expr)
+#endif
+
+#if defined(__GNUC__) || defined(__clang__)
+#define UPB_UNREACHABLE() do { assert(0); __builtin_unreachable(); } while(0)
+#else
+#define UPB_UNREACHABLE() do { assert(0); } while(0)
+#endif
+
+/* UPB_SETJMP() / UPB_LONGJMP(): avoid setting/restoring signal mask. */
+#ifdef __APPLE__
+#define UPB_SETJMP(buf) _setjmp(buf)
+#define UPB_LONGJMP(buf, val) _longjmp(buf, val)
+#else
+#define UPB_SETJMP(buf) setjmp(buf)
+#define UPB_LONGJMP(buf, val) longjmp(buf, val)
+#endif
+
+/* Configure whether fasttable is switched on or not. *************************/
+
+#if defined(__x86_64__) && defined(__GNUC__)
+#define UPB_FASTTABLE_SUPPORTED 1
+#else
+#define UPB_FASTTABLE_SUPPORTED 0
+#endif
+
+/* define UPB_ENABLE_FASTTABLE to force fast table support.
+ * This is useful when we want to ensure we are really getting fasttable,
+ * for example for testing or benchmarking. */
+#if defined(UPB_ENABLE_FASTTABLE)
+#if !UPB_FASTTABLE_SUPPORTED
+#error fasttable is x86-64 + Clang/GCC only
+#endif
+#define UPB_FASTTABLE 1
+/* Define UPB_TRY_ENABLE_FASTTABLE to use fasttable if possible.
+ * This is useful for releasing code that might be used on multiple platforms,
+ * for example the PHP or Ruby C extensions. */
+#elif defined(UPB_TRY_ENABLE_FASTTABLE)
+#define UPB_FASTTABLE UPB_FASTTABLE_SUPPORTED
+#else
+#define UPB_FASTTABLE 0
+#endif
+
+/* UPB_FASTTABLE_INIT() allows protos compiled for fasttable to gracefully
+ * degrade to non-fasttable if we are using UPB_TRY_ENABLE_FASTTABLE. */
+#if !UPB_FASTTABLE && defined(UPB_TRY_ENABLE_FASTTABLE)
+#define UPB_FASTTABLE_INIT(...)
+#else
+#define UPB_FASTTABLE_INIT(...) __VA_ARGS__
+#endif
+
+#undef UPB_FASTTABLE_SUPPORTED
+
+/* ASAN poisoning (for arena) *************************************************/
+
+#if defined(__SANITIZE_ADDRESS__)
+#define UPB_ASAN 1
+#ifdef __cplusplus
+extern "C" {
+#endif
+void __asan_poison_memory_region(void const volatile *addr, size_t size);
+void __asan_unpoison_memory_region(void const volatile *addr, size_t size);
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+#define UPB_POISON_MEMORY_REGION(addr, size) \
+ __asan_poison_memory_region((addr), (size))
+#define UPB_UNPOISON_MEMORY_REGION(addr, size) \
+ __asan_unpoison_memory_region((addr), (size))
+#else
+#define UPB_ASAN 0
+#define UPB_POISON_MEMORY_REGION(addr, size) \
+ ((void)(addr), (void)(size))
+#define UPB_UNPOISON_MEMORY_REGION(addr, size) \
+ ((void)(addr), (void)(size))
+#endif
+
+
+#include
+#include
+
+
+/* Must be last. */
+
+/* Maps descriptor type -> elem_size_lg2. */
+static const uint8_t desctype_to_elem_size_lg2[] = {
+ -1, /* invalid descriptor type */
+ 3, /* DOUBLE */
+ 2, /* FLOAT */
+ 3, /* INT64 */
+ 3, /* UINT64 */
+ 2, /* INT32 */
+ 3, /* FIXED64 */
+ 2, /* FIXED32 */
+ 0, /* BOOL */
+ UPB_SIZE(3, 4), /* STRING */
+ UPB_SIZE(2, 3), /* GROUP */
+ UPB_SIZE(2, 3), /* MESSAGE */
+ UPB_SIZE(3, 4), /* BYTES */
+ 2, /* UINT32 */
+ 2, /* ENUM */
+ 2, /* SFIXED32 */
+ 3, /* SFIXED64 */
+ 2, /* SINT32 */
+ 3, /* SINT64 */
+};
+
+/* Maps descriptor type -> upb map size. */
+static const uint8_t desctype_to_mapsize[] = {
+ -1, /* invalid descriptor type */
+ 8, /* DOUBLE */
+ 4, /* FLOAT */
+ 8, /* INT64 */
+ 8, /* UINT64 */
+ 4, /* INT32 */
+ 8, /* FIXED64 */
+ 4, /* FIXED32 */
+ 1, /* BOOL */
+ UPB_MAPTYPE_STRING, /* STRING */
+ sizeof(void *), /* GROUP */
+ sizeof(void *), /* MESSAGE */
+ UPB_MAPTYPE_STRING, /* BYTES */
+ 4, /* UINT32 */
+ 4, /* ENUM */
+ 4, /* SFIXED32 */
+ 8, /* SFIXED64 */
+ 4, /* SINT32 */
+ 8, /* SINT64 */
+};
+
+static const unsigned fixed32_ok = (1 << UPB_DTYPE_FLOAT) |
+ (1 << UPB_DTYPE_FIXED32) |
+ (1 << UPB_DTYPE_SFIXED32);
+
+static const unsigned fixed64_ok = (1 << UPB_DTYPE_DOUBLE) |
+ (1 << UPB_DTYPE_FIXED64) |
+ (1 << UPB_DTYPE_SFIXED64);
+
+/* Op: an action to be performed for a wire-type/field-type combination. */
+#define OP_SCALAR_LG2(n) (n) /* n in [0, 2, 3] => op in [0, 2, 3] */
+#define OP_STRING 4
+#define OP_BYTES 5
+#define OP_SUBMSG 6
+/* Ops above are scalar-only. Repeated fields can use any op. */
+#define OP_FIXPCK_LG2(n) (n + 5) /* n in [2, 3] => op in [7, 8] */
+#define OP_VARPCK_LG2(n) (n + 9) /* n in [0, 2, 3] => op in [9, 11, 12] */
+
+static const int8_t varint_ops[19] = {
+ -1, /* field not found */
+ -1, /* DOUBLE */
+ -1, /* FLOAT */
+ OP_SCALAR_LG2(3), /* INT64 */
+ OP_SCALAR_LG2(3), /* UINT64 */
+ OP_SCALAR_LG2(2), /* INT32 */
+ -1, /* FIXED64 */
+ -1, /* FIXED32 */
+ OP_SCALAR_LG2(0), /* BOOL */
+ -1, /* STRING */
+ -1, /* GROUP */
+ -1, /* MESSAGE */
+ -1, /* BYTES */
+ OP_SCALAR_LG2(2), /* UINT32 */
+ OP_SCALAR_LG2(2), /* ENUM */
+ -1, /* SFIXED32 */
+ -1, /* SFIXED64 */
+ OP_SCALAR_LG2(2), /* SINT32 */
+ OP_SCALAR_LG2(3), /* SINT64 */
+};
+
+static const int8_t delim_ops[37] = {
+ /* For non-repeated field type. */
+ -1, /* field not found */
+ -1, /* DOUBLE */
+ -1, /* FLOAT */
+ -1, /* INT64 */
+ -1, /* UINT64 */
+ -1, /* INT32 */
+ -1, /* FIXED64 */
+ -1, /* FIXED32 */
+ -1, /* BOOL */
+ OP_STRING, /* STRING */
+ -1, /* GROUP */
+ OP_SUBMSG, /* MESSAGE */
+ OP_BYTES, /* BYTES */
+ -1, /* UINT32 */
+ -1, /* ENUM */
+ -1, /* SFIXED32 */
+ -1, /* SFIXED64 */
+ -1, /* SINT32 */
+ -1, /* SINT64 */
+ /* For repeated field type. */
+ OP_FIXPCK_LG2(3), /* REPEATED DOUBLE */
+ OP_FIXPCK_LG2(2), /* REPEATED FLOAT */
+ OP_VARPCK_LG2(3), /* REPEATED INT64 */
+ OP_VARPCK_LG2(3), /* REPEATED UINT64 */
+ OP_VARPCK_LG2(2), /* REPEATED INT32 */
+ OP_FIXPCK_LG2(3), /* REPEATED FIXED64 */
+ OP_FIXPCK_LG2(2), /* REPEATED FIXED32 */
+ OP_VARPCK_LG2(0), /* REPEATED BOOL */
+ OP_STRING, /* REPEATED STRING */
+ OP_SUBMSG, /* REPEATED GROUP */
+ OP_SUBMSG, /* REPEATED MESSAGE */
+ OP_BYTES, /* REPEATED BYTES */
+ OP_VARPCK_LG2(2), /* REPEATED UINT32 */
+ OP_VARPCK_LG2(2), /* REPEATED ENUM */
+ OP_FIXPCK_LG2(2), /* REPEATED SFIXED32 */
+ OP_FIXPCK_LG2(3), /* REPEATED SFIXED64 */
+ OP_VARPCK_LG2(2), /* REPEATED SINT32 */
+ OP_VARPCK_LG2(3), /* REPEATED SINT64 */
+};
+
+typedef union {
+ bool bool_val;
+ uint32_t uint32_val;
+ uint64_t uint64_val;
+ uint32_t size;
+} wireval;
+
+static const char *decode_msg(upb_decstate *d, const char *ptr, upb_msg *msg,
+ const upb_msglayout *layout);
+
+UPB_NORETURN static void decode_err(upb_decstate *d) { UPB_LONGJMP(d->err, 1); }
+
+// We don't want to mark this NORETURN, see comment in .h.
+// Unfortunately this code to suppress the warning doesn't appear to be working.
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunknown-warning-option"
+#pragma clang diagnostic ignored "-Wsuggest-attribute"
+#endif
+
+const char *fastdecode_err(upb_decstate *d) {
+ longjmp(d->err, 1);
+ return NULL;
+}
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+const uint8_t upb_utf8_offsets[] = {
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+static void decode_verifyutf8(upb_decstate *d, const char *buf, int len) {
+ if (!decode_verifyutf8_inl(buf, len)) decode_err(d);
+}
+
+static bool decode_reserve(upb_decstate *d, upb_array *arr, size_t elem) {
+ bool need_realloc = arr->size - arr->len < elem;
+ if (need_realloc && !_upb_array_realloc(arr, arr->len + elem, &d->arena)) {
+ decode_err(d);
+ }
+ return need_realloc;
+}
+
+typedef struct {
+ const char *ptr;
+ uint64_t val;
+} decode_vret;
+
+UPB_NOINLINE
+static decode_vret decode_longvarint64(const char *ptr, uint64_t val) {
+ decode_vret ret = {NULL, 0};
+ uint64_t byte;
+ int i;
+ for (i = 1; i < 10; i++) {
+ byte = (uint8_t)ptr[i];
+ val += (byte - 1) << (i * 7);
+ if (!(byte & 0x80)) {
+ ret.ptr = ptr + i + 1;
+ ret.val = val;
+ return ret;
+ }
+ }
+ return ret;
+}
+
+UPB_FORCEINLINE
+static const char *decode_varint64(upb_decstate *d, const char *ptr,
+ uint64_t *val) {
+ uint64_t byte = (uint8_t)*ptr;
+ if (UPB_LIKELY((byte & 0x80) == 0)) {
+ *val = byte;
+ return ptr + 1;
+ } else {
+ decode_vret res = decode_longvarint64(ptr, byte);
+ if (!res.ptr) decode_err(d);
+ *val = res.val;
+ return res.ptr;
+ }
+}
+
+UPB_FORCEINLINE
+static const char *decode_tag(upb_decstate *d, const char *ptr,
+ uint32_t *val) {
+ uint64_t byte = (uint8_t)*ptr;
+ if (UPB_LIKELY((byte & 0x80) == 0)) {
+ *val = byte;
+ return ptr + 1;
+ } else {
+ const char *start = ptr;
+ decode_vret res = decode_longvarint64(ptr, byte);
+ ptr = res.ptr;
+ *val = res.val;
+ if (!ptr || *val > UINT32_MAX || ptr - start > 5) decode_err(d);
+ return ptr;
+ }
+}
+
+static void decode_munge(int type, wireval *val) {
+ switch (type) {
+ case UPB_DESCRIPTOR_TYPE_BOOL:
+ val->bool_val = val->uint64_val != 0;
+ break;
+ case UPB_DESCRIPTOR_TYPE_SINT32: {
+ uint32_t n = val->uint32_val;
+ val->uint32_val = (n >> 1) ^ -(int32_t)(n & 1);
+ break;
+ }
+ case UPB_DESCRIPTOR_TYPE_SINT64: {
+ uint64_t n = val->uint64_val;
+ val->uint64_val = (n >> 1) ^ -(int64_t)(n & 1);
+ break;
+ }
+ case UPB_DESCRIPTOR_TYPE_INT32:
+ case UPB_DESCRIPTOR_TYPE_UINT32:
+ if (!_upb_isle()) {
+ /* The next stage will memcpy(dst, &val, 4) */
+ val->uint32_val = val->uint64_val;
+ }
+ break;
+ }
+}
+
+static const upb_msglayout_field *upb_find_field(const upb_msglayout *l,
+ uint32_t field_number) {
+ static upb_msglayout_field none = {0, 0, 0, 0, 0, 0};
+
+ /* Lots of optimization opportunities here. */
+ int i;
+ if (l == NULL) return &none;
+ for (i = 0; i < l->field_count; i++) {
+ if (l->fields[i].number == field_number) {
+ return &l->fields[i];
+ }
+ }
+
+ return &none; /* Unknown field. */
+}
+
+static upb_msg *decode_newsubmsg(upb_decstate *d, const upb_msglayout *layout,
+ const upb_msglayout_field *field) {
+ const upb_msglayout *subl = layout->submsgs[field->submsg_index];
+ return _upb_msg_new_inl(subl, &d->arena);
+}
+
+UPB_NOINLINE
+const char *decode_isdonefallback(upb_decstate *d, const char *ptr,
+ int overrun) {
+ ptr = decode_isdonefallback_inl(d, ptr, overrun);
+ if (ptr == NULL) {
+ decode_err(d);
+ }
+ return ptr;
+}
+
+static const char *decode_readstr(upb_decstate *d, const char *ptr, int size,
+ upb_strview *str) {
+ if (d->alias) {
+ str->data = ptr;
+ } else {
+ char *data = upb_arena_malloc(&d->arena, size);
+ if (!data) decode_err(d);
+ memcpy(data, ptr, size);
+ str->data = data;
+ }
+ str->size = size;
+ return ptr + size;
+}
+
+UPB_FORCEINLINE
+static const char *decode_tosubmsg(upb_decstate *d, const char *ptr,
+ upb_msg *submsg, const upb_msglayout *layout,
+ const upb_msglayout_field *field, int size) {
+ const upb_msglayout *subl = layout->submsgs[field->submsg_index];
+ int saved_delta = decode_pushlimit(d, ptr, size);
+ if (--d->depth < 0) decode_err(d);
+ if (!decode_isdone(d, &ptr)) {
+ ptr = decode_msg(d, ptr, submsg, subl);
+ }
+ if (d->end_group != DECODE_NOGROUP) decode_err(d);
+ decode_poplimit(d, ptr, saved_delta);
+ d->depth++;
+ return ptr;
+}
+
+UPB_FORCEINLINE
+static const char *decode_group(upb_decstate *d, const char *ptr,
+ upb_msg *submsg, const upb_msglayout *subl,
+ uint32_t number) {
+ if (--d->depth < 0) decode_err(d);
+ if (decode_isdone(d, &ptr)) {
+ decode_err(d);
+ }
+ ptr = decode_msg(d, ptr, submsg, subl);
+ if (d->end_group != number) decode_err(d);
+ d->end_group = DECODE_NOGROUP;
+ d->depth++;
+ return ptr;
+}
+
+UPB_FORCEINLINE
+static const char *decode_togroup(upb_decstate *d, const char *ptr,
+ upb_msg *submsg, const upb_msglayout *layout,
+ const upb_msglayout_field *field) {
+ const upb_msglayout *subl = layout->submsgs[field->submsg_index];
+ return decode_group(d, ptr, submsg, subl, field->number);
+}
+
+static const char *decode_toarray(upb_decstate *d, const char *ptr,
+ upb_msg *msg, const upb_msglayout *layout,
+ const upb_msglayout_field *field, wireval val,
+ int op) {
+ upb_array **arrp = UPB_PTR_AT(msg, field->offset, void);
+ upb_array *arr = *arrp;
+ void *mem;
+
+ if (arr) {
+ decode_reserve(d, arr, 1);
+ } else {
+ size_t lg2 = desctype_to_elem_size_lg2[field->descriptortype];
+ arr = _upb_array_new(&d->arena, 4, lg2);
+ if (!arr) decode_err(d);
+ *arrp = arr;
+ }
+
+ switch (op) {
+ case OP_SCALAR_LG2(0):
+ case OP_SCALAR_LG2(2):
+ case OP_SCALAR_LG2(3):
+ /* Append scalar value. */
+ mem = UPB_PTR_AT(_upb_array_ptr(arr), arr->len << op, void);
+ arr->len++;
+ memcpy(mem, &val, 1 << op);
+ return ptr;
+ case OP_STRING:
+ decode_verifyutf8(d, ptr, val.size);
+ /* Fallthrough. */
+ case OP_BYTES: {
+ /* Append bytes. */
+ upb_strview *str = (upb_strview*)_upb_array_ptr(arr) + arr->len;
+ arr->len++;
+ return decode_readstr(d, ptr, val.size, str);
+ }
+ case OP_SUBMSG: {
+ /* Append submessage / group. */
+ upb_msg *submsg = decode_newsubmsg(d, layout, field);
+ *UPB_PTR_AT(_upb_array_ptr(arr), arr->len * sizeof(void *), upb_msg *) =
+ submsg;
+ arr->len++;
+ if (UPB_UNLIKELY(field->descriptortype == UPB_DTYPE_GROUP)) {
+ return decode_togroup(d, ptr, submsg, layout, field);
+ } else {
+ return decode_tosubmsg(d, ptr, submsg, layout, field, val.size);
+ }
+ }
+ case OP_FIXPCK_LG2(2):
+ case OP_FIXPCK_LG2(3): {
+ /* Fixed packed. */
+ int lg2 = op - OP_FIXPCK_LG2(0);
+ int mask = (1 << lg2) - 1;
+ size_t count = val.size >> lg2;
+ if ((val.size & mask) != 0) {
+ decode_err(d); /* Length isn't a round multiple of elem size. */
+ }
+ decode_reserve(d, arr, count);
+ mem = UPB_PTR_AT(_upb_array_ptr(arr), arr->len << lg2, void);
+ arr->len += count;
+ memcpy(mem, ptr, val.size); /* XXX: ptr boundary. */
+ return ptr + val.size;
+ }
+ case OP_VARPCK_LG2(0):
+ case OP_VARPCK_LG2(2):
+ case OP_VARPCK_LG2(3): {
+ /* Varint packed. */
+ int lg2 = op - OP_VARPCK_LG2(0);
+ int scale = 1 << lg2;
+ int saved_limit = decode_pushlimit(d, ptr, val.size);
+ char *out = UPB_PTR_AT(_upb_array_ptr(arr), arr->len << lg2, void);
+ while (!decode_isdone(d, &ptr)) {
+ wireval elem;
+ ptr = decode_varint64(d, ptr, &elem.uint64_val);
+ decode_munge(field->descriptortype, &elem);
+ if (decode_reserve(d, arr, 1)) {
+ out = UPB_PTR_AT(_upb_array_ptr(arr), arr->len << lg2, void);
+ }
+ arr->len++;
+ memcpy(out, &elem, scale);
+ out += scale;
+ }
+ decode_poplimit(d, ptr, saved_limit);
+ return ptr;
+ }
+ default:
+ UPB_UNREACHABLE();
+ }
+}
+
+static const char *decode_tomap(upb_decstate *d, const char *ptr, upb_msg *msg,
+ const upb_msglayout *layout,
+ const upb_msglayout_field *field, wireval val) {
+ upb_map **map_p = UPB_PTR_AT(msg, field->offset, upb_map *);
+ upb_map *map = *map_p;
+ upb_map_entry ent;
+ const upb_msglayout *entry = layout->submsgs[field->submsg_index];
+
+ if (!map) {
+ /* Lazily create map. */
+ const upb_msglayout *entry = layout->submsgs[field->submsg_index];
+ const upb_msglayout_field *key_field = &entry->fields[0];
+ const upb_msglayout_field *val_field = &entry->fields[1];
+ char key_size = desctype_to_mapsize[key_field->descriptortype];
+ char val_size = desctype_to_mapsize[val_field->descriptortype];
+ UPB_ASSERT(key_field->offset == 0);
+ UPB_ASSERT(val_field->offset == sizeof(upb_strview));
+ map = _upb_map_new(&d->arena, key_size, val_size);
+ *map_p = map;
+ }
+
+ /* Parse map entry. */
+ memset(&ent, 0, sizeof(ent));
+
+ if (entry->fields[1].descriptortype == UPB_DESCRIPTOR_TYPE_MESSAGE ||
+ entry->fields[1].descriptortype == UPB_DESCRIPTOR_TYPE_GROUP) {
+ /* Create proactively to handle the case where it doesn't appear. */
+ ent.v.val = upb_value_ptr(_upb_msg_new(entry->submsgs[0], &d->arena));
+ }
+
+ ptr = decode_tosubmsg(d, ptr, &ent.k, layout, field, val.size);
+ _upb_map_set(map, &ent.k, map->key_size, &ent.v, map->val_size, &d->arena);
+ return ptr;
+}
+
+static const char *decode_tomsg(upb_decstate *d, const char *ptr, upb_msg *msg,
+ const upb_msglayout *layout,
+ const upb_msglayout_field *field, wireval val,
+ int op) {
+ void *mem = UPB_PTR_AT(msg, field->offset, void);
+ int type = field->descriptortype;
+
+ /* Set presence if necessary. */
+ if (field->presence < 0) {
+ /* Oneof case */
+ uint32_t *oneof_case = _upb_oneofcase_field(msg, field);
+ if (op == OP_SUBMSG && *oneof_case != field->number) {
+ memset(mem, 0, sizeof(void*));
+ }
+ *oneof_case = field->number;
+ } else if (field->presence > 0) {
+ _upb_sethas_field(msg, field);
+ }
+
+ /* Store into message. */
+ switch (op) {
+ case OP_SUBMSG: {
+ upb_msg **submsgp = mem;
+ upb_msg *submsg = *submsgp;
+ if (!submsg) {
+ submsg = decode_newsubmsg(d, layout, field);
+ *submsgp = submsg;
+ }
+ if (UPB_UNLIKELY(type == UPB_DTYPE_GROUP)) {
+ ptr = decode_togroup(d, ptr, submsg, layout, field);
+ } else {
+ ptr = decode_tosubmsg(d, ptr, submsg, layout, field, val.size);
+ }
+ break;
+ }
+ case OP_STRING:
+ decode_verifyutf8(d, ptr, val.size);
+ /* Fallthrough. */
+ case OP_BYTES:
+ return decode_readstr(d, ptr, val.size, mem);
+ case OP_SCALAR_LG2(3):
+ memcpy(mem, &val, 8);
+ break;
+ case OP_SCALAR_LG2(2):
+ memcpy(mem, &val, 4);
+ break;
+ case OP_SCALAR_LG2(0):
+ memcpy(mem, &val, 1);
+ break;
+ default:
+ UPB_UNREACHABLE();
+ }
+
+ return ptr;
+}
+
+UPB_FORCEINLINE
+static bool decode_tryfastdispatch(upb_decstate *d, const char **ptr,
+ upb_msg *msg, const upb_msglayout *layout) {
+#if UPB_FASTTABLE
+ if (layout && layout->table_mask != (unsigned char)-1) {
+ uint16_t tag = fastdecode_loadtag(*ptr);
+ intptr_t table = decode_totable(layout);
+ *ptr = fastdecode_tagdispatch(d, *ptr, msg, table, 0, tag);
+ return true;
+ }
+#endif
+ return false;
+}
+
+UPB_NOINLINE
+static const char *decode_msg(upb_decstate *d, const char *ptr, upb_msg *msg,
+ const upb_msglayout *layout) {
+ while (true) {
+ uint32_t tag;
+ const upb_msglayout_field *field;
+ int field_number;
+ int wire_type;
+ const char *field_start = ptr;
+ wireval val;
+ int op;
+
+ UPB_ASSERT(ptr < d->limit_ptr);
+ ptr = decode_tag(d, ptr, &tag);
+ field_number = tag >> 3;
+ wire_type = tag & 7;
+
+ field = upb_find_field(layout, field_number);
+
+ switch (wire_type) {
+ case UPB_WIRE_TYPE_VARINT:
+ ptr = decode_varint64(d, ptr, &val.uint64_val);
+ op = varint_ops[field->descriptortype];
+ decode_munge(field->descriptortype, &val);
+ break;
+ case UPB_WIRE_TYPE_32BIT:
+ memcpy(&val.uint32_val, ptr, 4);
+ val.uint32_val = _upb_be_swap32(val.uint32_val);
+ ptr += 4;
+ op = OP_SCALAR_LG2(2);
+ if (((1 << field->descriptortype) & fixed32_ok) == 0) goto unknown;
+ break;
+ case UPB_WIRE_TYPE_64BIT:
+ memcpy(&val.uint64_val, ptr, 8);
+ val.uint64_val = _upb_be_swap64(val.uint64_val);
+ ptr += 8;
+ op = OP_SCALAR_LG2(3);
+ if (((1 << field->descriptortype) & fixed64_ok) == 0) goto unknown;
+ break;
+ case UPB_WIRE_TYPE_DELIMITED: {
+ int ndx = field->descriptortype;
+ uint64_t size;
+ if (_upb_isrepeated(field)) ndx += 18;
+ ptr = decode_varint64(d, ptr, &size);
+ if (size >= INT32_MAX ||
+ ptr - d->end + (int32_t)size > d->limit) {
+ decode_err(d); /* Length overflow. */
+ }
+ op = delim_ops[ndx];
+ val.size = size;
+ break;
+ }
+ case UPB_WIRE_TYPE_START_GROUP:
+ val.uint32_val = field_number;
+ op = OP_SUBMSG;
+ if (field->descriptortype != UPB_DTYPE_GROUP) goto unknown;
+ break;
+ case UPB_WIRE_TYPE_END_GROUP:
+ d->end_group = field_number;
+ return ptr;
+ default:
+ decode_err(d);
+ }
+
+ if (op >= 0) {
+ /* Parse, using op for dispatch. */
+ switch (field->label) {
+ case UPB_LABEL_REPEATED:
+ case _UPB_LABEL_PACKED:
+ ptr = decode_toarray(d, ptr, msg, layout, field, val, op);
+ break;
+ case _UPB_LABEL_MAP:
+ ptr = decode_tomap(d, ptr, msg, layout, field, val);
+ break;
+ default:
+ ptr = decode_tomsg(d, ptr, msg, layout, field, val, op);
+ break;
+ }
+ } else {
+ unknown:
+ /* Skip unknown field. */
+ if (field_number == 0) decode_err(d);
+ if (wire_type == UPB_WIRE_TYPE_DELIMITED) ptr += val.size;
+ if (msg) {
+ if (wire_type == UPB_WIRE_TYPE_START_GROUP) {
+ d->unknown = field_start;
+ d->unknown_msg = msg;
+ ptr = decode_group(d, ptr, NULL, NULL, field_number);
+ d->unknown_msg = NULL;
+ field_start = d->unknown;
+ }
+ if (!_upb_msg_addunknown(msg, field_start, ptr - field_start,
+ &d->arena)) {
+ decode_err(d);
+ }
+ } else if (wire_type == UPB_WIRE_TYPE_START_GROUP) {
+ ptr = decode_group(d, ptr, NULL, NULL, field_number);
+ }
+ }
+
+ if (decode_isdone(d, &ptr)) return ptr;
+ if (decode_tryfastdispatch(d, &ptr, msg, layout)) return ptr;
+ }
+}
+
+const char *fastdecode_generic(struct upb_decstate *d, const char *ptr,
+ upb_msg *msg, intptr_t table, uint64_t hasbits,
+ uint64_t data) {
+ (void)data;
+ *(uint32_t*)msg |= hasbits;
+ return decode_msg(d, ptr, msg, decode_totablep(table));
+}
+
+static bool decode_top(struct upb_decstate *d, const char *buf, void *msg,
+ const upb_msglayout *l) {
+ if (!decode_tryfastdispatch(d, &buf, msg, l)) {
+ decode_msg(d, buf, msg, l);
+ }
+ return d->end_group == DECODE_NOGROUP;
+}
+
+bool _upb_decode(const char *buf, size_t size, void *msg,
+ const upb_msglayout *l, upb_arena *arena, int options) {
+ bool ok;
+ upb_decstate state;
+ unsigned depth = (unsigned)options >> 16;
+
+ if (size == 0) {
+ return true;
+ } else if (size <= 16) {
+ memset(&state.patch, 0, 32);
+ memcpy(&state.patch, buf, size);
+ buf = state.patch;
+ state.end = buf + size;
+ state.limit = 0;
+ state.alias = false;
+ } else {
+ state.end = buf + size - 16;
+ state.limit = 16;
+ state.alias = options & UPB_DECODE_ALIAS;
+ }
+
+ state.limit_ptr = state.end;
+ state.unknown_msg = NULL;
+ state.depth = depth ? depth : 64;
+ state.end_group = DECODE_NOGROUP;
+ state.arena.head = arena->head;
+ state.arena.last_size = arena->last_size;
+ state.arena.cleanups = arena->cleanups;
+ state.arena.parent = arena;
+
+ if (UPB_UNLIKELY(UPB_SETJMP(state.err))) {
+ ok = false;
+ } else {
+ ok = decode_top(&state, buf, msg, l);
+ }
+
+ arena->head.ptr = state.arena.head.ptr;
+ arena->head.end = state.arena.head.end;
+ arena->cleanups = state.arena.cleanups;
+ return ok;
+}
+
+#undef OP_SCALAR_LG2
+#undef OP_FIXPCK_LG2
+#undef OP_VARPCK_LG2
+#undef OP_STRING
+#undef OP_SUBMSG
+/* We encode backwards, to avoid pre-computing lengths (one-pass encode). */
+
+
+#include
+#include
+
+
+/* Must be last. */
+
+#define UPB_PB_VARINT_MAX_LEN 10
+
+UPB_NOINLINE
+static size_t encode_varint64(uint64_t val, char *buf) {
+ size_t i = 0;
+ do {
+ uint8_t byte = val & 0x7fU;
+ val >>= 7;
+ if (val) byte |= 0x80U;
+ buf[i++] = byte;
+ } while (val);
+ return i;
+}
+
+static uint32_t encode_zz32(int32_t n) { return ((uint32_t)n << 1) ^ (n >> 31); }
+static uint64_t encode_zz64(int64_t n) { return ((uint64_t)n << 1) ^ (n >> 63); }
+
+typedef struct {
+ jmp_buf err;
+ upb_alloc *alloc;
+ char *buf, *ptr, *limit;
+ int options;
+ int depth;
+ _upb_mapsorter sorter;
+} upb_encstate;
+
+static size_t upb_roundup_pow2(size_t bytes) {
+ size_t ret = 128;
+ while (ret < bytes) {
+ ret *= 2;
+ }
+ return ret;
+}
+
+UPB_NORETURN static void encode_err(upb_encstate *e) {
+ UPB_LONGJMP(e->err, 1);
+}
+
+UPB_NOINLINE
+static void encode_growbuffer(upb_encstate *e, size_t bytes) {
+ size_t old_size = e->limit - e->buf;
+ size_t new_size = upb_roundup_pow2(bytes + (e->limit - e->ptr));
+ char *new_buf = upb_realloc(e->alloc, e->buf, old_size, new_size);
+
+ if (!new_buf) encode_err(e);
+
+ /* We want previous data at the end, realloc() put it at the beginning. */
+ if (old_size > 0) {
+ memmove(new_buf + new_size - old_size, e->buf, old_size);
+ }
+
+ e->ptr = new_buf + new_size - (e->limit - e->ptr);
+ e->limit = new_buf + new_size;
+ e->buf = new_buf;
+
+ e->ptr -= bytes;
+}
+
+/* Call to ensure that at least "bytes" bytes are available for writing at
+ * e->ptr. Returns false if the bytes could not be allocated. */
+UPB_FORCEINLINE
+static void encode_reserve(upb_encstate *e, size_t bytes) {
+ if ((size_t)(e->ptr - e->buf) < bytes) {
+ encode_growbuffer(e, bytes);
+ return;
+ }
+
+ e->ptr -= bytes;
+}
+
+/* Writes the given bytes to the buffer, handling reserve/advance. */
+static void encode_bytes(upb_encstate *e, const void *data, size_t len) {
+ if (len == 0) return; /* memcpy() with zero size is UB */
+ encode_reserve(e, len);
+ memcpy(e->ptr, data, len);
+}
+
+static void encode_fixed64(upb_encstate *e, uint64_t val) {
+ val = _upb_be_swap64(val);
+ encode_bytes(e, &val, sizeof(uint64_t));
+}
+
+static void encode_fixed32(upb_encstate *e, uint32_t val) {
+ val = _upb_be_swap32(val);
+ encode_bytes(e, &val, sizeof(uint32_t));
+}
+
+UPB_NOINLINE
+static void encode_longvarint(upb_encstate *e, uint64_t val) {
+ size_t len;
+ char *start;
+
+ encode_reserve(e, UPB_PB_VARINT_MAX_LEN);
+ len = encode_varint64(val, e->ptr);
+ start = e->ptr + UPB_PB_VARINT_MAX_LEN - len;
+ memmove(start, e->ptr, len);
+ e->ptr = start;
+}
+
+UPB_FORCEINLINE
+static void encode_varint(upb_encstate *e, uint64_t val) {
+ if (val < 128 && e->ptr != e->buf) {
+ --e->ptr;
+ *e->ptr = val;
+ } else {
+ encode_longvarint(e, val);
+ }
+}
+
+static void encode_double(upb_encstate *e, double d) {
+ uint64_t u64;
+ UPB_ASSERT(sizeof(double) == sizeof(uint64_t));
+ memcpy(&u64, &d, sizeof(uint64_t));
+ encode_fixed64(e, u64);
+}
+
+static void encode_float(upb_encstate *e, float d) {
+ uint32_t u32;
+ UPB_ASSERT(sizeof(float) == sizeof(uint32_t));
+ memcpy(&u32, &d, sizeof(uint32_t));
+ encode_fixed32(e, u32);
+}
+
+static void encode_tag(upb_encstate *e, uint32_t field_number,
+ uint8_t wire_type) {
+ encode_varint(e, (field_number << 3) | wire_type);
+}
+
+static void encode_fixedarray(upb_encstate *e, const upb_array *arr,
+ size_t elem_size, uint32_t tag) {
+ size_t bytes = arr->len * elem_size;
+ const char* data = _upb_array_constptr(arr);
+ const char* ptr = data + bytes - elem_size;
+ if (tag) {
+ while (true) {
+ encode_bytes(e, ptr, elem_size);
+ encode_varint(e, tag);
+ if (ptr == data) break;
+ ptr -= elem_size;
+ }
+ } else {
+ encode_bytes(e, data, bytes);
+ }
+}
+
+static void encode_message(upb_encstate *e, const char *msg,
+ const upb_msglayout *m, size_t *size);
+
+static void encode_scalar(upb_encstate *e, const void *_field_mem,
+ const upb_msglayout *m, const upb_msglayout_field *f,
+ bool skip_zero_value) {
+ const char *field_mem = _field_mem;
+ int wire_type;
+
+#define CASE(ctype, type, wtype, encodeval) \
+ { \
+ ctype val = *(ctype *)field_mem; \
+ if (skip_zero_value && val == 0) { \
+ return; \
+ } \
+ encode_##type(e, encodeval); \
+ wire_type = wtype; \
+ break; \
+ }
+
+ switch (f->descriptortype) {
+ case UPB_DESCRIPTOR_TYPE_DOUBLE:
+ CASE(double, double, UPB_WIRE_TYPE_64BIT, val);
+ case UPB_DESCRIPTOR_TYPE_FLOAT:
+ CASE(float, float, UPB_WIRE_TYPE_32BIT, val);
+ case UPB_DESCRIPTOR_TYPE_INT64:
+ case UPB_DESCRIPTOR_TYPE_UINT64:
+ CASE(uint64_t, varint, UPB_WIRE_TYPE_VARINT, val);
+ case UPB_DESCRIPTOR_TYPE_UINT32:
+ CASE(uint32_t, varint, UPB_WIRE_TYPE_VARINT, val);
+ case UPB_DESCRIPTOR_TYPE_INT32:
+ case UPB_DESCRIPTOR_TYPE_ENUM:
+ CASE(int32_t, varint, UPB_WIRE_TYPE_VARINT, (int64_t)val);
+ case UPB_DESCRIPTOR_TYPE_SFIXED64:
+ case UPB_DESCRIPTOR_TYPE_FIXED64:
+ CASE(uint64_t, fixed64, UPB_WIRE_TYPE_64BIT, val);
+ case UPB_DESCRIPTOR_TYPE_FIXED32:
+ case UPB_DESCRIPTOR_TYPE_SFIXED32:
+ CASE(uint32_t, fixed32, UPB_WIRE_TYPE_32BIT, val);
+ case UPB_DESCRIPTOR_TYPE_BOOL:
+ CASE(bool, varint, UPB_WIRE_TYPE_VARINT, val);
+ case UPB_DESCRIPTOR_TYPE_SINT32:
+ CASE(int32_t, varint, UPB_WIRE_TYPE_VARINT, encode_zz32(val));
+ case UPB_DESCRIPTOR_TYPE_SINT64:
+ CASE(int64_t, varint, UPB_WIRE_TYPE_VARINT, encode_zz64(val));
+ case UPB_DESCRIPTOR_TYPE_STRING:
+ case UPB_DESCRIPTOR_TYPE_BYTES: {
+ upb_strview view = *(upb_strview*)field_mem;
+ if (skip_zero_value && view.size == 0) {
+ return;
+ }
+ encode_bytes(e, view.data, view.size);
+ encode_varint(e, view.size);
+ wire_type = UPB_WIRE_TYPE_DELIMITED;
+ break;
+ }
+ case UPB_DESCRIPTOR_TYPE_GROUP: {
+ size_t size;
+ void *submsg = *(void **)field_mem;
+ const upb_msglayout *subm = m->submsgs[f->submsg_index];
+ if (submsg == NULL) {
+ return;
+ }
+ if (--e->depth == 0) encode_err(e);
+ encode_tag(e, f->number, UPB_WIRE_TYPE_END_GROUP);
+ encode_message(e, submsg, subm, &size);
+ wire_type = UPB_WIRE_TYPE_START_GROUP;
+ e->depth++;
+ break;
+ }
+ case UPB_DESCRIPTOR_TYPE_MESSAGE: {
+ size_t size;
+ void *submsg = *(void **)field_mem;
+ const upb_msglayout *subm = m->submsgs[f->submsg_index];
+ if (submsg == NULL) {
+ return;
+ }
+ if (--e->depth == 0) encode_err(e);
+ encode_message(e, submsg, subm, &size);
+ encode_varint(e, size);
+ wire_type = UPB_WIRE_TYPE_DELIMITED;
+ e->depth++;
+ break;
+ }
+ default:
+ UPB_UNREACHABLE();
+ }
+#undef CASE
+
+ encode_tag(e, f->number, wire_type);
+}
+
+static void encode_array(upb_encstate *e, const char *field_mem,
+ const upb_msglayout *m, const upb_msglayout_field *f) {
+ const upb_array *arr = *(const upb_array**)field_mem;
+ bool packed = f->label == _UPB_LABEL_PACKED;
+ size_t pre_len = e->limit - e->ptr;
+
+ if (arr == NULL || arr->len == 0) {
+ return;
+ }
+
+#define VARINT_CASE(ctype, encode) \
+ { \
+ const ctype *start = _upb_array_constptr(arr); \
+ const ctype *ptr = start + arr->len; \
+ uint32_t tag = packed ? 0 : (f->number << 3) | UPB_WIRE_TYPE_VARINT; \
+ do { \
+ ptr--; \
+ encode_varint(e, encode); \
+ if (tag) encode_varint(e, tag); \
+ } while (ptr != start); \
+ } \
+ break;
+
+#define TAG(wire_type) (packed ? 0 : (f->number << 3 | wire_type))
+
+ switch (f->descriptortype) {
+ case UPB_DESCRIPTOR_TYPE_DOUBLE:
+ encode_fixedarray(e, arr, sizeof(double), TAG(UPB_WIRE_TYPE_64BIT));
+ break;
+ case UPB_DESCRIPTOR_TYPE_FLOAT:
+ encode_fixedarray(e, arr, sizeof(float), TAG(UPB_WIRE_TYPE_32BIT));
+ break;
+ case UPB_DESCRIPTOR_TYPE_SFIXED64:
+ case UPB_DESCRIPTOR_TYPE_FIXED64:
+ encode_fixedarray(e, arr, sizeof(uint64_t), TAG(UPB_WIRE_TYPE_64BIT));
+ break;
+ case UPB_DESCRIPTOR_TYPE_FIXED32:
+ case UPB_DESCRIPTOR_TYPE_SFIXED32:
+ encode_fixedarray(e, arr, sizeof(uint32_t), TAG(UPB_WIRE_TYPE_32BIT));
+ break;
+ case UPB_DESCRIPTOR_TYPE_INT64:
+ case UPB_DESCRIPTOR_TYPE_UINT64:
+ VARINT_CASE(uint64_t, *ptr);
+ case UPB_DESCRIPTOR_TYPE_UINT32:
+ VARINT_CASE(uint32_t, *ptr);
+ case UPB_DESCRIPTOR_TYPE_INT32:
+ case UPB_DESCRIPTOR_TYPE_ENUM:
+ VARINT_CASE(int32_t, (int64_t)*ptr);
+ case UPB_DESCRIPTOR_TYPE_BOOL:
+ VARINT_CASE(bool, *ptr);
+ case UPB_DESCRIPTOR_TYPE_SINT32:
+ VARINT_CASE(int32_t, encode_zz32(*ptr));
+ case UPB_DESCRIPTOR_TYPE_SINT64:
+ VARINT_CASE(int64_t, encode_zz64(*ptr));
+ case UPB_DESCRIPTOR_TYPE_STRING:
+ case UPB_DESCRIPTOR_TYPE_BYTES: {
+ const upb_strview *start = _upb_array_constptr(arr);
+ const upb_strview *ptr = start + arr->len;
+ do {
+ ptr--;
+ encode_bytes(e, ptr->data, ptr->size);
+ encode_varint(e, ptr->size);
+ encode_tag(e, f->number, UPB_WIRE_TYPE_DELIMITED);
+ } while (ptr != start);
+ return;
+ }
+ case UPB_DESCRIPTOR_TYPE_GROUP: {
+ const void *const*start = _upb_array_constptr(arr);
+ const void *const*ptr = start + arr->len;
+ const upb_msglayout *subm = m->submsgs[f->submsg_index];
+ if (--e->depth == 0) encode_err(e);
+ do {
+ size_t size;
+ ptr--;
+ encode_tag(e, f->number, UPB_WIRE_TYPE_END_GROUP);
+ encode_message(e, *ptr, subm, &size);
+ encode_tag(e, f->number, UPB_WIRE_TYPE_START_GROUP);
+ } while (ptr != start);
+ e->depth++;
+ return;
+ }
+ case UPB_DESCRIPTOR_TYPE_MESSAGE: {
+ const void *const*start = _upb_array_constptr(arr);
+ const void *const*ptr = start + arr->len;
+ const upb_msglayout *subm = m->submsgs[f->submsg_index];
+ if (--e->depth == 0) encode_err(e);
+ do {
+ size_t size;
+ ptr--;
+ encode_message(e, *ptr, subm, &size);
+ encode_varint(e, size);
+ encode_tag(e, f->number, UPB_WIRE_TYPE_DELIMITED);
+ } while (ptr != start);
+ e->depth++;
+ return;
+ }
+ }
+#undef VARINT_CASE
+
+ if (packed) {
+ encode_varint(e, e->limit - e->ptr - pre_len);
+ encode_tag(e, f->number, UPB_WIRE_TYPE_DELIMITED);
+ }
+}
+
+static void encode_mapentry(upb_encstate *e, uint32_t number,
+ const upb_msglayout *layout,
+ const upb_map_entry *ent) {
+ const upb_msglayout_field *key_field = &layout->fields[0];
+ const upb_msglayout_field *val_field = &layout->fields[1];
+ size_t pre_len = e->limit - e->ptr;
+ size_t size;
+ encode_scalar(e, &ent->v, layout, val_field, false);
+ encode_scalar(e, &ent->k, layout, key_field, false);
+ size = (e->limit - e->ptr) - pre_len;
+ encode_varint(e, size);
+ encode_tag(e, number, UPB_WIRE_TYPE_DELIMITED);
+}
+
+static void encode_map(upb_encstate *e, const char *field_mem,
+ const upb_msglayout *m, const upb_msglayout_field *f) {
+ const upb_map *map = *(const upb_map**)field_mem;
+ const upb_msglayout *layout = m->submsgs[f->submsg_index];
+ UPB_ASSERT(layout->field_count == 2);
+
+ if (map == NULL) return;
+
+ if (e->options & UPB_ENCODE_DETERMINISTIC) {
+ _upb_sortedmap sorted;
+ _upb_mapsorter_pushmap(&e->sorter, layout->fields[0].descriptortype, map,
+ &sorted);
+ upb_map_entry ent;
+ while (_upb_sortedmap_next(&e->sorter, map, &sorted, &ent)) {
+ encode_mapentry(e, f->number, layout, &ent);
+ }
+ _upb_mapsorter_popmap(&e->sorter, &sorted);
+ } else {
+ upb_strtable_iter i;
+ upb_strtable_begin(&i, &map->table);
+ for(; !upb_strtable_done(&i); upb_strtable_next(&i)) {
+ upb_strview key = upb_strtable_iter_key(&i);
+ const upb_value val = upb_strtable_iter_value(&i);
+ upb_map_entry ent;
+ _upb_map_fromkey(key, &ent.k, map->key_size);
+ _upb_map_fromvalue(val, &ent.v, map->val_size);
+ encode_mapentry(e, f->number, layout, &ent);
+ }
+ }
+}
+
+static void encode_scalarfield(upb_encstate *e, const char *msg,
+ const upb_msglayout *m,
+ const upb_msglayout_field *f) {
+ bool skip_empty = false;
+ if (f->presence == 0) {
+ /* Proto3 presence. */
+ skip_empty = true;
+ } else if (f->presence > 0) {
+ /* Proto2 presence: hasbit. */
+ if (!_upb_hasbit_field(msg, f)) return;
+ } else {
+ /* Field is in a oneof. */
+ if (_upb_getoneofcase_field(msg, f) != f->number) return;
+ }
+ encode_scalar(e, msg + f->offset, m, f, skip_empty);
+}
+
+static void encode_message(upb_encstate *e, const char *msg,
+ const upb_msglayout *m, size_t *size) {
+ size_t pre_len = e->limit - e->ptr;
+ const upb_msglayout_field *f = &m->fields[m->field_count];
+ const upb_msglayout_field *first = &m->fields[0];
+
+ if ((e->options & UPB_ENCODE_SKIPUNKNOWN) == 0) {
+ size_t unknown_size;
+ const char *unknown = upb_msg_getunknown(msg, &unknown_size);
+
+ if (unknown) {
+ encode_bytes(e, unknown, unknown_size);
+ }
+ }
+
+ while (f != first) {
+ f--;
+ if (_upb_isrepeated(f)) {
+ encode_array(e, msg + f->offset, m, f);
+ } else if (f->label == _UPB_LABEL_MAP) {
+ encode_map(e, msg + f->offset, m, f);
+ } else {
+ encode_scalarfield(e, msg, m, f);
+ }
+ }
+
+ *size = (e->limit - e->ptr) - pre_len;
+}
+
+char *upb_encode_ex(const void *msg, const upb_msglayout *l, int options,
+ upb_arena *arena, size_t *size) {
+ upb_encstate e;
+ unsigned depth = (unsigned)options >> 16;
+
+ e.alloc = upb_arena_alloc(arena);
+ e.buf = NULL;
+ e.limit = NULL;
+ e.ptr = NULL;
+ e.depth = depth ? depth : 64;
+ e.options = options;
+ _upb_mapsorter_init(&e.sorter);
+ char *ret = NULL;
+
+ if (UPB_SETJMP(e.err)) {
+ *size = 0;
+ ret = NULL;
+ } else {
+ encode_message(&e, msg, l, size);
+ *size = e.limit - e.ptr;
+ if (*size == 0) {
+ static char ch;
+ ret = &ch;
+ } else {
+ UPB_ASSERT(e.ptr);
+ ret = e.ptr;
+ }
+ }
+
+ _upb_mapsorter_destroy(&e.sorter);
+ return ret;
+}
+
+
+
+
+/** upb_msg *******************************************************************/
+
+static const size_t overhead = sizeof(upb_msg_internal);
+
+static const upb_msg_internal *upb_msg_getinternal_const(const upb_msg *msg) {
+ ptrdiff_t size = sizeof(upb_msg_internal);
+ return (upb_msg_internal*)((char*)msg - size);
+}
+
+upb_msg *_upb_msg_new(const upb_msglayout *l, upb_arena *a) {
+ return _upb_msg_new_inl(l, a);
+}
+
+void _upb_msg_clear(upb_msg *msg, const upb_msglayout *l) {
+ void *mem = UPB_PTR_AT(msg, -sizeof(upb_msg_internal), char);
+ memset(mem, 0, upb_msg_sizeof(l));
+}
+
+bool _upb_msg_addunknown(upb_msg *msg, const char *data, size_t len,
+ upb_arena *arena) {
+
+ upb_msg_internal *in = upb_msg_getinternal(msg);
+ if (!in->unknown) {
+ size_t size = 128;
+ while (size < len) size *= 2;
+ in->unknown = upb_arena_malloc(arena, size + overhead);
+ if (!in->unknown) return false;
+ in->unknown->size = size;
+ in->unknown->len = 0;
+ } else if (in->unknown->size - in->unknown->len < len) {
+ size_t need = in->unknown->len + len;
+ size_t size = in->unknown->size;
+ while (size < need) size *= 2;
+ in->unknown = upb_arena_realloc(
+ arena, in->unknown, in->unknown->size + overhead, size + overhead);
+ if (!in->unknown) return false;
+ in->unknown->size = size;
+ }
+ memcpy(UPB_PTR_AT(in->unknown + 1, in->unknown->len, char), data, len);
+ in->unknown->len += len;
+ return true;
+}
+
+void _upb_msg_discardunknown_shallow(upb_msg *msg) {
+ upb_msg_internal *in = upb_msg_getinternal(msg);
+ if (in->unknown) {
+ in->unknown->len = 0;
+ }
+}
+
+const char *upb_msg_getunknown(const upb_msg *msg, size_t *len) {
+ const upb_msg_internal *in = upb_msg_getinternal_const(msg);
+ if (in->unknown) {
+ *len = in->unknown->len;
+ return (char*)(in->unknown + 1);
+ } else {
+ *len = 0;
+ return NULL;
+ }
+}
+
+/** upb_array *****************************************************************/
+
+bool _upb_array_realloc(upb_array *arr, size_t min_size, upb_arena *arena) {
+ size_t new_size = UPB_MAX(arr->size, 4);
+ int elem_size_lg2 = arr->data & 7;
+ size_t old_bytes = arr->size << elem_size_lg2;
+ size_t new_bytes;
+ void* ptr = _upb_array_ptr(arr);
+
+ /* Log2 ceiling of size. */
+ while (new_size < min_size) new_size *= 2;
+
+ new_bytes = new_size << elem_size_lg2;
+ ptr = upb_arena_realloc(arena, ptr, old_bytes, new_bytes);
+
+ if (!ptr) {
+ return false;
+ }
+
+ arr->data = _upb_tag_arrptr(ptr, elem_size_lg2);
+ arr->size = new_size;
+ return true;
+}
+
+static upb_array *getorcreate_array(upb_array **arr_ptr, int elem_size_lg2,
+ upb_arena *arena) {
+ upb_array *arr = *arr_ptr;
+ if (!arr) {
+ arr = _upb_array_new(arena, 4, elem_size_lg2);
+ if (!arr) return NULL;
+ *arr_ptr = arr;
+ }
+ return arr;
+}
+
+void *_upb_array_resize_fallback(upb_array **arr_ptr, size_t size,
+ int elem_size_lg2, upb_arena *arena) {
+ upb_array *arr = getorcreate_array(arr_ptr, elem_size_lg2, arena);
+ return arr && _upb_array_resize(arr, size, arena) ? _upb_array_ptr(arr)
+ : NULL;
+}
+
+bool _upb_array_append_fallback(upb_array **arr_ptr, const void *value,
+ int elem_size_lg2, upb_arena *arena) {
+ upb_array *arr = getorcreate_array(arr_ptr, elem_size_lg2, arena);
+ if (!arr) return false;
+
+ size_t elems = arr->len;
+
+ if (!_upb_array_resize(arr, elems + 1, arena)) {
+ return false;
+ }
+
+ char *data = _upb_array_ptr(arr);
+ memcpy(data + (elems << elem_size_lg2), value, 1 << elem_size_lg2);
+ return true;
+}
+
+/** upb_map *******************************************************************/
+
+upb_map *_upb_map_new(upb_arena *a, size_t key_size, size_t value_size) {
+ upb_map *map = upb_arena_malloc(a, sizeof(upb_map));
+
+ if (!map) {
+ return NULL;
+ }
+
+ upb_strtable_init2(&map->table, UPB_CTYPE_INT32, 4, upb_arena_alloc(a));
+ map->key_size = key_size;
+ map->val_size = value_size;
+
+ return map;
+}
+
+static void _upb_mapsorter_getkeys(const void *_a, const void *_b, void *a_key,
+ void *b_key, size_t size) {
+ const upb_tabent *const*a = _a;
+ const upb_tabent *const*b = _b;
+ upb_strview a_tabkey = upb_tabstrview((*a)->key);
+ upb_strview b_tabkey = upb_tabstrview((*b)->key);
+ _upb_map_fromkey(a_tabkey, a_key, size);
+ _upb_map_fromkey(b_tabkey, b_key, size);
+}
+
+static int _upb_mapsorter_cmpi64(const void *_a, const void *_b) {
+ int64_t a, b;
+ _upb_mapsorter_getkeys(_a, _b, &a, &b, 8);
+ return a - b;
+}
+
+static int _upb_mapsorter_cmpu64(const void *_a, const void *_b) {
+ uint64_t a, b;
+ _upb_mapsorter_getkeys(_a, _b, &a, &b, 8);
+ return a - b;
+}
+
+static int _upb_mapsorter_cmpi32(const void *_a, const void *_b) {
+ int32_t a, b;
+ _upb_mapsorter_getkeys(_a, _b, &a, &b, 4);
+ return a - b;
+}
+
+static int _upb_mapsorter_cmpu32(const void *_a, const void *_b) {
+ uint32_t a, b;
+ _upb_mapsorter_getkeys(_a, _b, &a, &b, 4);
+ return a - b;
+}
+
+static int _upb_mapsorter_cmpbool(const void *_a, const void *_b) {
+ bool a, b;
+ _upb_mapsorter_getkeys(_a, _b, &a, &b, 1);
+ return a - b;
+}
+
+static int _upb_mapsorter_cmpstr(const void *_a, const void *_b) {
+ upb_strview a, b;
+ _upb_mapsorter_getkeys(_a, _b, &a, &b, UPB_MAPTYPE_STRING);
+ size_t common_size = UPB_MIN(a.size, b.size);
+ int cmp = memcmp(a.data, b.data, common_size);
+ if (cmp) return cmp;
+ return a.size - b.size;
+}
+
+bool _upb_mapsorter_pushmap(_upb_mapsorter *s, upb_descriptortype_t key_type,
+ const upb_map *map, _upb_sortedmap *sorted) {
+ int map_size = _upb_map_size(map);
+ sorted->start = s->size;
+ sorted->pos = sorted->start;
+ sorted->end = sorted->start + map_size;
+
+ /* Grow s->entries if necessary. */
+ if (sorted->end > s->cap) {
+ s->cap = _upb_lg2ceilsize(sorted->end);
+ s->entries = realloc(s->entries, s->cap * sizeof(*s->entries));
+ if (!s->entries) return false;
+ }
+
+ s->size = sorted->end;
+
+ /* Copy non-empty entries from the table to s->entries. */
+ upb_tabent const**dst = &s->entries[sorted->start];
+ const upb_tabent *src = map->table.t.entries;
+ const upb_tabent *end = src + upb_table_size(&map->table.t);
+ for (; src < end; src++) {
+ if (!upb_tabent_isempty(src)) {
+ *dst = src;
+ dst++;
+ }
+ }
+ UPB_ASSERT(dst == &s->entries[sorted->end]);
+
+ /* Sort entries according to the key type. */
+
+ int (*compar)(const void *, const void *);
+
+ switch (key_type) {
+ case UPB_DESCRIPTOR_TYPE_INT64:
+ case UPB_DESCRIPTOR_TYPE_SFIXED64:
+ case UPB_DESCRIPTOR_TYPE_SINT64:
+ compar = _upb_mapsorter_cmpi64;
+ break;
+ case UPB_DESCRIPTOR_TYPE_UINT64:
+ case UPB_DESCRIPTOR_TYPE_FIXED64:
+ compar = _upb_mapsorter_cmpu64;
+ break;
+ case UPB_DESCRIPTOR_TYPE_INT32:
+ case UPB_DESCRIPTOR_TYPE_SINT32:
+ case UPB_DESCRIPTOR_TYPE_SFIXED32:
+ case UPB_DESCRIPTOR_TYPE_ENUM:
+ compar = _upb_mapsorter_cmpi32;
+ break;
+ case UPB_DESCRIPTOR_TYPE_UINT32:
+ case UPB_DESCRIPTOR_TYPE_FIXED32:
+ compar = _upb_mapsorter_cmpu32;
+ break;
+ case UPB_DESCRIPTOR_TYPE_BOOL:
+ compar = _upb_mapsorter_cmpbool;
+ break;
+ case UPB_DESCRIPTOR_TYPE_STRING:
+ compar = _upb_mapsorter_cmpstr;
+ break;
+ default:
+ UPB_UNREACHABLE();
+ }
+
+ qsort(&s->entries[sorted->start], map_size, sizeof(*s->entries), compar);
+ return true;
+}
+/*
+** upb_table Implementation
+**
+** Implementation is heavily inspired by Lua's ltable.c.
+*/
+
+#include
+
+#include "third_party/wyhash/wyhash.h"
+
+/* Must be last. */
+
+#define UPB_MAXARRSIZE 16 /* 64k. */
+
+/* From Chromium. */
+#define ARRAY_SIZE(x) \
+ ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x])))))
+
+static const double MAX_LOAD = 0.85;
+
+/* The minimum utilization of the array part of a mixed hash/array table. This
+ * is a speed/memory-usage tradeoff (though it's not straightforward because of
+ * cache effects). The lower this is, the more memory we'll use. */
+static const double MIN_DENSITY = 0.1;
+
+bool is_pow2(uint64_t v) { return v == 0 || (v & (v - 1)) == 0; }
+
+int log2ceil(uint64_t v) {
+ int ret = 0;
+ bool pow2 = is_pow2(v);
+ while (v >>= 1) ret++;
+ ret = pow2 ? ret : ret + 1; /* Ceiling. */
+ return UPB_MIN(UPB_MAXARRSIZE, ret);
+}
+
+char *upb_strdup(const char *s, upb_alloc *a) {
+ return upb_strdup2(s, strlen(s), a);
+}
+
+char *upb_strdup2(const char *s, size_t len, upb_alloc *a) {
+ size_t n;
+ char *p;
+
+ /* Prevent overflow errors. */
+ if (len == SIZE_MAX) return NULL;
+ /* Always null-terminate, even if binary data; but don't rely on the input to
+ * have a null-terminating byte since it may be a raw binary buffer. */
+ n = len + 1;
+ p = upb_malloc(a, n);
+ if (p) {
+ memcpy(p, s, len);
+ p[len] = 0;
+ }
+ return p;
+}
+
+/* A type to represent the lookup key of either a strtable or an inttable. */
+typedef union {
+ uintptr_t num;
+ struct {
+ const char *str;
+ size_t len;
+ } str;
+} lookupkey_t;
+
+static lookupkey_t strkey2(const char *str, size_t len) {
+ lookupkey_t k;
+ k.str.str = str;
+ k.str.len = len;
+ return k;
+}
+
+static lookupkey_t intkey(uintptr_t key) {
+ lookupkey_t k;
+ k.num = key;
+ return k;
+}
+
+typedef uint32_t hashfunc_t(upb_tabkey key);
+typedef bool eqlfunc_t(upb_tabkey k1, lookupkey_t k2);
+
+/* Base table (shared code) ***************************************************/
+
+/* For when we need to cast away const. */
+static upb_tabent *mutable_entries(upb_table *t) {
+ return (upb_tabent*)t->entries;
+}
+
+static bool isfull(upb_table *t) {
+ return t->count == t->max_count;
+}
+
+static bool init(upb_table *t, uint8_t size_lg2, upb_alloc *a) {
+ size_t bytes;
+
+ t->count = 0;
+ t->size_lg2 = size_lg2;
+ t->mask = upb_table_size(t) ? upb_table_size(t) - 1 : 0;
+ t->max_count = upb_table_size(t) * MAX_LOAD;
+ bytes = upb_table_size(t) * sizeof(upb_tabent);
+ if (bytes > 0) {
+ t->entries = upb_malloc(a, bytes);
+ if (!t->entries) return false;
+ memset(mutable_entries(t), 0, bytes);
+ } else {
+ t->entries = NULL;
+ }
+ return true;
+}
+
+static void uninit(upb_table *t, upb_alloc *a) {
+ upb_free(a, mutable_entries(t));
+}
+
+static upb_tabent *emptyent(upb_table *t, upb_tabent *e) {
+ upb_tabent *begin = mutable_entries(t);
+ upb_tabent *end = begin + upb_table_size(t);
+ for (e = e + 1; e < end; e++) {
+ if (upb_tabent_isempty(e)) return e;
+ }
+ for (e = begin; e < end; e++) {
+ if (upb_tabent_isempty(e)) return e;
+ }
+ UPB_ASSERT(false);
+ return NULL;
+}
+
+static upb_tabent *getentry_mutable(upb_table *t, uint32_t hash) {
+ return (upb_tabent*)upb_getentry(t, hash);
+}
+
+static const upb_tabent *findentry(const upb_table *t, lookupkey_t key,
+ uint32_t hash, eqlfunc_t *eql) {
+ const upb_tabent *e;
+
+ if (t->size_lg2 == 0) return NULL;
+ e = upb_getentry(t, hash);
+ if (upb_tabent_isempty(e)) return NULL;
+ while (1) {
+ if (eql(e->key, key)) return e;
+ if ((e = e->next) == NULL) return NULL;
+ }
+}
+
+static upb_tabent *findentry_mutable(upb_table *t, lookupkey_t key,
+ uint32_t hash, eqlfunc_t *eql) {
+ return (upb_tabent*)findentry(t, key, hash, eql);
+}
+
+static bool lookup(const upb_table *t, lookupkey_t key, upb_value *v,
+ uint32_t hash, eqlfunc_t *eql) {
+ const upb_tabent *e = findentry(t, key, hash, eql);
+ if (e) {
+ if (v) {
+ _upb_value_setval(v, e->val.val);
+ }
+ return true;
+ } else {
+ return false;
+ }
+}
+
+/* The given key must not already exist in the table. */
+static void insert(upb_table *t, lookupkey_t key, upb_tabkey tabkey,
+ upb_value val, uint32_t hash,
+ hashfunc_t *hashfunc, eqlfunc_t *eql) {
+ upb_tabent *mainpos_e;
+ upb_tabent *our_e;
+
+ UPB_ASSERT(findentry(t, key, hash, eql) == NULL);
+
+ t->count++;
+ mainpos_e = getentry_mutable(t, hash);
+ our_e = mainpos_e;
+
+ if (upb_tabent_isempty(mainpos_e)) {
+ /* Our main position is empty; use it. */
+ our_e->next = NULL;
+ } else {
+ /* Collision. */
+ upb_tabent *new_e = emptyent(t, mainpos_e);
+ /* Head of collider's chain. */
+ upb_tabent *chain = getentry_mutable(t, hashfunc(mainpos_e->key));
+ if (chain == mainpos_e) {
+ /* Existing ent is in its main position (it has the same hash as us, and
+ * is the head of our chain). Insert to new ent and append to this chain. */
+ new_e->next = mainpos_e->next;
+ mainpos_e->next = new_e;
+ our_e = new_e;
+ } else {
+ /* Existing ent is not in its main position (it is a node in some other
+ * chain). This implies that no existing ent in the table has our hash.
+ * Evict it (updating its chain) and use its ent for head of our chain. */
+ *new_e = *mainpos_e; /* copies next. */
+ while (chain->next != mainpos_e) {
+ chain = (upb_tabent*)chain->next;
+ UPB_ASSERT(chain);
+ }
+ chain->next = new_e;
+ our_e = mainpos_e;
+ our_e->next = NULL;
+ }
+ }
+ our_e->key = tabkey;
+ our_e->val.val = val.val;
+ UPB_ASSERT(findentry(t, key, hash, eql) == our_e);
+}
+
+static bool rm(upb_table *t, lookupkey_t key, upb_value *val,
+ upb_tabkey *removed, uint32_t hash, eqlfunc_t *eql) {
+ upb_tabent *chain = getentry_mutable(t, hash);
+ if (upb_tabent_isempty(chain)) return false;
+ if (eql(chain->key, key)) {
+ /* Element to remove is at the head of its chain. */
+ t->count--;
+ if (val) _upb_value_setval(val, chain->val.val);
+ if (removed) *removed = chain->key;
+ if (chain->next) {
+ upb_tabent *move = (upb_tabent*)chain->next;
+ *chain = *move;
+ move->key = 0; /* Make the slot empty. */
+ } else {
+ chain->key = 0; /* Make the slot empty. */
+ }
+ return true;
+ } else {
+ /* Element to remove is either in a non-head position or not in the
+ * table. */
+ while (chain->next && !eql(chain->next->key, key)) {
+ chain = (upb_tabent*)chain->next;
+ }
+ if (chain->next) {
+ /* Found element to remove. */
+ upb_tabent *rm = (upb_tabent*)chain->next;
+ t->count--;
+ if (val) _upb_value_setval(val, chain->next->val.val);
+ if (removed) *removed = rm->key;
+ rm->key = 0; /* Make the slot empty. */
+ chain->next = rm->next;
+ return true;
+ } else {
+ /* Element to remove is not in the table. */
+ return false;
+ }
+ }
+}
+
+static size_t next(const upb_table *t, size_t i) {
+ do {
+ if (++i >= upb_table_size(t))
+ return SIZE_MAX - 1; /* Distinct from -1. */
+ } while(upb_tabent_isempty(&t->entries[i]));
+
+ return i;
+}
+
+static size_t begin(const upb_table *t) {
+ return next(t, -1);
+}
+
+
+/* upb_strtable ***************************************************************/
+
+/* A simple "subclass" of upb_table that only adds a hash function for strings. */
+
+static upb_tabkey strcopy(lookupkey_t k2, upb_alloc *a) {
+ uint32_t len = (uint32_t) k2.str.len;
+ char *str = upb_malloc(a, k2.str.len + sizeof(uint32_t) + 1);
+ if (str == NULL) return 0;
+ memcpy(str, &len, sizeof(uint32_t));
+ if (k2.str.len) memcpy(str + sizeof(uint32_t), k2.str.str, k2.str.len);
+ str[sizeof(uint32_t) + k2.str.len] = '\0';
+ return (uintptr_t)str;
+}
+
+static uint32_t table_hash(const char *p, size_t n) {
+ return wyhash(p, n, 0, _wyp);
+}
+
+static uint32_t strhash(upb_tabkey key) {
+ uint32_t len;
+ char *str = upb_tabstr(key, &len);
+ return table_hash(str, len);
+}
+
+static bool streql(upb_tabkey k1, lookupkey_t k2) {
+ uint32_t len;
+ char *str = upb_tabstr(k1, &len);
+ return len == k2.str.len && (len == 0 || memcmp(str, k2.str.str, len) == 0);
+}
+
+bool upb_strtable_init2(upb_strtable *t, upb_ctype_t ctype,
+ size_t expected_size, upb_alloc *a) {
+ UPB_UNUSED(ctype); /* TODO(haberman): rm */
+ // Multiply by approximate reciprocal of MAX_LOAD (0.85), with pow2 denominator.
+ size_t need_entries = (expected_size + 1) * 1204 / 1024;
+ UPB_ASSERT(need_entries >= expected_size * 0.85);
+ int size_lg2 = _upb_lg2ceil(need_entries);
+ return init(&t->t, size_lg2, a);
+}
+
+void upb_strtable_clear(upb_strtable *t) {
+ size_t bytes = upb_table_size(&t->t) * sizeof(upb_tabent);
+ t->t.count = 0;
+ memset((char*)t->t.entries, 0, bytes);
+}
+
+void upb_strtable_uninit2(upb_strtable *t, upb_alloc *a) {
+ size_t i;
+ for (i = 0; i < upb_table_size(&t->t); i++)
+ upb_free(a, (void*)t->t.entries[i].key);
+ uninit(&t->t, a);
+}
+
+bool upb_strtable_resize(upb_strtable *t, size_t size_lg2, upb_alloc *a) {
+ upb_strtable new_table;
+ upb_strtable_iter i;
+
+ if (!init(&new_table.t, size_lg2, a))
+ return false;
+ upb_strtable_begin(&i, t);
+ for ( ; !upb_strtable_done(&i); upb_strtable_next(&i)) {
+ upb_strview key = upb_strtable_iter_key(&i);
+ upb_strtable_insert3(
+ &new_table, key.data, key.size,
+ upb_strtable_iter_value(&i), a);
+ }
+ upb_strtable_uninit2(t, a);
+ *t = new_table;
+ return true;
+}
+
+bool upb_strtable_insert3(upb_strtable *t, const char *k, size_t len,
+ upb_value v, upb_alloc *a) {
+ lookupkey_t key;
+ upb_tabkey tabkey;
+ uint32_t hash;
+
+ if (isfull(&t->t)) {
+ /* Need to resize. New table of double the size, add old elements to it. */
+ if (!upb_strtable_resize(t, t->t.size_lg2 + 1, a)) {
+ return false;
+ }
+ }
+
+ key = strkey2(k, len);
+ tabkey = strcopy(key, a);
+ if (tabkey == 0) return false;
+
+ hash = table_hash(key.str.str, key.str.len);
+ insert(&t->t, key, tabkey, v, hash, &strhash, &streql);
+ return true;
+}
+
+bool upb_strtable_lookup2(const upb_strtable *t, const char *key, size_t len,
+ upb_value *v) {
+ uint32_t hash = table_hash(key, len);
+ return lookup(&t->t, strkey2(key, len), v, hash, &streql);
+}
+
+bool upb_strtable_remove3(upb_strtable *t, const char *key, size_t len,
+ upb_value *val, upb_alloc *alloc) {
+ uint32_t hash = table_hash(key, len);
+ upb_tabkey tabkey;
+ if (rm(&t->t, strkey2(key, len), val, &tabkey, hash, &streql)) {
+ if (alloc) {
+ /* Arena-based allocs don't need to free and won't pass this. */
+ upb_free(alloc, (void*)tabkey);
+ }
+ return true;
+ } else {
+ return false;
+ }
+}
+
+/* Iteration */
+
+void upb_strtable_begin(upb_strtable_iter *i, const upb_strtable *t) {
+ i->t = t;
+ i->index = begin(&t->t);
+}
+
+void upb_strtable_next(upb_strtable_iter *i) {
+ i->index = next(&i->t->t, i->index);
+}
+
+bool upb_strtable_done(const upb_strtable_iter *i) {
+ if (!i->t) return true;
+ return i->index >= upb_table_size(&i->t->t) ||
+ upb_tabent_isempty(str_tabent(i));
+}
+
+upb_strview upb_strtable_iter_key(const upb_strtable_iter *i) {
+ upb_strview key;
+ uint32_t len;
+ UPB_ASSERT(!upb_strtable_done(i));
+ key.data = upb_tabstr(str_tabent(i)->key, &len);
+ key.size = len;
+ return key;
+}
+
+upb_value upb_strtable_iter_value(const upb_strtable_iter *i) {
+ UPB_ASSERT(!upb_strtable_done(i));
+ return _upb_value_val(str_tabent(i)->val.val);
+}
+
+void upb_strtable_iter_setdone(upb_strtable_iter *i) {
+ i->t = NULL;
+ i->index = SIZE_MAX;
+}
+
+bool upb_strtable_iter_isequal(const upb_strtable_iter *i1,
+ const upb_strtable_iter *i2) {
+ if (upb_strtable_done(i1) && upb_strtable_done(i2))
+ return true;
+ return i1->t == i2->t && i1->index == i2->index;
+}
+
+
+/* upb_inttable ***************************************************************/
+
+/* For inttables we use a hybrid structure where small keys are kept in an
+ * array and large keys are put in the hash table. */
+
+static uint32_t inthash(upb_tabkey key) { return upb_inthash(key); }
+
+static bool inteql(upb_tabkey k1, lookupkey_t k2) {
+ return k1 == k2.num;
+}
+
+static upb_tabval *mutable_array(upb_inttable *t) {
+ return (upb_tabval*)t->array;
+}
+
+static upb_tabval *inttable_val(upb_inttable *t, uintptr_t key) {
+ if (key < t->array_size) {
+ return upb_arrhas(t->array[key]) ? &(mutable_array(t)[key]) : NULL;
+ } else {
+ upb_tabent *e =
+ findentry_mutable(&t->t, intkey(key), upb_inthash(key), &inteql);
+ return e ? &e->val : NULL;
+ }
+}
+
+static const upb_tabval *inttable_val_const(const upb_inttable *t,
+ uintptr_t key) {
+ return inttable_val((upb_inttable*)t, key);
+}
+
+size_t upb_inttable_count(const upb_inttable *t) {
+ return t->t.count + t->array_count;
+}
+
+static void check(upb_inttable *t) {
+ UPB_UNUSED(t);
+#if defined(UPB_DEBUG_TABLE) && !defined(NDEBUG)
+ {
+ /* This check is very expensive (makes inserts/deletes O(N)). */
+ size_t count = 0;
+ upb_inttable_iter i;
+ upb_inttable_begin(&i, t);
+ for(; !upb_inttable_done(&i); upb_inttable_next(&i), count++) {
+ UPB_ASSERT(upb_inttable_lookup(t, upb_inttable_iter_key(&i), NULL));
+ }
+ UPB_ASSERT(count == upb_inttable_count(t));
+ }
+#endif
+}
+
+bool upb_inttable_sizedinit(upb_inttable *t, size_t asize, int hsize_lg2,
+ upb_alloc *a) {
+ size_t array_bytes;
+
+ if (!init(&t->t, hsize_lg2, a)) return false;
+ /* Always make the array part at least 1 long, so that we know key 0
+ * won't be in the hash part, which simplifies things. */
+ t->array_size = UPB_MAX(1, asize);
+ t->array_count = 0;
+ array_bytes = t->array_size * sizeof(upb_value);
+ t->array = upb_malloc(a, array_bytes);
+ if (!t->array) {
+ uninit(&t->t, a);
+ return false;
+ }
+ memset(mutable_array(t), 0xff, array_bytes);
+ check(t);
+ return true;
+}
+
+bool upb_inttable_init2(upb_inttable *t, upb_ctype_t ctype, upb_alloc *a) {
+ UPB_UNUSED(ctype); /* TODO(haberman): rm */
+ return upb_inttable_sizedinit(t, 0, 4, a);
+}
+
+void upb_inttable_uninit2(upb_inttable *t, upb_alloc *a) {
+ uninit(&t->t, a);
+ upb_free(a, mutable_array(t));
+}
+
+bool upb_inttable_insert2(upb_inttable *t, uintptr_t key, upb_value val,
+ upb_alloc *a) {
+ upb_tabval tabval;
+ tabval.val = val.val;
+ UPB_ASSERT(upb_arrhas(tabval)); /* This will reject (uint64_t)-1. Fix this. */
+
+ if (key < t->array_size) {
+ UPB_ASSERT(!upb_arrhas(t->array[key]));
+ t->array_count++;
+ mutable_array(t)[key].val = val.val;
+ } else {
+ if (isfull(&t->t)) {
+ /* Need to resize the hash part, but we re-use the array part. */
+ size_t i;
+ upb_table new_table;
+
+ if (!init(&new_table, t->t.size_lg2 + 1, a)) {
+ return false;
+ }
+
+ for (i = begin(&t->t); i < upb_table_size(&t->t); i = next(&t->t, i)) {
+ const upb_tabent *e = &t->t.entries[i];
+ uint32_t hash;
+ upb_value v;
+
+ _upb_value_setval(&v, e->val.val);
+ hash = upb_inthash(e->key);
+ insert(&new_table, intkey(e->key), e->key, v, hash, &inthash, &inteql);
+ }
+
+ UPB_ASSERT(t->t.count == new_table.count);
+
+ uninit(&t->t, a);
+ t->t = new_table;
+ }
+ insert(&t->t, intkey(key), key, val, upb_inthash(key), &inthash, &inteql);
+ }
+ check(t);
+ return true;
+}
+
+bool upb_inttable_lookup(const upb_inttable *t, uintptr_t key, upb_value *v) {
+ const upb_tabval *table_v = inttable_val_const(t, key);
+ if (!table_v) return false;
+ if (v) _upb_value_setval(v, table_v->val);
+ return true;
+}
+
+bool upb_inttable_replace(upb_inttable *t, uintptr_t key, upb_value val) {
+ upb_tabval *table_v = inttable_val(t, key);
+ if (!table_v) return false;
+ table_v->val = val.val;
+ return true;
+}
+
+bool upb_inttable_remove(upb_inttable *t, uintptr_t key, upb_value *val) {
+ bool success;
+ if (key < t->array_size) {
+ if (upb_arrhas(t->array[key])) {
+ upb_tabval empty = UPB_TABVALUE_EMPTY_INIT;
+ t->array_count--;
+ if (val) {
+ _upb_value_setval(val, t->array[key].val);
+ }
+ mutable_array(t)[key] = empty;
+ success = true;
+ } else {
+ success = false;
+ }
+ } else {
+ success = rm(&t->t, intkey(key), val, NULL, upb_inthash(key), &inteql);
+ }
+ check(t);
+ return success;
+}
+
+bool upb_inttable_insertptr2(upb_inttable *t, const void *key, upb_value val,
+ upb_alloc *a) {
+ return upb_inttable_insert2(t, (uintptr_t)key, val, a);
+}
+
+bool upb_inttable_lookupptr(const upb_inttable *t, const void *key,
+ upb_value *v) {
+ return upb_inttable_lookup(t, (uintptr_t)key, v);
+}
+
+bool upb_inttable_removeptr(upb_inttable *t, const void *key, upb_value *val) {
+ return upb_inttable_remove(t, (uintptr_t)key, val);
+}
+
+void upb_inttable_compact2(upb_inttable *t, upb_alloc *a) {
+ /* A power-of-two histogram of the table keys. */
+ size_t counts[UPB_MAXARRSIZE + 1] = {0};
+
+ /* The max key in each bucket. */
+ uintptr_t max[UPB_MAXARRSIZE + 1] = {0};
+
+ upb_inttable_iter i;
+ size_t arr_count;
+ int size_lg2;
+ upb_inttable new_t;
+
+ upb_inttable_begin(&i, t);
+ for (; !upb_inttable_done(&i); upb_inttable_next(&i)) {
+ uintptr_t key = upb_inttable_iter_key(&i);
+ int bucket = log2ceil(key);
+ max[bucket] = UPB_MAX(max[bucket], key);
+ counts[bucket]++;
+ }
+
+ /* Find the largest power of two that satisfies the MIN_DENSITY
+ * definition (while actually having some keys). */
+ arr_count = upb_inttable_count(t);
+
+ for (size_lg2 = ARRAY_SIZE(counts) - 1; size_lg2 > 0; size_lg2--) {
+ if (counts[size_lg2] == 0) {
+ /* We can halve again without losing any entries. */
+ continue;
+ } else if (arr_count >= (1 << size_lg2) * MIN_DENSITY) {
+ break;
+ }
+
+ arr_count -= counts[size_lg2];
+ }
+
+ UPB_ASSERT(arr_count <= upb_inttable_count(t));
+
+ {
+ /* Insert all elements into new, perfectly-sized table. */
+ size_t arr_size = max[size_lg2] + 1; /* +1 so arr[max] will fit. */
+ size_t hash_count = upb_inttable_count(t) - arr_count;
+ size_t hash_size = hash_count ? (hash_count / MAX_LOAD) + 1 : 0;
+ int hashsize_lg2 = log2ceil(hash_size);
+
+ upb_inttable_sizedinit(&new_t, arr_size, hashsize_lg2, a);
+ upb_inttable_begin(&i, t);
+ for (; !upb_inttable_done(&i); upb_inttable_next(&i)) {
+ uintptr_t k = upb_inttable_iter_key(&i);
+ upb_inttable_insert2(&new_t, k, upb_inttable_iter_value(&i), a);
+ }
+ UPB_ASSERT(new_t.array_size == arr_size);
+ UPB_ASSERT(new_t.t.size_lg2 == hashsize_lg2);
+ }
+ upb_inttable_uninit2(t, a);
+ *t = new_t;
+}
+
+/* Iteration. */
+
+static const upb_tabent *int_tabent(const upb_inttable_iter *i) {
+ UPB_ASSERT(!i->array_part);
+ return &i->t->t.entries[i->index];
+}
+
+static upb_tabval int_arrent(const upb_inttable_iter *i) {
+ UPB_ASSERT(i->array_part);
+ return i->t->array[i->index];
+}
+
+void upb_inttable_begin(upb_inttable_iter *i, const upb_inttable *t) {
+ i->t = t;
+ i->index = -1;
+ i->array_part = true;
+ upb_inttable_next(i);
+}
+
+void upb_inttable_next(upb_inttable_iter *iter) {
+ const upb_inttable *t = iter->t;
+ if (iter->array_part) {
+ while (++iter->index < t->array_size) {
+ if (upb_arrhas(int_arrent(iter))) {
+ return;
+ }
+ }
+ iter->array_part = false;
+ iter->index = begin(&t->t);
+ } else {
+ iter->index = next(&t->t, iter->index);
+ }
+}
+
+bool upb_inttable_done(const upb_inttable_iter *i) {
+ if (!i->t) return true;
+ if (i->array_part) {
+ return i->index >= i->t->array_size ||
+ !upb_arrhas(int_arrent(i));
+ } else {
+ return i->index >= upb_table_size(&i->t->t) ||
+ upb_tabent_isempty(int_tabent(i));
+ }
+}
+
+uintptr_t upb_inttable_iter_key(const upb_inttable_iter *i) {
+ UPB_ASSERT(!upb_inttable_done(i));
+ return i->array_part ? i->index : int_tabent(i)->key;
+}
+
+upb_value upb_inttable_iter_value(const upb_inttable_iter *i) {
+ UPB_ASSERT(!upb_inttable_done(i));
+ return _upb_value_val(
+ i->array_part ? i->t->array[i->index].val : int_tabent(i)->val.val);
+}
+
+void upb_inttable_iter_setdone(upb_inttable_iter *i) {
+ i->t = NULL;
+ i->index = SIZE_MAX;
+ i->array_part = false;
+}
+
+bool upb_inttable_iter_isequal(const upb_inttable_iter *i1,
+ const upb_inttable_iter *i2) {
+ if (upb_inttable_done(i1) && upb_inttable_done(i2))
+ return true;
+ return i1->t == i2->t && i1->index == i2->index &&
+ i1->array_part == i2->array_part;
+}
+
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+
+/* upb_status *****************************************************************/
+
+void upb_status_clear(upb_status *status) {
+ if (!status) return;
+ status->ok = true;
+ status->msg[0] = '\0';
+}
+
+bool upb_ok(const upb_status *status) { return status->ok; }
+
+const char *upb_status_errmsg(const upb_status *status) { return status->msg; }
+
+void upb_status_seterrmsg(upb_status *status, const char *msg) {
+ if (!status) return;
+ status->ok = false;
+ strncpy(status->msg, msg, UPB_STATUS_MAX_MESSAGE - 1);
+ status->msg[UPB_STATUS_MAX_MESSAGE - 1] = '\0';
+}
+
+void upb_status_seterrf(upb_status *status, const char *fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+ upb_status_vseterrf(status, fmt, args);
+ va_end(args);
+}
+
+void upb_status_vseterrf(upb_status *status, const char *fmt, va_list args) {
+ if (!status) return;
+ status->ok = false;
+ vsnprintf(status->msg, sizeof(status->msg), fmt, args);
+ status->msg[UPB_STATUS_MAX_MESSAGE - 1] = '\0';
+}
+
+void upb_status_vappenderrf(upb_status *status, const char *fmt, va_list args) {
+ size_t len;
+ if (!status) return;
+ status->ok = false;
+ len = strlen(status->msg);
+ vsnprintf(status->msg + len, sizeof(status->msg) - len, fmt, args);
+ status->msg[UPB_STATUS_MAX_MESSAGE - 1] = '\0';
+}
+
+/* upb_alloc ******************************************************************/
+
+static void *upb_global_allocfunc(upb_alloc *alloc, void *ptr, size_t oldsize,
+ size_t size) {
+ UPB_UNUSED(alloc);
+ UPB_UNUSED(oldsize);
+ if (size == 0) {
+ free(ptr);
+ return NULL;
+ } else {
+ return realloc(ptr, size);
+ }
+}
+
+upb_alloc upb_alloc_global = {&upb_global_allocfunc};
+
+/* upb_arena ******************************************************************/
+
+/* Be conservative and choose 16 in case anyone is using SSE. */
+
+struct mem_block {
+ struct mem_block *next;
+ uint32_t size;
+ uint32_t cleanups;
+ /* Data follows. */
+};
+
+typedef struct cleanup_ent {
+ upb_cleanup_func *cleanup;
+ void *ud;
+} cleanup_ent;
+
+static const size_t memblock_reserve = UPB_ALIGN_UP(sizeof(mem_block), 16);
+
+static upb_arena *arena_findroot(upb_arena *a) {
+ /* Path splitting keeps time complexity down, see:
+ * https://en.wikipedia.org/wiki/Disjoint-set_data_structure */
+ while (a->parent != a) {
+ upb_arena *next = a->parent;
+ a->parent = next->parent;
+ a = next;
+ }
+ return a;
+}
+
+static void upb_arena_addblock(upb_arena *a, upb_arena *root, void *ptr,
+ size_t size) {
+ mem_block *block = ptr;
+
+ /* The block is for arena |a|, but should appear in the freelist of |root|. */
+ block->next = root->freelist;
+ block->size = (uint32_t)size;
+ block->cleanups = 0;
+ root->freelist = block;
+ a->last_size = block->size;
+ if (!root->freelist_tail) root->freelist_tail = block;
+
+ a->head.ptr = UPB_PTR_AT(block, memblock_reserve, char);
+ a->head.end = UPB_PTR_AT(block, size, char);
+ a->cleanups = &block->cleanups;
+
+ UPB_POISON_MEMORY_REGION(a->head.ptr, a->head.end - a->head.ptr);
+}
+
+static bool upb_arena_allocblock(upb_arena *a, size_t size) {
+ upb_arena *root = arena_findroot(a);
+ size_t block_size = UPB_MAX(size, a->last_size * 2) + memblock_reserve;
+ mem_block *block = upb_malloc(root->block_alloc, block_size);
+
+ if (!block) return false;
+ upb_arena_addblock(a, root, block, block_size);
+ return true;
+}
+
+void *_upb_arena_slowmalloc(upb_arena *a, size_t size) {
+ if (!upb_arena_allocblock(a, size)) return NULL; /* Out of memory. */
+ UPB_ASSERT(_upb_arenahas(a) >= size);
+ return upb_arena_malloc(a, size);
+}
+
+static void *upb_arena_doalloc(upb_alloc *alloc, void *ptr, size_t oldsize,
+ size_t size) {
+ upb_arena *a = (upb_arena*)alloc; /* upb_alloc is initial member. */
+ return upb_arena_realloc(a, ptr, oldsize, size);
+}
+
+/* Public Arena API ***********************************************************/
+
+upb_arena *arena_initslow(void *mem, size_t n, upb_alloc *alloc) {
+ const size_t first_block_overhead = sizeof(upb_arena) + memblock_reserve;
+ upb_arena *a;
+
+ /* We need to malloc the initial block. */
+ n = first_block_overhead + 256;
+ if (!alloc || !(mem = upb_malloc(alloc, n))) {
+ return NULL;
+ }
+
+ a = UPB_PTR_AT(mem, n - sizeof(*a), upb_arena);
+ n -= sizeof(*a);
+
+ a->head.alloc.func = &upb_arena_doalloc;
+ a->block_alloc = alloc;
+ a->parent = a;
+ a->refcount = 1;
+ a->freelist = NULL;
+ a->freelist_tail = NULL;
+
+ upb_arena_addblock(a, a, mem, n);
+
+ return a;
+}
+
+upb_arena *upb_arena_init(void *mem, size_t n, upb_alloc *alloc) {
+ upb_arena *a;
+
+ /* Round block size down to alignof(*a) since we will allocate the arena
+ * itself at the end. */
+ n = UPB_ALIGN_DOWN(n, UPB_ALIGN_OF(upb_arena));
+
+ if (UPB_UNLIKELY(n < sizeof(upb_arena))) {
+ return arena_initslow(mem, n, alloc);
+ }
+
+ a = UPB_PTR_AT(mem, n - sizeof(*a), upb_arena);
+
+ a->head.alloc.func = &upb_arena_doalloc;
+ a->block_alloc = alloc;
+ a->parent = a;
+ a->refcount = 1;
+ a->last_size = UPB_MAX(128, n);
+ a->head.ptr = mem;
+ a->head.end = UPB_PTR_AT(mem, n - sizeof(*a), char);
+ a->freelist = NULL;
+ a->cleanups = NULL;
+
+ return a;
+}
+
+static void arena_dofree(upb_arena *a) {
+ mem_block *block = a->freelist;
+ UPB_ASSERT(a->parent == a);
+ UPB_ASSERT(a->refcount == 0);
+
+ while (block) {
+ /* Load first since we are deleting block. */
+ mem_block *next = block->next;
+
+ if (block->cleanups > 0) {
+ cleanup_ent *end = UPB_PTR_AT(block, block->size, void);
+ cleanup_ent *ptr = end - block->cleanups;
+
+ for (; ptr < end; ptr++) {
+ ptr->cleanup(ptr->ud);
+ }
+ }
+
+ upb_free(a->block_alloc, block);
+ block = next;
+ }
+}
+
+void upb_arena_free(upb_arena *a) {
+ a = arena_findroot(a);
+ if (--a->refcount == 0) arena_dofree(a);
+}
+
+bool upb_arena_addcleanup(upb_arena *a, void *ud, upb_cleanup_func *func) {
+ cleanup_ent *ent;
+
+ if (!a->cleanups || _upb_arenahas(a) < sizeof(cleanup_ent)) {
+ if (!upb_arena_allocblock(a, 128)) return false; /* Out of memory. */
+ UPB_ASSERT(_upb_arenahas(a) >= sizeof(cleanup_ent));
+ }
+
+ a->head.end -= sizeof(cleanup_ent);
+ ent = (cleanup_ent*)a->head.end;
+ (*a->cleanups)++;
+ UPB_UNPOISON_MEMORY_REGION(ent, sizeof(cleanup_ent));
+
+ ent->cleanup = func;
+ ent->ud = ud;
+
+ return true;
+}
+
+void upb_arena_fuse(upb_arena *a1, upb_arena *a2) {
+ upb_arena *r1 = arena_findroot(a1);
+ upb_arena *r2 = arena_findroot(a2);
+
+ if (r1 == r2) return; /* Already fused. */
+
+ /* We want to join the smaller tree to the larger tree.
+ * So swap first if they are backwards. */
+ if (r1->refcount < r2->refcount) {
+ upb_arena *tmp = r1;
+ r1 = r2;
+ r2 = tmp;
+ }
+
+ /* r1 takes over r2's freelist and refcount. */
+ r1->refcount += r2->refcount;
+ if (r2->freelist_tail) {
+ UPB_ASSERT(r2->freelist_tail->next == NULL);
+ r2->freelist_tail->next = r1->freelist;
+ r1->freelist = r2->freelist;
+ }
+ r2->parent = r1;
+}
+// Fast decoder: ~3x the speed of decode.c, but x86-64 specific.
+// Also the table size grows by 2x.
+//
+// Could potentially be ported to ARM64 or other 64-bit archs that pass at
+// least six arguments in registers.
+//
+// The overall design is to create specialized functions for every possible
+// field type (eg. oneof boolean field with a 1 byte tag) and then dispatch
+// to the specialized function as quickly as possible.
+
+
+
+/* Must be last. */
+
+#if UPB_FASTTABLE
+
+// The standard set of arguments passed to each parsing function.
+// Thanks to x86-64 calling conventions, these will stay in registers.
+#define UPB_PARSE_PARAMS \
+ upb_decstate *d, const char *ptr, upb_msg *msg, intptr_t table, \
+ uint64_t hasbits, uint64_t data
+
+#define UPB_PARSE_ARGS d, ptr, msg, table, hasbits, data
+
+#define RETURN_GENERIC(m) \
+ /* fprintf(stderr, m); */ \
+ return fastdecode_generic(d, ptr, msg, table, hasbits, 0);
+
+typedef enum {
+ CARD_s = 0, /* Singular (optional, non-repeated) */
+ CARD_o = 1, /* Oneof */
+ CARD_r = 2, /* Repeated */
+ CARD_p = 3 /* Packed Repeated */
+} upb_card;
+
+UPB_NOINLINE
+static const char *fastdecode_isdonefallback(upb_decstate *d, const char *ptr,
+ upb_msg *msg, intptr_t table,
+ uint64_t hasbits, int overrun) {
+ ptr = decode_isdonefallback_inl(d, ptr, overrun);
+ if (ptr == NULL) {
+ return fastdecode_err(d);
+ }
+ uint16_t tag = fastdecode_loadtag(ptr);
+ return fastdecode_tagdispatch(d, ptr, msg, table, hasbits, tag);
+}
+
+UPB_FORCEINLINE
+static const char *fastdecode_dispatch(upb_decstate *d, const char *ptr,
+ upb_msg *msg, intptr_t table,
+ uint64_t hasbits) {
+ if (UPB_UNLIKELY(ptr >= d->limit_ptr)) {
+ int overrun = ptr - d->end;
+ if (UPB_LIKELY(overrun == d->limit)) {
+ // Parse is finished.
+ *(uint32_t*)msg |= hasbits; // Sync hasbits.
+ return ptr;
+ } else {
+ return fastdecode_isdonefallback(d, ptr, msg, table, hasbits, overrun);
+ }
+ }
+
+ // Read two bytes of tag data (for a one-byte tag, the high byte is junk).
+ uint16_t tag = fastdecode_loadtag(ptr);
+ return fastdecode_tagdispatch(d, ptr, msg, table, hasbits, tag);
+}
+
+UPB_FORCEINLINE
+static bool fastdecode_checktag(uint64_t data, int tagbytes) {
+ if (tagbytes == 1) {
+ return (data & 0xff) == 0;
+ } else {
+ return (data & 0xffff) == 0;
+ }
+}
+
+UPB_FORCEINLINE
+static const char *fastdecode_longsize(const char *ptr, int *size) {
+ int i;
+ UPB_ASSERT(*size & 0x80);
+ *size &= 0xff;
+ for (i = 0; i < 3; i++) {
+ ptr++;
+ size_t byte = (uint8_t)ptr[-1];
+ *size += (byte - 1) << (7 + 7 * i);
+ if (UPB_LIKELY((byte & 0x80) == 0)) return ptr;
+ }
+ ptr++;
+ size_t byte = (uint8_t)ptr[-1];
+ // len is limited by 2gb not 4gb, hence 8 and not 16 as normally expected
+ // for a 32 bit varint.
+ if (UPB_UNLIKELY(byte >= 8)) return NULL;
+ *size += (byte - 1) << 28;
+ return ptr;
+}
+
+UPB_FORCEINLINE
+static bool fastdecode_boundscheck(const char *ptr, size_t len,
+ const char *end) {
+ uintptr_t uptr = (uintptr_t)ptr;
+ uintptr_t uend = (uintptr_t)end + 16;
+ uintptr_t res = uptr + len;
+ return res < uptr || res > uend;
+}
+
+UPB_FORCEINLINE
+static bool fastdecode_boundscheck2(const char *ptr, size_t len,
+ const char *end) {
+ // This is one extra branch compared to the more normal:
+ // return (size_t)(end - ptr) < size;
+ // However it is one less computation if we are just about to use "ptr + len":
+ // https://godbolt.org/z/35YGPz
+ // In microbenchmarks this shows an overall 4% improvement.
+ uintptr_t uptr = (uintptr_t)ptr;
+ uintptr_t uend = (uintptr_t)end;
+ uintptr_t res = uptr + len;
+ return res < uptr || res > uend;
+}
+
+typedef const char *fastdecode_delimfunc(upb_decstate *d, const char *ptr,
+ void *ctx);
+
+UPB_FORCEINLINE
+static const char *fastdecode_delimited(upb_decstate *d, const char *ptr,
+ fastdecode_delimfunc *func, void *ctx) {
+ ptr++;
+ int len = (int8_t)ptr[-1];
+ if (fastdecode_boundscheck2(ptr, len, d->limit_ptr)) {
+ // Slow case: Sub-message is >=128 bytes and/or exceeds the current buffer.
+ // If it exceeds the buffer limit, limit/limit_ptr will change during
+ // sub-message parsing, so we need to preserve delta, not limit.
+ if (UPB_UNLIKELY(len & 0x80)) {
+ // Size varint >1 byte (length >= 128).
+ ptr = fastdecode_longsize(ptr, &len);
+ if (!ptr) {
+ // Corrupt wire format: size exceeded INT_MAX.
+ return NULL;
+ }
+ }
+ if (ptr - d->end + (int)len > d->limit) {
+ // Corrupt wire format: invalid limit.
+ return NULL;
+ }
+ int delta = decode_pushlimit(d, ptr, len);
+ ptr = func(d, ptr, ctx);
+ decode_poplimit(d, ptr, delta);
+ } else {
+ // Fast case: Sub-message is <128 bytes and fits in the current buffer.
+ // This means we can preserve limit/limit_ptr verbatim.
+ const char *saved_limit_ptr = d->limit_ptr;
+ int saved_limit = d->limit;
+ d->limit_ptr = ptr + len;
+ d->limit = d->limit_ptr - d->end;
+ UPB_ASSERT(d->limit_ptr == d->end + UPB_MIN(0, d->limit));
+ ptr = func(d, ptr, ctx);
+ d->limit_ptr = saved_limit_ptr;
+ d->limit = saved_limit;
+ UPB_ASSERT(d->limit_ptr == d->end + UPB_MIN(0, d->limit));
+ }
+ return ptr;
+}
+
+/* singular, oneof, repeated field handling ***********************************/
+
+typedef struct {
+ upb_array *arr;
+ void *end;
+} fastdecode_arr;
+
+typedef enum {
+ FD_NEXT_ATLIMIT,
+ FD_NEXT_SAMEFIELD,
+ FD_NEXT_OTHERFIELD
+} fastdecode_next;
+
+typedef struct {
+ void *dst;
+ fastdecode_next next;
+ uint32_t tag;
+} fastdecode_nextret;
+
+UPB_FORCEINLINE
+static void *fastdecode_resizearr(upb_decstate *d, void *dst,
+ fastdecode_arr *farr, int valbytes) {
+ if (UPB_UNLIKELY(dst == farr->end)) {
+ size_t old_size = farr->arr->size;
+ size_t old_bytes = old_size * valbytes;
+ size_t new_size = old_size * 2;
+ size_t new_bytes = new_size * valbytes;
+ char *old_ptr = _upb_array_ptr(farr->arr);
+ char *new_ptr = upb_arena_realloc(&d->arena, old_ptr, old_bytes, new_bytes);
+ uint8_t elem_size_lg2 = __builtin_ctz(valbytes);
+ farr->arr->size = new_size;
+ farr->arr->data = _upb_array_tagptr(new_ptr, elem_size_lg2);
+ dst = (void*)(new_ptr + (old_size * valbytes));
+ farr->end = (void*)(new_ptr + (new_size * valbytes));
+ }
+ return dst;
+}
+
+UPB_FORCEINLINE
+static bool fastdecode_tagmatch(uint32_t tag, uint64_t data, int tagbytes) {
+ if (tagbytes == 1) {
+ return (uint8_t)tag == (uint8_t)data;
+ } else {
+ return (uint16_t)tag == (uint16_t)data;
+ }
+}
+
+UPB_FORCEINLINE
+static void fastdecode_commitarr(void *dst, fastdecode_arr *farr,
+ int valbytes) {
+ farr->arr->len =
+ (size_t)((char *)dst - (char *)_upb_array_ptr(farr->arr)) / valbytes;
+}
+
+UPB_FORCEINLINE
+static fastdecode_nextret fastdecode_nextrepeated(upb_decstate *d, void *dst,
+ const char **ptr,
+ fastdecode_arr *farr,
+ uint64_t data, int tagbytes,
+ int valbytes) {
+ fastdecode_nextret ret;
+ dst = (char *)dst + valbytes;
+
+ if (UPB_LIKELY(!decode_isdone(d, ptr))) {
+ ret.tag = fastdecode_loadtag(*ptr);
+ if (fastdecode_tagmatch(ret.tag, data, tagbytes)) {
+ ret.next = FD_NEXT_SAMEFIELD;
+ } else {
+ fastdecode_commitarr(dst, farr, valbytes);
+ ret.next = FD_NEXT_OTHERFIELD;
+ }
+ } else {
+ fastdecode_commitarr(dst, farr, valbytes);
+ ret.next = FD_NEXT_ATLIMIT;
+ }
+
+ ret.dst = dst;
+ return ret;
+}
+
+UPB_FORCEINLINE
+static void *fastdecode_fieldmem(upb_msg *msg, uint64_t data) {
+ size_t ofs = data >> 48;
+ return (char *)msg + ofs;
+}
+
+UPB_FORCEINLINE
+static void *fastdecode_getfield(upb_decstate *d, const char *ptr, upb_msg *msg,
+ uint64_t *data, uint64_t *hasbits,
+ fastdecode_arr *farr, int valbytes,
+ upb_card card) {
+ switch (card) {
+ case CARD_s: {
+ uint8_t hasbit_index = *data >> 24;
+ // Set hasbit and return pointer to scalar field.
+ *hasbits |= 1ull << hasbit_index;
+ return fastdecode_fieldmem(msg, *data);
+ }
+ case CARD_o: {
+ uint16_t case_ofs = *data >> 32;
+ uint32_t *oneof_case = UPB_PTR_AT(msg, case_ofs, uint32_t);
+ uint8_t field_number = *data >> 24;
+ *oneof_case = field_number;
+ return fastdecode_fieldmem(msg, *data);
+ }
+ case CARD_r: {
+ // Get pointer to upb_array and allocate/expand if necessary.
+ uint8_t elem_size_lg2 = __builtin_ctz(valbytes);
+ upb_array **arr_p = fastdecode_fieldmem(msg, *data);
+ char *begin;
+ *(uint32_t*)msg |= *hasbits;
+ *hasbits = 0;
+ if (UPB_LIKELY(!*arr_p)) {
+ farr->arr = _upb_array_new(&d->arena, 8, elem_size_lg2);
+ *arr_p = farr->arr;
+ } else {
+ farr->arr = *arr_p;
+ }
+ begin = _upb_array_ptr(farr->arr);
+ farr->end = begin + (farr->arr->size * valbytes);
+ *data = fastdecode_loadtag(ptr);
+ return begin + (farr->arr->len * valbytes);
+ }
+ default:
+ UPB_UNREACHABLE();
+ }
+}
+
+UPB_FORCEINLINE
+static bool fastdecode_flippacked(uint64_t *data, int tagbytes) {
+ *data ^= (0x2 ^ 0x0); // Patch data to match packed wiretype.
+ return fastdecode_checktag(*data, tagbytes);
+}
+
+/* varint fields **************************************************************/
+
+UPB_FORCEINLINE
+static uint64_t fastdecode_munge(uint64_t val, int valbytes, bool zigzag) {
+ if (valbytes == 1) {
+ return val != 0;
+ } else if (zigzag) {
+ if (valbytes == 4) {
+ uint32_t n = val;
+ return (n >> 1) ^ -(int32_t)(n & 1);
+ } else if (valbytes == 8) {
+ return (val >> 1) ^ -(int64_t)(val & 1);
+ }
+ UPB_UNREACHABLE();
+ }
+ return val;
+}
+
+UPB_FORCEINLINE
+static const char *fastdecode_varint64(const char *ptr, uint64_t *val) {
+ ptr++;
+ *val = (uint8_t)ptr[-1];
+ if (UPB_UNLIKELY(*val & 0x80)) {
+ int i;
+ for (i = 0; i < 8; i++) {
+ ptr++;
+ uint64_t byte = (uint8_t)ptr[-1];
+ *val += (byte - 1) << (7 + 7 * i);
+ if (UPB_LIKELY((byte & 0x80) == 0)) goto done;
+ }
+ ptr++;
+ uint64_t byte = (uint8_t)ptr[-1];
+ if (byte > 1) {
+ return NULL;
+ }
+ *val += (byte - 1) << 63;
+ }
+done:
+ UPB_ASSUME(ptr != NULL);
+ return ptr;
+}
+
+UPB_FORCEINLINE
+static const char *fastdecode_unpackedvarint(UPB_PARSE_PARAMS, int tagbytes,
+ int valbytes, upb_card card,
+ bool zigzag,
+ _upb_field_parser *packed) {
+ uint64_t val;
+ void *dst;
+ fastdecode_arr farr;
+
+ if (UPB_UNLIKELY(!fastdecode_checktag(data, tagbytes))) {
+ if (card == CARD_r && fastdecode_flippacked(&data, tagbytes)) {
+ return packed(UPB_PARSE_ARGS);
+ }
+ RETURN_GENERIC("varint field tag mismatch\n");
+ }
+
+ dst =
+ fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr, valbytes, card);
+ if (card == CARD_r) {
+ if (UPB_UNLIKELY(!dst)) {
+ RETURN_GENERIC("need array resize\n");
+ }
+ }
+
+again:
+ if (card == CARD_r) {
+ dst = fastdecode_resizearr(d, dst, &farr, valbytes);
+ }
+
+ ptr += tagbytes;
+ ptr = fastdecode_varint64(ptr, &val);
+ if (ptr == NULL) return fastdecode_err(d);
+ val = fastdecode_munge(val, valbytes, zigzag);
+ memcpy(dst, &val, valbytes);
+
+ if (card == CARD_r) {
+ fastdecode_nextret ret =
+ fastdecode_nextrepeated(d, dst, &ptr, &farr, data, tagbytes, valbytes);
+ switch (ret.next) {
+ case FD_NEXT_SAMEFIELD:
+ dst = ret.dst;
+ goto again;
+ case FD_NEXT_OTHERFIELD:
+ return fastdecode_tagdispatch(d, ptr, msg, table, hasbits, ret.tag);
+ case FD_NEXT_ATLIMIT:
+ return ptr;
+ }
+ }
+
+ return fastdecode_dispatch(d, ptr, msg, table, hasbits);
+}
+
+typedef struct {
+ uint8_t valbytes;
+ bool zigzag;
+ void *dst;
+ fastdecode_arr farr;
+} fastdecode_varintdata;
+
+UPB_FORCEINLINE
+static const char *fastdecode_topackedvarint(upb_decstate *d, const char *ptr,
+ void *ctx) {
+ fastdecode_varintdata *data = ctx;
+ void *dst = data->dst;
+ uint64_t val;
+
+ while (!decode_isdone(d, &ptr)) {
+ dst = fastdecode_resizearr(d, dst, &data->farr, data->valbytes);
+ ptr = fastdecode_varint64(ptr, &val);
+ if (ptr == NULL) return NULL;
+ val = fastdecode_munge(val, data->valbytes, data->zigzag);
+ memcpy(dst, &val, data->valbytes);
+ dst = (char *)dst + data->valbytes;
+ }
+
+ fastdecode_commitarr(dst, &data->farr, data->valbytes);
+ return ptr;
+}
+
+UPB_FORCEINLINE
+static const char *fastdecode_packedvarint(UPB_PARSE_PARAMS, int tagbytes,
+ int valbytes, bool zigzag,
+ _upb_field_parser *unpacked) {
+ fastdecode_varintdata ctx = {valbytes, zigzag};
+
+ if (UPB_UNLIKELY(!fastdecode_checktag(data, tagbytes))) {
+ if (fastdecode_flippacked(&data, tagbytes)) {
+ return unpacked(UPB_PARSE_ARGS);
+ } else {
+ RETURN_GENERIC("varint field tag mismatch\n");
+ }
+ }
+
+ ctx.dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &ctx.farr,
+ valbytes, CARD_r);
+ if (UPB_UNLIKELY(!ctx.dst)) {
+ RETURN_GENERIC("need array resize\n");
+ }
+
+ ptr += tagbytes;
+ ptr = fastdecode_delimited(d, ptr, &fastdecode_topackedvarint, &ctx);
+
+ if (UPB_UNLIKELY(ptr == NULL)) {
+ return fastdecode_err(d);
+ }
+
+ return fastdecode_dispatch(d, ptr, msg, table, hasbits);
+}
+
+UPB_FORCEINLINE
+static const char *fastdecode_varint(UPB_PARSE_PARAMS, int tagbytes,
+ int valbytes, upb_card card, bool zigzag,
+ _upb_field_parser *unpacked,
+ _upb_field_parser *packed) {
+ if (card == CARD_p) {
+ return fastdecode_packedvarint(UPB_PARSE_ARGS, tagbytes, valbytes, zigzag,
+ unpacked);
+ } else {
+ return fastdecode_unpackedvarint(UPB_PARSE_ARGS, tagbytes, valbytes, card,
+ zigzag, packed);
+ }
+}
+
+#define z_ZZ true
+#define b_ZZ false
+#define v_ZZ false
+
+/* Generate all combinations:
+ * {s,o,r,p} x {b1,v4,z4,v8,z8} x {1bt,2bt} */
+
+#define F(card, type, valbytes, tagbytes) \
+ UPB_NOINLINE \
+ const char *upb_p##card##type##valbytes##_##tagbytes##bt(UPB_PARSE_PARAMS) { \
+ return fastdecode_varint(UPB_PARSE_ARGS, tagbytes, valbytes, CARD_##card, \
+ type##_ZZ, \
+ &upb_pr##type##valbytes##_##tagbytes##bt, \
+ &upb_pp##type##valbytes##_##tagbytes##bt); \
+ }
+
+#define TYPES(card, tagbytes) \
+ F(card, b, 1, tagbytes) \
+ F(card, v, 4, tagbytes) \
+ F(card, v, 8, tagbytes) \
+ F(card, z, 4, tagbytes) \
+ F(card, z, 8, tagbytes)
+
+#define TAGBYTES(card) \
+ TYPES(card, 1) \
+ TYPES(card, 2)
+
+TAGBYTES(s)
+TAGBYTES(o)
+TAGBYTES(r)
+TAGBYTES(p)
+
+#undef z_ZZ
+#undef b_ZZ
+#undef v_ZZ
+#undef o_ONEOF
+#undef s_ONEOF
+#undef r_ONEOF
+#undef F
+#undef TYPES
+#undef TAGBYTES
+
+
+/* fixed fields ***************************************************************/
+
+UPB_FORCEINLINE
+static const char *fastdecode_unpackedfixed(UPB_PARSE_PARAMS, int tagbytes,
+ int valbytes, upb_card card,
+ _upb_field_parser *packed) {
+ void *dst;
+ fastdecode_arr farr;
+
+ if (UPB_UNLIKELY(!fastdecode_checktag(data, tagbytes))) {
+ if (card == CARD_r && fastdecode_flippacked(&data, tagbytes)) {
+ return packed(UPB_PARSE_ARGS);
+ }
+ RETURN_GENERIC("fixed field tag mismatch\n");
+ }
+
+ dst =
+ fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr, valbytes, card);
+ if (card == CARD_r) {
+ if (UPB_UNLIKELY(!dst)) {
+ RETURN_GENERIC("couldn't allocate array in arena\n");
+ }
+ }
+
+
+again:
+ if (card == CARD_r) {
+ dst = fastdecode_resizearr(d, dst, &farr, valbytes);
+ }
+
+ ptr += tagbytes;
+ memcpy(dst, ptr, valbytes);
+ ptr += valbytes;
+
+ if (card == CARD_r) {
+ fastdecode_nextret ret =
+ fastdecode_nextrepeated(d, dst, &ptr, &farr, data, tagbytes, valbytes);
+ switch (ret.next) {
+ case FD_NEXT_SAMEFIELD:
+ dst = ret.dst;
+ goto again;
+ case FD_NEXT_OTHERFIELD:
+ return fastdecode_tagdispatch(d, ptr, msg, table, hasbits, ret.tag);
+ case FD_NEXT_ATLIMIT:
+ return ptr;
+ }
+ }
+
+ return fastdecode_dispatch(d, ptr, msg, table, hasbits);
+}
+
+UPB_FORCEINLINE
+static const char *fastdecode_packedfixed(UPB_PARSE_PARAMS, int tagbytes,
+ int valbytes,
+ _upb_field_parser *unpacked) {
+ if (UPB_UNLIKELY(!fastdecode_checktag(data, tagbytes))) {
+ if (fastdecode_flippacked(&data, tagbytes)) {
+ return unpacked(UPB_PARSE_ARGS);
+ } else {
+ RETURN_GENERIC("varint field tag mismatch\n");
+ }
+ }
+
+ ptr += tagbytes;
+ int size = (uint8_t)ptr[0];
+ ptr++;
+ if (size & 0x80) {
+ ptr = fastdecode_longsize(ptr, &size);
+ }
+
+ if (UPB_UNLIKELY(fastdecode_boundscheck(ptr, size, d->limit_ptr)) ||
+ (size % valbytes) != 0) {
+ return fastdecode_err(d);
+ }
+
+ upb_array **arr_p = fastdecode_fieldmem(msg, data);
+ upb_array *arr = *arr_p;
+ uint8_t elem_size_lg2 = __builtin_ctz(valbytes);
+ int elems = size / valbytes;
+
+ if (UPB_LIKELY(!arr)) {
+ *arr_p = arr = _upb_array_new(&d->arena, elems, elem_size_lg2);
+ if (!arr) {
+ return fastdecode_err(d);
+ }
+ } else {
+ _upb_array_resize(arr, elems, &d->arena);
+ }
+
+ char *dst = _upb_array_ptr(arr);
+ memcpy(dst, ptr, size);
+ arr->len = elems;
+
+ return fastdecode_dispatch(d, ptr + size, msg, table, hasbits);
+}
+
+UPB_FORCEINLINE
+static const char *fastdecode_fixed(UPB_PARSE_PARAMS, int tagbytes,
+ int valbytes, upb_card card,
+ _upb_field_parser *unpacked,
+ _upb_field_parser *packed) {
+ if (card == CARD_p) {
+ return fastdecode_packedfixed(UPB_PARSE_ARGS, tagbytes, valbytes, unpacked);
+ } else {
+ return fastdecode_unpackedfixed(UPB_PARSE_ARGS, tagbytes, valbytes, card,
+ packed);
+ }
+}
+
+/* Generate all combinations:
+ * {s,o,r,p} x {f4,f8} x {1bt,2bt} */
+
+#define F(card, valbytes, tagbytes) \
+ UPB_NOINLINE \
+ const char *upb_p##card##f##valbytes##_##tagbytes##bt(UPB_PARSE_PARAMS) { \
+ return fastdecode_fixed(UPB_PARSE_ARGS, tagbytes, valbytes, CARD_##card, \
+ &upb_ppf##valbytes##_##tagbytes##bt, \
+ &upb_prf##valbytes##_##tagbytes##bt); \
+ }
+
+#define TYPES(card, tagbytes) \
+ F(card, 4, tagbytes) \
+ F(card, 8, tagbytes)
+
+#define TAGBYTES(card) \
+ TYPES(card, 1) \
+ TYPES(card, 2)
+
+TAGBYTES(s)
+TAGBYTES(o)
+TAGBYTES(r)
+TAGBYTES(p)
+
+#undef F
+#undef TYPES
+#undef TAGBYTES
+
+/* string fields **************************************************************/
+
+typedef const char *fastdecode_copystr_func(struct upb_decstate *d,
+ const char *ptr, upb_msg *msg,
+ const upb_msglayout *table,
+ uint64_t hasbits, upb_strview *dst);
+
+UPB_NOINLINE
+static const char *fastdecode_verifyutf8(upb_decstate *d, const char *ptr,
+ upb_msg *msg, intptr_t table,
+ uint64_t hasbits, upb_strview *dst) {
+ if (!decode_verifyutf8_inl(dst->data, dst->size)) {
+ return fastdecode_err(d);
+ }
+ return fastdecode_dispatch(d, ptr, msg, table, hasbits);
+}
+
+UPB_FORCEINLINE
+static const char *fastdecode_longstring(struct upb_decstate *d,
+ const char *ptr, upb_msg *msg,
+ intptr_t table, uint64_t hasbits,
+ upb_strview *dst,
+ bool validate_utf8) {
+ int size = (uint8_t)ptr[0]; // Could plumb through hasbits.
+ ptr++;
+ if (size & 0x80) {
+ ptr = fastdecode_longsize(ptr, &size);
+ }
+
+ if (UPB_UNLIKELY(fastdecode_boundscheck(ptr, size, d->limit_ptr))) {
+ dst->size = 0;
+ return fastdecode_err(d);
+ }
+
+ if (d->alias) {
+ dst->data = ptr;
+ dst->size = size;
+ } else {
+ char *data = upb_arena_malloc(&d->arena, size);
+ if (!data) {
+ return fastdecode_err(d);
+ }
+ memcpy(data, ptr, size);
+ dst->data = data;
+ dst->size = size;
+ }
+
+ if (validate_utf8) {
+ return fastdecode_verifyutf8(d, ptr + size, msg, table, hasbits, dst);
+ } else {
+ return fastdecode_dispatch(d, ptr + size, msg, table, hasbits);
+ }
+}
+
+UPB_NOINLINE
+static const char *fastdecode_longstring_utf8(struct upb_decstate *d,
+ const char *ptr, upb_msg *msg,
+ intptr_t table, uint64_t hasbits,
+ upb_strview *dst) {
+ return fastdecode_longstring(d, ptr, msg, table, hasbits, dst, true);
+}
+
+UPB_NOINLINE
+static const char *fastdecode_longstring_noutf8(struct upb_decstate *d,
+ const char *ptr, upb_msg *msg,
+ intptr_t table,
+ uint64_t hasbits,
+ upb_strview *dst) {
+ return fastdecode_longstring(d, ptr, msg, table, hasbits, dst, false);
+}
+
+UPB_FORCEINLINE
+static void fastdecode_docopy(upb_decstate *d, const char *ptr, uint32_t size,
+ int copy, char *data, upb_strview *dst) {
+ d->arena.head.ptr += copy;
+ dst->data = data;
+ UPB_UNPOISON_MEMORY_REGION(data, copy);
+ memcpy(data, ptr, copy);
+ UPB_POISON_MEMORY_REGION(data + size, copy - size);
+}
+
+UPB_FORCEINLINE
+static const char *fastdecode_copystring(UPB_PARSE_PARAMS, int tagbytes,
+ upb_card card, bool validate_utf8) {
+ upb_strview *dst;
+ fastdecode_arr farr;
+ int64_t size;
+ size_t arena_has;
+ size_t common_has;
+ char *buf;
+
+ UPB_ASSERT(!d->alias);
+ UPB_ASSERT(fastdecode_checktag(data, tagbytes));
+
+ dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr,
+ sizeof(upb_strview), card);
+
+again:
+ if (card == CARD_r) {
+ dst = fastdecode_resizearr(d, dst, &farr, sizeof(upb_strview));
+ }
+
+ size = (uint8_t)ptr[tagbytes];
+ ptr += tagbytes + 1;
+ dst->size = size;
+
+ buf = d->arena.head.ptr;
+ arena_has = _upb_arenahas(&d->arena);
+ common_has = UPB_MIN(arena_has, (d->end - ptr) + 16);
+
+ if (UPB_LIKELY(size <= 15 - tagbytes)) {
+ if (arena_has < 16) goto longstr;
+ d->arena.head.ptr += 16;
+ memcpy(buf, ptr - tagbytes - 1, 16);
+ dst->data = buf + tagbytes + 1;
+ } else if (UPB_LIKELY(size <= 32)) {
+ if (UPB_UNLIKELY(common_has < 32)) goto longstr;
+ fastdecode_docopy(d, ptr, size, 32, buf, dst);
+ } else if (UPB_LIKELY(size <= 64)) {
+ if (UPB_UNLIKELY(common_has < 64)) goto longstr;
+ fastdecode_docopy(d, ptr, size, 64, buf, dst);
+ } else if (UPB_LIKELY(size < 128)) {
+ if (UPB_UNLIKELY(common_has < 128)) goto longstr;
+ fastdecode_docopy(d, ptr, size, 128, buf, dst);
+ } else {
+ goto longstr;
+ }
+
+ ptr += size;
+
+ if (card == CARD_r) {
+ if (validate_utf8 && !decode_verifyutf8_inl(dst->data, dst->size)) {
+ return fastdecode_err(d);
+ }
+ fastdecode_nextret ret = fastdecode_nextrepeated(
+ d, dst, &ptr, &farr, data, tagbytes, sizeof(upb_strview));
+ switch (ret.next) {
+ case FD_NEXT_SAMEFIELD:
+ dst = ret.dst;
+ goto again;
+ case FD_NEXT_OTHERFIELD:
+ return fastdecode_tagdispatch(d, ptr, msg, table, hasbits, ret.tag);
+ case FD_NEXT_ATLIMIT:
+ return ptr;
+ }
+ }
+
+ if (card != CARD_r && validate_utf8) {
+ return fastdecode_verifyutf8(d, ptr, msg, table, hasbits, dst);
+ }
+
+ return fastdecode_dispatch(d, ptr, msg, table, hasbits);
+
+longstr:
+ ptr--;
+ if (validate_utf8) {
+ return fastdecode_longstring_utf8(d, ptr, msg, table, hasbits, dst);
+ } else {
+ return fastdecode_longstring_noutf8(d, ptr, msg, table, hasbits, dst);
+ }
+}
+
+UPB_FORCEINLINE
+static const char *fastdecode_string(UPB_PARSE_PARAMS, int tagbytes,
+ upb_card card, _upb_field_parser *copyfunc,
+ bool validate_utf8) {
+ upb_strview *dst;
+ fastdecode_arr farr;
+ int64_t size;
+
+ if (UPB_UNLIKELY(!fastdecode_checktag(data, tagbytes))) {
+ RETURN_GENERIC("string field tag mismatch\n");
+ }
+
+ if (UPB_UNLIKELY(!d->alias)) {
+ return copyfunc(UPB_PARSE_ARGS);
+ }
+
+ dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr,
+ sizeof(upb_strview), card);
+
+again:
+ if (card == CARD_r) {
+ dst = fastdecode_resizearr(d, dst, &farr, sizeof(upb_strview));
+ }
+
+ size = (int8_t)ptr[tagbytes];
+ ptr += tagbytes + 1;
+ dst->data = ptr;
+ dst->size = size;
+
+ if (UPB_UNLIKELY(fastdecode_boundscheck(ptr, size, d->end))) {
+ ptr--;
+ if (validate_utf8) {
+ return fastdecode_longstring_utf8(d, ptr, msg, table, hasbits, dst);
+ } else {
+ return fastdecode_longstring_noutf8(d, ptr, msg, table, hasbits, dst);
+ }
+ }
+
+ ptr += size;
+
+ if (card == CARD_r) {
+ if (validate_utf8 && !decode_verifyutf8_inl(dst->data, dst->size)) {
+ return fastdecode_err(d);
+ }
+ fastdecode_nextret ret = fastdecode_nextrepeated(
+ d, dst, &ptr, &farr, data, tagbytes, sizeof(upb_strview));
+ switch (ret.next) {
+ case FD_NEXT_SAMEFIELD:
+ dst = ret.dst;
+ if (UPB_UNLIKELY(!d->alias)) {
+ // Buffer flipped and we can't alias any more. Bounce to copyfunc(),
+ // but via dispatch since we need to reload table data also.
+ fastdecode_commitarr(dst, &farr, sizeof(upb_strview));
+ return fastdecode_tagdispatch(d, ptr, msg, table, hasbits, ret.tag);
+ }
+ goto again;
+ case FD_NEXT_OTHERFIELD:
+ return fastdecode_tagdispatch(d, ptr, msg, table, hasbits, ret.tag);
+ case FD_NEXT_ATLIMIT:
+ return ptr;
+ }
+ }
+
+ if (card != CARD_r && validate_utf8) {
+ return fastdecode_verifyutf8(d, ptr, msg, table, hasbits, dst);
+ }
+
+ return fastdecode_dispatch(d, ptr, msg, table, hasbits);
+}
+
+/* Generate all combinations:
+ * {p,c} x {s,o,r} x {s, b} x {1bt,2bt} */
+
+#define s_VALIDATE true
+#define b_VALIDATE false
+
+#define F(card, tagbytes, type) \
+ UPB_NOINLINE \
+ const char *upb_c##card##type##_##tagbytes##bt(UPB_PARSE_PARAMS) { \
+ return fastdecode_copystring(UPB_PARSE_ARGS, tagbytes, CARD_##card, \
+ type##_VALIDATE); \
+ } \
+ const char *upb_p##card##type##_##tagbytes##bt(UPB_PARSE_PARAMS) { \
+ return fastdecode_string(UPB_PARSE_ARGS, tagbytes, CARD_##card, \
+ &upb_c##card##type##_##tagbytes##bt, \
+ type##_VALIDATE); \
+ }
+
+#define UTF8(card, tagbytes) \
+ F(card, tagbytes, s) \
+ F(card, tagbytes, b)
+
+#define TAGBYTES(card) \
+ UTF8(card, 1) \
+ UTF8(card, 2)
+
+TAGBYTES(s)
+TAGBYTES(o)
+TAGBYTES(r)
+
+#undef s_VALIDATE
+#undef b_VALIDATE
+#undef F
+#undef TAGBYTES
+
+/* message fields *************************************************************/
+
+UPB_INLINE
+upb_msg *decode_newmsg_ceil(upb_decstate *d, const upb_msglayout *l,
+ int msg_ceil_bytes) {
+ size_t size = l->size + sizeof(upb_msg_internal);
+ char *msg_data;
+ if (UPB_LIKELY(msg_ceil_bytes > 0 &&
+ _upb_arenahas(&d->arena) >= msg_ceil_bytes)) {
+ UPB_ASSERT(size <= (size_t)msg_ceil_bytes);
+ msg_data = d->arena.head.ptr;
+ d->arena.head.ptr += size;
+ UPB_UNPOISON_MEMORY_REGION(msg_data, msg_ceil_bytes);
+ memset(msg_data, 0, msg_ceil_bytes);
+ UPB_POISON_MEMORY_REGION(msg_data + size, msg_ceil_bytes - size);
+ } else {
+ msg_data = (char*)upb_arena_malloc(&d->arena, size);
+ memset(msg_data, 0, size);
+ }
+ return msg_data + sizeof(upb_msg_internal);
+}
+
+typedef struct {
+ intptr_t table;
+ upb_msg *msg;
+} fastdecode_submsgdata;
+
+UPB_FORCEINLINE
+static const char *fastdecode_tosubmsg(upb_decstate *d, const char *ptr,
+ void *ctx) {
+ fastdecode_submsgdata *submsg = ctx;
+ ptr = fastdecode_dispatch(d, ptr, submsg->msg, submsg->table, 0);
+ UPB_ASSUME(ptr != NULL);
+ return ptr;
+}
+
+UPB_FORCEINLINE
+static const char *fastdecode_submsg(UPB_PARSE_PARAMS, int tagbytes,
+ int msg_ceil_bytes, upb_card card) {
+
+ if (UPB_UNLIKELY(!fastdecode_checktag(data, tagbytes))) {
+ RETURN_GENERIC("submessage field tag mismatch\n");
+ }
+
+ if (--d->depth == 0) return fastdecode_err(d);
+
+ upb_msg **dst;
+ uint32_t submsg_idx = (data >> 16) & 0xff;
+ const upb_msglayout *tablep = decode_totablep(table);
+ const upb_msglayout *subtablep = tablep->submsgs[submsg_idx];
+ fastdecode_submsgdata submsg = {decode_totable(subtablep)};
+ fastdecode_arr farr;
+
+ if (subtablep->table_mask == (uint8_t)-1) {
+ RETURN_GENERIC("submessage doesn't have fast tables.");
+ }
+
+ dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr,
+ sizeof(upb_msg *), card);
+
+ if (card == CARD_s) {
+ *(uint32_t*)msg |= hasbits;
+ hasbits = 0;
+ }
+
+again:
+ if (card == CARD_r) {
+ dst = fastdecode_resizearr(d, dst, &farr, sizeof(upb_msg*));
+ }
+
+ submsg.msg = *dst;
+
+ if (card == CARD_r || UPB_LIKELY(!submsg.msg)) {
+ *dst = submsg.msg = decode_newmsg_ceil(d, subtablep, msg_ceil_bytes);
+ }
+
+ ptr += tagbytes;
+ ptr = fastdecode_delimited(d, ptr, fastdecode_tosubmsg, &submsg);
+
+ if (UPB_UNLIKELY(ptr == NULL || d->end_group != DECODE_NOGROUP)) {
+ return fastdecode_err(d);
+ }
+
+ if (card == CARD_r) {
+ fastdecode_nextret ret = fastdecode_nextrepeated(
+ d, dst, &ptr, &farr, data, tagbytes, sizeof(upb_msg *));
+ switch (ret.next) {
+ case FD_NEXT_SAMEFIELD:
+ dst = ret.dst;
+ goto again;
+ case FD_NEXT_OTHERFIELD:
+ d->depth++;
+ return fastdecode_tagdispatch(d, ptr, msg, table, hasbits, ret.tag);
+ case FD_NEXT_ATLIMIT:
+ d->depth++;
+ return ptr;
+ }
+ }
+
+ d->depth++;
+ return fastdecode_dispatch(d, ptr, msg, table, hasbits);
+}
+
+#define F(card, tagbytes, size_ceil, ceil_arg) \
+ const char *upb_p##card##m_##tagbytes##bt_max##size_ceil##b( \
+ UPB_PARSE_PARAMS) { \
+ return fastdecode_submsg(UPB_PARSE_ARGS, tagbytes, ceil_arg, CARD_##card); \
+ }
+
+#define SIZES(card, tagbytes) \
+ F(card, tagbytes, 64, 64) \
+ F(card, tagbytes, 128, 128) \
+ F(card, tagbytes, 192, 192) \
+ F(card, tagbytes, 256, 256) \
+ F(card, tagbytes, max, -1)
+
+#define TAGBYTES(card) \
+ SIZES(card, 1) \
+ SIZES(card, 2)
+
+TAGBYTES(s)
+TAGBYTES(o)
+TAGBYTES(r)
+
+#undef TAGBYTES
+#undef SIZES
+#undef F
+
+#endif /* UPB_FASTTABLE */
+/* This file was generated by upbc (the upb compiler) from the input
+ * file:
+ *
+ * google/protobuf/descriptor.proto
+ *
+ * Do not edit -- your changes will be discarded when the file is
+ * regenerated. */
+
+#include
+
+
+static const upb_msglayout *const google_protobuf_FileDescriptorSet_submsgs[1] = {
+ &google_protobuf_FileDescriptorProto_msginit,
+};
+
+static const upb_msglayout_field google_protobuf_FileDescriptorSet__fields[1] = {
+ {1, UPB_SIZE(0, 0), 0, 0, 11, 3},
+};
+
+const upb_msglayout google_protobuf_FileDescriptorSet_msginit = {
+ &google_protobuf_FileDescriptorSet_submsgs[0],
+ &google_protobuf_FileDescriptorSet__fields[0],
+ UPB_SIZE(8, 8), 1, false, 255,
+};
+
+static const upb_msglayout *const google_protobuf_FileDescriptorProto_submsgs[6] = {
+ &google_protobuf_DescriptorProto_msginit,
+ &google_protobuf_EnumDescriptorProto_msginit,
+ &google_protobuf_FieldDescriptorProto_msginit,
+ &google_protobuf_FileOptions_msginit,
+ &google_protobuf_ServiceDescriptorProto_msginit,
+ &google_protobuf_SourceCodeInfo_msginit,
+};
+
+static const upb_msglayout_field google_protobuf_FileDescriptorProto__fields[12] = {
+ {1, UPB_SIZE(4, 8), 1, 0, 12, 1},
+ {2, UPB_SIZE(12, 24), 2, 0, 12, 1},
+ {3, UPB_SIZE(36, 72), 0, 0, 12, 3},
+ {4, UPB_SIZE(40, 80), 0, 0, 11, 3},
+ {5, UPB_SIZE(44, 88), 0, 1, 11, 3},
+ {6, UPB_SIZE(48, 96), 0, 4, 11, 3},
+ {7, UPB_SIZE(52, 104), 0, 2, 11, 3},
+ {8, UPB_SIZE(28, 56), 3, 3, 11, 1},
+ {9, UPB_SIZE(32, 64), 4, 5, 11, 1},
+ {10, UPB_SIZE(56, 112), 0, 0, 5, 3},
+ {11, UPB_SIZE(60, 120), 0, 0, 5, 3},
+ {12, UPB_SIZE(20, 40), 5, 0, 12, 1},
+};
+
+const upb_msglayout google_protobuf_FileDescriptorProto_msginit = {
+ &google_protobuf_FileDescriptorProto_submsgs[0],
+ &google_protobuf_FileDescriptorProto__fields[0],
+ UPB_SIZE(64, 128), 12, false, 255,
+};
+
+static const upb_msglayout *const google_protobuf_DescriptorProto_submsgs[7] = {
+ &google_protobuf_DescriptorProto_msginit,
+ &google_protobuf_DescriptorProto_ExtensionRange_msginit,
+ &google_protobuf_DescriptorProto_ReservedRange_msginit,
+ &google_protobuf_EnumDescriptorProto_msginit,
+ &google_protobuf_FieldDescriptorProto_msginit,
+ &google_protobuf_MessageOptions_msginit,
+ &google_protobuf_OneofDescriptorProto_msginit,
+};
+
+static const upb_msglayout_field google_protobuf_DescriptorProto__fields[10] = {
+ {1, UPB_SIZE(4, 8), 1, 0, 12, 1},
+ {2, UPB_SIZE(16, 32), 0, 4, 11, 3},
+ {3, UPB_SIZE(20, 40), 0, 0, 11, 3},
+ {4, UPB_SIZE(24, 48), 0, 3, 11, 3},
+ {5, UPB_SIZE(28, 56), 0, 1, 11, 3},
+ {6, UPB_SIZE(32, 64), 0, 4, 11, 3},
+ {7, UPB_SIZE(12, 24), 2, 5, 11, 1},
+ {8, UPB_SIZE(36, 72), 0, 6, 11, 3},
+ {9, UPB_SIZE(40, 80), 0, 2, 11, 3},
+ {10, UPB_SIZE(44, 88), 0, 0, 12, 3},
+};
+
+const upb_msglayout google_protobuf_DescriptorProto_msginit = {
+ &google_protobuf_DescriptorProto_submsgs[0],
+ &google_protobuf_DescriptorProto__fields[0],
+ UPB_SIZE(48, 96), 10, false, 255,
+};
+
+static const upb_msglayout *const google_protobuf_DescriptorProto_ExtensionRange_submsgs[1] = {
+ &google_protobuf_ExtensionRangeOptions_msginit,
+};
+
+static const upb_msglayout_field google_protobuf_DescriptorProto_ExtensionRange__fields[3] = {
+ {1, UPB_SIZE(4, 4), 1, 0, 5, 1},
+ {2, UPB_SIZE(8, 8), 2, 0, 5, 1},
+ {3, UPB_SIZE(12, 16), 3, 0, 11, 1},
+};
+
+const upb_msglayout google_protobuf_DescriptorProto_ExtensionRange_msginit = {
+ &google_protobuf_DescriptorProto_ExtensionRange_submsgs[0],
+ &google_protobuf_DescriptorProto_ExtensionRange__fields[0],
+ UPB_SIZE(16, 24), 3, false, 255,
+};
+
+static const upb_msglayout_field google_protobuf_DescriptorProto_ReservedRange__fields[2] = {
+ {1, UPB_SIZE(4, 4), 1, 0, 5, 1},
+ {2, UPB_SIZE(8, 8), 2, 0, 5, 1},
+};
+
+const upb_msglayout google_protobuf_DescriptorProto_ReservedRange_msginit = {
+ NULL,
+ &google_protobuf_DescriptorProto_ReservedRange__fields[0],
+ UPB_SIZE(16, 16), 2, false, 255,
+};
+
+static const upb_msglayout *const google_protobuf_ExtensionRangeOptions_submsgs[1] = {
+ &google_protobuf_UninterpretedOption_msginit,
+};
+
+static const upb_msglayout_field google_protobuf_ExtensionRangeOptions__fields[1] = {
+ {999, UPB_SIZE(0, 0), 0, 0, 11, 3},
+};
+
+const upb_msglayout google_protobuf_ExtensionRangeOptions_msginit = {
+ &google_protobuf_ExtensionRangeOptions_submsgs[0],
+ &google_protobuf_ExtensionRangeOptions__fields[0],
+ UPB_SIZE(8, 8), 1, false, 255,
+};
+
+static const upb_msglayout *const google_protobuf_FieldDescriptorProto_submsgs[1] = {
+ &google_protobuf_FieldOptions_msginit,
+};
+
+static const upb_msglayout_field google_protobuf_FieldDescriptorProto__fields[11] = {
+ {1, UPB_SIZE(24, 24), 1, 0, 12, 1},
+ {2, UPB_SIZE(32, 40), 2, 0, 12, 1},
+ {3, UPB_SIZE(12, 12), 3, 0, 5, 1},
+ {4, UPB_SIZE(4, 4), 4, 0, 14, 1},
+ {5, UPB_SIZE(8, 8), 5, 0, 14, 1},
+ {6, UPB_SIZE(40, 56), 6, 0, 12, 1},
+ {7, UPB_SIZE(48, 72), 7, 0, 12, 1},
+ {8, UPB_SIZE(64, 104), 8, 0, 11, 1},
+ {9, UPB_SIZE(16, 16), 9, 0, 5, 1},
+ {10, UPB_SIZE(56, 88), 10, 0, 12, 1},
+ {17, UPB_SIZE(20, 20), 11, 0, 8, 1},
+};
+
+const upb_msglayout google_protobuf_FieldDescriptorProto_msginit = {
+ &google_protobuf_FieldDescriptorProto_submsgs[0],
+ &google_protobuf_FieldDescriptorProto__fields[0],
+ UPB_SIZE(72, 112), 11, false, 255,
+};
+
+static const upb_msglayout *const google_protobuf_OneofDescriptorProto_submsgs[1] = {
+ &google_protobuf_OneofOptions_msginit,
+};
+
+static const upb_msglayout_field google_protobuf_OneofDescriptorProto__fields[2] = {
+ {1, UPB_SIZE(4, 8), 1, 0, 12, 1},
+ {2, UPB_SIZE(12, 24), 2, 0, 11, 1},
+};
+
+const upb_msglayout google_protobuf_OneofDescriptorProto_msginit = {
+ &google_protobuf_OneofDescriptorProto_submsgs[0],
+ &google_protobuf_OneofDescriptorProto__fields[0],
+ UPB_SIZE(16, 32), 2, false, 255,
+};
+
+static const upb_msglayout *const google_protobuf_EnumDescriptorProto_submsgs[3] = {
+ &google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit,
+ &google_protobuf_EnumOptions_msginit,
+ &google_protobuf_EnumValueDescriptorProto_msginit,
+};
+
+static const upb_msglayout_field google_protobuf_EnumDescriptorProto__fields[5] = {
+ {1, UPB_SIZE(4, 8), 1, 0, 12, 1},
+ {2, UPB_SIZE(16, 32), 0, 2, 11, 3},
+ {3, UPB_SIZE(12, 24), 2, 1, 11, 1},
+ {4, UPB_SIZE(20, 40), 0, 0, 11, 3},
+ {5, UPB_SIZE(24, 48), 0, 0, 12, 3},
+};
+
+const upb_msglayout google_protobuf_EnumDescriptorProto_msginit = {
+ &google_protobuf_EnumDescriptorProto_submsgs[0],
+ &google_protobuf_EnumDescriptorProto__fields[0],
+ UPB_SIZE(32, 64), 5, false, 255,
+};
+
+static const upb_msglayout_field google_protobuf_EnumDescriptorProto_EnumReservedRange__fields[2] = {
+ {1, UPB_SIZE(4, 4), 1, 0, 5, 1},
+ {2, UPB_SIZE(8, 8), 2, 0, 5, 1},
+};
+
+const upb_msglayout google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit = {
+ NULL,
+ &google_protobuf_EnumDescriptorProto_EnumReservedRange__fields[0],
+ UPB_SIZE(16, 16), 2, false, 255,
+};
+
+static const upb_msglayout *const google_protobuf_EnumValueDescriptorProto_submsgs[1] = {
+ &google_protobuf_EnumValueOptions_msginit,
+};
+
+static const upb_msglayout_field google_protobuf_EnumValueDescriptorProto__fields[3] = {
+ {1, UPB_SIZE(8, 8), 1, 0, 12, 1},
+ {2, UPB_SIZE(4, 4), 2, 0, 5, 1},
+ {3, UPB_SIZE(16, 24), 3, 0, 11, 1},
+};
+
+const upb_msglayout google_protobuf_EnumValueDescriptorProto_msginit = {
+ &google_protobuf_EnumValueDescriptorProto_submsgs[0],
+ &google_protobuf_EnumValueDescriptorProto__fields[0],
+ UPB_SIZE(24, 32), 3, false, 255,
+};
+
+static const upb_msglayout *const google_protobuf_ServiceDescriptorProto_submsgs[2] = {
+ &google_protobuf_MethodDescriptorProto_msginit,
+ &google_protobuf_ServiceOptions_msginit,
+};
+
+static const upb_msglayout_field google_protobuf_ServiceDescriptorProto__fields[3] = {
+ {1, UPB_SIZE(4, 8), 1, 0, 12, 1},
+ {2, UPB_SIZE(16, 32), 0, 0, 11, 3},
+ {3, UPB_SIZE(12, 24), 2, 1, 11, 1},
+};
+
+const upb_msglayout google_protobuf_ServiceDescriptorProto_msginit = {
+ &google_protobuf_ServiceDescriptorProto_submsgs[0],
+ &google_protobuf_ServiceDescriptorProto__fields[0],
+ UPB_SIZE(24, 48), 3, false, 255,
+};
+
+static const upb_msglayout *const google_protobuf_MethodDescriptorProto_submsgs[1] = {
+ &google_protobuf_MethodOptions_msginit,
+};
+
+static const upb_msglayout_field google_protobuf_MethodDescriptorProto__fields[6] = {
+ {1, UPB_SIZE(4, 8), 1, 0, 12, 1},
+ {2, UPB_SIZE(12, 24), 2, 0, 12, 1},
+ {3, UPB_SIZE(20, 40), 3, 0, 12, 1},
+ {4, UPB_SIZE(28, 56), 4, 0, 11, 1},
+ {5, UPB_SIZE(1, 1), 5, 0, 8, 1},
+ {6, UPB_SIZE(2, 2), 6, 0, 8, 1},
+};
+
+const upb_msglayout google_protobuf_MethodDescriptorProto_msginit = {
+ &google_protobuf_MethodDescriptorProto_submsgs[0],
+ &google_protobuf_MethodDescriptorProto__fields[0],
+ UPB_SIZE(32, 64), 6, false, 255,
+};
+
+static const upb_msglayout *const google_protobuf_FileOptions_submsgs[1] = {
+ &google_protobuf_UninterpretedOption_msginit,
+};
+
+static const upb_msglayout_field google_protobuf_FileOptions__fields[21] = {
+ {1, UPB_SIZE(20, 24), 1, 0, 12, 1},
+ {8, UPB_SIZE(28, 40), 2, 0, 12, 1},
+ {9, UPB_SIZE(4, 4), 3, 0, 14, 1},
+ {10, UPB_SIZE(8, 8), 4, 0, 8, 1},
+ {11, UPB_SIZE(36, 56), 5, 0, 12, 1},
+ {16, UPB_SIZE(9, 9), 6, 0, 8, 1},
+ {17, UPB_SIZE(10, 10), 7, 0, 8, 1},
+ {18, UPB_SIZE(11, 11), 8, 0, 8, 1},
+ {20, UPB_SIZE(12, 12), 9, 0, 8, 1},
+ {23, UPB_SIZE(13, 13), 10, 0, 8, 1},
+ {27, UPB_SIZE(14, 14), 11, 0, 8, 1},
+ {31, UPB_SIZE(15, 15), 12, 0, 8, 1},
+ {36, UPB_SIZE(44, 72), 13, 0, 12, 1},
+ {37, UPB_SIZE(52, 88), 14, 0, 12, 1},
+ {39, UPB_SIZE(60, 104), 15, 0, 12, 1},
+ {40, UPB_SIZE(68, 120), 16, 0, 12, 1},
+ {41, UPB_SIZE(76, 136), 17, 0, 12, 1},
+ {42, UPB_SIZE(16, 16), 18, 0, 8, 1},
+ {44, UPB_SIZE(84, 152), 19, 0, 12, 1},
+ {45, UPB_SIZE(92, 168), 20, 0, 12, 1},
+ {999, UPB_SIZE(100, 184), 0, 0, 11, 3},
+};
+
+const upb_msglayout google_protobuf_FileOptions_msginit = {
+ &google_protobuf_FileOptions_submsgs[0],
+ &google_protobuf_FileOptions__fields[0],
+ UPB_SIZE(104, 192), 21, false, 255,
+};
+
+static const upb_msglayout *const google_protobuf_MessageOptions_submsgs[1] = {
+ &google_protobuf_UninterpretedOption_msginit,
+};
+
+static const upb_msglayout_field google_protobuf_MessageOptions__fields[5] = {
+ {1, UPB_SIZE(1, 1), 1, 0, 8, 1},
+ {2, UPB_SIZE(2, 2), 2, 0, 8, 1},
+ {3, UPB_SIZE(3, 3), 3, 0, 8, 1},
+ {7, UPB_SIZE(4, 4), 4, 0, 8, 1},
+ {999, UPB_SIZE(8, 8), 0, 0, 11, 3},
+};
+
+const upb_msglayout google_protobuf_MessageOptions_msginit = {
+ &google_protobuf_MessageOptions_submsgs[0],
+ &google_protobuf_MessageOptions__fields[0],
+ UPB_SIZE(16, 16), 5, false, 255,
+};
+
+static const upb_msglayout *const google_protobuf_FieldOptions_submsgs[1] = {
+ &google_protobuf_UninterpretedOption_msginit,
+};
+
+static const upb_msglayout_field google_protobuf_FieldOptions__fields[7] = {
+ {1, UPB_SIZE(4, 4), 1, 0, 14, 1},
+ {2, UPB_SIZE(12, 12), 2, 0, 8, 1},
+ {3, UPB_SIZE(13, 13), 3, 0, 8, 1},
+ {5, UPB_SIZE(14, 14), 4, 0, 8, 1},
+ {6, UPB_SIZE(8, 8), 5, 0, 14, 1},
+ {10, UPB_SIZE(15, 15), 6, 0, 8, 1},
+ {999, UPB_SIZE(16, 16), 0, 0, 11, 3},
+};
+
+const upb_msglayout google_protobuf_FieldOptions_msginit = {
+ &google_protobuf_FieldOptions_submsgs[0],
+ &google_protobuf_FieldOptions__fields[0],
+ UPB_SIZE(24, 24), 7, false, 255,
+};
+
+static const upb_msglayout *const google_protobuf_OneofOptions_submsgs[1] = {
+ &google_protobuf_UninterpretedOption_msginit,
+};
+
+static const upb_msglayout_field google_protobuf_OneofOptions__fields[1] = {
+ {999, UPB_SIZE(0, 0), 0, 0, 11, 3},
+};
+
+const upb_msglayout google_protobuf_OneofOptions_msginit = {
+ &google_protobuf_OneofOptions_submsgs[0],
+ &google_protobuf_OneofOptions__fields[0],
+ UPB_SIZE(8, 8), 1, false, 255,
+};
+
+static const upb_msglayout *const google_protobuf_EnumOptions_submsgs[1] = {
+ &google_protobuf_UninterpretedOption_msginit,
+};
+
+static const upb_msglayout_field google_protobuf_EnumOptions__fields[3] = {
+ {2, UPB_SIZE(1, 1), 1, 0, 8, 1},
+ {3, UPB_SIZE(2, 2), 2, 0, 8, 1},
+ {999, UPB_SIZE(4, 8), 0, 0, 11, 3},
+};
+
+const upb_msglayout google_protobuf_EnumOptions_msginit = {
+ &google_protobuf_EnumOptions_submsgs[0],
+ &google_protobuf_EnumOptions__fields[0],
+ UPB_SIZE(8, 16), 3, false, 255,
+};
+
+static const upb_msglayout *const google_protobuf_EnumValueOptions_submsgs[1] = {
+ &google_protobuf_UninterpretedOption_msginit,
+};
+
+static const upb_msglayout_field google_protobuf_EnumValueOptions__fields[2] = {
+ {1, UPB_SIZE(1, 1), 1, 0, 8, 1},
+ {999, UPB_SIZE(4, 8), 0, 0, 11, 3},
+};
+
+const upb_msglayout google_protobuf_EnumValueOptions_msginit = {
+ &google_protobuf_EnumValueOptions_submsgs[0],
+ &google_protobuf_EnumValueOptions__fields[0],
+ UPB_SIZE(8, 16), 2, false, 255,
+};
+
+static const upb_msglayout *const google_protobuf_ServiceOptions_submsgs[1] = {
+ &google_protobuf_UninterpretedOption_msginit,
+};
+
+static const upb_msglayout_field google_protobuf_ServiceOptions__fields[2] = {
+ {33, UPB_SIZE(1, 1), 1, 0, 8, 1},
+ {999, UPB_SIZE(4, 8), 0, 0, 11, 3},
+};
+
+const upb_msglayout google_protobuf_ServiceOptions_msginit = {
+ &google_protobuf_ServiceOptions_submsgs[0],
+ &google_protobuf_ServiceOptions__fields[0],
+ UPB_SIZE(8, 16), 2, false, 255,
+};
+
+static const upb_msglayout *const google_protobuf_MethodOptions_submsgs[1] = {
+ &google_protobuf_UninterpretedOption_msginit,
+};
+
+static const upb_msglayout_field google_protobuf_MethodOptions__fields[3] = {
+ {33, UPB_SIZE(8, 8), 1, 0, 8, 1},
+ {34, UPB_SIZE(4, 4), 2, 0, 14, 1},
+ {999, UPB_SIZE(12, 16), 0, 0, 11, 3},
+};
+
+const upb_msglayout google_protobuf_MethodOptions_msginit = {
+ &google_protobuf_MethodOptions_submsgs[0],
+ &google_protobuf_MethodOptions__fields[0],
+ UPB_SIZE(16, 24), 3, false, 255,
+};
+
+static const upb_msglayout *const google_protobuf_UninterpretedOption_submsgs[1] = {
+ &google_protobuf_UninterpretedOption_NamePart_msginit,
+};
+
+static const upb_msglayout_field google_protobuf_UninterpretedOption__fields[7] = {
+ {2, UPB_SIZE(56, 80), 0, 0, 11, 3},
+ {3, UPB_SIZE(32, 32), 1, 0, 12, 1},
+ {4, UPB_SIZE(8, 8), 2, 0, 4, 1},
+ {5, UPB_SIZE(16, 16), 3, 0, 3, 1},
+ {6, UPB_SIZE(24, 24), 4, 0, 1, 1},
+ {7, UPB_SIZE(40, 48), 5, 0, 12, 1},
+ {8, UPB_SIZE(48, 64), 6, 0, 12, 1},
+};
+
+const upb_msglayout google_protobuf_UninterpretedOption_msginit = {
+ &google_protobuf_UninterpretedOption_submsgs[0],
+ &google_protobuf_UninterpretedOption__fields[0],
+ UPB_SIZE(64, 96), 7, false, 255,
+};
+
+static const upb_msglayout_field google_protobuf_UninterpretedOption_NamePart__fields[2] = {
+ {1, UPB_SIZE(4, 8), 1, 0, 12, 2},
+ {2, UPB_SIZE(1, 1), 2, 0, 8, 2},
+};
+
+const upb_msglayout google_protobuf_UninterpretedOption_NamePart_msginit = {
+ NULL,
+ &google_protobuf_UninterpretedOption_NamePart__fields[0],
+ UPB_SIZE(16, 32), 2, false, 255,
+};
+
+static const upb_msglayout *const google_protobuf_SourceCodeInfo_submsgs[1] = {
+ &google_protobuf_SourceCodeInfo_Location_msginit,
+};
+
+static const upb_msglayout_field google_protobuf_SourceCodeInfo__fields[1] = {
+ {1, UPB_SIZE(0, 0), 0, 0, 11, 3},
+};
+
+const upb_msglayout google_protobuf_SourceCodeInfo_msginit = {
+ &google_protobuf_SourceCodeInfo_submsgs[0],
+ &google_protobuf_SourceCodeInfo__fields[0],
+ UPB_SIZE(8, 8), 1, false, 255,
+};
+
+static const upb_msglayout_field google_protobuf_SourceCodeInfo_Location__fields[5] = {
+ {1, UPB_SIZE(20, 40), 0, 0, 5, _UPB_LABEL_PACKED},
+ {2, UPB_SIZE(24, 48), 0, 0, 5, _UPB_LABEL_PACKED},
+ {3, UPB_SIZE(4, 8), 1, 0, 12, 1},
+ {4, UPB_SIZE(12, 24), 2, 0, 12, 1},
+ {6, UPB_SIZE(28, 56), 0, 0, 12, 3},
+};
+
+const upb_msglayout google_protobuf_SourceCodeInfo_Location_msginit = {
+ NULL,
+ &google_protobuf_SourceCodeInfo_Location__fields[0],
+ UPB_SIZE(32, 64), 5, false, 255,
+};
+
+static const upb_msglayout *const google_protobuf_GeneratedCodeInfo_submsgs[1] = {
+ &google_protobuf_GeneratedCodeInfo_Annotation_msginit,
+};
+
+static const upb_msglayout_field google_protobuf_GeneratedCodeInfo__fields[1] = {
+ {1, UPB_SIZE(0, 0), 0, 0, 11, 3},
+};
+
+const upb_msglayout google_protobuf_GeneratedCodeInfo_msginit = {
+ &google_protobuf_GeneratedCodeInfo_submsgs[0],
+ &google_protobuf_GeneratedCodeInfo__fields[0],
+ UPB_SIZE(8, 8), 1, false, 255,
+};
+
+static const upb_msglayout_field google_protobuf_GeneratedCodeInfo_Annotation__fields[4] = {
+ {1, UPB_SIZE(20, 32), 0, 0, 5, _UPB_LABEL_PACKED},
+ {2, UPB_SIZE(12, 16), 1, 0, 12, 1},
+ {3, UPB_SIZE(4, 4), 2, 0, 5, 1},
+ {4, UPB_SIZE(8, 8), 3, 0, 5, 1},
+};
+
+const upb_msglayout google_protobuf_GeneratedCodeInfo_Annotation_msginit = {
+ NULL,
+ &google_protobuf_GeneratedCodeInfo_Annotation__fields[0],
+ UPB_SIZE(24, 48), 4, false, 255,
+};
+
+
+
+
+#include
+#include
+#include
+#include
+#include
+
+
+/* Must be last. */
+
+typedef struct {
+ size_t len;
+ char str[1]; /* Null-terminated string data follows. */
+} str_t;
+
+struct upb_fielddef {
+ const upb_filedef *file;
+ const upb_msgdef *msgdef;
+ const char *full_name;
+ const char *json_name;
+ union {
+ int64_t sint;
+ uint64_t uint;
+ double dbl;
+ float flt;
+ bool boolean;
+ str_t *str;
+ } defaultval;
+ const upb_oneofdef *oneof;
+ union {
+ const upb_msgdef *msgdef;
+ const upb_enumdef *enumdef;
+ const google_protobuf_FieldDescriptorProto *unresolved;
+ } sub;
+ uint32_t number_;
+ uint16_t index_;
+ uint16_t layout_index;
+ uint32_t selector_base; /* Used to index into a upb::Handlers table. */
+ bool is_extension_;
+ bool lazy_;
+ bool packed_;
+ bool proto3_optional_;
+ upb_descriptortype_t type_;
+ upb_label_t label_;
+};
+
+struct upb_msgdef {
+ const upb_msglayout *layout;
+ const upb_filedef *file;
+ const char *full_name;
+ uint32_t selector_count;
+ uint32_t submsg_field_count;
+
+ /* Tables for looking up fields by number and name. */
+ upb_inttable itof;
+ upb_strtable ntof;
+
+ const upb_fielddef *fields;
+ const upb_oneofdef *oneofs;
+ int field_count;
+ int oneof_count;
+ int real_oneof_count;
+
+ /* Is this a map-entry message? */
+ bool map_entry;
+ upb_wellknowntype_t well_known_type;
+
+ /* TODO(haberman): proper extension ranges (there can be multiple). */
+};
+
+struct upb_enumdef {
+ const upb_filedef *file;
+ const char *full_name;
+ upb_strtable ntoi;
+ upb_inttable iton;
+ int32_t defaultval;
+};
+
+struct upb_oneofdef {
+ const upb_msgdef *parent;
+ const char *full_name;
+ int field_count;
+ bool synthetic;
+ const upb_fielddef **fields;
+ upb_strtable ntof;
+ upb_inttable itof;
+};
+
+struct upb_filedef {
+ const char *name;
+ const char *package;
+ const char *phpprefix;
+ const char *phpnamespace;
+
+ const upb_filedef **deps;
+ const upb_msgdef *msgs;
+ const upb_enumdef *enums;
+ const upb_fielddef *exts;
+ const upb_symtab *symtab;
+
+ int dep_count;
+ int msg_count;
+ int enum_count;
+ int ext_count;
+ upb_syntax_t syntax;
+};
+
+struct upb_symtab {
+ upb_arena *arena;
+ upb_strtable syms; /* full_name -> packed def ptr */
+ upb_strtable files; /* file_name -> upb_filedef* */
+ size_t bytes_loaded;
+};
+
+/* Inside a symtab we store tagged pointers to specific def types. */
+typedef enum {
+ UPB_DEFTYPE_FIELD = 0,
+
+ /* Only inside symtab table. */
+ UPB_DEFTYPE_MSG = 1,
+ UPB_DEFTYPE_ENUM = 2,
+
+ /* Only inside message table. */
+ UPB_DEFTYPE_ONEOF = 1,
+ UPB_DEFTYPE_FIELD_JSONNAME = 2
+} upb_deftype_t;
+
+static const void *unpack_def(upb_value v, upb_deftype_t type) {
+ uintptr_t num = (uintptr_t)upb_value_getconstptr(v);
+ return (num & 3) == type ? (const void*)(num & ~3) : NULL;
+}
+
+static upb_value pack_def(const void *ptr, upb_deftype_t type) {
+ uintptr_t num = (uintptr_t)ptr | type;
+ return upb_value_constptr((const void*)num);
+}
+
+/* isalpha() etc. from are locale-dependent, which we don't want. */
+static bool upb_isbetween(char c, char low, char high) {
+ return c >= low && c <= high;
+}
+
+static bool upb_isletter(char c) {
+ return upb_isbetween(c, 'A', 'Z') || upb_isbetween(c, 'a', 'z') || c == '_';
+}
+
+static bool upb_isalphanum(char c) {
+ return upb_isletter(c) || upb_isbetween(c, '0', '9');
+}
+
+static const char *shortdefname(const char *fullname) {
+ const char *p;
+
+ if (fullname == NULL) {
+ return NULL;
+ } else if ((p = strrchr(fullname, '.')) == NULL) {
+ /* No '.' in the name, return the full string. */
+ return fullname;
+ } else {
+ /* Return one past the last '.'. */
+ return p + 1;
+ }
+}
+
+/* All submessage fields are lower than all other fields.
+ * Secondly, fields are increasing in order. */
+uint32_t field_rank(const upb_fielddef *f) {
+ uint32_t ret = upb_fielddef_number(f);
+ const uint32_t high_bit = 1 << 30;
+ UPB_ASSERT(ret < high_bit);
+ if (!upb_fielddef_issubmsg(f))
+ ret |= high_bit;
+ return ret;
+}
+
+int cmp_fields(const void *p1, const void *p2) {
+ const upb_fielddef *f1 = *(upb_fielddef*const*)p1;
+ const upb_fielddef *f2 = *(upb_fielddef*const*)p2;
+ return field_rank(f1) - field_rank(f2);
+}
+
+/* A few implementation details of handlers. We put these here to avoid
+ * a def -> handlers dependency. */
+
+#define UPB_STATIC_SELECTOR_COUNT 3 /* Warning: also in upb/handlers.h. */
+
+static uint32_t upb_handlers_selectorbaseoffset(const upb_fielddef *f) {
+ return upb_fielddef_isseq(f) ? 2 : 0;
+}
+
+static uint32_t upb_handlers_selectorcount(const upb_fielddef *f) {
+ uint32_t ret = 1;
+ if (upb_fielddef_isseq(f)) ret += 2; /* STARTSEQ/ENDSEQ */
+ if (upb_fielddef_isstring(f)) ret += 2; /* [STRING]/STARTSTR/ENDSTR */
+ if (upb_fielddef_issubmsg(f)) {
+ /* ENDSUBMSG (STARTSUBMSG is at table beginning) */
+ ret += 0;
+ if (upb_fielddef_lazy(f)) {
+ /* STARTSTR/ENDSTR/STRING (for lazy) */
+ ret += 3;
+ }
+ }
+ return ret;
+}
+
+static void upb_status_setoom(upb_status *status) {
+ upb_status_seterrmsg(status, "out of memory");
+}
+
+static void assign_msg_wellknowntype(upb_msgdef *m) {
+ const char *name = upb_msgdef_fullname(m);
+ if (name == NULL) {
+ m->well_known_type = UPB_WELLKNOWN_UNSPECIFIED;
+ return;
+ }
+ if (!strcmp(name, "google.protobuf.Any")) {
+ m->well_known_type = UPB_WELLKNOWN_ANY;
+ } else if (!strcmp(name, "google.protobuf.FieldMask")) {
+ m->well_known_type = UPB_WELLKNOWN_FIELDMASK;
+ } else if (!strcmp(name, "google.protobuf.Duration")) {
+ m->well_known_type = UPB_WELLKNOWN_DURATION;
+ } else if (!strcmp(name, "google.protobuf.Timestamp")) {
+ m->well_known_type = UPB_WELLKNOWN_TIMESTAMP;
+ } else if (!strcmp(name, "google.protobuf.DoubleValue")) {
+ m->well_known_type = UPB_WELLKNOWN_DOUBLEVALUE;
+ } else if (!strcmp(name, "google.protobuf.FloatValue")) {
+ m->well_known_type = UPB_WELLKNOWN_FLOATVALUE;
+ } else if (!strcmp(name, "google.protobuf.Int64Value")) {
+ m->well_known_type = UPB_WELLKNOWN_INT64VALUE;
+ } else if (!strcmp(name, "google.protobuf.UInt64Value")) {
+ m->well_known_type = UPB_WELLKNOWN_UINT64VALUE;
+ } else if (!strcmp(name, "google.protobuf.Int32Value")) {
+ m->well_known_type = UPB_WELLKNOWN_INT32VALUE;
+ } else if (!strcmp(name, "google.protobuf.UInt32Value")) {
+ m->well_known_type = UPB_WELLKNOWN_UINT32VALUE;
+ } else if (!strcmp(name, "google.protobuf.BoolValue")) {
+ m->well_known_type = UPB_WELLKNOWN_BOOLVALUE;
+ } else if (!strcmp(name, "google.protobuf.StringValue")) {
+ m->well_known_type = UPB_WELLKNOWN_STRINGVALUE;
+ } else if (!strcmp(name, "google.protobuf.BytesValue")) {
+ m->well_known_type = UPB_WELLKNOWN_BYTESVALUE;
+ } else if (!strcmp(name, "google.protobuf.Value")) {
+ m->well_known_type = UPB_WELLKNOWN_VALUE;
+ } else if (!strcmp(name, "google.protobuf.ListValue")) {
+ m->well_known_type = UPB_WELLKNOWN_LISTVALUE;
+ } else if (!strcmp(name, "google.protobuf.Struct")) {
+ m->well_known_type = UPB_WELLKNOWN_STRUCT;
+ } else {
+ m->well_known_type = UPB_WELLKNOWN_UNSPECIFIED;
+ }
+}
+
+
+/* upb_enumdef ****************************************************************/
+
+const char *upb_enumdef_fullname(const upb_enumdef *e) {
+ return e->full_name;
+}
+
+const char *upb_enumdef_name(const upb_enumdef *e) {
+ return shortdefname(e->full_name);
+}
+
+const upb_filedef *upb_enumdef_file(const upb_enumdef *e) {
+ return e->file;
+}
+
+int32_t upb_enumdef_default(const upb_enumdef *e) {
+ UPB_ASSERT(upb_enumdef_iton(e, e->defaultval));
+ return e->defaultval;
+}
+
+int upb_enumdef_numvals(const upb_enumdef *e) {
+ return (int)upb_strtable_count(&e->ntoi);
+}
+
+void upb_enum_begin(upb_enum_iter *i, const upb_enumdef *e) {
+ /* We iterate over the ntoi table, to account for duplicate numbers. */
+ upb_strtable_begin(i, &e->ntoi);
+}
+
+void upb_enum_next(upb_enum_iter *iter) { upb_strtable_next(iter); }
+bool upb_enum_done(upb_enum_iter *iter) { return upb_strtable_done(iter); }
+
+bool upb_enumdef_ntoi(const upb_enumdef *def, const char *name,
+ size_t len, int32_t *num) {
+ upb_value v;
+ if (!upb_strtable_lookup2(&def->ntoi, name, len, &v)) {
+ return false;
+ }
+ if (num) *num = upb_value_getint32(v);
+ return true;
+}
+
+const char *upb_enumdef_iton(const upb_enumdef *def, int32_t num) {
+ upb_value v;
+ return upb_inttable_lookup32(&def->iton, num, &v) ?
+ upb_value_getcstr(v) : NULL;
+}
+
+const char *upb_enum_iter_name(upb_enum_iter *iter) {
+ return upb_strtable_iter_key(iter).data;
+}
+
+int32_t upb_enum_iter_number(upb_enum_iter *iter) {
+ return upb_value_getint32(upb_strtable_iter_value(iter));
+}
+
+
+/* upb_fielddef ***************************************************************/
+
+const char *upb_fielddef_fullname(const upb_fielddef *f) {
+ return f->full_name;
+}
+
+upb_fieldtype_t upb_fielddef_type(const upb_fielddef *f) {
+ switch (f->type_) {
+ case UPB_DESCRIPTOR_TYPE_DOUBLE:
+ return UPB_TYPE_DOUBLE;
+ case UPB_DESCRIPTOR_TYPE_FLOAT:
+ return UPB_TYPE_FLOAT;
+ case UPB_DESCRIPTOR_TYPE_INT64:
+ case UPB_DESCRIPTOR_TYPE_SINT64:
+ case UPB_DESCRIPTOR_TYPE_SFIXED64:
+ return UPB_TYPE_INT64;
+ case UPB_DESCRIPTOR_TYPE_INT32:
+ case UPB_DESCRIPTOR_TYPE_SFIXED32:
+ case UPB_DESCRIPTOR_TYPE_SINT32:
+ return UPB_TYPE_INT32;
+ case UPB_DESCRIPTOR_TYPE_UINT64:
+ case UPB_DESCRIPTOR_TYPE_FIXED64:
+ return UPB_TYPE_UINT64;
+ case UPB_DESCRIPTOR_TYPE_UINT32:
+ case UPB_DESCRIPTOR_TYPE_FIXED32:
+ return UPB_TYPE_UINT32;
+ case UPB_DESCRIPTOR_TYPE_ENUM:
+ return UPB_TYPE_ENUM;
+ case UPB_DESCRIPTOR_TYPE_BOOL:
+ return UPB_TYPE_BOOL;
+ case UPB_DESCRIPTOR_TYPE_STRING:
+ return UPB_TYPE_STRING;
+ case UPB_DESCRIPTOR_TYPE_BYTES:
+ return UPB_TYPE_BYTES;
+ case UPB_DESCRIPTOR_TYPE_GROUP:
+ case UPB_DESCRIPTOR_TYPE_MESSAGE:
+ return UPB_TYPE_MESSAGE;
+ }
+ UPB_UNREACHABLE();
+}
+
+upb_descriptortype_t upb_fielddef_descriptortype(const upb_fielddef *f) {
+ return f->type_;
+}
+
+uint32_t upb_fielddef_index(const upb_fielddef *f) {
+ return f->index_;
+}
+
+upb_label_t upb_fielddef_label(const upb_fielddef *f) {
+ return f->label_;
+}
+
+uint32_t upb_fielddef_number(const upb_fielddef *f) {
+ return f->number_;
+}
+
+bool upb_fielddef_isextension(const upb_fielddef *f) {
+ return f->is_extension_;
+}
+
+bool upb_fielddef_lazy(const upb_fielddef *f) {
+ return f->lazy_;
+}
+
+bool upb_fielddef_packed(const upb_fielddef *f) {
+ return f->packed_;
+}
+
+const char *upb_fielddef_name(const upb_fielddef *f) {
+ return shortdefname(f->full_name);
+}
+
+const char *upb_fielddef_jsonname(const upb_fielddef *f) {
+ return f->json_name;
+}
+
+uint32_t upb_fielddef_selectorbase(const upb_fielddef *f) {
+ return f->selector_base;
+}
+
+const upb_filedef *upb_fielddef_file(const upb_fielddef *f) {
+ return f->file;
+}
+
+const upb_msgdef *upb_fielddef_containingtype(const upb_fielddef *f) {
+ return f->msgdef;
+}
+
+const upb_oneofdef *upb_fielddef_containingoneof(const upb_fielddef *f) {
+ return f->oneof;
+}
+
+const upb_oneofdef *upb_fielddef_realcontainingoneof(const upb_fielddef *f) {
+ if (!f->oneof || upb_oneofdef_issynthetic(f->oneof)) return NULL;
+ return f->oneof;
+}
+
+upb_msgval upb_fielddef_default(const upb_fielddef *f) {
+ UPB_ASSERT(!upb_fielddef_issubmsg(f));
+ upb_msgval ret;
+ if (upb_fielddef_isstring(f)) {
+ str_t *str = f->defaultval.str;
+ if (str) {
+ ret.str_val.data = str->str;
+ ret.str_val.size = str->len;
+ } else {
+ ret.str_val.size = 0;
+ }
+ } else {
+ memcpy(&ret, &f->defaultval, 8);
+ }
+ return ret;
+}
+
+static void chkdefaulttype(const upb_fielddef *f, int ctype) {
+ UPB_UNUSED(f);
+ UPB_UNUSED(ctype);
+}
+
+int64_t upb_fielddef_defaultint64(const upb_fielddef *f) {
+ chkdefaulttype(f, UPB_TYPE_INT64);
+ return f->defaultval.sint;
+}
+
+int32_t upb_fielddef_defaultint32(const upb_fielddef *f) {
+ chkdefaulttype(f, UPB_TYPE_INT32);
+ return (int32_t)f->defaultval.sint;
+}
+
+uint64_t upb_fielddef_defaultuint64(const upb_fielddef *f) {
+ chkdefaulttype(f, UPB_TYPE_UINT64);
+ return f->defaultval.uint;
+}
+
+uint32_t upb_fielddef_defaultuint32(const upb_fielddef *f) {
+ chkdefaulttype(f, UPB_TYPE_UINT32);
+ return (uint32_t)f->defaultval.uint;
+}
+
+bool upb_fielddef_defaultbool(const upb_fielddef *f) {
+ chkdefaulttype(f, UPB_TYPE_BOOL);
+ return f->defaultval.boolean;
+}
+
+float upb_fielddef_defaultfloat(const upb_fielddef *f) {
+ chkdefaulttype(f, UPB_TYPE_FLOAT);
+ return f->defaultval.flt;
+}
+
+double upb_fielddef_defaultdouble(const upb_fielddef *f) {
+ chkdefaulttype(f, UPB_TYPE_DOUBLE);
+ return f->defaultval.dbl;
+}
+
+const char *upb_fielddef_defaultstr(const upb_fielddef *f, size_t *len) {
+ str_t *str = f->defaultval.str;
+ UPB_ASSERT(upb_fielddef_type(f) == UPB_TYPE_STRING ||
+ upb_fielddef_type(f) == UPB_TYPE_BYTES ||
+ upb_fielddef_type(f) == UPB_TYPE_ENUM);
+ if (str) {
+ if (len) *len = str->len;
+ return str->str;
+ } else {
+ if (len) *len = 0;
+ return NULL;
+ }
+}
+
+const upb_msgdef *upb_fielddef_msgsubdef(const upb_fielddef *f) {
+ return upb_fielddef_type(f) == UPB_TYPE_MESSAGE ? f->sub.msgdef : NULL;
+}
+
+const upb_enumdef *upb_fielddef_enumsubdef(const upb_fielddef *f) {
+ return upb_fielddef_type(f) == UPB_TYPE_ENUM ? f->sub.enumdef : NULL;
+}
+
+const upb_msglayout_field *upb_fielddef_layout(const upb_fielddef *f) {
+ return &f->msgdef->layout->fields[f->layout_index];
+}
+
+bool upb_fielddef_issubmsg(const upb_fielddef *f) {
+ return upb_fielddef_type(f) == UPB_TYPE_MESSAGE;
+}
+
+bool upb_fielddef_isstring(const upb_fielddef *f) {
+ return upb_fielddef_type(f) == UPB_TYPE_STRING ||
+ upb_fielddef_type(f) == UPB_TYPE_BYTES;
+}
+
+bool upb_fielddef_isseq(const upb_fielddef *f) {
+ return upb_fielddef_label(f) == UPB_LABEL_REPEATED;
+}
+
+bool upb_fielddef_isprimitive(const upb_fielddef *f) {
+ return !upb_fielddef_isstring(f) && !upb_fielddef_issubmsg(f);
+}
+
+bool upb_fielddef_ismap(const upb_fielddef *f) {
+ return upb_fielddef_isseq(f) && upb_fielddef_issubmsg(f) &&
+ upb_msgdef_mapentry(upb_fielddef_msgsubdef(f));
+}
+
+bool upb_fielddef_hassubdef(const upb_fielddef *f) {
+ return upb_fielddef_issubmsg(f) || upb_fielddef_type(f) == UPB_TYPE_ENUM;
+}
+
+bool upb_fielddef_haspresence(const upb_fielddef *f) {
+ if (upb_fielddef_isseq(f)) return false;
+ return upb_fielddef_issubmsg(f) || upb_fielddef_containingoneof(f) ||
+ f->file->syntax == UPB_SYNTAX_PROTO2;
+}
+
+static bool between(int32_t x, int32_t low, int32_t high) {
+ return x >= low && x <= high;
+}
+
+bool upb_fielddef_checklabel(int32_t label) { return between(label, 1, 3); }
+bool upb_fielddef_checktype(int32_t type) { return between(type, 1, 11); }
+bool upb_fielddef_checkintfmt(int32_t fmt) { return between(fmt, 1, 3); }
+
+bool upb_fielddef_checkdescriptortype(int32_t type) {
+ return between(type, 1, 18);
+}
+
+/* upb_msgdef *****************************************************************/
+
+const char *upb_msgdef_fullname(const upb_msgdef *m) {
+ return m->full_name;
+}
+
+const upb_filedef *upb_msgdef_file(const upb_msgdef *m) {
+ return m->file;
+}
+
+const char *upb_msgdef_name(const upb_msgdef *m) {
+ return shortdefname(m->full_name);
+}
+
+upb_syntax_t upb_msgdef_syntax(const upb_msgdef *m) {
+ return m->file->syntax;
+}
+
+size_t upb_msgdef_selectorcount(const upb_msgdef *m) {
+ return m->selector_count;
+}
+
+uint32_t upb_msgdef_submsgfieldcount(const upb_msgdef *m) {
+ return m->submsg_field_count;
+}
+
+const upb_fielddef *upb_msgdef_itof(const upb_msgdef *m, uint32_t i) {
+ upb_value val;
+ return upb_inttable_lookup32(&m->itof, i, &val) ?
+ upb_value_getconstptr(val) : NULL;
+}
+
+const upb_fielddef *upb_msgdef_ntof(const upb_msgdef *m, const char *name,
+ size_t len) {
+ upb_value val;
+
+ if (!upb_strtable_lookup2(&m->ntof, name, len, &val)) {
+ return NULL;
+ }
+
+ return unpack_def(val, UPB_DEFTYPE_FIELD);
+}
+
+const upb_oneofdef *upb_msgdef_ntoo(const upb_msgdef *m, const char *name,
+ size_t len) {
+ upb_value val;
+
+ if (!upb_strtable_lookup2(&m->ntof, name, len, &val)) {
+ return NULL;
+ }
+
+ return unpack_def(val, UPB_DEFTYPE_ONEOF);
+}
+
+bool upb_msgdef_lookupname(const upb_msgdef *m, const char *name, size_t len,
+ const upb_fielddef **f, const upb_oneofdef **o) {
+ upb_value val;
+
+ if (!upb_strtable_lookup2(&m->ntof, name, len, &val)) {
+ return false;
+ }
+
+ *o = unpack_def(val, UPB_DEFTYPE_ONEOF);
+ *f = unpack_def(val, UPB_DEFTYPE_FIELD);
+ return *o || *f; /* False if this was a JSON name. */
+}
+
+const upb_fielddef *upb_msgdef_lookupjsonname(const upb_msgdef *m,
+ const char *name, size_t len) {
+ upb_value val;
+ const upb_fielddef* f;
+
+ if (!upb_strtable_lookup2(&m->ntof, name, len, &val)) {
+ return NULL;
+ }
+
+ f = unpack_def(val, UPB_DEFTYPE_FIELD);
+ if (!f) f = unpack_def(val, UPB_DEFTYPE_FIELD_JSONNAME);
+
+ return f;
+}
+
+int upb_msgdef_numfields(const upb_msgdef *m) {
+ return m->field_count;
+}
+
+int upb_msgdef_numoneofs(const upb_msgdef *m) {
+ return m->oneof_count;
+}
+
+int upb_msgdef_numrealoneofs(const upb_msgdef *m) {
+ return m->real_oneof_count;
+}
+
+int upb_msgdef_fieldcount(const upb_msgdef *m) {
+ return m->field_count;
+}
+
+int upb_msgdef_oneofcount(const upb_msgdef *m) {
+ return m->oneof_count;
+}
+
+int upb_msgdef_realoneofcount(const upb_msgdef *m) {
+ return m->real_oneof_count;
+}
+
+const upb_msglayout *upb_msgdef_layout(const upb_msgdef *m) {
+ return m->layout;
+}
+
+const upb_fielddef *upb_msgdef_field(const upb_msgdef *m, int i) {
+ UPB_ASSERT(i >= 0 && i < m->field_count);
+ return &m->fields[i];
+}
+
+const upb_oneofdef *upb_msgdef_oneof(const upb_msgdef *m, int i) {
+ UPB_ASSERT(i >= 0 && i < m->oneof_count);
+ return &m->oneofs[i];
+}
+
+bool upb_msgdef_mapentry(const upb_msgdef *m) {
+ return m->map_entry;
+}
+
+upb_wellknowntype_t upb_msgdef_wellknowntype(const upb_msgdef *m) {
+ return m->well_known_type;
+}
+
+bool upb_msgdef_isnumberwrapper(const upb_msgdef *m) {
+ upb_wellknowntype_t type = upb_msgdef_wellknowntype(m);
+ return type >= UPB_WELLKNOWN_DOUBLEVALUE &&
+ type <= UPB_WELLKNOWN_UINT32VALUE;
+}
+
+bool upb_msgdef_iswrapper(const upb_msgdef *m) {
+ upb_wellknowntype_t type = upb_msgdef_wellknowntype(m);
+ return type >= UPB_WELLKNOWN_DOUBLEVALUE &&
+ type <= UPB_WELLKNOWN_BOOLVALUE;
+}
+
+void upb_msg_field_begin(upb_msg_field_iter *iter, const upb_msgdef *m) {
+ upb_inttable_begin(iter, &m->itof);
+}
+
+void upb_msg_field_next(upb_msg_field_iter *iter) { upb_inttable_next(iter); }
+
+bool upb_msg_field_done(const upb_msg_field_iter *iter) {
+ return upb_inttable_done(iter);
+}
+
+upb_fielddef *upb_msg_iter_field(const upb_msg_field_iter *iter) {
+ return (upb_fielddef *)upb_value_getconstptr(upb_inttable_iter_value(iter));
+}
+
+void upb_msg_field_iter_setdone(upb_msg_field_iter *iter) {
+ upb_inttable_iter_setdone(iter);
+}
+
+bool upb_msg_field_iter_isequal(const upb_msg_field_iter * iter1,
+ const upb_msg_field_iter * iter2) {
+ return upb_inttable_iter_isequal(iter1, iter2);
+}
+
+void upb_msg_oneof_begin(upb_msg_oneof_iter *iter, const upb_msgdef *m) {
+ upb_strtable_begin(iter, &m->ntof);
+ /* We need to skip past any initial fields. */
+ while (!upb_strtable_done(iter) &&
+ !unpack_def(upb_strtable_iter_value(iter), UPB_DEFTYPE_ONEOF)) {
+ upb_strtable_next(iter);
+ }
+}
+
+void upb_msg_oneof_next(upb_msg_oneof_iter *iter) {
+ /* We need to skip past fields to return only oneofs. */
+ do {
+ upb_strtable_next(iter);
+ } while (!upb_strtable_done(iter) &&
+ !unpack_def(upb_strtable_iter_value(iter), UPB_DEFTYPE_ONEOF));
+}
+
+bool upb_msg_oneof_done(const upb_msg_oneof_iter *iter) {
+ return upb_strtable_done(iter);
+}
+
+const upb_oneofdef *upb_msg_iter_oneof(const upb_msg_oneof_iter *iter) {
+ return unpack_def(upb_strtable_iter_value(iter), UPB_DEFTYPE_ONEOF);
+}
+
+void upb_msg_oneof_iter_setdone(upb_msg_oneof_iter *iter) {
+ upb_strtable_iter_setdone(iter);
+}
+
+bool upb_msg_oneof_iter_isequal(const upb_msg_oneof_iter *iter1,
+ const upb_msg_oneof_iter *iter2) {
+ return upb_strtable_iter_isequal(iter1, iter2);
+}
+
+/* upb_oneofdef ***************************************************************/
+
+const char *upb_oneofdef_name(const upb_oneofdef *o) {
+ return shortdefname(o->full_name);
+}
+
+const upb_msgdef *upb_oneofdef_containingtype(const upb_oneofdef *o) {
+ return o->parent;
+}
+
+int upb_oneofdef_fieldcount(const upb_oneofdef *o) {
+ return o->field_count;
+}
+
+const upb_fielddef *upb_oneofdef_field(const upb_oneofdef *o, int i) {
+ UPB_ASSERT(i < o->field_count);
+ return o->fields[i];
+}
+
+int upb_oneofdef_numfields(const upb_oneofdef *o) {
+ return o->field_count;
+}
+
+uint32_t upb_oneofdef_index(const upb_oneofdef *o) {
+ return o - o->parent->oneofs;
+}
+
+bool upb_oneofdef_issynthetic(const upb_oneofdef *o) {
+ return o->synthetic;
+}
+
+const upb_fielddef *upb_oneofdef_ntof(const upb_oneofdef *o,
+ const char *name, size_t length) {
+ upb_value val;
+ return upb_strtable_lookup2(&o->ntof, name, length, &val) ?
+ upb_value_getptr(val) : NULL;
+}
+
+const upb_fielddef *upb_oneofdef_itof(const upb_oneofdef *o, uint32_t num) {
+ upb_value val;
+ return upb_inttable_lookup32(&o->itof, num, &val) ?
+ upb_value_getptr(val) : NULL;
+}
+
+void upb_oneof_begin(upb_oneof_iter *iter, const upb_oneofdef *o) {
+ upb_inttable_begin(iter, &o->itof);
+}
+
+void upb_oneof_next(upb_oneof_iter *iter) {
+ upb_inttable_next(iter);
+}
+
+bool upb_oneof_done(upb_oneof_iter *iter) {
+ return upb_inttable_done(iter);
+}
+
+upb_fielddef *upb_oneof_iter_field(const upb_oneof_iter *iter) {
+ return (upb_fielddef *)upb_value_getconstptr(upb_inttable_iter_value(iter));
+}
+
+void upb_oneof_iter_setdone(upb_oneof_iter *iter) {
+ upb_inttable_iter_setdone(iter);
+}
+
+/* upb_filedef ****************************************************************/
+
+const char *upb_filedef_name(const upb_filedef *f) {
+ return f->name;
+}
+
+const char *upb_filedef_package(const upb_filedef *f) {
+ return f->package;
+}
+
+const char *upb_filedef_phpprefix(const upb_filedef *f) {
+ return f->phpprefix;
+}
+
+const char *upb_filedef_phpnamespace(const upb_filedef *f) {
+ return f->phpnamespace;
+}
+
+upb_syntax_t upb_filedef_syntax(const upb_filedef *f) {
+ return f->syntax;
+}
+
+int upb_filedef_msgcount(const upb_filedef *f) {
+ return f->msg_count;
+}
+
+int upb_filedef_depcount(const upb_filedef *f) {
+ return f->dep_count;
+}
+
+int upb_filedef_enumcount(const upb_filedef *f) {
+ return f->enum_count;
+}
+
+const upb_filedef *upb_filedef_dep(const upb_filedef *f, int i) {
+ return i < 0 || i >= f->dep_count ? NULL : f->deps[i];
+}
+
+const upb_msgdef *upb_filedef_msg(const upb_filedef *f, int i) {
+ return i < 0 || i >= f->msg_count ? NULL : &f->msgs[i];
+}
+
+const upb_enumdef *upb_filedef_enum(const upb_filedef *f, int i) {
+ return i < 0 || i >= f->enum_count ? NULL : &f->enums[i];
+}
+
+const upb_symtab *upb_filedef_symtab(const upb_filedef *f) {
+ return f->symtab;
+}
+
+void upb_symtab_free(upb_symtab *s) {
+ upb_arena_free(s->arena);
+ upb_gfree(s);
+}
+
+upb_symtab *upb_symtab_new(void) {
+ upb_symtab *s = upb_gmalloc(sizeof(*s));
+ upb_alloc *alloc;
+
+ if (!s) {
+ return NULL;
+ }
+
+ s->arena = upb_arena_new();
+ s->bytes_loaded = 0;
+ alloc = upb_arena_alloc(s->arena);
+
+ if (!upb_strtable_init2(&s->syms, UPB_CTYPE_CONSTPTR, 32, alloc) ||
+ !upb_strtable_init2(&s->files, UPB_CTYPE_CONSTPTR, 4, alloc)) {
+ upb_arena_free(s->arena);
+ upb_gfree(s);
+ s = NULL;
+ }
+ return s;
+}
+
+const upb_msgdef *upb_symtab_lookupmsg(const upb_symtab *s, const char *sym) {
+ upb_value v;
+ return upb_strtable_lookup(&s->syms, sym, &v) ?
+ unpack_def(v, UPB_DEFTYPE_MSG) : NULL;
+}
+
+const upb_msgdef *upb_symtab_lookupmsg2(const upb_symtab *s, const char *sym,
+ size_t len) {
+ upb_value v;
+ return upb_strtable_lookup2(&s->syms, sym, len, &v) ?
+ unpack_def(v, UPB_DEFTYPE_MSG) : NULL;
+}
+
+const upb_enumdef *upb_symtab_lookupenum(const upb_symtab *s, const char *sym) {
+ upb_value v;
+ return upb_strtable_lookup(&s->syms, sym, &v) ?
+ unpack_def(v, UPB_DEFTYPE_ENUM) : NULL;
+}
+
+const upb_filedef *upb_symtab_lookupfile(const upb_symtab *s, const char *name) {
+ upb_value v;
+ return upb_strtable_lookup(&s->files, name, &v) ? upb_value_getconstptr(v)
+ : NULL;
+}
+
+const upb_filedef *upb_symtab_lookupfile2(
+ const upb_symtab *s, const char *name, size_t len) {
+ upb_value v;
+ return upb_strtable_lookup2(&s->files, name, len, &v) ?
+ upb_value_getconstptr(v) : NULL;
+}
+
+int upb_symtab_filecount(const upb_symtab *s) {
+ return (int)upb_strtable_count(&s->files);
+}
+
+/* Code to build defs from descriptor protos. *********************************/
+
+/* There is a question of how much validation to do here. It will be difficult
+ * to perfectly match the amount of validation performed by proto2. But since
+ * this code is used to directly build defs from Ruby (for example) we do need
+ * to validate important constraints like uniqueness of names and numbers. */
+
+#define CHK_OOM(x) if (!(x)) { symtab_oomerr(ctx); }
+
+typedef struct {
+ upb_symtab *symtab;
+ upb_filedef *file; /* File we are building. */
+ upb_arena *file_arena; /* Allocate defs here. */
+ upb_alloc *alloc; /* Alloc of file_arena, for tables. */
+ const upb_msglayout **layouts; /* NULL if we should build layouts. */
+ upb_status *status; /* Record errors here. */
+ jmp_buf err; /* longjmp() on error. */
+} symtab_addctx;
+
+UPB_NORETURN UPB_NOINLINE UPB_PRINTF(2, 3)
+static void symtab_errf(symtab_addctx *ctx, const char *fmt, ...) {
+ va_list argp;
+ va_start(argp, fmt);
+ upb_status_vseterrf(ctx->status, fmt, argp);
+ va_end(argp);
+ UPB_LONGJMP(ctx->err, 1);
+}
+
+UPB_NORETURN UPB_NOINLINE
+static void symtab_oomerr(symtab_addctx *ctx) {
+ upb_status_setoom(ctx->status);
+ UPB_LONGJMP(ctx->err, 1);
+}
+
+void *symtab_alloc(symtab_addctx *ctx, size_t bytes) {
+ void *ret = upb_arena_malloc(ctx->file_arena, bytes);
+ if (!ret) symtab_oomerr(ctx);
+ return ret;
+}
+
+static void check_ident(symtab_addctx *ctx, upb_strview name, bool full) {
+ const char *str = name.data;
+ size_t len = name.size;
+ bool start = true;
+ size_t i;
+ for (i = 0; i < len; i++) {
+ char c = str[i];
+ if (c == '.') {
+ if (start || !full) {
+ symtab_errf(ctx, "invalid name: unexpected '.' (%.*s)", (int)len, str);
+ }
+ start = true;
+ } else if (start) {
+ if (!upb_isletter(c)) {
+ symtab_errf(
+ ctx,
+ "invalid name: path components must start with a letter (%.*s)",
+ (int)len, str);
+ }
+ start = false;
+ } else {
+ if (!upb_isalphanum(c)) {
+ symtab_errf(ctx, "invalid name: non-alphanumeric character (%.*s)",
+ (int)len, str);
+ }
+ }
+ }
+ if (start) {
+ symtab_errf(ctx, "invalid name: empty part (%.*s)", (int)len, str);
+ }
+}
+
+static size_t div_round_up(size_t n, size_t d) {
+ return (n + d - 1) / d;
+}
+
+static size_t upb_msgval_sizeof(upb_fieldtype_t type) {
+ switch (type) {
+ case UPB_TYPE_DOUBLE:
+ case UPB_TYPE_INT64:
+ case UPB_TYPE_UINT64:
+ return 8;
+ case UPB_TYPE_ENUM:
+ case UPB_TYPE_INT32:
+ case UPB_TYPE_UINT32:
+ case UPB_TYPE_FLOAT:
+ return 4;
+ case UPB_TYPE_BOOL:
+ return 1;
+ case UPB_TYPE_MESSAGE:
+ return sizeof(void*);
+ case UPB_TYPE_BYTES:
+ case UPB_TYPE_STRING:
+ return sizeof(upb_strview);
+ }
+ UPB_UNREACHABLE();
+}
+
+static uint8_t upb_msg_fielddefsize(const upb_fielddef *f) {
+ if (upb_msgdef_mapentry(upb_fielddef_containingtype(f))) {
+ upb_map_entry ent;
+ UPB_ASSERT(sizeof(ent.k) == sizeof(ent.v));
+ return sizeof(ent.k);
+ } else if (upb_fielddef_isseq(f)) {
+ return sizeof(void*);
+ } else {
+ return upb_msgval_sizeof(upb_fielddef_type(f));
+ }
+}
+
+static uint32_t upb_msglayout_place(upb_msglayout *l, size_t size) {
+ uint32_t ret;
+
+ l->size = UPB_ALIGN_UP(l->size, size);
+ ret = l->size;
+ l->size += size;
+ return ret;
+}
+
+static int field_number_cmp(const void *p1, const void *p2) {
+ const upb_msglayout_field *f1 = p1;
+ const upb_msglayout_field *f2 = p2;
+ return f1->number - f2->number;
+}
+
+static void assign_layout_indices(const upb_msgdef *m, upb_msglayout_field *fields) {
+ int i;
+ int n = upb_msgdef_numfields(m);
+ for (i = 0; i < n; i++) {
+ upb_fielddef *f = (upb_fielddef*)upb_msgdef_itof(m, fields[i].number);
+ UPB_ASSERT(f);
+ f->layout_index = i;
+ }
+}
+
+/* This function is the dynamic equivalent of message_layout.{cc,h} in upbc.
+ * It computes a dynamic layout for all of the fields in |m|. */
+static void make_layout(symtab_addctx *ctx, const upb_msgdef *m) {
+ upb_msglayout *l = (upb_msglayout*)m->layout;
+ upb_msg_field_iter it;
+ upb_msg_oneof_iter oit;
+ size_t hasbit;
+ size_t submsg_count = m->submsg_field_count;
+ const upb_msglayout **submsgs;
+ upb_msglayout_field *fields;
+
+ memset(l, 0, sizeof(*l) + sizeof(_upb_fasttable_entry));
+
+ fields = symtab_alloc(ctx, upb_msgdef_numfields(m) * sizeof(*fields));
+ submsgs = symtab_alloc(ctx, submsg_count * sizeof(*submsgs));
+
+ l->field_count = upb_msgdef_numfields(m);
+ l->fields = fields;
+ l->submsgs = submsgs;
+ l->table_mask = 0;
+
+ /* TODO(haberman): initialize fast tables so that reflection-based parsing
+ * can get the same speeds as linked-in types. */
+ l->fasttable[0].field_parser = &fastdecode_generic;
+ l->fasttable[0].field_data = 0;
+
+ if (upb_msgdef_mapentry(m)) {
+ /* TODO(haberman): refactor this method so this special case is more
+ * elegant. */
+ const upb_fielddef *key = upb_msgdef_itof(m, 1);
+ const upb_fielddef *val = upb_msgdef_itof(m, 2);
+ fields[0].number = 1;
+ fields[1].number = 2;
+ fields[0].label = UPB_LABEL_OPTIONAL;
+ fields[1].label = UPB_LABEL_OPTIONAL;
+ fields[0].presence = 0;
+ fields[1].presence = 0;
+ fields[0].descriptortype = upb_fielddef_descriptortype(key);
+ fields[1].descriptortype = upb_fielddef_descriptortype(val);
+ fields[0].offset = 0;
+ fields[1].offset = sizeof(upb_strview);
+ fields[1].submsg_index = 0;
+
+ if (upb_fielddef_type(val) == UPB_TYPE_MESSAGE) {
+ submsgs[0] = upb_fielddef_msgsubdef(val)->layout;
+ }
+
+ l->field_count = 2;
+ l->size = 2 * sizeof(upb_strview);
+ l->size = UPB_ALIGN_UP(l->size, 8);
+ return;
+ }
+
+ /* Allocate data offsets in three stages:
+ *
+ * 1. hasbits.
+ * 2. regular fields.
+ * 3. oneof fields.
+ *
+ * OPT: There is a lot of room for optimization here to minimize the size.
+ */
+
+ /* Allocate hasbits and set basic field attributes. */
+ submsg_count = 0;
+ for (upb_msg_field_begin(&it, m), hasbit = 0;
+ !upb_msg_field_done(&it);
+ upb_msg_field_next(&it)) {
+ upb_fielddef* f = upb_msg_iter_field(&it);
+ upb_msglayout_field *field = &fields[upb_fielddef_index(f)];
+
+ field->number = upb_fielddef_number(f);
+ field->descriptortype = upb_fielddef_descriptortype(f);
+ field->label = upb_fielddef_label(f);
+
+ if (field->descriptortype == UPB_DTYPE_STRING &&
+ f->file->syntax == UPB_SYNTAX_PROTO2) {
+ /* See TableDescriptorType() in upbc/generator.cc for details and
+ * rationale. */
+ field->descriptortype = UPB_DTYPE_BYTES;
+ }
+
+ if (upb_fielddef_ismap(f)) {
+ field->label = _UPB_LABEL_MAP;
+ } else if (upb_fielddef_packed(f)) {
+ field->label = _UPB_LABEL_PACKED;
+ }
+
+ if (upb_fielddef_issubmsg(f)) {
+ const upb_msgdef *subm = upb_fielddef_msgsubdef(f);
+ field->submsg_index = submsg_count++;
+ submsgs[field->submsg_index] = subm->layout;
+ }
+
+ if (upb_fielddef_haspresence(f) && !upb_fielddef_realcontainingoneof(f)) {
+ /* We don't use hasbit 0, so that 0 can indicate "no presence" in the
+ * table. This wastes one hasbit, but we don't worry about it for now. */
+ field->presence = ++hasbit;
+ } else {
+ field->presence = 0;
+ }
+ }
+
+ /* Account for space used by hasbits. */
+ l->size = div_round_up(hasbit, 8);
+
+ /* Allocate non-oneof fields. */
+ for (upb_msg_field_begin(&it, m); !upb_msg_field_done(&it);
+ upb_msg_field_next(&it)) {
+ const upb_fielddef* f = upb_msg_iter_field(&it);
+ size_t field_size = upb_msg_fielddefsize(f);
+ size_t index = upb_fielddef_index(f);
+
+ if (upb_fielddef_realcontainingoneof(f)) {
+ /* Oneofs are handled separately below. */
+ continue;
+ }
+
+ fields[index].offset = upb_msglayout_place(l, field_size);
+ }
+
+ /* Allocate oneof fields. Each oneof field consists of a uint32 for the case
+ * and space for the actual data. */
+ for (upb_msg_oneof_begin(&oit, m); !upb_msg_oneof_done(&oit);
+ upb_msg_oneof_next(&oit)) {
+ const upb_oneofdef* o = upb_msg_iter_oneof(&oit);
+ upb_oneof_iter fit;
+
+ size_t case_size = sizeof(uint32_t); /* Could potentially optimize this. */
+ size_t field_size = 0;
+ uint32_t case_offset;
+ uint32_t data_offset;
+
+ if (upb_oneofdef_issynthetic(o)) continue;
+
+ /* Calculate field size: the max of all field sizes. */
+ for (upb_oneof_begin(&fit, o);
+ !upb_oneof_done(&fit);
+ upb_oneof_next(&fit)) {
+ const upb_fielddef* f = upb_oneof_iter_field(&fit);
+ field_size = UPB_MAX(field_size, upb_msg_fielddefsize(f));
+ }
+
+ /* Align and allocate case offset. */
+ case_offset = upb_msglayout_place(l, case_size);
+ data_offset = upb_msglayout_place(l, field_size);
+
+ for (upb_oneof_begin(&fit, o);
+ !upb_oneof_done(&fit);
+ upb_oneof_next(&fit)) {
+ const upb_fielddef* f = upb_oneof_iter_field(&fit);
+ fields[upb_fielddef_index(f)].offset = data_offset;
+ fields[upb_fielddef_index(f)].presence = ~case_offset;
+ }
+ }
+
+ /* Size of the entire structure should be a multiple of its greatest
+ * alignment. TODO: track overall alignment for real? */
+ l->size = UPB_ALIGN_UP(l->size, 8);
+
+ /* Sort fields by number. */
+ qsort(fields, upb_msgdef_numfields(m), sizeof(*fields), field_number_cmp);
+ assign_layout_indices(m, fields);
+}
+
+static void assign_msg_indices(symtab_addctx *ctx, upb_msgdef *m) {
+ /* Sort fields. upb internally relies on UPB_TYPE_MESSAGE fields having the
+ * lowest indexes, but we do not publicly guarantee this. */
+ upb_msg_field_iter j;
+ int i;
+ uint32_t selector;
+ int n = upb_msgdef_numfields(m);
+ upb_fielddef **fields;
+
+ if (n == 0) {
+ m->selector_count = UPB_STATIC_SELECTOR_COUNT;
+ m->submsg_field_count = 0;
+ return;
+ }
+
+ fields = upb_gmalloc(n * sizeof(*fields));
+
+ m->submsg_field_count = 0;
+ for(i = 0, upb_msg_field_begin(&j, m);
+ !upb_msg_field_done(&j);
+ upb_msg_field_next(&j), i++) {
+ upb_fielddef *f = upb_msg_iter_field(&j);
+ UPB_ASSERT(f->msgdef == m);
+ if (upb_fielddef_issubmsg(f)) {
+ m->submsg_field_count++;
+ }
+ fields[i] = f;
+ }
+
+ qsort(fields, n, sizeof(*fields), cmp_fields);
+
+ selector = UPB_STATIC_SELECTOR_COUNT + m->submsg_field_count;
+ for (i = 0; i < n; i++) {
+ upb_fielddef *f = fields[i];
+ f->index_ = i;
+ f->selector_base = selector + upb_handlers_selectorbaseoffset(f);
+ selector += upb_handlers_selectorcount(f);
+ }
+ m->selector_count = selector;
+
+ upb_gfree(fields);
+}
+
+static char *strviewdup(symtab_addctx *ctx, upb_strview view) {
+ return upb_strdup2(view.data, view.size, ctx->alloc);
+}
+
+static bool streql2(const char *a, size_t n, const char *b) {
+ return n == strlen(b) && memcmp(a, b, n) == 0;
+}
+
+static bool streql_view(upb_strview view, const char *b) {
+ return streql2(view.data, view.size, b);
+}
+
+static const char *makefullname(symtab_addctx *ctx, const char *prefix,
+ upb_strview name) {
+ if (prefix) {
+ /* ret = prefix + '.' + name; */
+ size_t n = strlen(prefix);
+ char *ret = symtab_alloc(ctx, n + name.size + 2);
+ strcpy(ret, prefix);
+ ret[n] = '.';
+ memcpy(&ret[n + 1], name.data, name.size);
+ ret[n + 1 + name.size] = '\0';
+ return ret;
+ } else {
+ return strviewdup(ctx, name);
+ }
+}
+
+static void finalize_oneofs(symtab_addctx *ctx, upb_msgdef *m) {
+ int i;
+ int synthetic_count = 0;
+ upb_oneofdef *mutable_oneofs = (upb_oneofdef*)m->oneofs;
+
+ for (i = 0; i < m->oneof_count; i++) {
+ upb_oneofdef *o = &mutable_oneofs[i];
+
+ if (o->synthetic && o->field_count != 1) {
+ symtab_errf(ctx, "Synthetic oneofs must have one field, not %d: %s",
+ o->field_count, upb_oneofdef_name(o));
+ }
+
+ if (o->synthetic) {
+ synthetic_count++;
+ } else if (synthetic_count != 0) {
+ symtab_errf(ctx, "Synthetic oneofs must be after all other oneofs: %s",
+ upb_oneofdef_name(o));
+ }
+
+ o->fields = symtab_alloc(ctx, sizeof(upb_fielddef *) * o->field_count);
+ o->field_count = 0;
+ }
+
+ for (i = 0; i < m->field_count; i++) {
+ const upb_fielddef *f = &m->fields[i];
+ upb_oneofdef *o = (upb_oneofdef*)f->oneof;
+ if (o) {
+ o->fields[o->field_count++] = f;
+ }
+ }
+
+ m->real_oneof_count = m->oneof_count - synthetic_count;
+}
+
+size_t getjsonname(const char *name, char *buf, size_t len) {
+ size_t src, dst = 0;
+ bool ucase_next = false;
+
+#define WRITE(byte) \
+ ++dst; \
+ if (dst < len) buf[dst - 1] = byte; \
+ else if (dst == len) buf[dst - 1] = '\0'
+
+ if (!name) {
+ WRITE('\0');
+ return 0;
+ }
+
+ /* Implement the transformation as described in the spec:
+ * 1. upper case all letters after an underscore.
+ * 2. remove all underscores.
+ */
+ for (src = 0; name[src]; src++) {
+ if (name[src] == '_') {
+ ucase_next = true;
+ continue;
+ }
+
+ if (ucase_next) {
+ WRITE(toupper(name[src]));
+ ucase_next = false;
+ } else {
+ WRITE(name[src]);
+ }
+ }
+
+ WRITE('\0');
+ return dst;
+
+#undef WRITE
+}
+
+static char* makejsonname(symtab_addctx *ctx, const char* name) {
+ size_t size = getjsonname(name, NULL, 0);
+ char* json_name = symtab_alloc(ctx, size);
+ getjsonname(name, json_name, size);
+ return json_name;
+}
+
+static void symtab_add(symtab_addctx *ctx, const char *name, upb_value v) {
+ if (upb_strtable_lookup(&ctx->symtab->syms, name, NULL)) {
+ symtab_errf(ctx, "duplicate symbol '%s'", name);
+ }
+ upb_alloc *alloc = upb_arena_alloc(ctx->symtab->arena);
+ size_t len = strlen(name);
+ CHK_OOM(upb_strtable_insert3(&ctx->symtab->syms, name, len, v, alloc));
+}
+
+/* Given a symbol and the base symbol inside which it is defined, find the
+ * symbol's definition in t. */
+static const void *symtab_resolve(symtab_addctx *ctx, const upb_fielddef *f,
+ const char *base, upb_strview sym,
+ upb_deftype_t type) {
+ const upb_strtable *t = &ctx->symtab->syms;
+ if(sym.size == 0) goto notfound;
+ if(sym.data[0] == '.') {
+ /* Symbols starting with '.' are absolute, so we do a single lookup.
+ * Slice to omit the leading '.' */
+ upb_value v;
+ if (!upb_strtable_lookup2(t, sym.data + 1, sym.size - 1, &v)) {
+ goto notfound;
+ }
+
+ const void *ret = unpack_def(v, type);
+ if (!ret) {
+ symtab_errf(ctx, "type mismatch when resolving field %s, name %s",
+ f->full_name, sym.data);
+ }
+ return ret;
+ } else {
+ /* Remove components from base until we find an entry or run out.
+ * TODO: This branch is totally broken, but currently not used. */
+ (void)base;
+ UPB_ASSERT(false);
+ goto notfound;
+ }
+
+notfound:
+ symtab_errf(ctx, "couldn't resolve name '%s'", sym.data);
+}
+
+static void create_oneofdef(
+ symtab_addctx *ctx, upb_msgdef *m,
+ const google_protobuf_OneofDescriptorProto *oneof_proto) {
+ upb_oneofdef *o;
+ upb_strview name = google_protobuf_OneofDescriptorProto_name(oneof_proto);
+ upb_value v;
+
+ o = (upb_oneofdef*)&m->oneofs[m->oneof_count++];
+ o->parent = m;
+ o->full_name = makefullname(ctx, m->full_name, name);
+ o->field_count = 0;
+ o->synthetic = false;
+
+ v = pack_def(o, UPB_DEFTYPE_ONEOF);
+ symtab_add(ctx, o->full_name, v);
+ CHK_OOM(upb_strtable_insert3(&m->ntof, name.data, name.size, v, ctx->alloc));
+
+ CHK_OOM(upb_inttable_init2(&o->itof, UPB_CTYPE_CONSTPTR, ctx->alloc));
+ CHK_OOM(upb_strtable_init2(&o->ntof, UPB_CTYPE_CONSTPTR, 4, ctx->alloc));
+}
+
+static str_t *newstr(symtab_addctx *ctx, const char *data, size_t len) {
+ str_t *ret = symtab_alloc(ctx, sizeof(*ret) + len);
+ if (!ret) return NULL;
+ ret->len = len;
+ if (len) memcpy(ret->str, data, len);
+ ret->str[len] = '\0';
+ return ret;
+}
+
+static void parse_default(symtab_addctx *ctx, const char *str, size_t len,
+ upb_fielddef *f) {
+ char *end;
+ char nullz[64];
+ errno = 0;
+
+ switch (upb_fielddef_type(f)) {
+ case UPB_TYPE_INT32:
+ case UPB_TYPE_INT64:
+ case UPB_TYPE_UINT32:
+ case UPB_TYPE_UINT64:
+ case UPB_TYPE_DOUBLE:
+ case UPB_TYPE_FLOAT:
+ /* Standard C number parsing functions expect null-terminated strings. */
+ if (len >= sizeof(nullz) - 1) {
+ symtab_errf(ctx, "Default too long: %.*s", (int)len, str);
+ }
+ memcpy(nullz, str, len);
+ nullz[len] = '\0';
+ str = nullz;
+ break;
+ default:
+ break;
+ }
+
+ switch (upb_fielddef_type(f)) {
+ case UPB_TYPE_INT32: {
+ long val = strtol(str, &end, 0);
+ if (val > INT32_MAX || val < INT32_MIN || errno == ERANGE || *end) {
+ goto invalid;
+ }
+ f->defaultval.sint = val;
+ break;
+ }
+ case UPB_TYPE_ENUM: {
+ const upb_enumdef *e = f->sub.enumdef;
+ int32_t val;
+ if (!upb_enumdef_ntoi(e, str, len, &val)) {
+ goto invalid;
+ }
+ f->defaultval.sint = val;
+ break;
+ }
+ case UPB_TYPE_INT64: {
+ /* XXX: Need to write our own strtoll, since it's not available in c89. */
+ int64_t val = strtol(str, &end, 0);
+ if (val > INT64_MAX || val < INT64_MIN || errno == ERANGE || *end) {
+ goto invalid;
+ }
+ f->defaultval.sint = val;
+ break;
+ }
+ case UPB_TYPE_UINT32: {
+ unsigned long val = strtoul(str, &end, 0);
+ if (val > UINT32_MAX || errno == ERANGE || *end) {
+ goto invalid;
+ }
+ f->defaultval.uint = val;
+ break;
+ }
+ case UPB_TYPE_UINT64: {
+ /* XXX: Need to write our own strtoull, since it's not available in c89. */
+ uint64_t val = strtoul(str, &end, 0);
+ if (val > UINT64_MAX || errno == ERANGE || *end) {
+ goto invalid;
+ }
+ f->defaultval.uint = val;
+ break;
+ }
+ case UPB_TYPE_DOUBLE: {
+ double val = strtod(str, &end);
+ if (errno == ERANGE || *end) {
+ goto invalid;
+ }
+ f->defaultval.dbl = val;
+ break;
+ }
+ case UPB_TYPE_FLOAT: {
+ /* XXX: Need to write our own strtof, since it's not available in c89. */
+ float val = strtod(str, &end);
+ if (errno == ERANGE || *end) {
+ goto invalid;
+ }
+ f->defaultval.flt = val;
+ break;
+ }
+ case UPB_TYPE_BOOL: {
+ if (streql2(str, len, "false")) {
+ f->defaultval.boolean = false;
+ } else if (streql2(str, len, "true")) {
+ f->defaultval.boolean = true;
+ } else {
+ }
+ break;
+ }
+ case UPB_TYPE_STRING:
+ f->defaultval.str = newstr(ctx, str, len);
+ break;
+ case UPB_TYPE_BYTES:
+ /* XXX: need to interpret the C-escaped value. */
+ f->defaultval.str = newstr(ctx, str, len);
+ break;
+ case UPB_TYPE_MESSAGE:
+ /* Should not have a default value. */
+ symtab_errf(ctx, "Message should not have a default (%s)",
+ upb_fielddef_fullname(f));
+ }
+
+ return;
+
+invalid:
+ symtab_errf(ctx, "Invalid default '%.*s' for field %s", (int)len, str,
+ upb_fielddef_fullname(f));
+}
+
+static void set_default_default(symtab_addctx *ctx, upb_fielddef *f) {
+ switch (upb_fielddef_type(f)) {
+ case UPB_TYPE_INT32:
+ case UPB_TYPE_INT64:
+ case UPB_TYPE_ENUM:
+ f->defaultval.sint = 0;
+ break;
+ case UPB_TYPE_UINT64:
+ case UPB_TYPE_UINT32:
+ f->defaultval.uint = 0;
+ break;
+ case UPB_TYPE_DOUBLE:
+ case UPB_TYPE_FLOAT:
+ f->defaultval.dbl = 0;
+ break;
+ case UPB_TYPE_STRING:
+ case UPB_TYPE_BYTES:
+ f->defaultval.str = newstr(ctx, NULL, 0);
+ break;
+ case UPB_TYPE_BOOL:
+ f->defaultval.boolean = false;
+ break;
+ case UPB_TYPE_MESSAGE:
+ break;
+ }
+}
+
+static void create_fielddef(
+ symtab_addctx *ctx, const char *prefix, upb_msgdef *m,
+ const google_protobuf_FieldDescriptorProto *field_proto) {
+ upb_alloc *alloc = ctx->alloc;
+ upb_fielddef *f;
+ const google_protobuf_FieldOptions *options;
+ upb_strview name;
+ const char *full_name;
+ const char *json_name;
+ const char *shortname;
+ uint32_t field_number;
+
+ if (!google_protobuf_FieldDescriptorProto_has_name(field_proto)) {
+ symtab_errf(ctx, "field has no name (%s)", upb_msgdef_fullname(m));
+ }
+
+ name = google_protobuf_FieldDescriptorProto_name(field_proto);
+ check_ident(ctx, name, false);
+ full_name = makefullname(ctx, prefix, name);
+ shortname = shortdefname(full_name);
+
+ if (google_protobuf_FieldDescriptorProto_has_json_name(field_proto)) {
+ json_name = strviewdup(
+ ctx, google_protobuf_FieldDescriptorProto_json_name(field_proto));
+ } else {
+ json_name = makejsonname(ctx, shortname);
+ }
+
+ field_number = google_protobuf_FieldDescriptorProto_number(field_proto);
+
+ if (field_number == 0 || field_number > UPB_MAX_FIELDNUMBER) {
+ symtab_errf(ctx, "invalid field number (%u)", field_number);
+ }
+
+ if (m) {
+ /* direct message field. */
+ upb_value v, field_v, json_v;
+ size_t json_size;
+
+ f = (upb_fielddef*)&m->fields[m->field_count++];
+ f->msgdef = m;
+ f->is_extension_ = false;
+
+ if (upb_strtable_lookup(&m->ntof, shortname, NULL)) {
+ symtab_errf(ctx, "duplicate field name (%s)", shortname);
+ }
+
+ if (upb_strtable_lookup(&m->ntof, json_name, NULL)) {
+ symtab_errf(ctx, "duplicate json_name (%s)", json_name);
+ }
+
+ if (upb_inttable_lookup(&m->itof, field_number, NULL)) {
+ symtab_errf(ctx, "duplicate field number (%u)", field_number);
+ }
+
+ field_v = pack_def(f, UPB_DEFTYPE_FIELD);
+ json_v = pack_def(f, UPB_DEFTYPE_FIELD_JSONNAME);
+ v = upb_value_constptr(f);
+ json_size = strlen(json_name);
+
+ CHK_OOM(
+ upb_strtable_insert3(&m->ntof, name.data, name.size, field_v, alloc));
+ CHK_OOM(upb_inttable_insert2(&m->itof, field_number, v, alloc));
+
+ if (strcmp(shortname, json_name) != 0) {
+ upb_strtable_insert3(&m->ntof, json_name, json_size, json_v, alloc);
+ }
+
+ if (ctx->layouts) {
+ const upb_msglayout_field *fields = m->layout->fields;
+ int count = m->layout->field_count;
+ bool found = false;
+ int i;
+ for (i = 0; i < count; i++) {
+ if (fields[i].number == field_number) {
+ f->layout_index = i;
+ found = true;
+ break;
+ }
+ }
+ UPB_ASSERT(found);
+ }
+ } else {
+ /* extension field. */
+ f = (upb_fielddef*)&ctx->file->exts[ctx->file->ext_count++];
+ f->is_extension_ = true;
+ symtab_add(ctx, full_name, pack_def(f, UPB_DEFTYPE_FIELD));
+ }
+
+ f->full_name = full_name;
+ f->json_name = json_name;
+ f->file = ctx->file;
+ f->type_ = (int)google_protobuf_FieldDescriptorProto_type(field_proto);
+ f->label_ = (int)google_protobuf_FieldDescriptorProto_label(field_proto);
+ f->number_ = field_number;
+ f->oneof = NULL;
+ f->proto3_optional_ =
+ google_protobuf_FieldDescriptorProto_proto3_optional(field_proto);
+
+ /* We can't resolve the subdef or (in the case of extensions) the containing
+ * message yet, because it may not have been defined yet. We stash a pointer
+ * to the field_proto until later when we can properly resolve it. */
+ f->sub.unresolved = field_proto;
+
+ if (f->label_ == UPB_LABEL_REQUIRED && f->file->syntax == UPB_SYNTAX_PROTO3) {
+ symtab_errf(ctx, "proto3 fields cannot be required (%s)", f->full_name);
+ }
+
+ if (google_protobuf_FieldDescriptorProto_has_oneof_index(field_proto)) {
+ int oneof_index =
+ google_protobuf_FieldDescriptorProto_oneof_index(field_proto);
+ upb_oneofdef *oneof;
+ upb_value v = upb_value_constptr(f);
+
+ if (upb_fielddef_label(f) != UPB_LABEL_OPTIONAL) {
+ symtab_errf(ctx, "fields in oneof must have OPTIONAL label (%s)",
+ f->full_name);
+ }
+
+ if (!m) {
+ symtab_errf(ctx, "oneof_index provided for extension field (%s)",
+ f->full_name);
+ }
+
+ if (oneof_index >= m->oneof_count) {
+ symtab_errf(ctx, "oneof_index out of range (%s)", f->full_name);
+ }
+
+ oneof = (upb_oneofdef*)&m->oneofs[oneof_index];
+ f->oneof = oneof;
+
+ oneof->field_count++;
+ if (f->proto3_optional_) {
+ oneof->synthetic = true;
+ }
+ CHK_OOM(upb_inttable_insert2(&oneof->itof, f->number_, v, alloc));
+ CHK_OOM(upb_strtable_insert3(&oneof->ntof, name.data, name.size, v, alloc));
+ } else {
+ f->oneof = NULL;
+ if (f->proto3_optional_) {
+ symtab_errf(ctx, "field with proto3_optional was not in a oneof (%s)",
+ f->full_name);
+ }
+ }
+
+ options = google_protobuf_FieldDescriptorProto_has_options(field_proto) ?
+ google_protobuf_FieldDescriptorProto_options(field_proto) : NULL;
+
+ if (options && google_protobuf_FieldOptions_has_packed(options)) {
+ f->packed_ = google_protobuf_FieldOptions_packed(options);
+ } else {
+ /* Repeated fields default to packed for proto3 only. */
+ f->packed_ = upb_fielddef_isprimitive(f) &&
+ f->label_ == UPB_LABEL_REPEATED && f->file->syntax == UPB_SYNTAX_PROTO3;
+ }
+
+ if (options) {
+ f->lazy_ = google_protobuf_FieldOptions_lazy(options);
+ } else {
+ f->lazy_ = false;
+ }
+}
+
+static void create_enumdef(
+ symtab_addctx *ctx, const char *prefix,
+ const google_protobuf_EnumDescriptorProto *enum_proto) {
+ upb_enumdef *e;
+ const google_protobuf_EnumValueDescriptorProto *const *values;
+ upb_strview name;
+ size_t i, n;
+
+ name = google_protobuf_EnumDescriptorProto_name(enum_proto);
+ check_ident(ctx, name, false);
+
+ e = (upb_enumdef*)&ctx->file->enums[ctx->file->enum_count++];
+ e->full_name = makefullname(ctx, prefix, name);
+ symtab_add(ctx, e->full_name, pack_def(e, UPB_DEFTYPE_ENUM));
+
+ values = google_protobuf_EnumDescriptorProto_value(enum_proto, &n);
+ CHK_OOM(upb_strtable_init2(&e->ntoi, UPB_CTYPE_INT32, n, ctx->alloc));
+ CHK_OOM(upb_inttable_init2(&e->iton, UPB_CTYPE_CSTR, ctx->alloc));
+
+ e->file = ctx->file;
+ e->defaultval = 0;
+
+ if (n == 0) {
+ symtab_errf(ctx, "enums must contain at least one value (%s)",
+ e->full_name);
+ }
+
+ for (i = 0; i < n; i++) {
+ const google_protobuf_EnumValueDescriptorProto *value = values[i];
+ upb_strview name = google_protobuf_EnumValueDescriptorProto_name(value);
+ char *name2 = strviewdup(ctx, name);
+ int32_t num = google_protobuf_EnumValueDescriptorProto_number(value);
+ upb_value v = upb_value_int32(num);
+
+ if (i == 0 && e->file->syntax == UPB_SYNTAX_PROTO3 && num != 0) {
+ symtab_errf(ctx, "for proto3, the first enum value must be zero (%s)",
+ e->full_name);
+ }
+
+ if (upb_strtable_lookup(&e->ntoi, name2, NULL)) {
+ symtab_errf(ctx, "duplicate enum label '%s'", name2);
+ }
+
+ CHK_OOM(name2)
+ CHK_OOM(
+ upb_strtable_insert3(&e->ntoi, name2, strlen(name2), v, ctx->alloc));
+
+ if (!upb_inttable_lookup(&e->iton, num, NULL)) {
+ upb_value v = upb_value_cstr(name2);
+ CHK_OOM(upb_inttable_insert2(&e->iton, num, v, ctx->alloc));
+ }
+ }
+
+ upb_inttable_compact2(&e->iton, ctx->alloc);
+}
+
+static void create_msgdef(symtab_addctx *ctx, const char *prefix,
+ const google_protobuf_DescriptorProto *msg_proto) {
+ upb_msgdef *m;
+ const google_protobuf_MessageOptions *options;
+ const google_protobuf_OneofDescriptorProto *const *oneofs;
+ const google_protobuf_FieldDescriptorProto *const *fields;
+ const google_protobuf_EnumDescriptorProto *const *enums;
+ const google_protobuf_DescriptorProto *const *msgs;
+ size_t i, n_oneof, n_field, n;
+ upb_strview name;
+
+ name = google_protobuf_DescriptorProto_name(msg_proto);
+ check_ident(ctx, name, false);
+
+ m = (upb_msgdef*)&ctx->file->msgs[ctx->file->msg_count++];
+ m->full_name = makefullname(ctx, prefix, name);
+ symtab_add(ctx, m->full_name, pack_def(m, UPB_DEFTYPE_MSG));
+
+ oneofs = google_protobuf_DescriptorProto_oneof_decl(msg_proto, &n_oneof);
+ fields = google_protobuf_DescriptorProto_field(msg_proto, &n_field);
+
+ CHK_OOM(upb_inttable_init2(&m->itof, UPB_CTYPE_CONSTPTR, ctx->alloc));
+ CHK_OOM(upb_strtable_init2(&m->ntof, UPB_CTYPE_CONSTPTR, n_oneof + n_field,
+ ctx->alloc));
+
+ m->file = ctx->file;
+ m->map_entry = false;
+
+ options = google_protobuf_DescriptorProto_options(msg_proto);
+
+ if (options) {
+ m->map_entry = google_protobuf_MessageOptions_map_entry(options);
+ }
+
+ if (ctx->layouts) {
+ m->layout = *ctx->layouts;
+ ctx->layouts++;
+ } else {
+ /* Allocate now (to allow cross-linking), populate later. */
+ m->layout = symtab_alloc(
+ ctx, sizeof(*m->layout) + sizeof(_upb_fasttable_entry));
+ }
+
+ m->oneof_count = 0;
+ m->oneofs = symtab_alloc(ctx, sizeof(*m->oneofs) * n_oneof);
+ for (i = 0; i < n_oneof; i++) {
+ create_oneofdef(ctx, m, oneofs[i]);
+ }
+
+ m->field_count = 0;
+ m->fields = symtab_alloc(ctx, sizeof(*m->fields) * n_field);
+ for (i = 0; i < n_field; i++) {
+ create_fielddef(ctx, m->full_name, m, fields[i]);
+ }
+
+ assign_msg_indices(ctx, m);
+ finalize_oneofs(ctx, m);
+ assign_msg_wellknowntype(m);
+ upb_inttable_compact2(&m->itof, ctx->alloc);
+
+ /* This message is built. Now build nested messages and enums. */
+
+ enums = google_protobuf_DescriptorProto_enum_type(msg_proto, &n);
+ for (i = 0; i < n; i++) {
+ create_enumdef(ctx, m->full_name, enums[i]);
+ }
+
+ msgs = google_protobuf_DescriptorProto_nested_type(msg_proto, &n);
+ for (i = 0; i < n; i++) {
+ create_msgdef(ctx, m->full_name, msgs[i]);
+ }
+}
+
+static void count_types_in_msg(const google_protobuf_DescriptorProto *msg_proto,
+ upb_filedef *file) {
+ const google_protobuf_DescriptorProto *const *msgs;
+ size_t i, n;
+
+ file->msg_count++;
+
+ msgs = google_protobuf_DescriptorProto_nested_type(msg_proto, &n);
+ for (i = 0; i < n; i++) {
+ count_types_in_msg(msgs[i], file);
+ }
+
+ google_protobuf_DescriptorProto_enum_type(msg_proto, &n);
+ file->enum_count += n;
+
+ google_protobuf_DescriptorProto_extension(msg_proto, &n);
+ file->ext_count += n;
+}
+
+static void count_types_in_file(
+ const google_protobuf_FileDescriptorProto *file_proto,
+ upb_filedef *file) {
+ const google_protobuf_DescriptorProto *const *msgs;
+ size_t i, n;
+
+ msgs = google_protobuf_FileDescriptorProto_message_type(file_proto, &n);
+ for (i = 0; i < n; i++) {
+ count_types_in_msg(msgs[i], file);
+ }
+
+ google_protobuf_FileDescriptorProto_enum_type(file_proto, &n);
+ file->enum_count += n;
+
+ google_protobuf_FileDescriptorProto_extension(file_proto, &n);
+ file->ext_count += n;
+}
+
+static void resolve_fielddef(symtab_addctx *ctx, const char *prefix,
+ upb_fielddef *f) {
+ upb_strview name;
+ const google_protobuf_FieldDescriptorProto *field_proto = f->sub.unresolved;
+
+ if (f->is_extension_) {
+ if (!google_protobuf_FieldDescriptorProto_has_extendee(field_proto)) {
+ symtab_errf(ctx, "extension for field '%s' had no extendee",
+ f->full_name);
+ }
+
+ name = google_protobuf_FieldDescriptorProto_extendee(field_proto);
+ f->msgdef = symtab_resolve(ctx, f, prefix, name, UPB_DEFTYPE_MSG);
+ }
+
+ if ((upb_fielddef_issubmsg(f) || f->type_ == UPB_DESCRIPTOR_TYPE_ENUM) &&
+ !google_protobuf_FieldDescriptorProto_has_type_name(field_proto)) {
+ symtab_errf(ctx, "field '%s' is missing type name", f->full_name);
+ }
+
+ name = google_protobuf_FieldDescriptorProto_type_name(field_proto);
+
+ if (upb_fielddef_issubmsg(f)) {
+ f->sub.msgdef = symtab_resolve(ctx, f, prefix, name, UPB_DEFTYPE_MSG);
+ } else if (f->type_ == UPB_DESCRIPTOR_TYPE_ENUM) {
+ f->sub.enumdef = symtab_resolve(ctx, f, prefix, name, UPB_DEFTYPE_ENUM);
+ }
+
+ /* Have to delay resolving of the default value until now because of the enum
+ * case, since enum defaults are specified with a label. */
+ if (google_protobuf_FieldDescriptorProto_has_default_value(field_proto)) {
+ upb_strview defaultval =
+ google_protobuf_FieldDescriptorProto_default_value(field_proto);
+
+ if (f->file->syntax == UPB_SYNTAX_PROTO3) {
+ symtab_errf(ctx, "proto3 fields cannot have explicit defaults (%s)",
+ f->full_name);
+ }
+
+ if (upb_fielddef_issubmsg(f)) {
+ symtab_errf(ctx, "message fields cannot have explicit defaults (%s)",
+ f->full_name);
+ }
+
+ parse_default(ctx, defaultval.data, defaultval.size, f);
+ } else {
+ set_default_default(ctx, f);
+ }
+}
+
+static void build_filedef(
+ symtab_addctx *ctx, upb_filedef *file,
+ const google_protobuf_FileDescriptorProto *file_proto) {
+ const google_protobuf_FileOptions *file_options_proto;
+ const google_protobuf_DescriptorProto *const *msgs;
+ const google_protobuf_EnumDescriptorProto *const *enums;
+ const google_protobuf_FieldDescriptorProto *const *exts;
+ const upb_strview* strs;
+ size_t i, n;
+
+ count_types_in_file(file_proto, file);
+
+ file->msgs = symtab_alloc(ctx, sizeof(*file->msgs) * file->msg_count);
+ file->enums = symtab_alloc(ctx, sizeof(*file->enums) * file->enum_count);
+ file->exts = symtab_alloc(ctx, sizeof(*file->exts) * file->ext_count);
+
+ /* We increment these as defs are added. */
+ file->msg_count = 0;
+ file->enum_count = 0;
+ file->ext_count = 0;
+
+ if (!google_protobuf_FileDescriptorProto_has_name(file_proto)) {
+ symtab_errf(ctx, "File has no name");
+ }
+
+ file->name =
+ strviewdup(ctx, google_protobuf_FileDescriptorProto_name(file_proto));
+ file->phpprefix = NULL;
+ file->phpnamespace = NULL;
+
+ if (google_protobuf_FileDescriptorProto_has_package(file_proto)) {
+ upb_strview package =
+ google_protobuf_FileDescriptorProto_package(file_proto);
+ check_ident(ctx, package, true);
+ file->package = strviewdup(ctx, package);
+ } else {
+ file->package = NULL;
+ }
+
+ if (google_protobuf_FileDescriptorProto_has_syntax(file_proto)) {
+ upb_strview syntax =
+ google_protobuf_FileDescriptorProto_syntax(file_proto);
+
+ if (streql_view(syntax, "proto2")) {
+ file->syntax = UPB_SYNTAX_PROTO2;
+ } else if (streql_view(syntax, "proto3")) {
+ file->syntax = UPB_SYNTAX_PROTO3;
+ } else {
+ symtab_errf(ctx, "Invalid syntax '" UPB_STRVIEW_FORMAT "'",
+ UPB_STRVIEW_ARGS(syntax));
+ }
+ } else {
+ file->syntax = UPB_SYNTAX_PROTO2;
+ }
+
+ /* Read options. */
+ file_options_proto = google_protobuf_FileDescriptorProto_options(file_proto);
+ if (file_options_proto) {
+ if (google_protobuf_FileOptions_has_php_class_prefix(file_options_proto)) {
+ file->phpprefix = strviewdup(
+ ctx,
+ google_protobuf_FileOptions_php_class_prefix(file_options_proto));
+ }
+ if (google_protobuf_FileOptions_has_php_namespace(file_options_proto)) {
+ file->phpnamespace = strviewdup(
+ ctx, google_protobuf_FileOptions_php_namespace(file_options_proto));
+ }
+ }
+
+ /* Verify dependencies. */
+ strs = google_protobuf_FileDescriptorProto_dependency(file_proto, &n);
+ file->deps = symtab_alloc(ctx, sizeof(*file->deps) * n);
+
+ for (i = 0; i < n; i++) {
+ upb_strview dep_name = strs[i];
+ upb_value v;
+ if (!upb_strtable_lookup2(&ctx->symtab->files, dep_name.data,
+ dep_name.size, &v)) {
+ symtab_errf(ctx,
+ "Depends on file '" UPB_STRVIEW_FORMAT
+ "', but it has not been loaded",
+ UPB_STRVIEW_ARGS(dep_name));
+ }
+ file->deps[i] = upb_value_getconstptr(v);
+ }
+
+ /* Create messages. */
+ msgs = google_protobuf_FileDescriptorProto_message_type(file_proto, &n);
+ for (i = 0; i < n; i++) {
+ create_msgdef(ctx, file->package, msgs[i]);
+ }
+
+ /* Create enums. */
+ enums = google_protobuf_FileDescriptorProto_enum_type(file_proto, &n);
+ for (i = 0; i < n; i++) {
+ create_enumdef(ctx, file->package, enums[i]);
+ }
+
+ /* Create extensions. */
+ exts = google_protobuf_FileDescriptorProto_extension(file_proto, &n);
+ file->exts = symtab_alloc(ctx, sizeof(*file->exts) * n);
+ for (i = 0; i < n; i++) {
+ create_fielddef(ctx, file->package, NULL, exts[i]);
+ }
+
+ /* Now that all names are in the table, build layouts and resolve refs. */
+ for (i = 0; i < (size_t)file->ext_count; i++) {
+ resolve_fielddef(ctx, file->package, (upb_fielddef*)&file->exts[i]);
+ }
+
+ for (i = 0; i < (size_t)file->msg_count; i++) {
+ const upb_msgdef *m = &file->msgs[i];
+ int j;
+ for (j = 0; j < m->field_count; j++) {
+ resolve_fielddef(ctx, m->full_name, (upb_fielddef*)&m->fields[j]);
+ }
+ }
+
+ if (!ctx->layouts) {
+ for (i = 0; i < (size_t)file->msg_count; i++) {
+ const upb_msgdef *m = &file->msgs[i];
+ make_layout(ctx, m);
+ }
+ }
+}
+
+static void remove_filedef(upb_symtab *s, upb_filedef *file) {
+ upb_alloc *alloc = upb_arena_alloc(s->arena);
+ int i;
+ for (i = 0; i < file->msg_count; i++) {
+ const char *name = file->msgs[i].full_name;
+ upb_strtable_remove3(&s->syms, name, strlen(name), NULL, alloc);
+ }
+ for (i = 0; i < file->enum_count; i++) {
+ const char *name = file->enums[i].full_name;
+ upb_strtable_remove3(&s->syms, name, strlen(name), NULL, alloc);
+ }
+ for (i = 0; i < file->ext_count; i++) {
+ const char *name = file->exts[i].full_name;
+ upb_strtable_remove3(&s->syms, name, strlen(name), NULL, alloc);
+ }
+}
+
+static const upb_filedef *_upb_symtab_addfile(
+ upb_symtab *s, const google_protobuf_FileDescriptorProto *file_proto,
+ const upb_msglayout **layouts, upb_status *status) {
+ upb_arena *file_arena = upb_arena_new();
+ upb_filedef *file;
+ symtab_addctx ctx;
+
+ if (!file_arena) return NULL;
+
+ file = upb_arena_malloc(file_arena, sizeof(*file));
+ if (!file) goto done;
+
+ ctx.file = file;
+ ctx.symtab = s;
+ ctx.file_arena = file_arena;
+ ctx.alloc = upb_arena_alloc(file_arena);
+ ctx.layouts = layouts;
+ ctx.status = status;
+
+ file->msg_count = 0;
+ file->enum_count = 0;
+ file->ext_count = 0;
+ file->symtab = s;
+
+ if (UPB_UNLIKELY(UPB_SETJMP(ctx.err))) {
+ UPB_ASSERT(!upb_ok(status));
+ remove_filedef(s, file);
+ file = NULL;
+ } else {
+ build_filedef(&ctx, file, file_proto);
+ upb_strtable_insert3(&s->files, file->name, strlen(file->name),
+ upb_value_constptr(file), ctx.alloc);
+ UPB_ASSERT(upb_ok(status));
+ upb_arena_fuse(s->arena, file_arena);
+ }
+
+done:
+ upb_arena_free(file_arena);
+ return file;
+}
+
+const upb_filedef *upb_symtab_addfile(
+ upb_symtab *s, const google_protobuf_FileDescriptorProto *file_proto,
+ upb_status *status) {
+ return _upb_symtab_addfile(s, file_proto, NULL, status);
+}
+
+/* Include here since we want most of this file to be stdio-free. */
+#include
+
+bool _upb_symtab_loaddefinit(upb_symtab *s, const upb_def_init *init) {
+ /* Since this function should never fail (it would indicate a bug in upb) we
+ * print errors to stderr instead of returning error status to the user. */
+ upb_def_init **deps = init->deps;
+ google_protobuf_FileDescriptorProto *file;
+ upb_arena *arena;
+ upb_status status;
+
+ upb_status_clear(&status);
+
+ if (upb_strtable_lookup(&s->files, init->filename, NULL)) {
+ return true;
+ }
+
+ arena = upb_arena_new();
+
+ for (; *deps; deps++) {
+ if (!_upb_symtab_loaddefinit(s, *deps)) goto err;
+ }
+
+ file = google_protobuf_FileDescriptorProto_parse_ex(
+ init->descriptor.data, init->descriptor.size, arena, UPB_DECODE_ALIAS);
+ s->bytes_loaded += init->descriptor.size;
+
+ if (!file) {
+ upb_status_seterrf(
+ &status,
+ "Failed to parse compiled-in descriptor for file '%s'. This should "
+ "never happen.",
+ init->filename);
+ goto err;
+ }
+
+ if (!_upb_symtab_addfile(s, file, init->layouts, &status)) goto err;
+
+ upb_arena_free(arena);
+ return true;
+
+err:
+ fprintf(stderr, "Error loading compiled-in descriptor: %s\n",
+ upb_status_errmsg(&status));
+ upb_arena_free(arena);
+ return false;
+}
+
+size_t _upb_symtab_bytesloaded(const upb_symtab *s) {
+ return s->bytes_loaded;
+}
+
+upb_arena *_upb_symtab_arena(const upb_symtab *s) {
+ return s->arena;
+}
+
+#undef CHK_OOM
+
+
+#include
+
+
+static size_t get_field_size(const upb_msglayout_field *f) {
+ static unsigned char sizes[] = {
+ 0,/* 0 */
+ 8, /* UPB_DESCRIPTOR_TYPE_DOUBLE */
+ 4, /* UPB_DESCRIPTOR_TYPE_FLOAT */
+ 8, /* UPB_DESCRIPTOR_TYPE_INT64 */
+ 8, /* UPB_DESCRIPTOR_TYPE_UINT64 */
+ 4, /* UPB_DESCRIPTOR_TYPE_INT32 */
+ 8, /* UPB_DESCRIPTOR_TYPE_FIXED64 */
+ 4, /* UPB_DESCRIPTOR_TYPE_FIXED32 */
+ 1, /* UPB_DESCRIPTOR_TYPE_BOOL */
+ sizeof(upb_strview), /* UPB_DESCRIPTOR_TYPE_STRING */
+ sizeof(void*), /* UPB_DESCRIPTOR_TYPE_GROUP */
+ sizeof(void*), /* UPB_DESCRIPTOR_TYPE_MESSAGE */
+ sizeof(upb_strview), /* UPB_DESCRIPTOR_TYPE_BYTES */
+ 4, /* UPB_DESCRIPTOR_TYPE_UINT32 */
+ 4, /* UPB_DESCRIPTOR_TYPE_ENUM */
+ 4, /* UPB_DESCRIPTOR_TYPE_SFIXED32 */
+ 8, /* UPB_DESCRIPTOR_TYPE_SFIXED64 */
+ 4, /* UPB_DESCRIPTOR_TYPE_SINT32 */
+ 8, /* UPB_DESCRIPTOR_TYPE_SINT64 */
+ };
+ return _upb_repeated_or_map(f) ? sizeof(void *) : sizes[f->descriptortype];
+}
+
+/* Strings/bytes are special-cased in maps. */
+static char _upb_fieldtype_to_mapsize[12] = {
+ 0,
+ 1, /* UPB_TYPE_BOOL */
+ 4, /* UPB_TYPE_FLOAT */
+ 4, /* UPB_TYPE_INT32 */
+ 4, /* UPB_TYPE_UINT32 */
+ 4, /* UPB_TYPE_ENUM */
+ sizeof(void*), /* UPB_TYPE_MESSAGE */
+ 8, /* UPB_TYPE_DOUBLE */
+ 8, /* UPB_TYPE_INT64 */
+ 8, /* UPB_TYPE_UINT64 */
+ 0, /* UPB_TYPE_STRING */
+ 0, /* UPB_TYPE_BYTES */
+};
+
+static const char _upb_fieldtype_to_sizelg2[12] = {
+ 0,
+ 0, /* UPB_TYPE_BOOL */
+ 2, /* UPB_TYPE_FLOAT */
+ 2, /* UPB_TYPE_INT32 */
+ 2, /* UPB_TYPE_UINT32 */
+ 2, /* UPB_TYPE_ENUM */
+ UPB_SIZE(2, 3), /* UPB_TYPE_MESSAGE */
+ 3, /* UPB_TYPE_DOUBLE */
+ 3, /* UPB_TYPE_INT64 */
+ 3, /* UPB_TYPE_UINT64 */
+ UPB_SIZE(3, 4), /* UPB_TYPE_STRING */
+ UPB_SIZE(3, 4), /* UPB_TYPE_BYTES */
+};
+
+/** upb_msg *******************************************************************/
+
+upb_msg *upb_msg_new(const upb_msgdef *m, upb_arena *a) {
+ return _upb_msg_new(upb_msgdef_layout(m), a);
+}
+
+static bool in_oneof(const upb_msglayout_field *field) {
+ return field->presence < 0;
+}
+
+static upb_msgval _upb_msg_getraw(const upb_msg *msg, const upb_fielddef *f) {
+ const upb_msglayout_field *field = upb_fielddef_layout(f);
+ const char *mem = UPB_PTR_AT(msg, field->offset, char);
+ upb_msgval val = {0};
+ memcpy(&val, mem, get_field_size(field));
+ return val;
+}
+
+bool upb_msg_has(const upb_msg *msg, const upb_fielddef *f) {
+ const upb_msglayout_field *field = upb_fielddef_layout(f);
+ if (in_oneof(field)) {
+ return _upb_getoneofcase_field(msg, field) == field->number;
+ } else if (field->presence > 0) {
+ return _upb_hasbit_field(msg, field);
+ } else {
+ UPB_ASSERT(field->descriptortype == UPB_DESCRIPTOR_TYPE_MESSAGE ||
+ field->descriptortype == UPB_DESCRIPTOR_TYPE_GROUP);
+ return _upb_msg_getraw(msg, f).msg_val != NULL;
+ }
+}
+
+const upb_fielddef *upb_msg_whichoneof(const upb_msg *msg,
+ const upb_oneofdef *o) {
+ const upb_fielddef *f = upb_oneofdef_field(o, 0);
+ if (upb_oneofdef_issynthetic(o)) {
+ UPB_ASSERT(upb_oneofdef_fieldcount(o) == 1);
+ return upb_msg_has(msg, f) ? f : NULL;
+ } else {
+ const upb_msglayout_field *field = upb_fielddef_layout(f);
+ uint32_t oneof_case = _upb_getoneofcase_field(msg, field);
+ f = oneof_case ? upb_oneofdef_itof(o, oneof_case) : NULL;
+ UPB_ASSERT((f != NULL) == (oneof_case != 0));
+ return f;
+ }
+}
+
+upb_msgval upb_msg_get(const upb_msg *msg, const upb_fielddef *f) {
+ if (!upb_fielddef_haspresence(f) || upb_msg_has(msg, f)) {
+ return _upb_msg_getraw(msg, f);
+ } else {
+ /* TODO(haberman): change upb_fielddef to not require this switch(). */
+ upb_msgval val = {0};
+ switch (upb_fielddef_type(f)) {
+ case UPB_TYPE_INT32:
+ case UPB_TYPE_ENUM:
+ val.int32_val = upb_fielddef_defaultint32(f);
+ break;
+ case UPB_TYPE_INT64:
+ val.int64_val = upb_fielddef_defaultint64(f);
+ break;
+ case UPB_TYPE_UINT32:
+ val.uint32_val = upb_fielddef_defaultuint32(f);
+ break;
+ case UPB_TYPE_UINT64:
+ val.uint64_val = upb_fielddef_defaultuint64(f);
+ break;
+ case UPB_TYPE_FLOAT:
+ val.float_val = upb_fielddef_defaultfloat(f);
+ break;
+ case UPB_TYPE_DOUBLE:
+ val.double_val = upb_fielddef_defaultdouble(f);
+ break;
+ case UPB_TYPE_BOOL:
+ val.bool_val = upb_fielddef_defaultbool(f);
+ break;
+ case UPB_TYPE_STRING:
+ case UPB_TYPE_BYTES:
+ val.str_val.data = upb_fielddef_defaultstr(f, &val.str_val.size);
+ break;
+ case UPB_TYPE_MESSAGE:
+ val.msg_val = NULL;
+ break;
+ }
+ return val;
+ }
+}
+
+upb_mutmsgval upb_msg_mutable(upb_msg *msg, const upb_fielddef *f,
+ upb_arena *a) {
+ const upb_msglayout_field *field = upb_fielddef_layout(f);
+ upb_mutmsgval ret;
+ char *mem = UPB_PTR_AT(msg, field->offset, char);
+ bool wrong_oneof =
+ in_oneof(field) && _upb_getoneofcase_field(msg, field) != field->number;
+
+ memcpy(&ret, mem, sizeof(void*));
+
+ if (a && (!ret.msg || wrong_oneof)) {
+ if (upb_fielddef_ismap(f)) {
+ const upb_msgdef *entry = upb_fielddef_msgsubdef(f);
+ const upb_fielddef *key = upb_msgdef_itof(entry, UPB_MAPENTRY_KEY);
+ const upb_fielddef *value = upb_msgdef_itof(entry, UPB_MAPENTRY_VALUE);
+ ret.map = upb_map_new(a, upb_fielddef_type(key), upb_fielddef_type(value));
+ } else if (upb_fielddef_isseq(f)) {
+ ret.array = upb_array_new(a, upb_fielddef_type(f));
+ } else {
+ UPB_ASSERT(upb_fielddef_issubmsg(f));
+ ret.msg = upb_msg_new(upb_fielddef_msgsubdef(f), a);
+ }
+
+ memcpy(mem, &ret, sizeof(void*));
+
+ if (wrong_oneof) {
+ *_upb_oneofcase_field(msg, field) = field->number;
+ } else if (field->presence > 0) {
+ _upb_sethas_field(msg, field);
+ }
+ }
+ return ret;
+}
+
+void upb_msg_set(upb_msg *msg, const upb_fielddef *f, upb_msgval val,
+ upb_arena *a) {
+ const upb_msglayout_field *field = upb_fielddef_layout(f);
+ char *mem = UPB_PTR_AT(msg, field->offset, char);
+ UPB_UNUSED(a); /* We reserve the right to make set insert into a map. */
+ memcpy(mem, &val, get_field_size(field));
+ if (field->presence > 0) {
+ _upb_sethas_field(msg, field);
+ } else if (in_oneof(field)) {
+ *_upb_oneofcase_field(msg, field) = field->number;
+ }
+}
+
+void upb_msg_clearfield(upb_msg *msg, const upb_fielddef *f) {
+ const upb_msglayout_field *field = upb_fielddef_layout(f);
+ char *mem = UPB_PTR_AT(msg, field->offset, char);
+
+ if (field->presence > 0) {
+ _upb_clearhas_field(msg, field);
+ } else if (in_oneof(field)) {
+ uint32_t *oneof_case = _upb_oneofcase_field(msg, field);
+ if (*oneof_case != field->number) return;
+ *oneof_case = 0;
+ }
+
+ memset(mem, 0, get_field_size(field));
+}
+
+void upb_msg_clear(upb_msg *msg, const upb_msgdef *m) {
+ _upb_msg_clear(msg, upb_msgdef_layout(m));
+}
+
+bool upb_msg_next(const upb_msg *msg, const upb_msgdef *m,
+ const upb_symtab *ext_pool, const upb_fielddef **out_f,
+ upb_msgval *out_val, size_t *iter) {
+ int i = *iter;
+ int n = upb_msgdef_fieldcount(m);
+ const upb_msgval zero = {0};
+ UPB_UNUSED(ext_pool);
+ while (++i < n) {
+ const upb_fielddef *f = upb_msgdef_field(m, i);
+ upb_msgval val = _upb_msg_getraw(msg, f);
+
+ /* Skip field if unset or empty. */
+ if (upb_fielddef_haspresence(f)) {
+ if (!upb_msg_has(msg, f)) continue;
+ } else {
+ upb_msgval test = val;
+ if (upb_fielddef_isstring(f) && !upb_fielddef_isseq(f)) {
+ /* Clear string pointer, only size matters (ptr could be non-NULL). */
+ test.str_val.data = NULL;
+ }
+ /* Continue if NULL or 0. */
+ if (memcmp(&test, &zero, sizeof(test)) == 0) continue;
+
+ /* Continue on empty array or map. */
+ if (upb_fielddef_ismap(f)) {
+ if (upb_map_size(test.map_val) == 0) continue;
+ } else if (upb_fielddef_isseq(f)) {
+ if (upb_array_size(test.array_val) == 0) continue;
+ }
+ }
+
+ *out_val = val;
+ *out_f = f;
+ *iter = i;
+ return true;
+ }
+ *iter = i;
+ return false;
+}
+
+bool _upb_msg_discardunknown(upb_msg *msg, const upb_msgdef *m, int depth) {
+ size_t iter = UPB_MSG_BEGIN;
+ const upb_fielddef *f;
+ upb_msgval val;
+ bool ret = true;
+
+ if (--depth == 0) return false;
+
+ _upb_msg_discardunknown_shallow(msg);
+
+ while (upb_msg_next(msg, m, NULL /*ext_pool*/, &f, &val, &iter)) {
+ const upb_msgdef *subm = upb_fielddef_msgsubdef(f);
+ if (!subm) continue;
+ if (upb_fielddef_ismap(f)) {
+ const upb_fielddef *val_f = upb_msgdef_itof(subm, 2);
+ const upb_msgdef *val_m = upb_fielddef_msgsubdef(val_f);
+ upb_map *map = (upb_map*)val.map_val;
+ size_t iter = UPB_MAP_BEGIN;
+
+ if (!val_m) continue;
+
+ while (upb_mapiter_next(map, &iter)) {
+ upb_msgval map_val = upb_mapiter_value(map, iter);
+ if (!_upb_msg_discardunknown((upb_msg*)map_val.msg_val, val_m, depth)) {
+ ret = false;
+ }
+ }
+ } else if (upb_fielddef_isseq(f)) {
+ const upb_array *arr = val.array_val;
+ size_t i, n = upb_array_size(arr);
+ for (i = 0; i < n; i++) {
+ upb_msgval elem = upb_array_get(arr, i);
+ if (!_upb_msg_discardunknown((upb_msg*)elem.msg_val, subm, depth)) {
+ ret = false;
+ }
+ }
+ } else {
+ if (!_upb_msg_discardunknown((upb_msg*)val.msg_val, subm, depth)) {
+ ret = false;
+ }
+ }
+ }
+
+ return ret;
+}
+
+bool upb_msg_discardunknown(upb_msg *msg, const upb_msgdef *m, int maxdepth) {
+ return _upb_msg_discardunknown(msg, m, maxdepth);
+}
+
+/** upb_array *****************************************************************/
+
+upb_array *upb_array_new(upb_arena *a, upb_fieldtype_t type) {
+ return _upb_array_new(a, 4, _upb_fieldtype_to_sizelg2[type]);
+}
+
+size_t upb_array_size(const upb_array *arr) {
+ return arr->len;
+}
+
+upb_msgval upb_array_get(const upb_array *arr, size_t i) {
+ upb_msgval ret;
+ const char* data = _upb_array_constptr(arr);
+ int lg2 = arr->data & 7;
+ UPB_ASSERT(i < arr->len);
+ memcpy(&ret, data + (i << lg2), 1 << lg2);
+ return ret;
+}
+
+void upb_array_set(upb_array *arr, size_t i, upb_msgval val) {
+ char* data = _upb_array_ptr(arr);
+ int lg2 = arr->data & 7;
+ UPB_ASSERT(i < arr->len);
+ memcpy(data + (i << lg2), &val, 1 << lg2);
+}
+
+bool upb_array_append(upb_array *arr, upb_msgval val, upb_arena *arena) {
+ if (!_upb_array_realloc(arr, arr->len + 1, arena)) {
+ return false;
+ }
+ arr->len++;
+ upb_array_set(arr, arr->len - 1, val);
+ return true;
+}
+
+bool upb_array_resize(upb_array *arr, size_t size, upb_arena *arena) {
+ return _upb_array_resize(arr, size, arena);
+}
+
+/** upb_map *******************************************************************/
+
+upb_map *upb_map_new(upb_arena *a, upb_fieldtype_t key_type,
+ upb_fieldtype_t value_type) {
+ return _upb_map_new(a, _upb_fieldtype_to_mapsize[key_type],
+ _upb_fieldtype_to_mapsize[value_type]);
+}
+
+size_t upb_map_size(const upb_map *map) {
+ return _upb_map_size(map);
+}
+
+bool upb_map_get(const upb_map *map, upb_msgval key, upb_msgval *val) {
+ return _upb_map_get(map, &key, map->key_size, val, map->val_size);
+}
+
+void upb_map_clear(upb_map *map) {
+ _upb_map_clear(map);
+}
+
+bool upb_map_set(upb_map *map, upb_msgval key, upb_msgval val,
+ upb_arena *arena) {
+ return _upb_map_set(map, &key, map->key_size, &val, map->val_size, arena);
+}
+
+bool upb_map_delete(upb_map *map, upb_msgval key) {
+ return _upb_map_delete(map, &key, map->key_size);
+}
+
+bool upb_mapiter_next(const upb_map *map, size_t *iter) {
+ return _upb_map_next(map, iter);
+}
+
+bool upb_mapiter_done(const upb_map *map, size_t iter) {
+ upb_strtable_iter i;
+ UPB_ASSERT(iter != UPB_MAP_BEGIN);
+ i.t = &map->table;
+ i.index = iter;
+ return upb_strtable_done(&i);
+}
+
+/* Returns the key and value for this entry of the map. */
+upb_msgval upb_mapiter_key(const upb_map *map, size_t iter) {
+ upb_strtable_iter i;
+ upb_msgval ret;
+ i.t = &map->table;
+ i.index = iter;
+ _upb_map_fromkey(upb_strtable_iter_key(&i), &ret, map->key_size);
+ return ret;
+}
+
+upb_msgval upb_mapiter_value(const upb_map *map, size_t iter) {
+ upb_strtable_iter i;
+ upb_msgval ret;
+ i.t = &map->table;
+ i.index = iter;
+ _upb_map_fromvalue(upb_strtable_iter_value(&i), &ret, map->val_size);
+ return ret;
+}
+
+/* void upb_mapiter_setvalue(upb_map *map, size_t iter, upb_msgval value); */
+
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+
+/* Special header, must be included last. */
+
+typedef struct {
+ const char *ptr, *end;
+ upb_arena *arena; /* TODO: should we have a tmp arena for tmp data? */
+ const upb_symtab *any_pool;
+ int depth;
+ upb_status *status;
+ jmp_buf err;
+ int line;
+ const char *line_begin;
+ bool is_first;
+ int options;
+ const upb_fielddef *debug_field;
+} jsondec;
+
+enum { JD_OBJECT, JD_ARRAY, JD_STRING, JD_NUMBER, JD_TRUE, JD_FALSE, JD_NULL };
+
+/* Forward declarations of mutually-recursive functions. */
+static void jsondec_wellknown(jsondec *d, upb_msg *msg, const upb_msgdef *m);
+static upb_msgval jsondec_value(jsondec *d, const upb_fielddef *f);
+static void jsondec_wellknownvalue(jsondec *d, upb_msg *msg,
+ const upb_msgdef *m);
+static void jsondec_object(jsondec *d, upb_msg *msg, const upb_msgdef *m);
+
+static bool jsondec_streql(upb_strview str, const char *lit) {
+ return str.size == strlen(lit) && memcmp(str.data, lit, str.size) == 0;
+}
+
+static bool jsondec_isnullvalue(const upb_fielddef *f) {
+ return upb_fielddef_type(f) == UPB_TYPE_ENUM &&
+ strcmp(upb_enumdef_fullname(upb_fielddef_enumsubdef(f)),
+ "google.protobuf.NullValue") == 0;
+}
+
+static bool jsondec_isvalue(const upb_fielddef *f) {
+ return (upb_fielddef_type(f) == UPB_TYPE_MESSAGE &&
+ upb_msgdef_wellknowntype(upb_fielddef_msgsubdef(f)) ==
+ UPB_WELLKNOWN_VALUE) ||
+ jsondec_isnullvalue(f);
+}
+
+UPB_NORETURN static void jsondec_err(jsondec *d, const char *msg) {
+ upb_status_seterrf(d->status, "Error parsing JSON @%d:%d: %s", d->line,
+ (int)(d->ptr - d->line_begin), msg);
+ UPB_LONGJMP(d->err, 1);
+}
+
+UPB_PRINTF(2, 3)
+UPB_NORETURN static void jsondec_errf(jsondec *d, const char *fmt, ...) {
+ va_list argp;
+ upb_status_seterrf(d->status, "Error parsing JSON @%d:%d: ", d->line,
+ (int)(d->ptr - d->line_begin));
+ va_start(argp, fmt);
+ upb_status_vappenderrf(d->status, fmt, argp);
+ va_end(argp);
+ UPB_LONGJMP(d->err, 1);
+}
+
+static void jsondec_skipws(jsondec *d) {
+ while (d->ptr != d->end) {
+ switch (*d->ptr) {
+ case '\n':
+ d->line++;
+ d->line_begin = d->ptr;
+ /* Fallthrough. */
+ case '\r':
+ case '\t':
+ case ' ':
+ d->ptr++;
+ break;
+ default:
+ return;
+ }
+ }
+ jsondec_err(d, "Unexpected EOF");
+}
+
+static bool jsondec_tryparsech(jsondec *d, char ch) {
+ if (d->ptr == d->end || *d->ptr != ch) return false;
+ d->ptr++;
+ return true;
+}
+
+static void jsondec_parselit(jsondec *d, const char *lit) {
+ size_t avail = d->end - d->ptr;
+ size_t len = strlen(lit);
+ if (avail < len || memcmp(d->ptr, lit, len) != 0) {
+ jsondec_errf(d, "Expected: '%s'", lit);
+ }
+ d->ptr += len;
+}
+
+static void jsondec_wsch(jsondec *d, char ch) {
+ jsondec_skipws(d);
+ if (!jsondec_tryparsech(d, ch)) {
+ jsondec_errf(d, "Expected: '%c'", ch);
+ }
+}
+
+static void jsondec_true(jsondec *d) { jsondec_parselit(d, "true"); }
+static void jsondec_false(jsondec *d) { jsondec_parselit(d, "false"); }
+static void jsondec_null(jsondec *d) { jsondec_parselit(d, "null"); }
+
+static void jsondec_entrysep(jsondec *d) {
+ jsondec_skipws(d);
+ jsondec_parselit(d, ":");
+}
+
+static int jsondec_rawpeek(jsondec *d) {
+ switch (*d->ptr) {
+ case '{':
+ return JD_OBJECT;
+ case '[':
+ return JD_ARRAY;
+ case '"':
+ return JD_STRING;
+ case '-':
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ return JD_NUMBER;
+ case 't':
+ return JD_TRUE;
+ case 'f':
+ return JD_FALSE;
+ case 'n':
+ return JD_NULL;
+ default:
+ jsondec_errf(d, "Unexpected character: '%c'", *d->ptr);
+ }
+}
+
+/* JSON object/array **********************************************************/
+
+/* These are used like so:
+ *
+ * jsondec_objstart(d);
+ * while (jsondec_objnext(d)) {
+ * ...
+ * }
+ * jsondec_objend(d) */
+
+static int jsondec_peek(jsondec *d) {
+ jsondec_skipws(d);
+ return jsondec_rawpeek(d);
+}
+
+static void jsondec_push(jsondec *d) {
+ if (--d->depth < 0) {
+ jsondec_err(d, "Recursion limit exceeded");
+ }
+ d->is_first = true;
+}
+
+static bool jsondec_seqnext(jsondec *d, char end_ch) {
+ bool is_first = d->is_first;
+ d->is_first = false;
+ jsondec_skipws(d);
+ if (*d->ptr == end_ch) return false;
+ if (!is_first) jsondec_parselit(d, ",");
+ return true;
+}
+
+static void jsondec_arrstart(jsondec *d) {
+ jsondec_push(d);
+ jsondec_wsch(d, '[');
+}
+
+static void jsondec_arrend(jsondec *d) {
+ d->depth++;
+ jsondec_wsch(d, ']');
+}
+
+static bool jsondec_arrnext(jsondec *d) {
+ return jsondec_seqnext(d, ']');
+}
+
+static void jsondec_objstart(jsondec *d) {
+ jsondec_push(d);
+ jsondec_wsch(d, '{');
+}
+
+static void jsondec_objend(jsondec *d) {
+ d->depth++;
+ jsondec_wsch(d, '}');
+}
+
+static bool jsondec_objnext(jsondec *d) {
+ if (!jsondec_seqnext(d, '}')) return false;
+ if (jsondec_peek(d) != JD_STRING) {
+ jsondec_err(d, "Object must start with string");
+ }
+ return true;
+}
+
+/* JSON number ****************************************************************/
+
+static bool jsondec_tryskipdigits(jsondec *d) {
+ const char *start = d->ptr;
+
+ while (d->ptr < d->end) {
+ if (*d->ptr < '0' || *d->ptr > '9') {
+ break;
+ }
+ d->ptr++;
+ }
+
+ return d->ptr != start;
+}
+
+static void jsondec_skipdigits(jsondec *d) {
+ if (!jsondec_tryskipdigits(d)) {
+ jsondec_err(d, "Expected one or more digits");
+ }
+}
+
+static double jsondec_number(jsondec *d) {
+ const char *start = d->ptr;
+
+ assert(jsondec_rawpeek(d) == JD_NUMBER);
+
+ /* Skip over the syntax of a number, as specified by JSON. */
+ if (*d->ptr == '-') d->ptr++;
+
+ if (jsondec_tryparsech(d, '0')) {
+ if (jsondec_tryskipdigits(d)) {
+ jsondec_err(d, "number cannot have leading zero");
+ }
+ } else {
+ jsondec_skipdigits(d);
+ }
+
+ if (d->ptr == d->end) goto parse;
+ if (jsondec_tryparsech(d, '.')) {
+ jsondec_skipdigits(d);
+ }
+ if (d->ptr == d->end) goto parse;
+
+ if (*d->ptr == 'e' || *d->ptr == 'E') {
+ d->ptr++;
+ if (d->ptr == d->end) {
+ jsondec_err(d, "Unexpected EOF in number");
+ }
+ if (*d->ptr == '+' || *d->ptr == '-') {
+ d->ptr++;
+ }
+ jsondec_skipdigits(d);
+ }
+
+parse:
+ /* Having verified the syntax of a JSON number, use strtod() to parse
+ * (strtod() accepts a superset of JSON syntax). */
+ errno = 0;
+ {
+ char* end;
+ double val = strtod(start, &end);
+ assert(end == d->ptr);
+
+ /* Currently the min/max-val conformance tests fail if we check this. Does
+ * this mean the conformance tests are wrong or strtod() is wrong, or
+ * something else? Investigate further. */
+ /*
+ if (errno == ERANGE) {
+ jsondec_err(d, "Number out of range");
+ }
+ */
+
+ if (val > DBL_MAX || val < -DBL_MAX) {
+ jsondec_err(d, "Number out of range");
+ }
+
+ return val;
+ }
+}
+
+/* JSON string ****************************************************************/
+
+static char jsondec_escape(jsondec *d) {
+ switch (*d->ptr++) {
+ case '"':
+ return '\"';
+ case '\\':
+ return '\\';
+ case '/':
+ return '/';
+ case 'b':
+ return '\b';
+ case 'f':
+ return '\f';
+ case 'n':
+ return '\n';
+ case 'r':
+ return '\r';
+ case 't':
+ return '\t';
+ default:
+ jsondec_err(d, "Invalid escape char");
+ }
+}
+
+static uint32_t jsondec_codepoint(jsondec *d) {
+ uint32_t cp = 0;
+ const char *end;
+
+ if (d->end - d->ptr < 4) {
+ jsondec_err(d, "EOF inside string");
+ }
+
+ end = d->ptr + 4;
+ while (d->ptr < end) {
+ char ch = *d->ptr++;
+ if (ch >= '0' && ch <= '9') {
+ ch -= '0';
+ } else if (ch >= 'a' && ch <= 'f') {
+ ch = ch - 'a' + 10;
+ } else if (ch >= 'A' && ch <= 'F') {
+ ch = ch - 'A' + 10;
+ } else {
+ jsondec_err(d, "Invalid hex digit");
+ }
+ cp = (cp << 4) | ch;
+ }
+
+ return cp;
+}
+
+/* Parses a \uXXXX unicode escape (possibly a surrogate pair). */
+static size_t jsondec_unicode(jsondec *d, char* out) {
+ uint32_t cp = jsondec_codepoint(d);
+ if (cp >= 0xd800 && cp <= 0xdbff) {
+ /* Surrogate pair: two 16-bit codepoints become a 32-bit codepoint. */
+ uint32_t high = cp;
+ uint32_t low;
+ jsondec_parselit(d, "\\u");
+ low = jsondec_codepoint(d);
+ if (low < 0xdc00 || low > 0xdfff) {
+ jsondec_err(d, "Invalid low surrogate");
+ }
+ cp = (high & 0x3ff) << 10;
+ cp |= (low & 0x3ff);
+ cp += 0x10000;
+ } else if (cp >= 0xdc00 && cp <= 0xdfff) {
+ jsondec_err(d, "Unpaired low surrogate");
+ }
+
+ /* Write to UTF-8 */
+ if (cp <= 0x7f) {
+ out[0] = cp;
+ return 1;
+ } else if (cp <= 0x07FF) {
+ out[0] = ((cp >> 6) & 0x1F) | 0xC0;
+ out[1] = ((cp >> 0) & 0x3F) | 0x80;
+ return 2;
+ } else if (cp <= 0xFFFF) {
+ out[0] = ((cp >> 12) & 0x0F) | 0xE0;
+ out[1] = ((cp >> 6) & 0x3F) | 0x80;
+ out[2] = ((cp >> 0) & 0x3F) | 0x80;
+ return 3;
+ } else if (cp < 0x10FFFF) {
+ out[0] = ((cp >> 18) & 0x07) | 0xF0;
+ out[1] = ((cp >> 12) & 0x3f) | 0x80;
+ out[2] = ((cp >> 6) & 0x3f) | 0x80;
+ out[3] = ((cp >> 0) & 0x3f) | 0x80;
+ return 4;
+ } else {
+ jsondec_err(d, "Invalid codepoint");
+ }
+}
+
+static void jsondec_resize(jsondec *d, char **buf, char **end, char **buf_end) {
+ size_t oldsize = *buf_end - *buf;
+ size_t len = *end - *buf;
+ size_t size = UPB_MAX(8, 2 * oldsize);
+
+ *buf = upb_arena_realloc(d->arena, *buf, len, size);
+ if (!*buf) jsondec_err(d, "Out of memory");
+
+ *end = *buf + len;
+ *buf_end = *buf + size;
+}
+
+static upb_strview jsondec_string(jsondec *d) {
+ char *buf = NULL;
+ char *end = NULL;
+ char *buf_end = NULL;
+
+ jsondec_skipws(d);
+
+ if (*d->ptr++ != '"') {
+ jsondec_err(d, "Expected string");
+ }
+
+ while (d->ptr < d->end) {
+ char ch = *d->ptr++;
+
+ if (end == buf_end) {
+ jsondec_resize(d, &buf, &end, &buf_end);
+ }
+
+ switch (ch) {
+ case '"': {
+ upb_strview ret;
+ ret.data = buf;
+ ret.size = end - buf;
+ *end = '\0'; /* Needed for possible strtod(). */
+ return ret;
+ }
+ case '\\':
+ if (d->ptr == d->end) goto eof;
+ if (*d->ptr == 'u') {
+ d->ptr++;
+ if (buf_end - end < 4) {
+ /* Allow space for maximum-sized code point (4 bytes). */
+ jsondec_resize(d, &buf, &end, &buf_end);
+ }
+ end += jsondec_unicode(d, end);
+ } else {
+ *end++ = jsondec_escape(d);
+ }
+ break;
+ default:
+ if ((unsigned char)*d->ptr < 0x20) {
+ jsondec_err(d, "Invalid char in JSON string");
+ }
+ *end++ = ch;
+ break;
+ }
+ }
+
+eof:
+ jsondec_err(d, "EOF inside string");
+}
+
+static void jsondec_skipval(jsondec *d) {
+ switch (jsondec_peek(d)) {
+ case JD_OBJECT:
+ jsondec_objstart(d);
+ while (jsondec_objnext(d)) {
+ jsondec_string(d);
+ jsondec_entrysep(d);
+ jsondec_skipval(d);
+ }
+ jsondec_objend(d);
+ break;
+ case JD_ARRAY:
+ jsondec_arrstart(d);
+ while (jsondec_arrnext(d)) {
+ jsondec_skipval(d);
+ }
+ jsondec_arrend(d);
+ break;
+ case JD_TRUE:
+ jsondec_true(d);
+ break;
+ case JD_FALSE:
+ jsondec_false(d);
+ break;
+ case JD_NULL:
+ jsondec_null(d);
+ break;
+ case JD_STRING:
+ jsondec_string(d);
+ break;
+ case JD_NUMBER:
+ jsondec_number(d);
+ break;
+ }
+}
+
+/* Base64 decoding for bytes fields. ******************************************/
+
+static unsigned int jsondec_base64_tablelookup(const char ch) {
+ /* Table includes the normal base64 chars plus the URL-safe variant. */
+ const signed char table[256] = {
+ -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1,
+ -1, 62 /*+*/, -1, 62 /*-*/, -1, 63 /*/ */, 52 /*0*/,
+ 53 /*1*/, 54 /*2*/, 55 /*3*/, 56 /*4*/, 57 /*5*/, 58 /*6*/, 59 /*7*/,
+ 60 /*8*/, 61 /*9*/, -1, -1, -1, -1, -1,
+ -1, -1, 0 /*A*/, 1 /*B*/, 2 /*C*/, 3 /*D*/, 4 /*E*/,
+ 5 /*F*/, 6 /*G*/, 07 /*H*/, 8 /*I*/, 9 /*J*/, 10 /*K*/, 11 /*L*/,
+ 12 /*M*/, 13 /*N*/, 14 /*O*/, 15 /*P*/, 16 /*Q*/, 17 /*R*/, 18 /*S*/,
+ 19 /*T*/, 20 /*U*/, 21 /*V*/, 22 /*W*/, 23 /*X*/, 24 /*Y*/, 25 /*Z*/,
+ -1, -1, -1, -1, 63 /*_*/, -1, 26 /*a*/,
+ 27 /*b*/, 28 /*c*/, 29 /*d*/, 30 /*e*/, 31 /*f*/, 32 /*g*/, 33 /*h*/,
+ 34 /*i*/, 35 /*j*/, 36 /*k*/, 37 /*l*/, 38 /*m*/, 39 /*n*/, 40 /*o*/,
+ 41 /*p*/, 42 /*q*/, 43 /*r*/, 44 /*s*/, 45 /*t*/, 46 /*u*/, 47 /*v*/,
+ 48 /*w*/, 49 /*x*/, 50 /*y*/, 51 /*z*/, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1};
+
+ /* Sign-extend return value so high bit will be set on any unexpected char. */
+ return table[(unsigned)ch];
+}
+
+static char *jsondec_partialbase64(jsondec *d, const char *ptr, const char *end,
+ char *out) {
+ int32_t val = -1;
+
+ switch (end - ptr) {
+ case 2:
+ val = jsondec_base64_tablelookup(ptr[0]) << 18 |
+ jsondec_base64_tablelookup(ptr[1]) << 12;
+ out[0] = val >> 16;
+ out += 1;
+ break;
+ case 3:
+ val = jsondec_base64_tablelookup(ptr[0]) << 18 |
+ jsondec_base64_tablelookup(ptr[1]) << 12 |
+ jsondec_base64_tablelookup(ptr[2]) << 6;
+ out[0] = val >> 16;
+ out[1] = (val >> 8) & 0xff;
+ out += 2;
+ break;
+ }
+
+ if (val < 0) {
+ jsondec_err(d, "Corrupt base64");
+ }
+
+ return out;
+}
+
+static size_t jsondec_base64(jsondec *d, upb_strview str) {
+ /* We decode in place. This is safe because this is a new buffer (not
+ * aliasing the input) and because base64 decoding shrinks 4 bytes into 3. */
+ char *out = (char*)str.data;
+ const char *ptr = str.data;
+ const char *end = ptr + str.size;
+ const char *end4 = ptr + (str.size & -4); /* Round down to multiple of 4. */
+
+ for (; ptr < end4; ptr += 4, out += 3) {
+ int val = jsondec_base64_tablelookup(ptr[0]) << 18 |
+ jsondec_base64_tablelookup(ptr[1]) << 12 |
+ jsondec_base64_tablelookup(ptr[2]) << 6 |
+ jsondec_base64_tablelookup(ptr[3]) << 0;
+
+ if (val < 0) {
+ /* Junk chars or padding. Remove trailing padding, if any. */
+ if (end - ptr == 4 && ptr[3] == '=') {
+ if (ptr[2] == '=') {
+ end -= 2;
+ } else {
+ end -= 1;
+ }
+ }
+ break;
+ }
+
+ out[0] = val >> 16;
+ out[1] = (val >> 8) & 0xff;
+ out[2] = val & 0xff;
+ }
+
+ if (ptr < end) {
+ /* Process remaining chars. We do not require padding. */
+ out = jsondec_partialbase64(d, ptr, end, out);
+ }
+
+ return out - str.data;
+}
+
+/* Low-level integer parsing **************************************************/
+
+/* We use these hand-written routines instead of strto[u]l() because the "long
+ * long" variants aren't in c89. Also our version allows setting a ptr limit. */
+
+static const char *jsondec_buftouint64(jsondec *d, const char *ptr,
+ const char *end, uint64_t *val) {
+ uint64_t u64 = 0;
+ while (ptr < end) {
+ unsigned ch = *ptr - '0';
+ if (ch >= 10) break;
+ if (u64 > UINT64_MAX / 10 || u64 * 10 > UINT64_MAX - ch) {
+ jsondec_err(d, "Integer overflow");
+ }
+ u64 *= 10;
+ u64 += ch;
+ ptr++;
+ }
+
+ *val = u64;
+ return ptr;
+}
+
+static const char *jsondec_buftoint64(jsondec *d, const char *ptr,
+ const char *end, int64_t *val) {
+ bool neg = false;
+ uint64_t u64;
+
+ if (ptr != end && *ptr == '-') {
+ ptr++;
+ neg = true;
+ }
+
+ ptr = jsondec_buftouint64(d, ptr, end, &u64);
+ if (u64 > (uint64_t)INT64_MAX + neg) {
+ jsondec_err(d, "Integer overflow");
+ }
+
+ *val = neg ? -u64 : u64;
+ return ptr;
+}
+
+static uint64_t jsondec_strtouint64(jsondec *d, upb_strview str) {
+ const char *end = str.data + str.size;
+ uint64_t ret;
+ if (jsondec_buftouint64(d, str.data, end, &ret) != end) {
+ jsondec_err(d, "Non-number characters in quoted integer");
+ }
+ return ret;
+}
+
+static int64_t jsondec_strtoint64(jsondec *d, upb_strview str) {
+ const char *end = str.data + str.size;
+ int64_t ret;
+ if (jsondec_buftoint64(d, str.data, end, &ret) != end) {
+ jsondec_err(d, "Non-number characters in quoted integer");
+ }
+ return ret;
+}
+
+/* Primitive value types ******************************************************/
+
+/* Parse INT32 or INT64 value. */
+static upb_msgval jsondec_int(jsondec *d, const upb_fielddef *f) {
+ upb_msgval val;
+
+ switch (jsondec_peek(d)) {
+ case JD_NUMBER: {
+ double dbl = jsondec_number(d);
+ if (dbl > 9223372036854774784.0 || dbl < -9223372036854775808.0) {
+ jsondec_err(d, "JSON number is out of range.");
+ }
+ val.int64_val = dbl; /* must be guarded, overflow here is UB */
+ if (val.int64_val != dbl) {
+ jsondec_errf(d, "JSON number was not integral (%f != %" PRId64 ")", dbl,
+ val.int64_val);
+ }
+ break;
+ }
+ case JD_STRING: {
+ upb_strview str = jsondec_string(d);
+ val.int64_val = jsondec_strtoint64(d, str);
+ break;
+ }
+ default:
+ jsondec_err(d, "Expected number or string");
+ }
+
+ if (upb_fielddef_type(f) == UPB_TYPE_INT32) {
+ if (val.int64_val > INT32_MAX || val.int64_val < INT32_MIN) {
+ jsondec_err(d, "Integer out of range.");
+ }
+ val.int32_val = (int32_t)val.int64_val;
+ }
+
+ return val;
+}
+
+/* Parse UINT32 or UINT64 value. */
+static upb_msgval jsondec_uint(jsondec *d, const upb_fielddef *f) {
+ upb_msgval val = {0};
+
+ switch (jsondec_peek(d)) {
+ case JD_NUMBER: {
+ double dbl = jsondec_number(d);
+ if (dbl > 18446744073709549568.0 || dbl < 0) {
+ jsondec_err(d, "JSON number is out of range.");
+ }
+ val.uint64_val = dbl; /* must be guarded, overflow here is UB */
+ if (val.uint64_val != dbl) {
+ jsondec_errf(d, "JSON number was not integral (%f != %" PRIu64 ")", dbl,
+ val.uint64_val);
+ }
+ break;
+ }
+ case JD_STRING: {
+ upb_strview str = jsondec_string(d);
+ val.uint64_val = jsondec_strtouint64(d, str);
+ break;
+ }
+ default:
+ jsondec_err(d, "Expected number or string");
+ }
+
+ if (upb_fielddef_type(f) == UPB_TYPE_UINT32) {
+ if (val.uint64_val > UINT32_MAX) {
+ jsondec_err(d, "Integer out of range.");
+ }
+ val.uint32_val = (uint32_t)val.uint64_val;
+ }
+
+ return val;
+}
+
+/* Parse DOUBLE or FLOAT value. */
+static upb_msgval jsondec_double(jsondec *d, const upb_fielddef *f) {
+ upb_strview str;
+ upb_msgval val = {0};
+
+ switch (jsondec_peek(d)) {
+ case JD_NUMBER:
+ val.double_val = jsondec_number(d);
+ break;
+ case JD_STRING:
+ str = jsondec_string(d);
+ if (jsondec_streql(str, "NaN")) {
+ val.double_val = NAN;
+ } else if (jsondec_streql(str, "Infinity")) {
+ val.double_val = INFINITY;
+ } else if (jsondec_streql(str, "-Infinity")) {
+ val.double_val = -INFINITY;
+ } else {
+ val.double_val = strtod(str.data, NULL);
+ }
+ break;
+ default:
+ jsondec_err(d, "Expected number or string");
+ }
+
+ if (upb_fielddef_type(f) == UPB_TYPE_FLOAT) {
+ if (val.double_val != INFINITY && val.double_val != -INFINITY &&
+ (val.double_val > FLT_MAX || val.double_val < -FLT_MAX)) {
+ jsondec_err(d, "Float out of range");
+ }
+ val.float_val = val.double_val;
+ }
+
+ return val;
+}
+
+/* Parse STRING or BYTES value. */
+static upb_msgval jsondec_strfield(jsondec *d, const upb_fielddef *f) {
+ upb_msgval val;
+ val.str_val = jsondec_string(d);
+ if (upb_fielddef_type(f) == UPB_TYPE_BYTES) {
+ val.str_val.size = jsondec_base64(d, val.str_val);
+ }
+ return val;
+}
+
+static upb_msgval jsondec_enum(jsondec *d, const upb_fielddef *f) {
+ switch (jsondec_peek(d)) {
+ case JD_STRING: {
+ const upb_enumdef *e = upb_fielddef_enumsubdef(f);
+ upb_strview str = jsondec_string(d);
+ upb_msgval val;
+ if (!upb_enumdef_ntoi(e, str.data, str.size, &val.int32_val)) {
+ if (d->options & UPB_JSONDEC_IGNOREUNKNOWN) {
+ val.int32_val = 0;
+ } else {
+ jsondec_errf(d, "Unknown enumerator: '" UPB_STRVIEW_FORMAT "'",
+ UPB_STRVIEW_ARGS(str));
+ }
+ }
+ return val;
+ }
+ case JD_NULL: {
+ if (jsondec_isnullvalue(f)) {
+ upb_msgval val;
+ jsondec_null(d);
+ val.int32_val = 0;
+ return val;
+ }
+ }
+ /* Fallthrough. */
+ default:
+ return jsondec_int(d, f);
+ }
+}
+
+static upb_msgval jsondec_bool(jsondec *d, const upb_fielddef *f) {
+ bool is_map_key = upb_fielddef_number(f) == 1 &&
+ upb_msgdef_mapentry(upb_fielddef_containingtype(f));
+ upb_msgval val;
+
+ if (is_map_key) {
+ upb_strview str = jsondec_string(d);
+ if (jsondec_streql(str, "true")) {
+ val.bool_val = true;
+ } else if (jsondec_streql(str, "false")) {
+ val.bool_val = false;
+ } else {
+ jsondec_err(d, "Invalid boolean map key");
+ }
+ } else {
+ switch (jsondec_peek(d)) {
+ case JD_TRUE:
+ val.bool_val = true;
+ jsondec_true(d);
+ break;
+ case JD_FALSE:
+ val.bool_val = false;
+ jsondec_false(d);
+ break;
+ default:
+ jsondec_err(d, "Expected true or false");
+ }
+ }
+
+ return val;
+}
+
+/* Composite types (array/message/map) ****************************************/
+
+static void jsondec_array(jsondec *d, upb_msg *msg, const upb_fielddef *f) {
+ upb_array *arr = upb_msg_mutable(msg, f, d->arena).array;
+
+ jsondec_arrstart(d);
+ while (jsondec_arrnext(d)) {
+ upb_msgval elem = jsondec_value(d, f);
+ upb_array_append(arr, elem, d->arena);
+ }
+ jsondec_arrend(d);
+}
+
+static void jsondec_map(jsondec *d, upb_msg *msg, const upb_fielddef *f) {
+ upb_map *map = upb_msg_mutable(msg, f, d->arena).map;
+ const upb_msgdef *entry = upb_fielddef_msgsubdef(f);
+ const upb_fielddef *key_f = upb_msgdef_itof(entry, 1);
+ const upb_fielddef *val_f = upb_msgdef_itof(entry, 2);
+
+ jsondec_objstart(d);
+ while (jsondec_objnext(d)) {
+ upb_msgval key, val;
+ key = jsondec_value(d, key_f);
+ jsondec_entrysep(d);
+ val = jsondec_value(d, val_f);
+ upb_map_set(map, key, val, d->arena);
+ }
+ jsondec_objend(d);
+}
+
+static void jsondec_tomsg(jsondec *d, upb_msg *msg, const upb_msgdef *m) {
+ if (upb_msgdef_wellknowntype(m) == UPB_WELLKNOWN_UNSPECIFIED) {
+ jsondec_object(d, msg, m);
+ } else {
+ jsondec_wellknown(d, msg, m);
+ }
+}
+
+static upb_msgval jsondec_msg(jsondec *d, const upb_fielddef *f) {
+ const upb_msgdef *m = upb_fielddef_msgsubdef(f);
+ upb_msg *msg = upb_msg_new(m, d->arena);
+ upb_msgval val;
+
+ jsondec_tomsg(d, msg, m);
+ val.msg_val = msg;
+ return val;
+}
+
+static void jsondec_field(jsondec *d, upb_msg *msg, const upb_msgdef *m) {
+ upb_strview name;
+ const upb_fielddef *f;
+ const upb_fielddef *preserved;
+
+ name = jsondec_string(d);
+ jsondec_entrysep(d);
+ f = upb_msgdef_lookupjsonname(m, name.data, name.size);
+
+ if (!f) {
+ if ((d->options & UPB_JSONDEC_IGNOREUNKNOWN) == 0) {
+ jsondec_errf(d, "No such field: " UPB_STRVIEW_FORMAT,
+ UPB_STRVIEW_ARGS(name));
+ }
+ jsondec_skipval(d);
+ return;
+ }
+
+ if (upb_fielddef_realcontainingoneof(f) &&
+ upb_msg_whichoneof(msg, upb_fielddef_containingoneof(f))) {
+ jsondec_err(d, "More than one field for this oneof.");
+ }
+
+ if (jsondec_peek(d) == JD_NULL && !jsondec_isvalue(f)) {
+ /* JSON "null" indicates a default value, so no need to set anything. */
+ jsondec_null(d);
+ return;
+ }
+
+ preserved = d->debug_field;
+ d->debug_field = f;
+
+ if (upb_fielddef_ismap(f)) {
+ jsondec_map(d, msg, f);
+ } else if (upb_fielddef_isseq(f)) {
+ jsondec_array(d, msg, f);
+ } else if (upb_fielddef_issubmsg(f)) {
+ upb_msg *submsg = upb_msg_mutable(msg, f, d->arena).msg;
+ const upb_msgdef *subm = upb_fielddef_msgsubdef(f);
+ jsondec_tomsg(d, submsg, subm);
+ } else {
+ upb_msgval val = jsondec_value(d, f);
+ upb_msg_set(msg, f, val, d->arena);
+ }
+
+ d->debug_field = preserved;
+}
+
+static void jsondec_object(jsondec *d, upb_msg *msg, const upb_msgdef *m) {
+ jsondec_objstart(d);
+ while (jsondec_objnext(d)) {
+ jsondec_field(d, msg, m);
+ }
+ jsondec_objend(d);
+}
+
+static upb_msgval jsondec_value(jsondec *d, const upb_fielddef *f) {
+ switch (upb_fielddef_type(f)) {
+ case UPB_TYPE_BOOL:
+ return jsondec_bool(d, f);
+ case UPB_TYPE_FLOAT:
+ case UPB_TYPE_DOUBLE:
+ return jsondec_double(d, f);
+ case UPB_TYPE_UINT32:
+ case UPB_TYPE_UINT64:
+ return jsondec_uint(d, f);
+ case UPB_TYPE_INT32:
+ case UPB_TYPE_INT64:
+ return jsondec_int(d, f);
+ case UPB_TYPE_STRING:
+ case UPB_TYPE_BYTES:
+ return jsondec_strfield(d, f);
+ case UPB_TYPE_ENUM:
+ return jsondec_enum(d, f);
+ case UPB_TYPE_MESSAGE:
+ return jsondec_msg(d, f);
+ default:
+ UPB_UNREACHABLE();
+ }
+}
+
+/* Well-known types ***********************************************************/
+
+static int jsondec_tsdigits(jsondec *d, const char **ptr, size_t digits,
+ const char *after) {
+ uint64_t val;
+ const char *p = *ptr;
+ const char *end = p + digits;
+ size_t after_len = after ? strlen(after) : 0;
+
+ UPB_ASSERT(digits <= 9); /* int can't overflow. */
+
+ if (jsondec_buftouint64(d, p, end, &val) != end ||
+ (after_len && memcmp(end, after, after_len) != 0)) {
+ jsondec_err(d, "Malformed timestamp");
+ }
+
+ UPB_ASSERT(val < INT_MAX);
+
+ *ptr = end + after_len;
+ return (int)val;
+}
+
+static int jsondec_nanos(jsondec *d, const char **ptr, const char *end) {
+ uint64_t nanos = 0;
+ const char *p = *ptr;
+
+ if (p != end && *p == '.') {
+ const char *nano_end = jsondec_buftouint64(d, p + 1, end, &nanos);
+ int digits = (int)(nano_end - p - 1);
+ int exp_lg10 = 9 - digits;
+ if (digits > 9) {
+ jsondec_err(d, "Too many digits for partial seconds");
+ }
+ while (exp_lg10--) nanos *= 10;
+ *ptr = nano_end;
+ }
+
+ UPB_ASSERT(nanos < INT_MAX);
+
+ return (int)nanos;
+}
+
+/* jsondec_epochdays(1970, 1, 1) == 1970-01-01 == 0. */
+int jsondec_epochdays(int y, int m, int d) {
+ const uint32_t year_base = 4800; /* Before min year, multiple of 400. */
+ const uint32_t m_adj = m - 3; /* March-based month. */
+ const uint32_t carry = m_adj > (uint32_t)m ? 1 : 0;
+ const uint32_t adjust = carry ? 12 : 0;
+ const uint32_t y_adj = y + year_base - carry;
+ const uint32_t month_days = ((m_adj + adjust) * 62719 + 769) / 2048;
+ const uint32_t leap_days = y_adj / 4 - y_adj / 100 + y_adj / 400;
+ return y_adj * 365 + leap_days + month_days + (d - 1) - 2472632;
+}
+
+static int64_t jsondec_unixtime(int y, int m, int d, int h, int min, int s) {
+ return (int64_t)jsondec_epochdays(y, m, d) * 86400 + h * 3600 + min * 60 + s;
+}
+
+static void jsondec_timestamp(jsondec *d, upb_msg *msg, const upb_msgdef *m) {
+ upb_msgval seconds;
+ upb_msgval nanos;
+ upb_strview str = jsondec_string(d);
+ const char *ptr = str.data;
+ const char *end = ptr + str.size;
+
+ if (str.size < 20) goto malformed;
+
+ {
+ /* 1972-01-01T01:00:00 */
+ int year = jsondec_tsdigits(d, &ptr, 4, "-");
+ int mon = jsondec_tsdigits(d, &ptr, 2, "-");
+ int day = jsondec_tsdigits(d, &ptr, 2, "T");
+ int hour = jsondec_tsdigits(d, &ptr, 2, ":");
+ int min = jsondec_tsdigits(d, &ptr, 2, ":");
+ int sec = jsondec_tsdigits(d, &ptr, 2, NULL);
+
+ seconds.int64_val = jsondec_unixtime(year, mon, day, hour, min, sec);
+ }
+
+ nanos.int32_val = jsondec_nanos(d, &ptr, end);
+
+ {
+ /* [+-]08:00 or Z */
+ int ofs = 0;
+ bool neg = false;
+
+ if (ptr == end) goto malformed;
+
+ switch (*ptr++) {
+ case '-':
+ neg = true;
+ /* fallthrough */
+ case '+':
+ if ((end - ptr) != 5) goto malformed;
+ ofs = jsondec_tsdigits(d, &ptr, 2, ":00");
+ ofs *= 60 * 60;
+ seconds.int64_val += (neg ? ofs : -ofs);
+ break;
+ case 'Z':
+ if (ptr != end) goto malformed;
+ break;
+ default:
+ goto malformed;
+ }
+ }
+
+ if (seconds.int64_val < -62135596800) {
+ jsondec_err(d, "Timestamp out of range");
+ }
+
+ upb_msg_set(msg, upb_msgdef_itof(m, 1), seconds, d->arena);
+ upb_msg_set(msg, upb_msgdef_itof(m, 2), nanos, d->arena);
+ return;
+
+malformed:
+ jsondec_err(d, "Malformed timestamp");
+}
+
+static void jsondec_duration(jsondec *d, upb_msg *msg, const upb_msgdef *m) {
+ upb_msgval seconds;
+ upb_msgval nanos;
+ upb_strview str = jsondec_string(d);
+ const char *ptr = str.data;
+ const char *end = ptr + str.size;
+ const int64_t max = (uint64_t)3652500 * 86400;
+
+ /* "3.000000001s", "3s", etc. */
+ ptr = jsondec_buftoint64(d, ptr, end, &seconds.int64_val);
+ nanos.int32_val = jsondec_nanos(d, &ptr, end);
+
+ if (end - ptr != 1 || *ptr != 's') {
+ jsondec_err(d, "Malformed duration");
+ }
+
+ if (seconds.int64_val < -max || seconds.int64_val > max) {
+ jsondec_err(d, "Duration out of range");
+ }
+
+ if (seconds.int64_val < 0) {
+ nanos.int32_val = - nanos.int32_val;
+ }
+
+ upb_msg_set(msg, upb_msgdef_itof(m, 1), seconds, d->arena);
+ upb_msg_set(msg, upb_msgdef_itof(m, 2), nanos, d->arena);
+}
+
+static void jsondec_listvalue(jsondec *d, upb_msg *msg, const upb_msgdef *m) {
+ const upb_fielddef *values_f = upb_msgdef_itof(m, 1);
+ const upb_msgdef *value_m = upb_fielddef_msgsubdef(values_f);
+ upb_array *values = upb_msg_mutable(msg, values_f, d->arena).array;
+
+ jsondec_arrstart(d);
+ while (jsondec_arrnext(d)) {
+ upb_msg *value_msg = upb_msg_new(value_m, d->arena);
+ upb_msgval value;
+ value.msg_val = value_msg;
+ upb_array_append(values, value, d->arena);
+ jsondec_wellknownvalue(d, value_msg, value_m);
+ }
+ jsondec_arrend(d);
+}
+
+static void jsondec_struct(jsondec *d, upb_msg *msg, const upb_msgdef *m) {
+ const upb_fielddef *fields_f = upb_msgdef_itof(m, 1);
+ const upb_msgdef *entry_m = upb_fielddef_msgsubdef(fields_f);
+ const upb_fielddef *value_f = upb_msgdef_itof(entry_m, 2);
+ const upb_msgdef *value_m = upb_fielddef_msgsubdef(value_f);
+ upb_map *fields = upb_msg_mutable(msg, fields_f, d->arena).map;
+
+ jsondec_objstart(d);
+ while (jsondec_objnext(d)) {
+ upb_msgval key, value;
+ upb_msg *value_msg = upb_msg_new(value_m, d->arena);
+ key.str_val = jsondec_string(d);
+ value.msg_val = value_msg;
+ upb_map_set(fields, key, value, d->arena);
+ jsondec_entrysep(d);
+ jsondec_wellknownvalue(d, value_msg, value_m);
+ }
+ jsondec_objend(d);
+}
+
+static void jsondec_wellknownvalue(jsondec *d, upb_msg *msg,
+ const upb_msgdef *m) {
+ upb_msgval val;
+ const upb_fielddef *f;
+ upb_msg *submsg;
+
+ switch (jsondec_peek(d)) {
+ case JD_NUMBER:
+ /* double number_value = 2; */
+ f = upb_msgdef_itof(m, 2);
+ val.double_val = jsondec_number(d);
+ break;
+ case JD_STRING:
+ /* string string_value = 3; */
+ f = upb_msgdef_itof(m, 3);
+ val.str_val = jsondec_string(d);
+ break;
+ case JD_FALSE:
+ /* bool bool_value = 4; */
+ f = upb_msgdef_itof(m, 4);
+ val.bool_val = false;
+ jsondec_false(d);
+ break;
+ case JD_TRUE:
+ /* bool bool_value = 4; */
+ f = upb_msgdef_itof(m, 4);
+ val.bool_val = true;
+ jsondec_true(d);
+ break;
+ case JD_NULL:
+ /* NullValue null_value = 1; */
+ f = upb_msgdef_itof(m, 1);
+ val.int32_val = 0;
+ jsondec_null(d);
+ break;
+ /* Note: these cases return, because upb_msg_mutable() is enough. */
+ case JD_OBJECT:
+ /* Struct struct_value = 5; */
+ f = upb_msgdef_itof(m, 5);
+ submsg = upb_msg_mutable(msg, f, d->arena).msg;
+ jsondec_struct(d, submsg, upb_fielddef_msgsubdef(f));
+ return;
+ case JD_ARRAY:
+ /* ListValue list_value = 6; */
+ f = upb_msgdef_itof(m, 6);
+ submsg = upb_msg_mutable(msg, f, d->arena).msg;
+ jsondec_listvalue(d, submsg, upb_fielddef_msgsubdef(f));
+ return;
+ default:
+ UPB_UNREACHABLE();
+ }
+
+ upb_msg_set(msg, f, val, d->arena);
+}
+
+static upb_strview jsondec_mask(jsondec *d, const char *buf, const char *end) {
+ /* FieldMask fields grow due to inserted '_' characters, so we can't do the
+ * transform in place. */
+ const char *ptr = buf;
+ upb_strview ret;
+ char *out;
+
+ ret.size = end - ptr;
+ while (ptr < end) {
+ ret.size += (*ptr >= 'A' && *ptr <= 'Z');
+ ptr++;
+ }
+
+ out = upb_arena_malloc(d->arena, ret.size);
+ ptr = buf;
+ ret.data = out;
+
+ while (ptr < end) {
+ char ch = *ptr++;
+ if (ch >= 'A' && ch <= 'Z') {
+ *out++ = '_';
+ *out++ = ch + 32;
+ } else if (ch == '_') {
+ jsondec_err(d, "field mask may not contain '_'");
+ } else {
+ *out++ = ch;
+ }
+ }
+
+ return ret;
+}
+
+static void jsondec_fieldmask(jsondec *d, upb_msg *msg, const upb_msgdef *m) {
+ /* repeated string paths = 1; */
+ const upb_fielddef *paths_f = upb_msgdef_itof(m, 1);
+ upb_array *arr = upb_msg_mutable(msg, paths_f, d->arena).array;
+ upb_strview str = jsondec_string(d);
+ const char *ptr = str.data;
+ const char *end = ptr + str.size;
+ upb_msgval val;
+
+ while (ptr < end) {
+ const char *elem_end = memchr(ptr, ',', end - ptr);
+ if (elem_end) {
+ val.str_val = jsondec_mask(d, ptr, elem_end);
+ ptr = elem_end + 1;
+ } else {
+ val.str_val = jsondec_mask(d, ptr, end);
+ ptr = end;
+ }
+ upb_array_append(arr, val, d->arena);
+ }
+}
+
+static void jsondec_anyfield(jsondec *d, upb_msg *msg, const upb_msgdef *m) {
+ if (upb_msgdef_wellknowntype(m) == UPB_WELLKNOWN_UNSPECIFIED) {
+ /* For regular types: {"@type": "[user type]", "f1": , "f2": }
+ * where f1, f2, etc. are the normal fields of this type. */
+ jsondec_field(d, msg, m);
+ } else {
+ /* For well-known types: {"@type": "[well-known type]", "value": }
+ * where is whatever encoding the WKT normally uses. */
+ upb_strview str = jsondec_string(d);
+ jsondec_entrysep(d);
+ if (!jsondec_streql(str, "value")) {
+ jsondec_err(d, "Key for well-known type must be 'value'");
+ }
+ jsondec_wellknown(d, msg, m);
+ }
+}
+
+static const upb_msgdef *jsondec_typeurl(jsondec *d, upb_msg *msg,
+ const upb_msgdef *m) {
+ const upb_fielddef *type_url_f = upb_msgdef_itof(m, 1);
+ const upb_msgdef *type_m;
+ upb_strview type_url = jsondec_string(d);
+ const char *end = type_url.data + type_url.size;
+ const char *ptr = end;
+ upb_msgval val;
+
+ val.str_val = type_url;
+ upb_msg_set(msg, type_url_f, val, d->arena);
+
+ /* Find message name after the last '/' */
+ while (ptr > type_url.data && *--ptr != '/') {}
+
+ if (ptr == type_url.data || ptr == end) {
+ jsondec_err(d, "Type url must have at least one '/' and non-empty host");
+ }
+
+ ptr++;
+ type_m = upb_symtab_lookupmsg2(d->any_pool, ptr, end - ptr);
+
+ if (!type_m) {
+ jsondec_err(d, "Type was not found");
+ }
+
+ return type_m;
+}
+
+static void jsondec_any(jsondec *d, upb_msg *msg, const upb_msgdef *m) {
+ /* string type_url = 1;
+ * bytes value = 2; */
+ const upb_fielddef *value_f = upb_msgdef_itof(m, 2);
+ upb_msg *any_msg;
+ const upb_msgdef *any_m = NULL;
+ const char *pre_type_data = NULL;
+ const char *pre_type_end = NULL;
+ upb_msgval encoded;
+
+ jsondec_objstart(d);
+
+ /* Scan looking for "@type", which is not necessarily first. */
+ while (!any_m && jsondec_objnext(d)) {
+ const char *start = d->ptr;
+ upb_strview name = jsondec_string(d);
+ jsondec_entrysep(d);
+ if (jsondec_streql(name, "@type")) {
+ any_m = jsondec_typeurl(d, msg, m);
+ if (pre_type_data) {
+ pre_type_end = start;
+ while (*pre_type_end != ',') pre_type_end--;
+ }
+ } else {
+ if (!pre_type_data) pre_type_data = start;
+ jsondec_skipval(d);
+ }
+ }
+
+ if (!any_m) {
+ jsondec_err(d, "Any object didn't contain a '@type' field");
+ }
+
+ any_msg = upb_msg_new(any_m, d->arena);
+
+ if (pre_type_data) {
+ size_t len = pre_type_end - pre_type_data + 1;
+ char *tmp = upb_arena_malloc(d->arena, len);
+ const char *saved_ptr = d->ptr;
+ const char *saved_end = d->end;
+ memcpy(tmp, pre_type_data, len - 1);
+ tmp[len - 1] = '}';
+ d->ptr = tmp;
+ d->end = tmp + len;
+ d->is_first = true;
+ while (jsondec_objnext(d)) {
+ jsondec_anyfield(d, any_msg, any_m);
+ }
+ d->ptr = saved_ptr;
+ d->end = saved_end;
+ }
+
+ while (jsondec_objnext(d)) {
+ jsondec_anyfield(d, any_msg, any_m);
+ }
+
+ jsondec_objend(d);
+
+ encoded.str_val.data = upb_encode(any_msg, upb_msgdef_layout(any_m), d->arena,
+ &encoded.str_val.size);
+ upb_msg_set(msg, value_f, encoded, d->arena);
+}
+
+static void jsondec_wrapper(jsondec *d, upb_msg *msg, const upb_msgdef *m) {
+ const upb_fielddef *value_f = upb_msgdef_itof(m, 1);
+ upb_msgval val = jsondec_value(d, value_f);
+ upb_msg_set(msg, value_f, val, d->arena);
+}
+
+static void jsondec_wellknown(jsondec *d, upb_msg *msg, const upb_msgdef *m) {
+ switch (upb_msgdef_wellknowntype(m)) {
+ case UPB_WELLKNOWN_ANY:
+ jsondec_any(d, msg, m);
+ break;
+ case UPB_WELLKNOWN_FIELDMASK:
+ jsondec_fieldmask(d, msg, m);
+ break;
+ case UPB_WELLKNOWN_DURATION:
+ jsondec_duration(d, msg, m);
+ break;
+ case UPB_WELLKNOWN_TIMESTAMP:
+ jsondec_timestamp(d, msg, m);
+ break;
+ case UPB_WELLKNOWN_VALUE:
+ jsondec_wellknownvalue(d, msg, m);
+ break;
+ case UPB_WELLKNOWN_LISTVALUE:
+ jsondec_listvalue(d, msg, m);
+ break;
+ case UPB_WELLKNOWN_STRUCT:
+ jsondec_struct(d, msg, m);
+ break;
+ case UPB_WELLKNOWN_DOUBLEVALUE:
+ case UPB_WELLKNOWN_FLOATVALUE:
+ case UPB_WELLKNOWN_INT64VALUE:
+ case UPB_WELLKNOWN_UINT64VALUE:
+ case UPB_WELLKNOWN_INT32VALUE:
+ case UPB_WELLKNOWN_UINT32VALUE:
+ case UPB_WELLKNOWN_STRINGVALUE:
+ case UPB_WELLKNOWN_BYTESVALUE:
+ case UPB_WELLKNOWN_BOOLVALUE:
+ jsondec_wrapper(d, msg, m);
+ break;
+ default:
+ UPB_UNREACHABLE();
+ }
+}
+
+bool upb_json_decode(const char *buf, size_t size, upb_msg *msg,
+ const upb_msgdef *m, const upb_symtab *any_pool,
+ int options, upb_arena *arena, upb_status *status) {
+ jsondec d;
+ d.ptr = buf;
+ d.end = buf + size;
+ d.arena = arena;
+ d.any_pool = any_pool;
+ d.status = status;
+ d.options = options;
+ d.depth = 64;
+ d.line = 1;
+ d.line_begin = d.ptr;
+ d.debug_field = NULL;
+ d.is_first = false;
+
+ if (UPB_SETJMP(d.err)) return false;
+
+ jsondec_tomsg(&d, msg, m);
+ return true;
+}
+
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+
+/* Must be last. */
+
+typedef struct {
+ char *buf, *ptr, *end;
+ size_t overflow;
+ int indent_depth;
+ int options;
+ const upb_symtab *ext_pool;
+ jmp_buf err;
+ upb_status *status;
+ upb_arena *arena;
+} jsonenc;
+
+static void jsonenc_msg(jsonenc *e, const upb_msg *msg, const upb_msgdef *m);
+static void jsonenc_scalar(jsonenc *e, upb_msgval val, const upb_fielddef *f);
+static void jsonenc_msgfield(jsonenc *e, const upb_msg *msg,
+ const upb_msgdef *m);
+static void jsonenc_msgfields(jsonenc *e, const upb_msg *msg,
+ const upb_msgdef *m);
+static void jsonenc_value(jsonenc *e, const upb_msg *msg, const upb_msgdef *m);
+
+UPB_NORETURN static void jsonenc_err(jsonenc *e, const char *msg) {
+ upb_status_seterrmsg(e->status, msg);
+ longjmp(e->err, 1);
+}
+
+UPB_PRINTF(2, 3)
+UPB_NORETURN static void jsonenc_errf(jsonenc *e, const char *fmt, ...) {
+ va_list argp;
+ va_start(argp, fmt);
+ upb_status_vseterrf(e->status, fmt, argp);
+ va_end(argp);
+ longjmp(e->err, 1);
+}
+
+static upb_arena *jsonenc_arena(jsonenc *e) {
+ /* Create lazily, since it's only needed for Any */
+ if (!e->arena) {
+ e->arena = upb_arena_new();
+ }
+ return e->arena;
+}
+
+static void jsonenc_putbytes(jsonenc *e, const void *data, size_t len) {
+ size_t have = e->end - e->ptr;
+ if (UPB_LIKELY(have >= len)) {
+ memcpy(e->ptr, data, len);
+ e->ptr += len;
+ } else {
+ if (have) memcpy(e->ptr, data, have);
+ e->ptr += have;
+ e->overflow += (len - have);
+ }
+}
+
+static void jsonenc_putstr(jsonenc *e, const char *str) {
+ jsonenc_putbytes(e, str, strlen(str));
+}
+
+UPB_PRINTF(2, 3)
+static void jsonenc_printf(jsonenc *e, const char *fmt, ...) {
+ size_t n;
+ size_t have = e->end - e->ptr;
+ va_list args;
+
+ va_start(args, fmt);
+ n = vsnprintf(e->ptr, have, fmt, args);
+ va_end(args);
+
+ if (UPB_LIKELY(have > n)) {
+ e->ptr += n;
+ } else {
+ e->ptr += have;
+ e->overflow += (n - have);
+ }
+}
+
+static void jsonenc_nanos(jsonenc *e, int32_t nanos) {
+ int digits = 9;
+
+ if (nanos == 0) return;
+ if (nanos < 0 || nanos >= 1000000000) {
+ jsonenc_err(e, "error formatting timestamp as JSON: invalid nanos");
+ }
+
+ while (nanos % 1000 == 0) {
+ nanos /= 1000;
+ digits -= 3;
+ }
+
+ jsonenc_printf(e, ".%.*" PRId32, digits, nanos);
+}
+
+static void jsonenc_timestamp(jsonenc *e, const upb_msg *msg,
+ const upb_msgdef *m) {
+ const upb_fielddef *seconds_f = upb_msgdef_itof(m, 1);
+ const upb_fielddef *nanos_f = upb_msgdef_itof(m, 2);
+ int64_t seconds = upb_msg_get(msg, seconds_f).int64_val;
+ int32_t nanos = upb_msg_get(msg, nanos_f).int32_val;
+ int L, N, I, J, K, hour, min, sec;
+
+ if (seconds < -62135596800) {
+ jsonenc_err(e,
+ "error formatting timestamp as JSON: minimum acceptable value "
+ "is 0001-01-01T00:00:00Z");
+ } else if (seconds > 253402300799) {
+ jsonenc_err(e,
+ "error formatting timestamp as JSON: maximum acceptable value "
+ "is 9999-12-31T23:59:59Z");
+ }
+
+ /* Julian Day -> Y/M/D, Algorithm from:
+ * Fliegel, H. F., and Van Flandern, T. C., "A Machine Algorithm for
+ * Processing Calendar Dates," Communications of the Association of
+ * Computing Machines, vol. 11 (1968), p. 657. */
+ L = (int)(seconds / 86400) + 68569 + 2440588;
+ N = 4 * L / 146097;
+ L = L - (146097 * N + 3) / 4;
+ I = 4000 * (L + 1) / 1461001;
+ L = L - 1461 * I / 4 + 31;
+ J = 80 * L / 2447;
+ K = L - 2447 * J / 80;
+ L = J / 11;
+ J = J + 2 - 12 * L;
+ I = 100 * (N - 49) + I + L;
+
+ sec = seconds % 60;
+ min = (seconds / 60) % 60;
+ hour = (seconds / 3600) % 24;
+
+ jsonenc_printf(e, "\"%04d-%02d-%02dT%02d:%02d:%02d", I, J, K, hour, min, sec);
+ jsonenc_nanos(e, nanos);
+ jsonenc_putstr(e, "Z\"");
+}
+
+static void jsonenc_duration(jsonenc *e, const upb_msg *msg, const upb_msgdef *m) {
+ const upb_fielddef *seconds_f = upb_msgdef_itof(m, 1);
+ const upb_fielddef *nanos_f = upb_msgdef_itof(m, 2);
+ int64_t seconds = upb_msg_get(msg, seconds_f).int64_val;
+ int32_t nanos = upb_msg_get(msg, nanos_f).int32_val;
+
+ if (seconds > 315576000000 || seconds < -315576000000 ||
+ (seconds < 0) != (nanos < 0)) {
+ jsonenc_err(e, "bad duration");
+ }
+
+ if (nanos < 0) {
+ nanos = -nanos;
+ }
+
+ jsonenc_printf(e, "\"%" PRId64, seconds);
+ jsonenc_nanos(e, nanos);
+ jsonenc_putstr(e, "s\"");
+}
+
+static void jsonenc_enum(int32_t val, const upb_fielddef *f, jsonenc *e) {
+ const upb_enumdef *e_def = upb_fielddef_enumsubdef(f);
+
+ if (strcmp(upb_enumdef_fullname(e_def), "google.protobuf.NullValue") == 0) {
+ jsonenc_putstr(e, "null");
+ } else {
+ const char *name = upb_enumdef_iton(e_def, val);
+
+ if (name) {
+ jsonenc_printf(e, "\"%s\"", name);
+ } else {
+ jsonenc_printf(e, "%" PRId32, val);
+ }
+ }
+}
+
+static void jsonenc_bytes(jsonenc *e, upb_strview str) {
+ /* This is the regular base64, not the "web-safe" version. */
+ static const char base64[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+ const unsigned char *ptr = (unsigned char*)str.data;
+ const unsigned char *end = ptr + str.size;
+ char buf[4];
+
+ jsonenc_putstr(e, "\"");
+
+ while (end - ptr >= 3) {
+ buf[0] = base64[ptr[0] >> 2];
+ buf[1] = base64[((ptr[0] & 0x3) << 4) | (ptr[1] >> 4)];
+ buf[2] = base64[((ptr[1] & 0xf) << 2) | (ptr[2] >> 6)];
+ buf[3] = base64[ptr[2] & 0x3f];
+ jsonenc_putbytes(e, buf, 4);
+ ptr += 3;
+ }
+
+ switch (end - ptr) {
+ case 2:
+ buf[0] = base64[ptr[0] >> 2];
+ buf[1] = base64[((ptr[0] & 0x3) << 4) | (ptr[1] >> 4)];
+ buf[2] = base64[(ptr[1] & 0xf) << 2];
+ buf[3] = '=';
+ jsonenc_putbytes(e, buf, 4);
+ break;
+ case 1:
+ buf[0] = base64[ptr[0] >> 2];
+ buf[1] = base64[((ptr[0] & 0x3) << 4)];
+ buf[2] = '=';
+ buf[3] = '=';
+ jsonenc_putbytes(e, buf, 4);
+ break;
+ }
+
+ jsonenc_putstr(e, "\"");
+}
+
+static void jsonenc_stringbody(jsonenc *e, upb_strview str) {
+ const char *ptr = str.data;
+ const char *end = ptr + str.size;
+
+ while (ptr < end) {
+ switch (*ptr) {
+ case '\n':
+ jsonenc_putstr(e, "\\n");
+ break;
+ case '\r':
+ jsonenc_putstr(e, "\\r");
+ break;
+ case '\t':
+ jsonenc_putstr(e, "\\t");
+ break;
+ case '\"':
+ jsonenc_putstr(e, "\\\"");
+ break;
+ case '\f':
+ jsonenc_putstr(e, "\\f");
+ break;
+ case '\b':
+ jsonenc_putstr(e, "\\b");
+ break;
+ case '\\':
+ jsonenc_putstr(e, "\\\\");
+ break;
+ default:
+ if ((uint8_t)*ptr < 0x20) {
+ jsonenc_printf(e, "\\u%04x", (int)(uint8_t)*ptr);
+ } else {
+ /* This could be a non-ASCII byte. We rely on the string being valid
+ * UTF-8. */
+ jsonenc_putbytes(e, ptr, 1);
+ }
+ break;
+ }
+ ptr++;
+ }
+}
+
+static void jsonenc_string(jsonenc *e, upb_strview str) {
+ jsonenc_putstr(e, "\"");
+ jsonenc_stringbody(e, str);
+ jsonenc_putstr(e, "\"");
+}
+
+static void jsonenc_double(jsonenc *e, const char *fmt, double val) {
+ if (val == INFINITY) {
+ jsonenc_putstr(e, "\"Infinity\"");
+ } else if (val == -INFINITY) {
+ jsonenc_putstr(e, "\"-Infinity\"");
+ } else if (val != val) {
+ jsonenc_putstr(e, "\"NaN\"");
+ } else {
+ jsonenc_printf(e, fmt, val);
+ }
+}
+
+static void jsonenc_wrapper(jsonenc *e, const upb_msg *msg,
+ const upb_msgdef *m) {
+ const upb_fielddef *val_f = upb_msgdef_itof(m, 1);
+ upb_msgval val = upb_msg_get(msg, val_f);
+ jsonenc_scalar(e, val, val_f);
+}
+
+static const upb_msgdef *jsonenc_getanymsg(jsonenc *e, upb_strview type_url) {
+ /* Find last '/', if any. */
+ const char *end = type_url.data + type_url.size;
+ const char *ptr = end;
+ const upb_msgdef *ret;
+
+ if (!e->ext_pool) {
+ jsonenc_err(e, "Tried to encode Any, but no symtab was provided");
+ }
+
+ if (type_url.size == 0) goto badurl;
+
+ while (true) {
+ if (--ptr == type_url.data) {
+ /* Type URL must contain at least one '/', with host before. */
+ goto badurl;
+ }
+ if (*ptr == '/') {
+ ptr++;
+ break;
+ }
+ }
+
+ ret = upb_symtab_lookupmsg2(e->ext_pool, ptr, end - ptr);
+
+ if (!ret) {
+ jsonenc_errf(e, "Couldn't find Any type: %.*s", (int)(end - ptr), ptr);
+ }
+
+ return ret;
+
+badurl:
+ jsonenc_errf(
+ e, "Bad type URL: " UPB_STRVIEW_FORMAT, UPB_STRVIEW_ARGS(type_url));
+}
+
+static void jsonenc_any(jsonenc *e, const upb_msg *msg, const upb_msgdef *m) {
+ const upb_fielddef *type_url_f = upb_msgdef_itof(m, 1);
+ const upb_fielddef *value_f = upb_msgdef_itof(m, 2);
+ upb_strview type_url = upb_msg_get(msg, type_url_f).str_val;
+ upb_strview value = upb_msg_get(msg, value_f).str_val;
+ const upb_msgdef *any_m = jsonenc_getanymsg(e, type_url);
+ const upb_msglayout *any_layout = upb_msgdef_layout(any_m);
+ upb_arena *arena = jsonenc_arena(e);
+ upb_msg *any = upb_msg_new(any_m, arena);
+
+ if (!upb_decode(value.data, value.size, any, any_layout, arena)) {
+ jsonenc_err(e, "Error decoding message in Any");
+ }
+
+ jsonenc_putstr(e, "{\"@type\":");
+ jsonenc_string(e, type_url);
+ jsonenc_putstr(e, ",");
+
+ if (upb_msgdef_wellknowntype(any_m) == UPB_WELLKNOWN_UNSPECIFIED) {
+ /* Regular messages: {"@type": "...","foo": 1, "bar": 2} */
+ jsonenc_msgfields(e, any, any_m);
+ } else {
+ /* Well-known type: {"@type": "...","value": } */
+ jsonenc_putstr(e, "\"value\":");
+ jsonenc_msgfield(e, any, any_m);
+ }
+
+ jsonenc_putstr(e, "}");
+}
+
+static void jsonenc_putsep(jsonenc *e, const char *str, bool *first) {
+ if (*first) {
+ *first = false;
+ } else {
+ jsonenc_putstr(e, str);
+ }
+}
+
+static void jsonenc_fieldpath(jsonenc *e, upb_strview path) {
+ const char *ptr = path.data;
+ const char *end = ptr + path.size;
+
+ while (ptr < end) {
+ char ch = *ptr;
+
+ if (ch >= 'A' && ch <= 'Z') {
+ jsonenc_err(e, "Field mask element may not have upper-case letter.");
+ } else if (ch == '_') {
+ if (ptr == end - 1 || *(ptr + 1) < 'a' || *(ptr + 1) > 'z') {
+ jsonenc_err(e, "Underscore must be followed by a lowercase letter.");
+ }
+ ch = *++ptr - 32;
+ }
+
+ jsonenc_putbytes(e, &ch, 1);
+ ptr++;
+ }
+}
+
+static void jsonenc_fieldmask(jsonenc *e, const upb_msg *msg,
+ const upb_msgdef *m) {
+ const upb_fielddef *paths_f = upb_msgdef_itof(m, 1);
+ const upb_array *paths = upb_msg_get(msg, paths_f).array_val;
+ bool first = true;
+ size_t i, n = 0;
+
+ if (paths) n = upb_array_size(paths);
+
+ jsonenc_putstr(e, "\"");
+
+ for (i = 0; i < n; i++) {
+ jsonenc_putsep(e, ",", &first);
+ jsonenc_fieldpath(e, upb_array_get(paths, i).str_val);
+ }
+
+ jsonenc_putstr(e, "\"");
+}
+
+static void jsonenc_struct(jsonenc *e, const upb_msg *msg,
+ const upb_msgdef *m) {
+ const upb_fielddef *fields_f = upb_msgdef_itof(m, 1);
+ const upb_map *fields = upb_msg_get(msg, fields_f).map_val;
+ const upb_msgdef *entry_m = upb_fielddef_msgsubdef(fields_f);
+ const upb_fielddef *value_f = upb_msgdef_itof(entry_m, 2);
+ size_t iter = UPB_MAP_BEGIN;
+ bool first = true;
+
+ jsonenc_putstr(e, "{");
+
+ if (fields) {
+ while (upb_mapiter_next(fields, &iter)) {
+ upb_msgval key = upb_mapiter_key(fields, iter);
+ upb_msgval val = upb_mapiter_value(fields, iter);
+
+ jsonenc_putsep(e, ",", &first);
+ jsonenc_string(e, key.str_val);
+ jsonenc_putstr(e, ":");
+ jsonenc_value(e, val.msg_val, upb_fielddef_msgsubdef(value_f));
+ }
+ }
+
+ jsonenc_putstr(e, "}");
+}
+
+static void jsonenc_listvalue(jsonenc *e, const upb_msg *msg,
+ const upb_msgdef *m) {
+ const upb_fielddef *values_f = upb_msgdef_itof(m, 1);
+ const upb_msgdef *values_m = upb_fielddef_msgsubdef(values_f);
+ const upb_array *values = upb_msg_get(msg, values_f).array_val;
+ size_t i;
+ bool first = true;
+
+ jsonenc_putstr(e, "[");
+
+ if (values) {
+ const size_t size = upb_array_size(values);
+ for (i = 0; i < size; i++) {
+ upb_msgval elem = upb_array_get(values, i);
+
+ jsonenc_putsep(e, ",", &first);
+ jsonenc_value(e, elem.msg_val, values_m);
+ }
+ }
+
+ jsonenc_putstr(e, "]");
+}
+
+static void jsonenc_value(jsonenc *e, const upb_msg *msg, const upb_msgdef *m) {
+ /* TODO(haberman): do we want a reflection method to get oneof case? */
+ size_t iter = UPB_MSG_BEGIN;
+ const upb_fielddef *f;
+ upb_msgval val;
+
+ if (!upb_msg_next(msg, m, NULL, &f, &val, &iter)) {
+ jsonenc_err(e, "No value set in Value proto");
+ }
+
+ switch (upb_fielddef_number(f)) {
+ case 1:
+ jsonenc_putstr(e, "null");
+ break;
+ case 2:
+ jsonenc_double(e, "%.17g", val.double_val);
+ break;
+ case 3:
+ jsonenc_string(e, val.str_val);
+ break;
+ case 4:
+ jsonenc_putstr(e, val.bool_val ? "true" : "false");
+ break;
+ case 5:
+ jsonenc_struct(e, val.msg_val, upb_fielddef_msgsubdef(f));
+ break;
+ case 6:
+ jsonenc_listvalue(e, val.msg_val, upb_fielddef_msgsubdef(f));
+ break;
+ }
+}
+
+static void jsonenc_msgfield(jsonenc *e, const upb_msg *msg,
+ const upb_msgdef *m) {
+ switch (upb_msgdef_wellknowntype(m)) {
+ case UPB_WELLKNOWN_UNSPECIFIED:
+ jsonenc_msg(e, msg, m);
+ break;
+ case UPB_WELLKNOWN_ANY:
+ jsonenc_any(e, msg, m);
+ break;
+ case UPB_WELLKNOWN_FIELDMASK:
+ jsonenc_fieldmask(e, msg, m);
+ break;
+ case UPB_WELLKNOWN_DURATION:
+ jsonenc_duration(e, msg, m);
+ break;
+ case UPB_WELLKNOWN_TIMESTAMP:
+ jsonenc_timestamp(e, msg, m);
+ break;
+ case UPB_WELLKNOWN_DOUBLEVALUE:
+ case UPB_WELLKNOWN_FLOATVALUE:
+ case UPB_WELLKNOWN_INT64VALUE:
+ case UPB_WELLKNOWN_UINT64VALUE:
+ case UPB_WELLKNOWN_INT32VALUE:
+ case UPB_WELLKNOWN_UINT32VALUE:
+ case UPB_WELLKNOWN_STRINGVALUE:
+ case UPB_WELLKNOWN_BYTESVALUE:
+ case UPB_WELLKNOWN_BOOLVALUE:
+ jsonenc_wrapper(e, msg, m);
+ break;
+ case UPB_WELLKNOWN_VALUE:
+ jsonenc_value(e, msg, m);
+ break;
+ case UPB_WELLKNOWN_LISTVALUE:
+ jsonenc_listvalue(e, msg, m);
+ break;
+ case UPB_WELLKNOWN_STRUCT:
+ jsonenc_struct(e, msg, m);
+ break;
+ }
+}
+
+static void jsonenc_scalar(jsonenc *e, upb_msgval val, const upb_fielddef *f) {
+ switch (upb_fielddef_type(f)) {
+ case UPB_TYPE_BOOL:
+ jsonenc_putstr(e, val.bool_val ? "true" : "false");
+ break;
+ case UPB_TYPE_FLOAT:
+ jsonenc_double(e, "%.9g", val.float_val);
+ break;
+ case UPB_TYPE_DOUBLE:
+ jsonenc_double(e, "%.17g", val.double_val);
+ break;
+ case UPB_TYPE_INT32:
+ jsonenc_printf(e, "%" PRId32, val.int32_val);
+ break;
+ case UPB_TYPE_UINT32:
+ jsonenc_printf(e, "%" PRIu32, val.uint32_val);
+ break;
+ case UPB_TYPE_INT64:
+ jsonenc_printf(e, "\"%" PRId64 "\"", val.int64_val);
+ break;
+ case UPB_TYPE_UINT64:
+ jsonenc_printf(e, "\"%" PRIu64 "\"", val.uint64_val);
+ break;
+ case UPB_TYPE_STRING:
+ jsonenc_string(e, val.str_val);
+ break;
+ case UPB_TYPE_BYTES:
+ jsonenc_bytes(e, val.str_val);
+ break;
+ case UPB_TYPE_ENUM:
+ jsonenc_enum(val.int32_val, f, e);
+ break;
+ case UPB_TYPE_MESSAGE:
+ jsonenc_msgfield(e, val.msg_val, upb_fielddef_msgsubdef(f));
+ break;
+ }
+}
+
+static void jsonenc_mapkey(jsonenc *e, upb_msgval val, const upb_fielddef *f) {
+ jsonenc_putstr(e, "\"");
+
+ switch (upb_fielddef_type(f)) {
+ case UPB_TYPE_BOOL:
+ jsonenc_putstr(e, val.bool_val ? "true" : "false");
+ break;
+ case UPB_TYPE_INT32:
+ jsonenc_printf(e, "%" PRId32, val.int32_val);
+ break;
+ case UPB_TYPE_UINT32:
+ jsonenc_printf(e, "%" PRIu32, val.uint32_val);
+ break;
+ case UPB_TYPE_INT64:
+ jsonenc_printf(e, "%" PRId64, val.int64_val);
+ break;
+ case UPB_TYPE_UINT64:
+ jsonenc_printf(e, "%" PRIu64, val.uint64_val);
+ break;
+ case UPB_TYPE_STRING:
+ jsonenc_stringbody(e, val.str_val);
+ break;
+ default:
+ UPB_UNREACHABLE();
+ }
+
+ jsonenc_putstr(e, "\":");
+}
+
+static void jsonenc_array(jsonenc *e, const upb_array *arr,
+ const upb_fielddef *f) {
+ size_t i;
+ size_t size = arr ? upb_array_size(arr) : 0;
+ bool first = true;
+
+ jsonenc_putstr(e, "[");
+
+ for (i = 0; i < size; i++) {
+ jsonenc_putsep(e, ",", &first);
+ jsonenc_scalar(e, upb_array_get(arr, i), f);
+ }
+
+ jsonenc_putstr(e, "]");
+}
+
+static void jsonenc_map(jsonenc *e, const upb_map *map, const upb_fielddef *f) {
+ const upb_msgdef *entry = upb_fielddef_msgsubdef(f);
+ const upb_fielddef *key_f = upb_msgdef_itof(entry, 1);
+ const upb_fielddef *val_f = upb_msgdef_itof(entry, 2);
+ size_t iter = UPB_MAP_BEGIN;
+ bool first = true;
+
+ jsonenc_putstr(e, "{");
+
+ if (map) {
+ while (upb_mapiter_next(map, &iter)) {
+ jsonenc_putsep(e, ",", &first);
+ jsonenc_mapkey(e, upb_mapiter_key(map, iter), key_f);
+ jsonenc_scalar(e, upb_mapiter_value(map, iter), val_f);
+ }
+ }
+
+ jsonenc_putstr(e, "}");
+}
+
+static void jsonenc_fieldval(jsonenc *e, const upb_fielddef *f,
+ upb_msgval val, bool *first) {
+ const char *name;
+
+ if (e->options & UPB_JSONENC_PROTONAMES) {
+ name = upb_fielddef_name(f);
+ } else {
+ name = upb_fielddef_jsonname(f);
+ }
+
+ jsonenc_putsep(e, ",", first);
+ jsonenc_printf(e, "\"%s\":", name);
+
+ if (upb_fielddef_ismap(f)) {
+ jsonenc_map(e, val.map_val, f);
+ } else if (upb_fielddef_isseq(f)) {
+ jsonenc_array(e, val.array_val, f);
+ } else {
+ jsonenc_scalar(e, val, f);
+ }
+}
+
+static void jsonenc_msgfields(jsonenc *e, const upb_msg *msg,
+ const upb_msgdef *m) {
+ upb_msgval val;
+ const upb_fielddef *f;
+ bool first = true;
+
+ if (e->options & UPB_JSONENC_EMITDEFAULTS) {
+ /* Iterate over all fields. */
+ int i = 0;
+ int n = upb_msgdef_fieldcount(m);
+ for (i = 0; i < n; i++) {
+ f = upb_msgdef_field(m, i);
+ if (!upb_fielddef_haspresence(f) || upb_msg_has(msg, f)) {
+ jsonenc_fieldval(e, f, upb_msg_get(msg, f), &first);
+ }
+ }
+ } else {
+ /* Iterate over non-empty fields. */
+ size_t iter = UPB_MSG_BEGIN;
+ while (upb_msg_next(msg, m, e->ext_pool, &f, &val, &iter)) {
+ jsonenc_fieldval(e, f, val, &first);
+ }
+ }
+}
+
+static void jsonenc_msg(jsonenc *e, const upb_msg *msg, const upb_msgdef *m) {
+ jsonenc_putstr(e, "{");
+ jsonenc_msgfields(e, msg, m);
+ jsonenc_putstr(e, "}");
+}
+
+static size_t jsonenc_nullz(jsonenc *e, size_t size) {
+ size_t ret = e->ptr - e->buf + e->overflow;
+
+ if (size > 0) {
+ if (e->ptr == e->end) e->ptr--;
+ *e->ptr = '\0';
+ }
+
+ return ret;
+}
+
+size_t upb_json_encode(const upb_msg *msg, const upb_msgdef *m,
+ const upb_symtab *ext_pool, int options, char *buf,
+ size_t size, upb_status *status) {
+ jsonenc e;
+
+ e.buf = buf;
+ e.ptr = buf;
+ e.end = buf + size;
+ e.overflow = 0;
+ e.options = options;
+ e.ext_pool = ext_pool;
+ e.status = status;
+ e.arena = NULL;
+
+ if (setjmp(e.err)) return -1;
+
+ jsonenc_msgfield(&e, msg, m);
+ if (e.arena) upb_arena_free(e.arena);
+ return jsonenc_nullz(&e, size);
+}
+/* See port_def.inc. This should #undef all macros #defined there. */
+
+#undef UPB_MAPTYPE_STRING
+#undef UPB_SIZE
+#undef UPB_PTR_AT
+#undef UPB_READ_ONEOF
+#undef UPB_WRITE_ONEOF
+#undef UPB_INLINE
+#undef UPB_ALIGN_UP
+#undef UPB_ALIGN_DOWN
+#undef UPB_ALIGN_MALLOC
+#undef UPB_ALIGN_OF
+#undef UPB_FORCEINLINE
+#undef UPB_NOINLINE
+#undef UPB_NORETURN
+#undef UPB_MAX
+#undef UPB_MIN
+#undef UPB_UNUSED
+#undef UPB_ASSUME
+#undef UPB_ASSERT
+#undef UPB_UNREACHABLE
+#undef UPB_POISON_MEMORY_REGION
+#undef UPB_UNPOISON_MEMORY_REGION
+#undef UPB_ASAN
diff --git a/ruby/ext/google/protobuf_c/upb.h b/ruby/ext/google/protobuf_c/ruby-upb.h
old mode 100644
new mode 100755
similarity index 58%
rename from ruby/ext/google/protobuf_c/upb.h
rename to ruby/ext/google/protobuf_c/ruby-upb.h
index b7da76fa00..106c73b693
--- a/ruby/ext/google/protobuf_c/upb.h
+++ b/ruby/ext/google/protobuf_c/ruby-upb.h
@@ -21,7 +21,15 @@
*
* This file is private and must not be included by users!
*/
+
+#if !((defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || \
+ (defined(__cplusplus) && __cplusplus >= 201103L) || \
+ (defined(_MSC_VER) && _MSC_VER >= 1900))
+#error upb requires C99 or C++11 or MSVC >= 2015.
+#endif
+
#include
+#include
#if UINTPTR_MAX == 0xffffffff
#define UPB_SIZE(size32, size64) size32
@@ -54,6 +62,11 @@
#define UPB_INLINE static
#endif
+#define UPB_ALIGN_UP(size, align) (((size) + (align) - 1) / (align) * (align))
+#define UPB_ALIGN_DOWN(size, align) ((size) / (align) * (align))
+#define UPB_ALIGN_MALLOC(size) UPB_ALIGN_UP(size, 16)
+#define UPB_ALIGN_OF(type) offsetof (struct { char c; type member; }, member)
+
/* Hints to the compiler about likely/unlikely branches. */
#if defined (__GNUC__) || defined(__clang__)
#define UPB_LIKELY(x) __builtin_expect((x),1)
@@ -63,64 +76,22 @@
#define UPB_UNLIKELY(x) (x)
#endif
-/* Define UPB_BIG_ENDIAN manually if you're on big endian and your compiler
- * doesn't provide these preprocessor symbols. */
-#if defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
-#define UPB_BIG_ENDIAN
-#endif
-
/* Macros for function attributes on compilers that support them. */
#ifdef __GNUC__
#define UPB_FORCEINLINE __inline__ __attribute__((always_inline))
#define UPB_NOINLINE __attribute__((noinline))
#define UPB_NORETURN __attribute__((__noreturn__))
+#define UPB_PRINTF(str, first_vararg) __attribute__((format (printf, str, first_vararg)))
+#elif defined(_MSC_VER)
+#define UPB_NOINLINE
+#define UPB_FORCEINLINE
+#define UPB_NORETURN __declspec(noreturn)
+#define UPB_PRINTF(str, first_vararg)
#else /* !defined(__GNUC__) */
#define UPB_FORCEINLINE
#define UPB_NOINLINE
#define UPB_NORETURN
-#endif
-
-#if __STDC_VERSION__ >= 199901L || __cplusplus >= 201103L
-/* C99/C++11 versions. */
-#include
-#define _upb_snprintf snprintf
-#define _upb_vsnprintf vsnprintf
-#define _upb_va_copy(a, b) va_copy(a, b)
-#elif defined(_MSC_VER)
-/* Microsoft C/C++ versions. */
-#include
-#include
-#if _MSC_VER < 1900
-int msvc_snprintf(char* s, size_t n, const char* format, ...);
-int msvc_vsnprintf(char* s, size_t n, const char* format, va_list arg);
-#define UPB_MSVC_VSNPRINTF
-#define _upb_snprintf msvc_snprintf
-#define _upb_vsnprintf msvc_vsnprintf
-#else
-#define _upb_snprintf snprintf
-#define _upb_vsnprintf vsnprintf
-#endif
-#define _upb_va_copy(a, b) va_copy(a, b)
-#elif defined __GNUC__
-/* A few hacky workarounds for functions not in C89.
- * For internal use only!
- * TODO(haberman): fix these by including our own implementations, or finding
- * another workaround.
- */
-#define _upb_snprintf __builtin_snprintf
-#define _upb_vsnprintf __builtin_vsnprintf
-#define _upb_va_copy(a, b) __va_copy(a, b)
-#else
-#error Need implementations of [v]snprintf and va_copy
-#endif
-
-#ifdef __cplusplus
-#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) || \
- (defined(_MSC_VER) && _MSC_VER >= 1900)
-/* C++11 is present */
-#else
-#error upb requires C++11 for C++ support
-#endif
+#define UPB_PRINTF(str, first_vararg)
#endif
#define UPB_MAX(x, y) ((x) > (y) ? (x) : (y))
@@ -133,8 +104,10 @@ int msvc_vsnprintf(char* s, size_t n, const char* format, va_list arg);
#ifdef NDEBUG
#ifdef __GNUC__
#define UPB_ASSUME(expr) if (!(expr)) __builtin_unreachable()
+#elif defined _MSC_VER
+#define UPB_ASSUME(expr) if (!(expr)) __assume(0)
#else
-#define UPB_ASSUME(expr) do {} if (false && (expr))
+#define UPB_ASSUME(expr) do {} while (false && (expr))
#endif
#else
#define UPB_ASSUME(expr) assert(expr)
@@ -148,23 +121,79 @@ int msvc_vsnprintf(char* s, size_t n, const char* format, va_list arg);
#define UPB_ASSERT(expr) assert(expr)
#endif
-/* UPB_ASSERT_DEBUGVAR(): assert that uses functions or variables that only
- * exist in debug mode. This turns into regular assert. */
-#define UPB_ASSERT_DEBUGVAR(expr) assert(expr)
-
#if defined(__GNUC__) || defined(__clang__)
#define UPB_UNREACHABLE() do { assert(0); __builtin_unreachable(); } while(0)
#else
#define UPB_UNREACHABLE() do { assert(0); } while(0)
#endif
-/* UPB_INFINITY representing floating-point positive infinity. */
-#include
-#ifdef INFINITY
-#define UPB_INFINITY INFINITY
+/* UPB_SETJMP() / UPB_LONGJMP(): avoid setting/restoring signal mask. */
+#ifdef __APPLE__
+#define UPB_SETJMP(buf) _setjmp(buf)
+#define UPB_LONGJMP(buf, val) _longjmp(buf, val)
+#else
+#define UPB_SETJMP(buf) setjmp(buf)
+#define UPB_LONGJMP(buf, val) longjmp(buf, val)
+#endif
+
+/* Configure whether fasttable is switched on or not. *************************/
+
+#if defined(__x86_64__) && defined(__GNUC__)
+#define UPB_FASTTABLE_SUPPORTED 1
+#else
+#define UPB_FASTTABLE_SUPPORTED 0
+#endif
+
+/* define UPB_ENABLE_FASTTABLE to force fast table support.
+ * This is useful when we want to ensure we are really getting fasttable,
+ * for example for testing or benchmarking. */
+#if defined(UPB_ENABLE_FASTTABLE)
+#if !UPB_FASTTABLE_SUPPORTED
+#error fasttable is x86-64 + Clang/GCC only
+#endif
+#define UPB_FASTTABLE 1
+/* Define UPB_TRY_ENABLE_FASTTABLE to use fasttable if possible.
+ * This is useful for releasing code that might be used on multiple platforms,
+ * for example the PHP or Ruby C extensions. */
+#elif defined(UPB_TRY_ENABLE_FASTTABLE)
+#define UPB_FASTTABLE UPB_FASTTABLE_SUPPORTED
+#else
+#define UPB_FASTTABLE 0
+#endif
+
+/* UPB_FASTTABLE_INIT() allows protos compiled for fasttable to gracefully
+ * degrade to non-fasttable if we are using UPB_TRY_ENABLE_FASTTABLE. */
+#if !UPB_FASTTABLE && defined(UPB_TRY_ENABLE_FASTTABLE)
+#define UPB_FASTTABLE_INIT(...)
#else
-#define UPB_INFINITY (1.0 / 0.0)
+#define UPB_FASTTABLE_INIT(...) __VA_ARGS__
+#endif
+
+#undef UPB_FASTTABLE_SUPPORTED
+
+/* ASAN poisoning (for arena) *************************************************/
+
+#if defined(__SANITIZE_ADDRESS__)
+#define UPB_ASAN 1
+#ifdef __cplusplus
+extern "C" {
+#endif
+void __asan_poison_memory_region(void const volatile *addr, size_t size);
+void __asan_unpoison_memory_region(void const volatile *addr, size_t size);
+#ifdef __cplusplus
+} /* extern "C" */
#endif
+#define UPB_POISON_MEMORY_REGION(addr, size) \
+ __asan_poison_memory_region((addr), (size))
+#define UPB_UNPOISON_MEMORY_REGION(addr, size) \
+ __asan_unpoison_memory_region((addr), (size))
+#else
+#define UPB_ASAN 0
+#define UPB_POISON_MEMORY_REGION(addr, size) \
+ ((void)(addr), (void)(size))
+#define UPB_UNPOISON_MEMORY_REGION(addr, size) \
+ ((void)(addr), (void)(size))
+#endif
/*
** upb_decode: parsing into a upb_msg using a upb_msglayout.
*/
@@ -183,6 +212,7 @@ int msvc_vsnprintf(char* s, size_t n, const char* format, va_list arg);
#define UPB_MSG_H_
#include
+#include
#include
/*
@@ -243,8 +273,12 @@ bool upb_ok(const upb_status *status);
/* These are no-op if |status| is NULL. */
void upb_status_clear(upb_status *status);
void upb_status_seterrmsg(upb_status *status, const char *msg);
-void upb_status_seterrf(upb_status *status, const char *fmt, ...);
-void upb_status_vseterrf(upb_status *status, const char *fmt, va_list args);
+void upb_status_seterrf(upb_status *status, const char *fmt, ...)
+ UPB_PRINTF(2, 3);
+void upb_status_vseterrf(upb_status *status, const char *fmt, va_list args)
+ UPB_PRINTF(2, 0);
+void upb_status_vappenderrf(upb_status *status, const char *fmt, va_list args)
+ UPB_PRINTF(2, 0);
/** upb_strview ************************************************************/
@@ -352,47 +386,65 @@ typedef struct upb_arena upb_arena;
typedef struct {
/* We implement the allocator interface.
- * This must be the first member of upb_arena! */
+ * This must be the first member of upb_arena!
+ * TODO(haberman): remove once handlers are gone. */
upb_alloc alloc;
char *ptr, *end;
} _upb_arena_head;
-UPB_INLINE size_t _upb_arena_alignup(size_t size) {
- const size_t maxalign = 16;
- return ((size + maxalign - 1) / maxalign) * maxalign;
-}
-
/* Creates an arena from the given initial block (if any -- n may be 0).
* Additional blocks will be allocated from |alloc|. If |alloc| is NULL, this
* is a fixed-size arena and cannot grow. */
upb_arena *upb_arena_init(void *mem, size_t n, upb_alloc *alloc);
void upb_arena_free(upb_arena *a);
bool upb_arena_addcleanup(upb_arena *a, void *ud, upb_cleanup_func *func);
-size_t upb_arena_bytesallocated(const upb_arena *a);
+void upb_arena_fuse(upb_arena *a, upb_arena *b);
void *_upb_arena_slowmalloc(upb_arena *a, size_t size);
UPB_INLINE upb_alloc *upb_arena_alloc(upb_arena *a) { return (upb_alloc*)a; }
+UPB_INLINE size_t _upb_arenahas(upb_arena *a) {
+ _upb_arena_head *h = (_upb_arena_head*)a;
+ return (size_t)(h->end - h->ptr);
+}
+
UPB_INLINE void *upb_arena_malloc(upb_arena *a, size_t size) {
_upb_arena_head *h = (_upb_arena_head*)a;
- size = _upb_arena_alignup(size);
- if (UPB_LIKELY((size_t)(h->end - h->ptr) >= size)) {
- void* ret = h->ptr;
- h->ptr += size;
- return ret;
- } else {
+ void* ret;
+ size = UPB_ALIGN_MALLOC(size);
+
+ if (UPB_UNLIKELY(_upb_arenahas(a) < size)) {
return _upb_arena_slowmalloc(a, size);
}
+
+ ret = h->ptr;
+ h->ptr += size;
+ UPB_UNPOISON_MEMORY_REGION(ret, size);
+
+#if UPB_ASAN
+ {
+ size_t guard_size = 32;
+ if (_upb_arenahas(a) >= guard_size) {
+ h->ptr += guard_size;
+ } else {
+ h->ptr = h->end;
+ }
+ }
+#endif
+
+ return ret;
}
UPB_INLINE void *upb_arena_realloc(upb_arena *a, void *ptr, size_t oldsize,
size_t size) {
- if (oldsize == 0) {
- return upb_arena_malloc(a, size);
- } else {
- return upb_realloc(upb_arena_alloc(a), ptr, oldsize, size);
+ void *ret = upb_arena_malloc(a, size);
+
+ if (ret && oldsize > 0) {
+ memcpy(ret, ptr, oldsize);
}
+
+ return ret;
}
UPB_INLINE upb_arena *upb_arena_new(void) {
@@ -480,7 +532,44 @@ typedef enum {
UPB_DTYPE_SINT64 = 18
} upb_descriptortype_t;
-#define UPB_MAP_BEGIN -1
+#define UPB_MAP_BEGIN ((size_t)-1)
+
+UPB_INLINE bool _upb_isle(void) {
+ int x = 1;
+ return *(char*)&x == 1;
+}
+
+UPB_INLINE uint32_t _upb_be_swap32(uint32_t val) {
+ if (_upb_isle()) {
+ return val;
+ } else {
+ return ((val & 0xff) << 24) | ((val & 0xff00) << 8) |
+ ((val & 0xff0000) >> 8) | ((val & 0xff000000) >> 24);
+ }
+}
+
+UPB_INLINE uint64_t _upb_be_swap64(uint64_t val) {
+ if (_upb_isle()) {
+ return val;
+ } else {
+ return ((uint64_t)_upb_be_swap32(val) << 32) | _upb_be_swap32(val >> 32);
+ }
+}
+
+UPB_INLINE int _upb_lg2ceil(int x) {
+ if (x <= 1) return 0;
+#ifdef __GNUC__
+ return 32 - __builtin_clz(x - 1);
+#else
+ int lg2 = 0;
+ while (1 << lg2 < x) lg2++;
+ return lg2;
+#endif
+}
+
+UPB_INLINE int _upb_lg2ceilsize(int x) {
+ return 1 << _upb_lg2ceil(x);
+}
#ifdef __cplusplus
@@ -611,10 +700,17 @@ UPB_INLINE char *upb_tabstr(upb_tabkey key, uint32_t *len) {
return mem + sizeof(*len);
}
+UPB_INLINE upb_strview upb_tabstrview(upb_tabkey key) {
+ upb_strview ret;
+ uint32_t len;
+ ret.data = upb_tabstr(key, &len);
+ ret.size = len;
+ return ret;
+}
/* upb_tabval *****************************************************************/
-typedef struct {
+typedef struct upb_tabval {
uint64_t val;
} upb_tabval;
@@ -635,7 +731,8 @@ typedef struct _upb_tabent {
typedef struct {
size_t count; /* Number of entries in the hash part. */
- size_t mask; /* Mask to turn hash value -> bucket. */
+ uint32_t mask; /* Mask to turn hash value -> bucket. */
+ uint32_t max_count; /* Max count before we hit our load limit. */
uint8_t size_lg2; /* Size of the hashtable part is 2^size_lg2 entries. */
/* Hash table entries.
@@ -694,7 +791,8 @@ UPB_INLINE bool upb_arrhas(upb_tabval key) {
/* Initialize and uninitialize a table, respectively. If memory allocation
* failed, false is returned that the table is uninitialized. */
bool upb_inttable_init2(upb_inttable *table, upb_ctype_t ctype, upb_alloc *a);
-bool upb_strtable_init2(upb_strtable *table, upb_ctype_t ctype, upb_alloc *a);
+bool upb_strtable_init2(upb_strtable *table, upb_ctype_t ctype,
+ size_t expected_size, upb_alloc *a);
void upb_inttable_uninit2(upb_inttable *table, upb_alloc *a);
void upb_strtable_uninit2(upb_strtable *table, upb_alloc *a);
@@ -703,7 +801,7 @@ UPB_INLINE bool upb_inttable_init(upb_inttable *table, upb_ctype_t ctype) {
}
UPB_INLINE bool upb_strtable_init(upb_strtable *table, upb_ctype_t ctype) {
- return upb_strtable_init2(table, ctype, &upb_alloc_global);
+ return upb_strtable_init2(table, ctype, 4, &upb_alloc_global);
}
UPB_INLINE void upb_inttable_uninit(upb_inttable *table) {
@@ -790,15 +888,6 @@ UPB_INLINE bool upb_strtable_remove(upb_strtable *t, const char *key,
* invalidate iterators. */
bool upb_inttable_replace(upb_inttable *t, uintptr_t key, upb_value val);
-/* Handy routines for treating an inttable like a stack. May not be mixed with
- * other insert/remove calls. */
-bool upb_inttable_push2(upb_inttable *t, upb_value val, upb_alloc *a);
-upb_value upb_inttable_pop(upb_inttable *t);
-
-UPB_INLINE bool upb_inttable_push(upb_inttable *t, upb_value val) {
- return upb_inttable_push2(t, val, &upb_alloc_global);
-}
-
/* Convenience routines for inttables with pointer keys. */
bool upb_inttable_insertptr2(upb_inttable *t, const void *key, upb_value val,
upb_alloc *a);
@@ -937,6 +1026,7 @@ bool upb_inttable_iter_isequal(const upb_inttable_iter *i1,
#endif /* UPB_TABLE_H_ */
+/* Must be last. */
#ifdef __cplusplus
extern "C" {
@@ -962,12 +1052,24 @@ enum {
typedef struct {
uint32_t number;
uint16_t offset;
- int16_t presence; /* If >0, hasbit_index. If <0, -oneof_index. */
+ int16_t presence; /* If >0, hasbit_index. If <0, ~oneof_index. */
uint16_t submsg_index; /* undefined if descriptortype != MESSAGE or GROUP. */
uint8_t descriptortype;
- uint8_t label;
+ uint8_t label; /* google.protobuf.Label or _UPB_LABEL_* above. */
} upb_msglayout_field;
+struct upb_decstate;
+struct upb_msglayout;
+
+typedef const char *_upb_field_parser(struct upb_decstate *d, const char *ptr,
+ upb_msg *msg, intptr_t table,
+ uint64_t hasbits, uint64_t data);
+
+typedef struct {
+ uint64_t field_data;
+ _upb_field_parser *field_parser;
+} _upb_fasttable_entry;
+
typedef struct upb_msglayout {
const struct upb_msglayout *const* submsgs;
const upb_msglayout_field *fields;
@@ -976,6 +1078,10 @@ typedef struct upb_msglayout {
uint16_t size;
uint16_t field_count;
bool extendable;
+ uint8_t table_mask;
+ /* To constant-initialize the tables of variable length, we need a flexible
+ * array member, and we need to compile in C99 mode. */
+ _upb_fasttable_entry fasttable[];
} upb_msglayout;
/** upb_msg *******************************************************************/
@@ -984,25 +1090,48 @@ typedef struct upb_msglayout {
* compatibility. We put these before the user's data. The user's upb_msg*
* points after the upb_msg_internal. */
-/* Used when a message is not extendable. */
typedef struct {
- char *unknown;
- size_t unknown_len;
- size_t unknown_size;
-} upb_msg_internal;
+ uint32_t len;
+ uint32_t size;
+ /* Data follows. */
+} upb_msg_unknowndata;
-/* Used when a message is extendable. */
+/* Used when a message is not extendable. */
typedef struct {
- upb_inttable *extdict;
- upb_msg_internal base;
-} upb_msg_internal_withext;
+ upb_msg_unknowndata *unknown;
+} upb_msg_internal;
/* Maps upb_fieldtype_t -> memory size. */
extern char _upb_fieldtype_to_size[12];
+UPB_INLINE size_t upb_msg_sizeof(const upb_msglayout *l) {
+ return l->size + sizeof(upb_msg_internal);
+}
+
+UPB_INLINE upb_msg *_upb_msg_new_inl(const upb_msglayout *l, upb_arena *a) {
+ size_t size = upb_msg_sizeof(l);
+ void *mem = upb_arena_malloc(a, size);
+ upb_msg *msg;
+ if (UPB_UNLIKELY(!mem)) return NULL;
+ msg = UPB_PTR_AT(mem, sizeof(upb_msg_internal), upb_msg);
+ memset(mem, 0, size);
+ return msg;
+}
+
/* Creates a new messages with the given layout on the given arena. */
upb_msg *_upb_msg_new(const upb_msglayout *l, upb_arena *a);
+UPB_INLINE upb_msg_internal *upb_msg_getinternal(upb_msg *msg) {
+ ptrdiff_t size = sizeof(upb_msg_internal);
+ return (upb_msg_internal*)((char*)msg - size);
+}
+
+/* Clears the given message. */
+void _upb_msg_clear(upb_msg *msg, const upb_msglayout *l);
+
+/* Discards the unknown fields for this message only. */
+void _upb_msg_discardunknown_shallow(upb_msg *msg);
+
/* Adds unknown data (serialized protobuf data) to the given message. The data
* is copied into the message instance. */
bool _upb_msg_addunknown(upb_msg *msg, const char *data, size_t len,
@@ -1011,30 +1140,77 @@ bool _upb_msg_addunknown(upb_msg *msg, const char *data, size_t len,
/* Returns a reference to the message's unknown data. */
const char *upb_msg_getunknown(const upb_msg *msg, size_t *len);
-UPB_INLINE bool _upb_has_field(const void *msg, size_t idx) {
+/** Hasbit access *************************************************************/
+
+UPB_INLINE bool _upb_hasbit(const upb_msg *msg, size_t idx) {
return (*PTR_AT(msg, idx / 8, const char) & (1 << (idx % 8))) != 0;
}
-UPB_INLINE bool _upb_sethas(const void *msg, size_t idx) {
- return (*PTR_AT(msg, idx / 8, char)) |= (char)(1 << (idx % 8));
+UPB_INLINE void _upb_sethas(const upb_msg *msg, size_t idx) {
+ (*PTR_AT(msg, idx / 8, char)) |= (char)(1 << (idx % 8));
+}
+
+UPB_INLINE void _upb_clearhas(const upb_msg *msg, size_t idx) {
+ (*PTR_AT(msg, idx / 8, char)) &= (char)(~(1 << (idx % 8)));
+}
+
+UPB_INLINE size_t _upb_msg_hasidx(const upb_msglayout_field *f) {
+ UPB_ASSERT(f->presence > 0);
+ return f->presence;
+}
+
+UPB_INLINE bool _upb_hasbit_field(const upb_msg *msg,
+ const upb_msglayout_field *f) {
+ return _upb_hasbit(msg, _upb_msg_hasidx(f));
+}
+
+UPB_INLINE void _upb_sethas_field(const upb_msg *msg,
+ const upb_msglayout_field *f) {
+ _upb_sethas(msg, _upb_msg_hasidx(f));
+}
+
+UPB_INLINE void _upb_clearhas_field(const upb_msg *msg,
+ const upb_msglayout_field *f) {
+ _upb_clearhas(msg, _upb_msg_hasidx(f));
+}
+
+/** Oneof case access *********************************************************/
+
+UPB_INLINE uint32_t *_upb_oneofcase(upb_msg *msg, size_t case_ofs) {
+ return PTR_AT(msg, case_ofs, uint32_t);
+}
+
+UPB_INLINE uint32_t _upb_getoneofcase(const void *msg, size_t case_ofs) {
+ return *PTR_AT(msg, case_ofs, uint32_t);
}
-UPB_INLINE bool _upb_clearhas(const void *msg, size_t idx) {
- return (*PTR_AT(msg, idx / 8, char)) &= (char)(~(1 << (idx % 8)));
+UPB_INLINE size_t _upb_oneofcase_ofs(const upb_msglayout_field *f) {
+ UPB_ASSERT(f->presence < 0);
+ return ~(ptrdiff_t)f->presence;
}
-UPB_INLINE bool _upb_has_oneof_field(const void *msg, size_t case_ofs, int32_t num) {
- return *PTR_AT(msg, case_ofs, int32_t) == num;
+UPB_INLINE uint32_t *_upb_oneofcase_field(upb_msg *msg,
+ const upb_msglayout_field *f) {
+ return _upb_oneofcase(msg, _upb_oneofcase_ofs(f));
}
-UPB_INLINE bool _upb_has_submsg_nohasbit(const void *msg, size_t ofs) {
- return *PTR_AT(msg, ofs, const void*) != NULL;
+UPB_INLINE uint32_t _upb_getoneofcase_field(const upb_msg *msg,
+ const upb_msglayout_field *f) {
+ return _upb_getoneofcase(msg, _upb_oneofcase_ofs(f));
+}
+
+UPB_INLINE bool _upb_has_submsg_nohasbit(const upb_msg *msg, size_t ofs) {
+ return *PTR_AT(msg, ofs, const upb_msg*) != NULL;
}
UPB_INLINE bool _upb_isrepeated(const upb_msglayout_field *field) {
return (field->label & 3) == UPB_LABEL_REPEATED;
}
+UPB_INLINE bool _upb_repeated_or_map(const upb_msglayout_field *field) {
+ return field->label >= UPB_LABEL_REPEATED;
+}
+
/** upb_array *****************************************************************/
/* Our internal representation for repeated fields. */
@@ -1042,27 +1218,62 @@ typedef struct {
uintptr_t data; /* Tagged ptr: low 3 bits of ptr are lg2(elem size). */
size_t len; /* Measured in elements. */
size_t size; /* Measured in elements. */
+ uint64_t junk;
} upb_array;
UPB_INLINE const void *_upb_array_constptr(const upb_array *arr) {
+ UPB_ASSERT((arr->data & 7) <= 4);
return (void*)(arr->data & ~(uintptr_t)7);
}
+UPB_INLINE uintptr_t _upb_array_tagptr(void* ptr, int elem_size_lg2) {
+ UPB_ASSERT(elem_size_lg2 <= 4);
+ return (uintptr_t)ptr | elem_size_lg2;
+}
+
UPB_INLINE void *_upb_array_ptr(upb_array *arr) {
return (void*)_upb_array_constptr(arr);
}
-/* Creates a new array on the given arena. */
-upb_array *_upb_array_new(upb_arena *a, upb_fieldtype_t type);
+UPB_INLINE uintptr_t _upb_tag_arrptr(void* ptr, int elem_size_lg2) {
+ UPB_ASSERT(elem_size_lg2 <= 4);
+ UPB_ASSERT(((uintptr_t)ptr & 7) == 0);
+ return (uintptr_t)ptr | (unsigned)elem_size_lg2;
+}
+
+UPB_INLINE upb_array *_upb_array_new(upb_arena *a, size_t init_size,
+ int elem_size_lg2) {
+ const size_t arr_size = UPB_ALIGN_UP(sizeof(upb_array), 8);
+ const size_t bytes = sizeof(upb_array) + (init_size << elem_size_lg2);
+ upb_array *arr = (upb_array*)upb_arena_malloc(a, bytes);
+ if (!arr) return NULL;
+ arr->data = _upb_tag_arrptr(UPB_PTR_AT(arr, arr_size, void), elem_size_lg2);
+ arr->len = 0;
+ arr->size = init_size;
+ return arr;
+}
/* Resizes the capacity of the array to be at least min_size. */
bool _upb_array_realloc(upb_array *arr, size_t min_size, upb_arena *arena);
/* Fallback functions for when the accessors require a resize. */
void *_upb_array_resize_fallback(upb_array **arr_ptr, size_t size,
- upb_fieldtype_t type, upb_arena *arena);
+ int elem_size_lg2, upb_arena *arena);
bool _upb_array_append_fallback(upb_array **arr_ptr, const void *value,
- upb_fieldtype_t type, upb_arena *arena);
+ int elem_size_lg2, upb_arena *arena);
+
+UPB_INLINE bool _upb_array_reserve(upb_array *arr, size_t size,
+ upb_arena *arena) {
+ if (arr->size < size) return _upb_array_realloc(arr, size, arena);
+ return true;
+}
+
+UPB_INLINE bool _upb_array_resize(upb_array *arr, size_t size,
+ upb_arena *arena) {
+ if (!_upb_array_reserve(arr, size, arena)) return false;
+ arr->len = size;
+ return true;
+}
UPB_INLINE const void *_upb_array_accessor(const void *msg, size_t ofs,
size_t *size) {
@@ -1088,29 +1299,28 @@ UPB_INLINE void *_upb_array_mutable_accessor(void *msg, size_t ofs,
}
}
-UPB_INLINE void *_upb_array_resize_accessor(void *msg, size_t ofs, size_t size,
- upb_fieldtype_t type,
- upb_arena *arena) {
- upb_array **arr_ptr = PTR_AT(msg, ofs, upb_array*);
+UPB_INLINE void *_upb_array_resize_accessor2(void *msg, size_t ofs, size_t size,
+ int elem_size_lg2,
+ upb_arena *arena) {
+ upb_array **arr_ptr = PTR_AT(msg, ofs, upb_array *);
upb_array *arr = *arr_ptr;
if (!arr || arr->size < size) {
- return _upb_array_resize_fallback(arr_ptr, size, type, arena);
+ return _upb_array_resize_fallback(arr_ptr, size, elem_size_lg2, arena);
}
arr->len = size;
return _upb_array_ptr(arr);
}
-
-UPB_INLINE bool _upb_array_append_accessor(void *msg, size_t ofs,
- size_t elem_size,
- upb_fieldtype_t type,
- const void *value,
- upb_arena *arena) {
- upb_array **arr_ptr = PTR_AT(msg, ofs, upb_array*);
+UPB_INLINE bool _upb_array_append_accessor2(void *msg, size_t ofs,
+ int elem_size_lg2,
+ const void *value,
+ upb_arena *arena) {
+ upb_array **arr_ptr = PTR_AT(msg, ofs, upb_array *);
+ size_t elem_size = 1 << elem_size_lg2;
upb_array *arr = *arr_ptr;
- void* ptr;
+ void *ptr;
if (!arr || arr->len == arr->size) {
- return _upb_array_append_fallback(arr_ptr, value, type, arena);
+ return _upb_array_append_fallback(arr_ptr, value, elem_size_lg2, arena);
}
ptr = _upb_array_ptr(arr);
memcpy(PTR_AT(ptr, arr->len * elem_size, char), value, elem_size);
@@ -1118,6 +1328,42 @@ UPB_INLINE bool _upb_array_append_accessor(void *msg, size_t ofs,
return true;
}
+/* Used by old generated code, remove once all code has been regenerated. */
+UPB_INLINE int _upb_sizelg2(upb_fieldtype_t type) {
+ switch (type) {
+ case UPB_TYPE_BOOL:
+ return 0;
+ case UPB_TYPE_FLOAT:
+ case UPB_TYPE_INT32:
+ case UPB_TYPE_UINT32:
+ case UPB_TYPE_ENUM:
+ return 2;
+ case UPB_TYPE_MESSAGE:
+ return UPB_SIZE(2, 3);
+ case UPB_TYPE_DOUBLE:
+ case UPB_TYPE_INT64:
+ case UPB_TYPE_UINT64:
+ return 3;
+ case UPB_TYPE_STRING:
+ case UPB_TYPE_BYTES:
+ return UPB_SIZE(3, 4);
+ }
+ UPB_UNREACHABLE();
+}
+UPB_INLINE void *_upb_array_resize_accessor(void *msg, size_t ofs, size_t size,
+ upb_fieldtype_t type,
+ upb_arena *arena) {
+ return _upb_array_resize_accessor2(msg, ofs, size, _upb_sizelg2(type), arena);
+}
+UPB_INLINE bool _upb_array_append_accessor(void *msg, size_t ofs,
+ size_t elem_size, upb_fieldtype_t type,
+ const void *value,
+ upb_arena *arena) {
+ (void)elem_size;
+ return _upb_array_append_accessor2(msg, ofs, _upb_sizelg2(type), value,
+ arena);
+}
+
/** upb_map *******************************************************************/
/* Right now we use strmaps for everything. We'll likely want to use
@@ -1174,17 +1420,17 @@ UPB_INLINE void _upb_map_fromkey(upb_strview key, void* out, size_t size) {
}
}
-UPB_INLINE upb_value _upb_map_tovalue(const void *val, size_t size,
- upb_arena *a) {
- upb_value ret = {0};
+UPB_INLINE bool _upb_map_tovalue(const void *val, size_t size, upb_value *msgval,
+ upb_arena *a) {
if (size == UPB_MAPTYPE_STRING) {
upb_strview *strp = (upb_strview*)upb_arena_malloc(a, sizeof(*strp));
+ if (!strp) return false;
*strp = *(upb_strview*)val;
- memcpy(&ret, &strp, sizeof(strp));
+ *msgval = upb_value_ptr(strp);
} else {
- memcpy(&ret, val, size);
+ memcpy(msgval, val, size);
}
- return ret;
+ return true;
}
UPB_INLINE void _upb_map_fromvalue(upb_value val, void* out, size_t size) {
@@ -1207,7 +1453,7 @@ UPB_INLINE bool _upb_map_get(const upb_map *map, const void *key,
upb_value tabval;
upb_strview k = _upb_map_tokey(key, key_size);
bool ret = upb_strtable_lookup2(&map->table, k.data, k.size, &tabval);
- if (ret) {
+ if (ret && val) {
_upb_map_fromvalue(tabval, val, val_size);
}
return ret;
@@ -1218,15 +1464,16 @@ UPB_INLINE void* _upb_map_next(const upb_map *map, size_t *iter) {
it.t = &map->table;
it.index = *iter;
upb_strtable_next(&it);
- if (upb_strtable_done(&it)) return NULL;
*iter = it.index;
+ if (upb_strtable_done(&it)) return NULL;
return (void*)str_tabent(&it);
}
UPB_INLINE bool _upb_map_set(upb_map *map, const void *key, size_t key_size,
void *val, size_t val_size, upb_arena *arena) {
upb_strview strkey = _upb_map_tokey(key, key_size);
- upb_value tabval = _upb_map_tovalue(val, val_size, arena);
+ upb_value tabval = {0};
+ if (!_upb_map_tovalue(val, val_size, &tabval, arena)) return false;
upb_alloc *a = upb_arena_alloc(arena);
/* TODO(haberman): add overwrite operation to minimize number of lookups. */
@@ -1311,13 +1558,60 @@ UPB_INLINE void _upb_msg_map_set_value(void* msg, const void* val, size_t size)
/* This is like _upb_map_tovalue() except the entry already exists so we can
* reuse the allocated upb_strview for string fields. */
if (size == UPB_MAPTYPE_STRING) {
- upb_strview *strp = (upb_strview*)ent->val.val;
+ upb_strview *strp = (upb_strview*)(uintptr_t)ent->val.val;
memcpy(strp, val, sizeof(*strp));
} else {
memcpy(&ent->val.val, val, size);
}
}
+/** _upb_mapsorter *************************************************************/
+
+/* _upb_mapsorter sorts maps and provides ordered iteration over the entries.
+ * Since maps can be recursive (map values can be messages which contain other maps).
+ * _upb_mapsorter can contain a stack of maps. */
+
+typedef struct {
+ upb_tabent const**entries;
+ int size;
+ int cap;
+} _upb_mapsorter;
+
+typedef struct {
+ int start;
+ int pos;
+ int end;
+} _upb_sortedmap;
+
+UPB_INLINE void _upb_mapsorter_init(_upb_mapsorter *s) {
+ s->entries = NULL;
+ s->size = 0;
+ s->cap = 0;
+}
+
+UPB_INLINE void _upb_mapsorter_destroy(_upb_mapsorter *s) {
+ if (s->entries) free(s->entries);
+}
+
+bool _upb_mapsorter_pushmap(_upb_mapsorter *s, upb_descriptortype_t key_type,
+ const upb_map *map, _upb_sortedmap *sorted);
+
+UPB_INLINE void _upb_mapsorter_popmap(_upb_mapsorter *s, _upb_sortedmap *sorted) {
+ s->size = sorted->start;
+}
+
+UPB_INLINE bool _upb_sortedmap_next(_upb_mapsorter *s, const upb_map *map,
+ _upb_sortedmap *sorted,
+ upb_map_entry *ent) {
+ if (sorted->pos == sorted->end) return false;
+ const upb_tabent *tabent = s->entries[sorted->pos++];
+ upb_strview key = upb_tabstrview(tabent->key);
+ _upb_map_fromkey(key, &ent->k, map->key_size);
+ upb_value val = {tabent->val.val};
+ _upb_map_fromvalue(val, &ent->v, map->val_size);
+ return true;
+}
+
#undef PTR_AT
#ifdef __cplusplus
@@ -1327,19 +1621,223 @@ UPB_INLINE void _upb_msg_map_set_value(void* msg, const void* val, size_t size)
#endif /* UPB_MSG_H_ */
+/* Must be last. */
+
#ifdef __cplusplus
extern "C" {
#endif
+enum {
+ /* If set, strings will alias the input buffer instead of copying into the
+ * arena. */
+ UPB_DECODE_ALIAS = 1,
+};
+
+#define UPB_DECODE_MAXDEPTH(depth) ((depth) << 16)
+
+bool _upb_decode(const char *buf, size_t size, upb_msg *msg,
+ const upb_msglayout *l, upb_arena *arena, int options);
+
+UPB_INLINE
bool upb_decode(const char *buf, size_t size, upb_msg *msg,
- const upb_msglayout *l, upb_arena *arena);
+ const upb_msglayout *l, upb_arena *arena) {
+ return _upb_decode(buf, size, msg, l, arena, 0);
+}
#ifdef __cplusplus
} /* extern "C" */
#endif
+
#endif /* UPB_DECODE_H_ */
/*
+** Internal implementation details of the decoder that are shared between
+** decode.c and decode_fast.c.
+*/
+
+#ifndef UPB_DECODE_INT_H_
+#define UPB_DECODE_INT_H_
+
+#include
+
+
+#ifndef UPB_INT_H_
+#define UPB_INT_H_
+
+
+struct mem_block;
+typedef struct mem_block mem_block;
+
+struct upb_arena {
+ _upb_arena_head head;
+ uint32_t *cleanups;
+
+ /* Allocator to allocate arena blocks. We are responsible for freeing these
+ * when we are destroyed. */
+ upb_alloc *block_alloc;
+ uint32_t last_size;
+
+ /* When multiple arenas are fused together, each arena points to a parent
+ * arena (root points to itself). The root tracks how many live arenas
+ * reference it. */
+ uint32_t refcount; /* Only used when a->parent == a */
+ struct upb_arena *parent;
+
+ /* Linked list of blocks to free/cleanup. */
+ mem_block *freelist, *freelist_tail;
+};
+
+#endif /* UPB_INT_H_ */
+
+/* Must be last. */
+
+#define DECODE_NOGROUP (uint32_t)-1
+
+typedef struct upb_decstate {
+ const char *end; /* Can read up to 16 bytes slop beyond this. */
+ const char *limit_ptr; /* = end + UPB_MIN(limit, 0) */
+ upb_msg *unknown_msg; /* If non-NULL, add unknown data at buffer flip. */
+ const char *unknown; /* Start of unknown data. */
+ int limit; /* Submessage limit relative to end. */
+ int depth;
+ uint32_t end_group; /* field number of END_GROUP tag, else DECODE_NOGROUP */
+ bool alias;
+ char patch[32];
+ upb_arena arena;
+ jmp_buf err;
+} upb_decstate;
+
+/* Error function that will abort decoding with longjmp(). We can't declare this
+ * UPB_NORETURN, even though it is appropriate, because if we do then compilers
+ * will "helpfully" refuse to tailcall to it
+ * (see: https://stackoverflow.com/a/55657013), which will defeat a major goal
+ * of our optimizations. That is also why we must declare it in a separate file,
+ * otherwise the compiler will see that it calls longjmp() and deduce that it is
+ * noreturn. */
+const char *fastdecode_err(upb_decstate *d);
+
+extern const uint8_t upb_utf8_offsets[];
+
+UPB_INLINE
+bool decode_verifyutf8_inl(const char *buf, int len) {
+ int i, j;
+ uint8_t offset;
+
+ i = 0;
+ while (i < len) {
+ offset = upb_utf8_offsets[(uint8_t)buf[i]];
+ if (offset == 0 || i + offset > len) {
+ return false;
+ }
+ for (j = i + 1; j < i + offset; j++) {
+ if ((buf[j] & 0xc0) != 0x80) {
+ return false;
+ }
+ }
+ i += offset;
+ }
+ return i == len;
+}
+
+/* x86-64 pointers always have the high 16 bits matching. So we can shift
+ * left 8 and right 8 without loss of information. */
+UPB_INLINE intptr_t decode_totable(const upb_msglayout *tablep) {
+ return ((intptr_t)tablep << 8) | tablep->table_mask;
+}
+
+UPB_INLINE const upb_msglayout *decode_totablep(intptr_t table) {
+ return (const upb_msglayout*)(table >> 8);
+}
+
+UPB_INLINE
+const char *decode_isdonefallback_inl(upb_decstate *d, const char *ptr,
+ int overrun) {
+ if (overrun < d->limit) {
+ /* Need to copy remaining data into patch buffer. */
+ UPB_ASSERT(overrun < 16);
+ if (d->unknown_msg) {
+ if (!_upb_msg_addunknown(d->unknown_msg, d->unknown, ptr - d->unknown,
+ &d->arena)) {
+ return NULL;
+ }
+ d->unknown = &d->patch[0] + overrun;
+ }
+ memset(d->patch + 16, 0, 16);
+ memcpy(d->patch, d->end, 16);
+ ptr = &d->patch[0] + overrun;
+ d->end = &d->patch[16];
+ d->limit -= 16;
+ d->limit_ptr = d->end + d->limit;
+ d->alias = false;
+ UPB_ASSERT(ptr < d->limit_ptr);
+ return ptr;
+ } else {
+ return NULL;
+ }
+}
+
+const char *decode_isdonefallback(upb_decstate *d, const char *ptr,
+ int overrun);
+
+UPB_INLINE
+bool decode_isdone(upb_decstate *d, const char **ptr) {
+ int overrun = *ptr - d->end;
+ if (UPB_LIKELY(*ptr < d->limit_ptr)) {
+ return false;
+ } else if (UPB_LIKELY(overrun == d->limit)) {
+ return true;
+ } else {
+ *ptr = decode_isdonefallback(d, *ptr, overrun);
+ return false;
+ }
+}
+
+UPB_INLINE
+const char *fastdecode_tagdispatch(upb_decstate *d, const char *ptr,
+ upb_msg *msg, intptr_t table,
+ uint64_t hasbits, uint32_t tag) {
+ const upb_msglayout *table_p = decode_totablep(table);
+ uint8_t mask = table;
+ uint64_t data;
+ size_t idx = tag & mask;
+ UPB_ASSUME((idx & 7) == 0);
+ idx >>= 3;
+ data = table_p->fasttable[idx].field_data ^ tag;
+ return table_p->fasttable[idx].field_parser(d, ptr, msg, table, hasbits, data);
+}
+
+UPB_INLINE uint32_t fastdecode_loadtag(const char* ptr) {
+ uint16_t tag;
+ memcpy(&tag, ptr, 2);
+ return tag;
+}
+
+UPB_INLINE void decode_checklimit(upb_decstate *d) {
+ UPB_ASSERT(d->limit_ptr == d->end + UPB_MIN(0, d->limit));
+}
+
+UPB_INLINE int decode_pushlimit(upb_decstate *d, const char *ptr, int size) {
+ int limit = size + (int)(ptr - d->end);
+ int delta = d->limit - limit;
+ decode_checklimit(d);
+ d->limit = limit;
+ d->limit_ptr = d->end + UPB_MIN(0, limit);
+ decode_checklimit(d);
+ return delta;
+}
+
+UPB_INLINE void decode_poplimit(upb_decstate *d, const char *ptr,
+ int saved_delta) {
+ UPB_ASSERT(ptr - d->end == d->limit);
+ decode_checklimit(d);
+ d->limit += saved_delta;
+ d->limit_ptr = d->end + UPB_MIN(0, d->limit);
+ decode_checklimit(d);
+}
+
+
+#endif /* UPB_DECODE_INT_H_ */
+/*
** upb_encode: parsing into a upb_msg using a upb_msglayout.
*/
@@ -1347,18 +1845,166 @@ bool upb_decode(const char *buf, size_t size, upb_msg *msg,
#define UPB_ENCODE_H_
+/* Must be last. */
+
#ifdef __cplusplus
extern "C" {
#endif
-char *upb_encode(const void *msg, const upb_msglayout *l, upb_arena *arena,
- size_t *size);
+enum {
+ /* If set, the results of serializing will be deterministic across all
+ * instances of this binary. There are no guarantees across different
+ * binary builds.
+ *
+ * If your proto contains maps, the encoder will need to malloc()/free()
+ * memory during encode. */
+ UPB_ENCODE_DETERMINISTIC = 1,
+
+ /* When set, unknown fields are not printed. */
+ UPB_ENCODE_SKIPUNKNOWN = 2,
+};
+
+#define UPB_ENCODE_MAXDEPTH(depth) ((depth) << 16)
+
+char *upb_encode_ex(const void *msg, const upb_msglayout *l, int options,
+ upb_arena *arena, size_t *size);
+
+UPB_INLINE char *upb_encode(const void *msg, const upb_msglayout *l,
+ upb_arena *arena, size_t *size) {
+ return upb_encode_ex(msg, l, 0, arena, size);
+}
+
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* UPB_ENCODE_H_ */
+// These are the specialized field parser functions for the fast parser.
+// Generated tables will refer to these by name.
+//
+// The function names are encoded with names like:
+//
+// // 123 4
+// upb_pss_1bt(); // Parse singular string, 1 byte tag.
+//
+// In position 1:
+// - 'p' for parse, most function use this
+// - 'c' for copy, for when we are copying strings instead of aliasing
+//
+// In position 2 (cardinality):
+// - 's' for singular, with or without hasbit
+// - 'o' for oneof
+// - 'r' for non-packed repeated
+// - 'p' for packed repeated
+//
+// In position 3 (type):
+// - 'b1' for bool
+// - 'v4' for 4-byte varint
+// - 'v8' for 8-byte varint
+// - 'z4' for zig-zag-encoded 4-byte varint
+// - 'z8' for zig-zag-encoded 8-byte varint
+// - 'f4' for 4-byte fixed
+// - 'f8' for 8-byte fixed
+// - 'm' for sub-message
+// - 's' for string (validate UTF-8)
+// - 'b' for bytes
+//
+// In position 4 (tag length):
+// - '1' for one-byte tags (field numbers 1-15)
+// - '2' for two-byte tags (field numbers 16-2048)
+
+#ifndef UPB_DECODE_FAST_H_
+#define UPB_DECODE_FAST_H_
+
+
+struct upb_decstate;
+
+// The fallback, generic parsing function that can handle any field type.
+// This just uses the regular (non-fast) parser to parse a single field.
+const char *fastdecode_generic(struct upb_decstate *d, const char *ptr,
+ upb_msg *msg, intptr_t table, uint64_t hasbits,
+ uint64_t data);
+
+#define UPB_PARSE_PARAMS \
+ struct upb_decstate *d, const char *ptr, upb_msg *msg, intptr_t table, \
+ uint64_t hasbits, uint64_t data
+
+/* primitive fields ***********************************************************/
+
+#define F(card, type, valbytes, tagbytes) \
+ const char *upb_p##card##type##valbytes##_##tagbytes##bt(UPB_PARSE_PARAMS);
+
+#define TYPES(card, tagbytes) \
+ F(card, b, 1, tagbytes) \
+ F(card, v, 4, tagbytes) \
+ F(card, v, 8, tagbytes) \
+ F(card, z, 4, tagbytes) \
+ F(card, z, 8, tagbytes) \
+ F(card, f, 4, tagbytes) \
+ F(card, f, 8, tagbytes)
+
+#define TAGBYTES(card) \
+ TYPES(card, 1) \
+ TYPES(card, 2)
+
+TAGBYTES(s)
+TAGBYTES(o)
+TAGBYTES(r)
+TAGBYTES(p)
+
+#undef F
+#undef TYPES
+#undef TAGBYTES
+
+/* string fields **************************************************************/
+
+#define F(card, tagbytes, type) \
+ const char *upb_p##card##type##_##tagbytes##bt(UPB_PARSE_PARAMS); \
+ const char *upb_c##card##type##_##tagbytes##bt(UPB_PARSE_PARAMS);
+
+#define UTF8(card, tagbytes) \
+ F(card, tagbytes, s) \
+ F(card, tagbytes, b)
+
+#define TAGBYTES(card) \
+ UTF8(card, 1) \
+ UTF8(card, 2)
+
+TAGBYTES(s)
+TAGBYTES(o)
+TAGBYTES(r)
+
+#undef F
+#undef TAGBYTES
+
+/* sub-message fields *********************************************************/
+
+#define F(card, tagbytes, size_ceil, ceil_arg) \
+ const char *upb_p##card##m_##tagbytes##bt_max##size_ceil##b(UPB_PARSE_PARAMS);
+
+#define SIZES(card, tagbytes) \
+ F(card, tagbytes, 64, 64) \
+ F(card, tagbytes, 128, 128) \
+ F(card, tagbytes, 192, 192) \
+ F(card, tagbytes, 256, 256) \
+ F(card, tagbytes, max, -1)
+
+#define TAGBYTES(card) \
+ SIZES(card, 1) \
+ SIZES(card, 2)
+
+TAGBYTES(s)
+TAGBYTES(o)
+TAGBYTES(r)
+
+#undef TAGBYTES
+#undef SIZES
+#undef F
+
+#undef UPB_PARSE_PARAMS
+
+#endif /* UPB_DECODE_FAST_H_ */
/* This file was generated by upbc (the upb compiler) from the input
* file:
*
@@ -1520,6 +2166,12 @@ UPB_INLINE google_protobuf_FileDescriptorSet *google_protobuf_FileDescriptorSet_
google_protobuf_FileDescriptorSet *ret = google_protobuf_FileDescriptorSet_new(arena);
return (ret && upb_decode(buf, size, ret, &google_protobuf_FileDescriptorSet_msginit, arena)) ? ret : NULL;
}
+UPB_INLINE google_protobuf_FileDescriptorSet *google_protobuf_FileDescriptorSet_parse_ex(const char *buf, size_t size,
+ upb_arena *arena, int options) {
+ google_protobuf_FileDescriptorSet *ret = google_protobuf_FileDescriptorSet_new(arena);
+ return (ret && _upb_decode(buf, size, ret, &google_protobuf_FileDescriptorSet_msginit, arena, options))
+ ? ret : NULL;
+}
UPB_INLINE char *google_protobuf_FileDescriptorSet_serialize(const google_protobuf_FileDescriptorSet *msg, upb_arena *arena, size_t *len) {
return upb_encode(msg, &google_protobuf_FileDescriptorSet_msginit, arena, len);
}
@@ -1531,12 +2183,12 @@ UPB_INLINE google_protobuf_FileDescriptorProto** google_protobuf_FileDescriptorS
return (google_protobuf_FileDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(0, 0), len);
}
UPB_INLINE google_protobuf_FileDescriptorProto** google_protobuf_FileDescriptorSet_resize_file(google_protobuf_FileDescriptorSet *msg, size_t len, upb_arena *arena) {
- return (google_protobuf_FileDescriptorProto**)_upb_array_resize_accessor(msg, UPB_SIZE(0, 0), len, UPB_TYPE_MESSAGE, arena);
+ return (google_protobuf_FileDescriptorProto**)_upb_array_resize_accessor2(msg, UPB_SIZE(0, 0), len, UPB_SIZE(2, 3), arena);
}
UPB_INLINE struct google_protobuf_FileDescriptorProto* google_protobuf_FileDescriptorSet_add_file(google_protobuf_FileDescriptorSet *msg, upb_arena *arena) {
struct google_protobuf_FileDescriptorProto* sub = (struct google_protobuf_FileDescriptorProto*)_upb_msg_new(&google_protobuf_FileDescriptorProto_msginit, arena);
- bool ok = _upb_array_append_accessor(
- msg, UPB_SIZE(0, 0), UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, &sub, arena);
+ bool ok = _upb_array_append_accessor2(
+ msg, UPB_SIZE(0, 0), UPB_SIZE(2, 3), &sub, arena);
if (!ok) return NULL;
return sub;
}
@@ -1551,13 +2203,19 @@ UPB_INLINE google_protobuf_FileDescriptorProto *google_protobuf_FileDescriptorPr
google_protobuf_FileDescriptorProto *ret = google_protobuf_FileDescriptorProto_new(arena);
return (ret && upb_decode(buf, size, ret, &google_protobuf_FileDescriptorProto_msginit, arena)) ? ret : NULL;
}
+UPB_INLINE google_protobuf_FileDescriptorProto *google_protobuf_FileDescriptorProto_parse_ex(const char *buf, size_t size,
+ upb_arena *arena, int options) {
+ google_protobuf_FileDescriptorProto *ret = google_protobuf_FileDescriptorProto_new(arena);
+ return (ret && _upb_decode(buf, size, ret, &google_protobuf_FileDescriptorProto_msginit, arena, options))
+ ? ret : NULL;
+}
UPB_INLINE char *google_protobuf_FileDescriptorProto_serialize(const google_protobuf_FileDescriptorProto *msg, upb_arena *arena, size_t *len) {
return upb_encode(msg, &google_protobuf_FileDescriptorProto_msginit, arena, len);
}
-UPB_INLINE bool google_protobuf_FileDescriptorProto_has_name(const google_protobuf_FileDescriptorProto *msg) { return _upb_has_field(msg, 1); }
+UPB_INLINE bool google_protobuf_FileDescriptorProto_has_name(const google_protobuf_FileDescriptorProto *msg) { return _upb_hasbit(msg, 1); }
UPB_INLINE upb_strview google_protobuf_FileDescriptorProto_name(const google_protobuf_FileDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview); }
-UPB_INLINE bool google_protobuf_FileDescriptorProto_has_package(const google_protobuf_FileDescriptorProto *msg) { return _upb_has_field(msg, 2); }
+UPB_INLINE bool google_protobuf_FileDescriptorProto_has_package(const google_protobuf_FileDescriptorProto *msg) { return _upb_hasbit(msg, 2); }
UPB_INLINE upb_strview google_protobuf_FileDescriptorProto_package(const google_protobuf_FileDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_strview); }
UPB_INLINE upb_strview const* google_protobuf_FileDescriptorProto_dependency(const google_protobuf_FileDescriptorProto *msg, size_t *len) { return (upb_strview const*)_upb_array_accessor(msg, UPB_SIZE(36, 72), len); }
UPB_INLINE bool google_protobuf_FileDescriptorProto_has_message_type(const google_protobuf_FileDescriptorProto *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(40, 80)); }
@@ -1568,13 +2226,13 @@ UPB_INLINE bool google_protobuf_FileDescriptorProto_has_service(const google_pro
UPB_INLINE const google_protobuf_ServiceDescriptorProto* const* google_protobuf_FileDescriptorProto_service(const google_protobuf_FileDescriptorProto *msg, size_t *len) { return (const google_protobuf_ServiceDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(48, 96), len); }
UPB_INLINE bool google_protobuf_FileDescriptorProto_has_extension(const google_protobuf_FileDescriptorProto *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(52, 104)); }
UPB_INLINE const google_protobuf_FieldDescriptorProto* const* google_protobuf_FileDescriptorProto_extension(const google_protobuf_FileDescriptorProto *msg, size_t *len) { return (const google_protobuf_FieldDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(52, 104), len); }
-UPB_INLINE bool google_protobuf_FileDescriptorProto_has_options(const google_protobuf_FileDescriptorProto *msg) { return _upb_has_field(msg, 4); }
+UPB_INLINE bool google_protobuf_FileDescriptorProto_has_options(const google_protobuf_FileDescriptorProto *msg) { return _upb_hasbit(msg, 3); }
UPB_INLINE const google_protobuf_FileOptions* google_protobuf_FileDescriptorProto_options(const google_protobuf_FileDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(28, 56), const google_protobuf_FileOptions*); }
-UPB_INLINE bool google_protobuf_FileDescriptorProto_has_source_code_info(const google_protobuf_FileDescriptorProto *msg) { return _upb_has_field(msg, 5); }
+UPB_INLINE bool google_protobuf_FileDescriptorProto_has_source_code_info(const google_protobuf_FileDescriptorProto *msg) { return _upb_hasbit(msg, 4); }
UPB_INLINE const google_protobuf_SourceCodeInfo* google_protobuf_FileDescriptorProto_source_code_info(const google_protobuf_FileDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(32, 64), const google_protobuf_SourceCodeInfo*); }
UPB_INLINE int32_t const* google_protobuf_FileDescriptorProto_public_dependency(const google_protobuf_FileDescriptorProto *msg, size_t *len) { return (int32_t const*)_upb_array_accessor(msg, UPB_SIZE(56, 112), len); }
UPB_INLINE int32_t const* google_protobuf_FileDescriptorProto_weak_dependency(const google_protobuf_FileDescriptorProto *msg, size_t *len) { return (int32_t const*)_upb_array_accessor(msg, UPB_SIZE(60, 120), len); }
-UPB_INLINE bool google_protobuf_FileDescriptorProto_has_syntax(const google_protobuf_FileDescriptorProto *msg) { return _upb_has_field(msg, 3); }
+UPB_INLINE bool google_protobuf_FileDescriptorProto_has_syntax(const google_protobuf_FileDescriptorProto *msg) { return _upb_hasbit(msg, 5); }
UPB_INLINE upb_strview google_protobuf_FileDescriptorProto_syntax(const google_protobuf_FileDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(20, 40), upb_strview); }
UPB_INLINE void google_protobuf_FileDescriptorProto_set_name(google_protobuf_FileDescriptorProto *msg, upb_strview value) {
@@ -1589,22 +2247,22 @@ UPB_INLINE upb_strview* google_protobuf_FileDescriptorProto_mutable_dependency(g
return (upb_strview*)_upb_array_mutable_accessor(msg, UPB_SIZE(36, 72), len);
}
UPB_INLINE upb_strview* google_protobuf_FileDescriptorProto_resize_dependency(google_protobuf_FileDescriptorProto *msg, size_t len, upb_arena *arena) {
- return (upb_strview*)_upb_array_resize_accessor(msg, UPB_SIZE(36, 72), len, UPB_TYPE_STRING, arena);
+ return (upb_strview*)_upb_array_resize_accessor2(msg, UPB_SIZE(36, 72), len, UPB_SIZE(3, 4), arena);
}
UPB_INLINE bool google_protobuf_FileDescriptorProto_add_dependency(google_protobuf_FileDescriptorProto *msg, upb_strview val, upb_arena *arena) {
- return _upb_array_append_accessor(msg, UPB_SIZE(36, 72), UPB_SIZE(8, 16), UPB_TYPE_STRING, &val,
+ return _upb_array_append_accessor2(msg, UPB_SIZE(36, 72), UPB_SIZE(3, 4), &val,
arena);
}
UPB_INLINE google_protobuf_DescriptorProto** google_protobuf_FileDescriptorProto_mutable_message_type(google_protobuf_FileDescriptorProto *msg, size_t *len) {
return (google_protobuf_DescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(40, 80), len);
}
UPB_INLINE google_protobuf_DescriptorProto** google_protobuf_FileDescriptorProto_resize_message_type(google_protobuf_FileDescriptorProto *msg, size_t len, upb_arena *arena) {
- return (google_protobuf_DescriptorProto**)_upb_array_resize_accessor(msg, UPB_SIZE(40, 80), len, UPB_TYPE_MESSAGE, arena);
+ return (google_protobuf_DescriptorProto**)_upb_array_resize_accessor2(msg, UPB_SIZE(40, 80), len, UPB_SIZE(2, 3), arena);
}
UPB_INLINE struct google_protobuf_DescriptorProto* google_protobuf_FileDescriptorProto_add_message_type(google_protobuf_FileDescriptorProto *msg, upb_arena *arena) {
struct google_protobuf_DescriptorProto* sub = (struct google_protobuf_DescriptorProto*)_upb_msg_new(&google_protobuf_DescriptorProto_msginit, arena);
- bool ok = _upb_array_append_accessor(
- msg, UPB_SIZE(40, 80), UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, &sub, arena);
+ bool ok = _upb_array_append_accessor2(
+ msg, UPB_SIZE(40, 80), UPB_SIZE(2, 3), &sub, arena);
if (!ok) return NULL;
return sub;
}
@@ -1612,12 +2270,12 @@ UPB_INLINE google_protobuf_EnumDescriptorProto** google_protobuf_FileDescriptorP
return (google_protobuf_EnumDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(44, 88), len);
}
UPB_INLINE google_protobuf_EnumDescriptorProto** google_protobuf_FileDescriptorProto_resize_enum_type(google_protobuf_FileDescriptorProto *msg, size_t len, upb_arena *arena) {
- return (google_protobuf_EnumDescriptorProto**)_upb_array_resize_accessor(msg, UPB_SIZE(44, 88), len, UPB_TYPE_MESSAGE, arena);
+ return (google_protobuf_EnumDescriptorProto**)_upb_array_resize_accessor2(msg, UPB_SIZE(44, 88), len, UPB_SIZE(2, 3), arena);
}
UPB_INLINE struct google_protobuf_EnumDescriptorProto* google_protobuf_FileDescriptorProto_add_enum_type(google_protobuf_FileDescriptorProto *msg, upb_arena *arena) {
struct google_protobuf_EnumDescriptorProto* sub = (struct google_protobuf_EnumDescriptorProto*)_upb_msg_new(&google_protobuf_EnumDescriptorProto_msginit, arena);
- bool ok = _upb_array_append_accessor(
- msg, UPB_SIZE(44, 88), UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, &sub, arena);
+ bool ok = _upb_array_append_accessor2(
+ msg, UPB_SIZE(44, 88), UPB_SIZE(2, 3), &sub, arena);
if (!ok) return NULL;
return sub;
}
@@ -1625,12 +2283,12 @@ UPB_INLINE google_protobuf_ServiceDescriptorProto** google_protobuf_FileDescript
return (google_protobuf_ServiceDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(48, 96), len);
}
UPB_INLINE google_protobuf_ServiceDescriptorProto** google_protobuf_FileDescriptorProto_resize_service(google_protobuf_FileDescriptorProto *msg, size_t len, upb_arena *arena) {
- return (google_protobuf_ServiceDescriptorProto**)_upb_array_resize_accessor(msg, UPB_SIZE(48, 96), len, UPB_TYPE_MESSAGE, arena);
+ return (google_protobuf_ServiceDescriptorProto**)_upb_array_resize_accessor2(msg, UPB_SIZE(48, 96), len, UPB_SIZE(2, 3), arena);
}
UPB_INLINE struct google_protobuf_ServiceDescriptorProto* google_protobuf_FileDescriptorProto_add_service(google_protobuf_FileDescriptorProto *msg, upb_arena *arena) {
struct google_protobuf_ServiceDescriptorProto* sub = (struct google_protobuf_ServiceDescriptorProto*)_upb_msg_new(&google_protobuf_ServiceDescriptorProto_msginit, arena);
- bool ok = _upb_array_append_accessor(
- msg, UPB_SIZE(48, 96), UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, &sub, arena);
+ bool ok = _upb_array_append_accessor2(
+ msg, UPB_SIZE(48, 96), UPB_SIZE(2, 3), &sub, arena);
if (!ok) return NULL;
return sub;
}
@@ -1638,17 +2296,17 @@ UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_FileDescriptor
return (google_protobuf_FieldDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(52, 104), len);
}
UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_FileDescriptorProto_resize_extension(google_protobuf_FileDescriptorProto *msg, size_t len, upb_arena *arena) {
- return (google_protobuf_FieldDescriptorProto**)_upb_array_resize_accessor(msg, UPB_SIZE(52, 104), len, UPB_TYPE_MESSAGE, arena);
+ return (google_protobuf_FieldDescriptorProto**)_upb_array_resize_accessor2(msg, UPB_SIZE(52, 104), len, UPB_SIZE(2, 3), arena);
}
UPB_INLINE struct google_protobuf_FieldDescriptorProto* google_protobuf_FileDescriptorProto_add_extension(google_protobuf_FileDescriptorProto *msg, upb_arena *arena) {
struct google_protobuf_FieldDescriptorProto* sub = (struct google_protobuf_FieldDescriptorProto*)_upb_msg_new(&google_protobuf_FieldDescriptorProto_msginit, arena);
- bool ok = _upb_array_append_accessor(
- msg, UPB_SIZE(52, 104), UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, &sub, arena);
+ bool ok = _upb_array_append_accessor2(
+ msg, UPB_SIZE(52, 104), UPB_SIZE(2, 3), &sub, arena);
if (!ok) return NULL;
return sub;
}
UPB_INLINE void google_protobuf_FileDescriptorProto_set_options(google_protobuf_FileDescriptorProto *msg, google_protobuf_FileOptions* value) {
- _upb_sethas(msg, 4);
+ _upb_sethas(msg, 3);
*UPB_PTR_AT(msg, UPB_SIZE(28, 56), google_protobuf_FileOptions*) = value;
}
UPB_INLINE struct google_protobuf_FileOptions* google_protobuf_FileDescriptorProto_mutable_options(google_protobuf_FileDescriptorProto *msg, upb_arena *arena) {
@@ -1661,7 +2319,7 @@ UPB_INLINE struct google_protobuf_FileOptions* google_protobuf_FileDescriptorPro
return sub;
}
UPB_INLINE void google_protobuf_FileDescriptorProto_set_source_code_info(google_protobuf_FileDescriptorProto *msg, google_protobuf_SourceCodeInfo* value) {
- _upb_sethas(msg, 5);
+ _upb_sethas(msg, 4);
*UPB_PTR_AT(msg, UPB_SIZE(32, 64), google_protobuf_SourceCodeInfo*) = value;
}
UPB_INLINE struct google_protobuf_SourceCodeInfo* google_protobuf_FileDescriptorProto_mutable_source_code_info(google_protobuf_FileDescriptorProto *msg, upb_arena *arena) {
@@ -1677,24 +2335,24 @@ UPB_INLINE int32_t* google_protobuf_FileDescriptorProto_mutable_public_dependenc
return (int32_t*)_upb_array_mutable_accessor(msg, UPB_SIZE(56, 112), len);
}
UPB_INLINE int32_t* google_protobuf_FileDescriptorProto_resize_public_dependency(google_protobuf_FileDescriptorProto *msg, size_t len, upb_arena *arena) {
- return (int32_t*)_upb_array_resize_accessor(msg, UPB_SIZE(56, 112), len, UPB_TYPE_INT32, arena);
+ return (int32_t*)_upb_array_resize_accessor2(msg, UPB_SIZE(56, 112), len, 2, arena);
}
UPB_INLINE bool google_protobuf_FileDescriptorProto_add_public_dependency(google_protobuf_FileDescriptorProto *msg, int32_t val, upb_arena *arena) {
- return _upb_array_append_accessor(msg, UPB_SIZE(56, 112), UPB_SIZE(4, 4), UPB_TYPE_INT32, &val,
+ return _upb_array_append_accessor2(msg, UPB_SIZE(56, 112), 2, &val,
arena);
}
UPB_INLINE int32_t* google_protobuf_FileDescriptorProto_mutable_weak_dependency(google_protobuf_FileDescriptorProto *msg, size_t *len) {
return (int32_t*)_upb_array_mutable_accessor(msg, UPB_SIZE(60, 120), len);
}
UPB_INLINE int32_t* google_protobuf_FileDescriptorProto_resize_weak_dependency(google_protobuf_FileDescriptorProto *msg, size_t len, upb_arena *arena) {
- return (int32_t*)_upb_array_resize_accessor(msg, UPB_SIZE(60, 120), len, UPB_TYPE_INT32, arena);
+ return (int32_t*)_upb_array_resize_accessor2(msg, UPB_SIZE(60, 120), len, 2, arena);
}
UPB_INLINE bool google_protobuf_FileDescriptorProto_add_weak_dependency(google_protobuf_FileDescriptorProto *msg, int32_t val, upb_arena *arena) {
- return _upb_array_append_accessor(msg, UPB_SIZE(60, 120), UPB_SIZE(4, 4), UPB_TYPE_INT32, &val,
+ return _upb_array_append_accessor2(msg, UPB_SIZE(60, 120), 2, &val,
arena);
}
UPB_INLINE void google_protobuf_FileDescriptorProto_set_syntax(google_protobuf_FileDescriptorProto *msg, upb_strview value) {
- _upb_sethas(msg, 3);
+ _upb_sethas(msg, 5);
*UPB_PTR_AT(msg, UPB_SIZE(20, 40), upb_strview) = value;
}
@@ -1708,11 +2366,17 @@ UPB_INLINE google_protobuf_DescriptorProto *google_protobuf_DescriptorProto_pars
google_protobuf_DescriptorProto *ret = google_protobuf_DescriptorProto_new(arena);
return (ret && upb_decode(buf, size, ret, &google_protobuf_DescriptorProto_msginit, arena)) ? ret : NULL;
}
+UPB_INLINE google_protobuf_DescriptorProto *google_protobuf_DescriptorProto_parse_ex(const char *buf, size_t size,
+ upb_arena *arena, int options) {
+ google_protobuf_DescriptorProto *ret = google_protobuf_DescriptorProto_new(arena);
+ return (ret && _upb_decode(buf, size, ret, &google_protobuf_DescriptorProto_msginit, arena, options))
+ ? ret : NULL;
+}
UPB_INLINE char *google_protobuf_DescriptorProto_serialize(const google_protobuf_DescriptorProto *msg, upb_arena *arena, size_t *len) {
return upb_encode(msg, &google_protobuf_DescriptorProto_msginit, arena, len);
}
-UPB_INLINE bool google_protobuf_DescriptorProto_has_name(const google_protobuf_DescriptorProto *msg) { return _upb_has_field(msg, 1); }
+UPB_INLINE bool google_protobuf_DescriptorProto_has_name(const google_protobuf_DescriptorProto *msg) { return _upb_hasbit(msg, 1); }
UPB_INLINE upb_strview google_protobuf_DescriptorProto_name(const google_protobuf_DescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview); }
UPB_INLINE bool google_protobuf_DescriptorProto_has_field(const google_protobuf_DescriptorProto *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(16, 32)); }
UPB_INLINE const google_protobuf_FieldDescriptorProto* const* google_protobuf_DescriptorProto_field(const google_protobuf_DescriptorProto *msg, size_t *len) { return (const google_protobuf_FieldDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(16, 32), len); }
@@ -1724,7 +2388,7 @@ UPB_INLINE bool google_protobuf_DescriptorProto_has_extension_range(const google
UPB_INLINE const google_protobuf_DescriptorProto_ExtensionRange* const* google_protobuf_DescriptorProto_extension_range(const google_protobuf_DescriptorProto *msg, size_t *len) { return (const google_protobuf_DescriptorProto_ExtensionRange* const*)_upb_array_accessor(msg, UPB_SIZE(28, 56), len); }
UPB_INLINE bool google_protobuf_DescriptorProto_has_extension(const google_protobuf_DescriptorProto *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(32, 64)); }
UPB_INLINE const google_protobuf_FieldDescriptorProto* const* google_protobuf_DescriptorProto_extension(const google_protobuf_DescriptorProto *msg, size_t *len) { return (const google_protobuf_FieldDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(32, 64), len); }
-UPB_INLINE bool google_protobuf_DescriptorProto_has_options(const google_protobuf_DescriptorProto *msg) { return _upb_has_field(msg, 2); }
+UPB_INLINE bool google_protobuf_DescriptorProto_has_options(const google_protobuf_DescriptorProto *msg) { return _upb_hasbit(msg, 2); }
UPB_INLINE const google_protobuf_MessageOptions* google_protobuf_DescriptorProto_options(const google_protobuf_DescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), const google_protobuf_MessageOptions*); }
UPB_INLINE bool google_protobuf_DescriptorProto_has_oneof_decl(const google_protobuf_DescriptorProto *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(36, 72)); }
UPB_INLINE const google_protobuf_OneofDescriptorProto* const* google_protobuf_DescriptorProto_oneof_decl(const google_protobuf_DescriptorProto *msg, size_t *len) { return (const google_protobuf_OneofDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(36, 72), len); }
@@ -1740,12 +2404,12 @@ UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_DescriptorProt
return (google_protobuf_FieldDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(16, 32), len);
}
UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_DescriptorProto_resize_field(google_protobuf_DescriptorProto *msg, size_t len, upb_arena *arena) {
- return (google_protobuf_FieldDescriptorProto**)_upb_array_resize_accessor(msg, UPB_SIZE(16, 32), len, UPB_TYPE_MESSAGE, arena);
+ return (google_protobuf_FieldDescriptorProto**)_upb_array_resize_accessor2(msg, UPB_SIZE(16, 32), len, UPB_SIZE(2, 3), arena);
}
UPB_INLINE struct google_protobuf_FieldDescriptorProto* google_protobuf_DescriptorProto_add_field(google_protobuf_DescriptorProto *msg, upb_arena *arena) {
struct google_protobuf_FieldDescriptorProto* sub = (struct google_protobuf_FieldDescriptorProto*)_upb_msg_new(&google_protobuf_FieldDescriptorProto_msginit, arena);
- bool ok = _upb_array_append_accessor(
- msg, UPB_SIZE(16, 32), UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, &sub, arena);
+ bool ok = _upb_array_append_accessor2(
+ msg, UPB_SIZE(16, 32), UPB_SIZE(2, 3), &sub, arena);
if (!ok) return NULL;
return sub;
}
@@ -1753,12 +2417,12 @@ UPB_INLINE google_protobuf_DescriptorProto** google_protobuf_DescriptorProto_mut
return (google_protobuf_DescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(20, 40), len);
}
UPB_INLINE google_protobuf_DescriptorProto** google_protobuf_DescriptorProto_resize_nested_type(google_protobuf_DescriptorProto *msg, size_t len, upb_arena *arena) {
- return (google_protobuf_DescriptorProto**)_upb_array_resize_accessor(msg, UPB_SIZE(20, 40), len, UPB_TYPE_MESSAGE, arena);
+ return (google_protobuf_DescriptorProto**)_upb_array_resize_accessor2(msg, UPB_SIZE(20, 40), len, UPB_SIZE(2, 3), arena);
}
UPB_INLINE struct google_protobuf_DescriptorProto* google_protobuf_DescriptorProto_add_nested_type(google_protobuf_DescriptorProto *msg, upb_arena *arena) {
struct google_protobuf_DescriptorProto* sub = (struct google_protobuf_DescriptorProto*)_upb_msg_new(&google_protobuf_DescriptorProto_msginit, arena);
- bool ok = _upb_array_append_accessor(
- msg, UPB_SIZE(20, 40), UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, &sub, arena);
+ bool ok = _upb_array_append_accessor2(
+ msg, UPB_SIZE(20, 40), UPB_SIZE(2, 3), &sub, arena);
if (!ok) return NULL;
return sub;
}
@@ -1766,12 +2430,12 @@ UPB_INLINE google_protobuf_EnumDescriptorProto** google_protobuf_DescriptorProto
return (google_protobuf_EnumDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(24, 48), len);
}
UPB_INLINE google_protobuf_EnumDescriptorProto** google_protobuf_DescriptorProto_resize_enum_type(google_protobuf_DescriptorProto *msg, size_t len, upb_arena *arena) {
- return (google_protobuf_EnumDescriptorProto**)_upb_array_resize_accessor(msg, UPB_SIZE(24, 48), len, UPB_TYPE_MESSAGE, arena);
+ return (google_protobuf_EnumDescriptorProto**)_upb_array_resize_accessor2(msg, UPB_SIZE(24, 48), len, UPB_SIZE(2, 3), arena);
}
UPB_INLINE struct google_protobuf_EnumDescriptorProto* google_protobuf_DescriptorProto_add_enum_type(google_protobuf_DescriptorProto *msg, upb_arena *arena) {
struct google_protobuf_EnumDescriptorProto* sub = (struct google_protobuf_EnumDescriptorProto*)_upb_msg_new(&google_protobuf_EnumDescriptorProto_msginit, arena);
- bool ok = _upb_array_append_accessor(
- msg, UPB_SIZE(24, 48), UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, &sub, arena);
+ bool ok = _upb_array_append_accessor2(
+ msg, UPB_SIZE(24, 48), UPB_SIZE(2, 3), &sub, arena);
if (!ok) return NULL;
return sub;
}
@@ -1779,12 +2443,12 @@ UPB_INLINE google_protobuf_DescriptorProto_ExtensionRange** google_protobuf_Desc
return (google_protobuf_DescriptorProto_ExtensionRange**)_upb_array_mutable_accessor(msg, UPB_SIZE(28, 56), len);
}
UPB_INLINE google_protobuf_DescriptorProto_ExtensionRange** google_protobuf_DescriptorProto_resize_extension_range(google_protobuf_DescriptorProto *msg, size_t len, upb_arena *arena) {
- return (google_protobuf_DescriptorProto_ExtensionRange**)_upb_array_resize_accessor(msg, UPB_SIZE(28, 56), len, UPB_TYPE_MESSAGE, arena);
+ return (google_protobuf_DescriptorProto_ExtensionRange**)_upb_array_resize_accessor2(msg, UPB_SIZE(28, 56), len, UPB_SIZE(2, 3), arena);
}
UPB_INLINE struct google_protobuf_DescriptorProto_ExtensionRange* google_protobuf_DescriptorProto_add_extension_range(google_protobuf_DescriptorProto *msg, upb_arena *arena) {
struct google_protobuf_DescriptorProto_ExtensionRange* sub = (struct google_protobuf_DescriptorProto_ExtensionRange*)_upb_msg_new(&google_protobuf_DescriptorProto_ExtensionRange_msginit, arena);
- bool ok = _upb_array_append_accessor(
- msg, UPB_SIZE(28, 56), UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, &sub, arena);
+ bool ok = _upb_array_append_accessor2(
+ msg, UPB_SIZE(28, 56), UPB_SIZE(2, 3), &sub, arena);
if (!ok) return NULL;
return sub;
}
@@ -1792,12 +2456,12 @@ UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_DescriptorProt
return (google_protobuf_FieldDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(32, 64), len);
}
UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_DescriptorProto_resize_extension(google_protobuf_DescriptorProto *msg, size_t len, upb_arena *arena) {
- return (google_protobuf_FieldDescriptorProto**)_upb_array_resize_accessor(msg, UPB_SIZE(32, 64), len, UPB_TYPE_MESSAGE, arena);
+ return (google_protobuf_FieldDescriptorProto**)_upb_array_resize_accessor2(msg, UPB_SIZE(32, 64), len, UPB_SIZE(2, 3), arena);
}
UPB_INLINE struct google_protobuf_FieldDescriptorProto* google_protobuf_DescriptorProto_add_extension(google_protobuf_DescriptorProto *msg, upb_arena *arena) {
struct google_protobuf_FieldDescriptorProto* sub = (struct google_protobuf_FieldDescriptorProto*)_upb_msg_new(&google_protobuf_FieldDescriptorProto_msginit, arena);
- bool ok = _upb_array_append_accessor(
- msg, UPB_SIZE(32, 64), UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, &sub, arena);
+ bool ok = _upb_array_append_accessor2(
+ msg, UPB_SIZE(32, 64), UPB_SIZE(2, 3), &sub, arena);
if (!ok) return NULL;
return sub;
}
@@ -1818,12 +2482,12 @@ UPB_INLINE google_protobuf_OneofDescriptorProto** google_protobuf_DescriptorProt
return (google_protobuf_OneofDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(36, 72), len);
}
UPB_INLINE google_protobuf_OneofDescriptorProto** google_protobuf_DescriptorProto_resize_oneof_decl(google_protobuf_DescriptorProto *msg, size_t len, upb_arena *arena) {
- return (google_protobuf_OneofDescriptorProto**)_upb_array_resize_accessor(msg, UPB_SIZE(36, 72), len, UPB_TYPE_MESSAGE, arena);
+ return (google_protobuf_OneofDescriptorProto**)_upb_array_resize_accessor2(msg, UPB_SIZE(36, 72), len, UPB_SIZE(2, 3), arena);
}
UPB_INLINE struct google_protobuf_OneofDescriptorProto* google_protobuf_DescriptorProto_add_oneof_decl(google_protobuf_DescriptorProto *msg, upb_arena *arena) {
struct google_protobuf_OneofDescriptorProto* sub = (struct google_protobuf_OneofDescriptorProto*)_upb_msg_new(&google_protobuf_OneofDescriptorProto_msginit, arena);
- bool ok = _upb_array_append_accessor(
- msg, UPB_SIZE(36, 72), UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, &sub, arena);
+ bool ok = _upb_array_append_accessor2(
+ msg, UPB_SIZE(36, 72), UPB_SIZE(2, 3), &sub, arena);
if (!ok) return NULL;
return sub;
}
@@ -1831,12 +2495,12 @@ UPB_INLINE google_protobuf_DescriptorProto_ReservedRange** google_protobuf_Descr
return (google_protobuf_DescriptorProto_ReservedRange**)_upb_array_mutable_accessor(msg, UPB_SIZE(40, 80), len);
}
UPB_INLINE google_protobuf_DescriptorProto_ReservedRange** google_protobuf_DescriptorProto_resize_reserved_range(google_protobuf_DescriptorProto *msg, size_t len, upb_arena *arena) {
- return (google_protobuf_DescriptorProto_ReservedRange**)_upb_array_resize_accessor(msg, UPB_SIZE(40, 80), len, UPB_TYPE_MESSAGE, arena);
+ return (google_protobuf_DescriptorProto_ReservedRange**)_upb_array_resize_accessor2(msg, UPB_SIZE(40, 80), len, UPB_SIZE(2, 3), arena);
}
UPB_INLINE struct google_protobuf_DescriptorProto_ReservedRange* google_protobuf_DescriptorProto_add_reserved_range(google_protobuf_DescriptorProto *msg, upb_arena *arena) {
struct google_protobuf_DescriptorProto_ReservedRange* sub = (struct google_protobuf_DescriptorProto_ReservedRange*)_upb_msg_new(&google_protobuf_DescriptorProto_ReservedRange_msginit, arena);
- bool ok = _upb_array_append_accessor(
- msg, UPB_SIZE(40, 80), UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, &sub, arena);
+ bool ok = _upb_array_append_accessor2(
+ msg, UPB_SIZE(40, 80), UPB_SIZE(2, 3), &sub, arena);
if (!ok) return NULL;
return sub;
}
@@ -1844,10 +2508,10 @@ UPB_INLINE upb_strview* google_protobuf_DescriptorProto_mutable_reserved_name(go
return (upb_strview*)_upb_array_mutable_accessor(msg, UPB_SIZE(44, 88), len);
}
UPB_INLINE upb_strview* google_protobuf_DescriptorProto_resize_reserved_name(google_protobuf_DescriptorProto *msg, size_t len, upb_arena *arena) {
- return (upb_strview*)_upb_array_resize_accessor(msg, UPB_SIZE(44, 88), len, UPB_TYPE_STRING, arena);
+ return (upb_strview*)_upb_array_resize_accessor2(msg, UPB_SIZE(44, 88), len, UPB_SIZE(3, 4), arena);
}
UPB_INLINE bool google_protobuf_DescriptorProto_add_reserved_name(google_protobuf_DescriptorProto *msg, upb_strview val, upb_arena *arena) {
- return _upb_array_append_accessor(msg, UPB_SIZE(44, 88), UPB_SIZE(8, 16), UPB_TYPE_STRING, &val,
+ return _upb_array_append_accessor2(msg, UPB_SIZE(44, 88), UPB_SIZE(3, 4), &val,
arena);
}
@@ -1861,15 +2525,21 @@ UPB_INLINE google_protobuf_DescriptorProto_ExtensionRange *google_protobuf_Descr
google_protobuf_DescriptorProto_ExtensionRange *ret = google_protobuf_DescriptorProto_ExtensionRange_new(arena);
return (ret && upb_decode(buf, size, ret, &google_protobuf_DescriptorProto_ExtensionRange_msginit, arena)) ? ret : NULL;
}
+UPB_INLINE google_protobuf_DescriptorProto_ExtensionRange *google_protobuf_DescriptorProto_ExtensionRange_parse_ex(const char *buf, size_t size,
+ upb_arena *arena, int options) {
+ google_protobuf_DescriptorProto_ExtensionRange *ret = google_protobuf_DescriptorProto_ExtensionRange_new(arena);
+ return (ret && _upb_decode(buf, size, ret, &google_protobuf_DescriptorProto_ExtensionRange_msginit, arena, options))
+ ? ret : NULL;
+}
UPB_INLINE char *google_protobuf_DescriptorProto_ExtensionRange_serialize(const google_protobuf_DescriptorProto_ExtensionRange *msg, upb_arena *arena, size_t *len) {
return upb_encode(msg, &google_protobuf_DescriptorProto_ExtensionRange_msginit, arena, len);
}
-UPB_INLINE bool google_protobuf_DescriptorProto_ExtensionRange_has_start(const google_protobuf_DescriptorProto_ExtensionRange *msg) { return _upb_has_field(msg, 1); }
+UPB_INLINE bool google_protobuf_DescriptorProto_ExtensionRange_has_start(const google_protobuf_DescriptorProto_ExtensionRange *msg) { return _upb_hasbit(msg, 1); }
UPB_INLINE int32_t google_protobuf_DescriptorProto_ExtensionRange_start(const google_protobuf_DescriptorProto_ExtensionRange *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t); }
-UPB_INLINE bool google_protobuf_DescriptorProto_ExtensionRange_has_end(const google_protobuf_DescriptorProto_ExtensionRange *msg) { return _upb_has_field(msg, 2); }
+UPB_INLINE bool google_protobuf_DescriptorProto_ExtensionRange_has_end(const google_protobuf_DescriptorProto_ExtensionRange *msg) { return _upb_hasbit(msg, 2); }
UPB_INLINE int32_t google_protobuf_DescriptorProto_ExtensionRange_end(const google_protobuf_DescriptorProto_ExtensionRange *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t); }
-UPB_INLINE bool google_protobuf_DescriptorProto_ExtensionRange_has_options(const google_protobuf_DescriptorProto_ExtensionRange *msg) { return _upb_has_field(msg, 3); }
+UPB_INLINE bool google_protobuf_DescriptorProto_ExtensionRange_has_options(const google_protobuf_DescriptorProto_ExtensionRange *msg) { return _upb_hasbit(msg, 3); }
UPB_INLINE const google_protobuf_ExtensionRangeOptions* google_protobuf_DescriptorProto_ExtensionRange_options(const google_protobuf_DescriptorProto_ExtensionRange *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 16), const google_protobuf_ExtensionRangeOptions*); }
UPB_INLINE void google_protobuf_DescriptorProto_ExtensionRange_set_start(google_protobuf_DescriptorProto_ExtensionRange *msg, int32_t value) {
@@ -1904,13 +2574,19 @@ UPB_INLINE google_protobuf_DescriptorProto_ReservedRange *google_protobuf_Descri
google_protobuf_DescriptorProto_ReservedRange *ret = google_protobuf_DescriptorProto_ReservedRange_new(arena);
return (ret && upb_decode(buf, size, ret, &google_protobuf_DescriptorProto_ReservedRange_msginit, arena)) ? ret : NULL;
}
+UPB_INLINE google_protobuf_DescriptorProto_ReservedRange *google_protobuf_DescriptorProto_ReservedRange_parse_ex(const char *buf, size_t size,
+ upb_arena *arena, int options) {
+ google_protobuf_DescriptorProto_ReservedRange *ret = google_protobuf_DescriptorProto_ReservedRange_new(arena);
+ return (ret && _upb_decode(buf, size, ret, &google_protobuf_DescriptorProto_ReservedRange_msginit, arena, options))
+ ? ret : NULL;
+}
UPB_INLINE char *google_protobuf_DescriptorProto_ReservedRange_serialize(const google_protobuf_DescriptorProto_ReservedRange *msg, upb_arena *arena, size_t *len) {
return upb_encode(msg, &google_protobuf_DescriptorProto_ReservedRange_msginit, arena, len);
}
-UPB_INLINE bool google_protobuf_DescriptorProto_ReservedRange_has_start(const google_protobuf_DescriptorProto_ReservedRange *msg) { return _upb_has_field(msg, 1); }
+UPB_INLINE bool google_protobuf_DescriptorProto_ReservedRange_has_start(const google_protobuf_DescriptorProto_ReservedRange *msg) { return _upb_hasbit(msg, 1); }
UPB_INLINE int32_t google_protobuf_DescriptorProto_ReservedRange_start(const google_protobuf_DescriptorProto_ReservedRange *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t); }
-UPB_INLINE bool google_protobuf_DescriptorProto_ReservedRange_has_end(const google_protobuf_DescriptorProto_ReservedRange *msg) { return _upb_has_field(msg, 2); }
+UPB_INLINE bool google_protobuf_DescriptorProto_ReservedRange_has_end(const google_protobuf_DescriptorProto_ReservedRange *msg) { return _upb_hasbit(msg, 2); }
UPB_INLINE int32_t google_protobuf_DescriptorProto_ReservedRange_end(const google_protobuf_DescriptorProto_ReservedRange *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t); }
UPB_INLINE void google_protobuf_DescriptorProto_ReservedRange_set_start(google_protobuf_DescriptorProto_ReservedRange *msg, int32_t value) {
@@ -1932,7 +2608,13 @@ UPB_INLINE google_protobuf_ExtensionRangeOptions *google_protobuf_ExtensionRange
google_protobuf_ExtensionRangeOptions *ret = google_protobuf_ExtensionRangeOptions_new(arena);
return (ret && upb_decode(buf, size, ret, &google_protobuf_ExtensionRangeOptions_msginit, arena)) ? ret : NULL;
}
-UPB_INLINE char *google_protobuf_ExtensionRangeOptions_serialize(const google_protobuf_ExtensionRangeOptions *msg, upb_arena *arena, size_t *len) {
+UPB_INLINE google_protobuf_ExtensionRangeOptions *google_protobuf_ExtensionRangeOptions_parse_ex(const char *buf, size_t size,
+ upb_arena *arena, int options) {
+ google_protobuf_ExtensionRangeOptions *ret = google_protobuf_ExtensionRangeOptions_new(arena);
+ return (ret && _upb_decode(buf, size, ret, &google_protobuf_ExtensionRangeOptions_msginit, arena, options))
+ ? ret : NULL;
+}
+UPB_INLINE char *google_protobuf_ExtensionRangeOptions_serialize(const google_protobuf_ExtensionRangeOptions *msg, upb_arena *arena, size_t *len) {
return upb_encode(msg, &google_protobuf_ExtensionRangeOptions_msginit, arena, len);
}
@@ -1943,12 +2625,12 @@ UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_ExtensionRangeO
return (google_protobuf_UninterpretedOption**)_upb_array_mutable_accessor(msg, UPB_SIZE(0, 0), len);
}
UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_ExtensionRangeOptions_resize_uninterpreted_option(google_protobuf_ExtensionRangeOptions *msg, size_t len, upb_arena *arena) {
- return (google_protobuf_UninterpretedOption**)_upb_array_resize_accessor(msg, UPB_SIZE(0, 0), len, UPB_TYPE_MESSAGE, arena);
+ return (google_protobuf_UninterpretedOption**)_upb_array_resize_accessor2(msg, UPB_SIZE(0, 0), len, UPB_SIZE(2, 3), arena);
}
UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_ExtensionRangeOptions_add_uninterpreted_option(google_protobuf_ExtensionRangeOptions *msg, upb_arena *arena) {
struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_msg_new(&google_protobuf_UninterpretedOption_msginit, arena);
- bool ok = _upb_array_append_accessor(
- msg, UPB_SIZE(0, 0), UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, &sub, arena);
+ bool ok = _upb_array_append_accessor2(
+ msg, UPB_SIZE(0, 0), UPB_SIZE(2, 3), &sub, arena);
if (!ok) return NULL;
return sub;
}
@@ -1963,64 +2645,70 @@ UPB_INLINE google_protobuf_FieldDescriptorProto *google_protobuf_FieldDescriptor
google_protobuf_FieldDescriptorProto *ret = google_protobuf_FieldDescriptorProto_new(arena);
return (ret && upb_decode(buf, size, ret, &google_protobuf_FieldDescriptorProto_msginit, arena)) ? ret : NULL;
}
+UPB_INLINE google_protobuf_FieldDescriptorProto *google_protobuf_FieldDescriptorProto_parse_ex(const char *buf, size_t size,
+ upb_arena *arena, int options) {
+ google_protobuf_FieldDescriptorProto *ret = google_protobuf_FieldDescriptorProto_new(arena);
+ return (ret && _upb_decode(buf, size, ret, &google_protobuf_FieldDescriptorProto_msginit, arena, options))
+ ? ret : NULL;
+}
UPB_INLINE char *google_protobuf_FieldDescriptorProto_serialize(const google_protobuf_FieldDescriptorProto *msg, upb_arena *arena, size_t *len) {
return upb_encode(msg, &google_protobuf_FieldDescriptorProto_msginit, arena, len);
}
-UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_name(const google_protobuf_FieldDescriptorProto *msg) { return _upb_has_field(msg, 6); }
-UPB_INLINE upb_strview google_protobuf_FieldDescriptorProto_name(const google_protobuf_FieldDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(36, 40), upb_strview); }
-UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_extendee(const google_protobuf_FieldDescriptorProto *msg) { return _upb_has_field(msg, 7); }
-UPB_INLINE upb_strview google_protobuf_FieldDescriptorProto_extendee(const google_protobuf_FieldDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(44, 56), upb_strview); }
-UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_number(const google_protobuf_FieldDescriptorProto *msg) { return _upb_has_field(msg, 3); }
-UPB_INLINE int32_t google_protobuf_FieldDescriptorProto_number(const google_protobuf_FieldDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(24, 24), int32_t); }
-UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_label(const google_protobuf_FieldDescriptorProto *msg) { return _upb_has_field(msg, 1); }
-UPB_INLINE int32_t google_protobuf_FieldDescriptorProto_label(const google_protobuf_FieldDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t); }
-UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_type(const google_protobuf_FieldDescriptorProto *msg) { return _upb_has_field(msg, 2); }
-UPB_INLINE int32_t google_protobuf_FieldDescriptorProto_type(const google_protobuf_FieldDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(16, 16), int32_t); }
-UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_type_name(const google_protobuf_FieldDescriptorProto *msg) { return _upb_has_field(msg, 8); }
-UPB_INLINE upb_strview google_protobuf_FieldDescriptorProto_type_name(const google_protobuf_FieldDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(52, 72), upb_strview); }
-UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_default_value(const google_protobuf_FieldDescriptorProto *msg) { return _upb_has_field(msg, 9); }
-UPB_INLINE upb_strview google_protobuf_FieldDescriptorProto_default_value(const google_protobuf_FieldDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(60, 88), upb_strview); }
-UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_options(const google_protobuf_FieldDescriptorProto *msg) { return _upb_has_field(msg, 11); }
-UPB_INLINE const google_protobuf_FieldOptions* google_protobuf_FieldDescriptorProto_options(const google_protobuf_FieldDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(76, 120), const google_protobuf_FieldOptions*); }
-UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_oneof_index(const google_protobuf_FieldDescriptorProto *msg) { return _upb_has_field(msg, 4); }
-UPB_INLINE int32_t google_protobuf_FieldDescriptorProto_oneof_index(const google_protobuf_FieldDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(28, 28), int32_t); }
-UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_json_name(const google_protobuf_FieldDescriptorProto *msg) { return _upb_has_field(msg, 10); }
-UPB_INLINE upb_strview google_protobuf_FieldDescriptorProto_json_name(const google_protobuf_FieldDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(68, 104), upb_strview); }
-UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_proto3_optional(const google_protobuf_FieldDescriptorProto *msg) { return _upb_has_field(msg, 5); }
-UPB_INLINE bool google_protobuf_FieldDescriptorProto_proto3_optional(const google_protobuf_FieldDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(32, 32), bool); }
+UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_name(const google_protobuf_FieldDescriptorProto *msg) { return _upb_hasbit(msg, 1); }
+UPB_INLINE upb_strview google_protobuf_FieldDescriptorProto_name(const google_protobuf_FieldDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(24, 24), upb_strview); }
+UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_extendee(const google_protobuf_FieldDescriptorProto *msg) { return _upb_hasbit(msg, 2); }
+UPB_INLINE upb_strview google_protobuf_FieldDescriptorProto_extendee(const google_protobuf_FieldDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(32, 40), upb_strview); }
+UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_number(const google_protobuf_FieldDescriptorProto *msg) { return _upb_hasbit(msg, 3); }
+UPB_INLINE int32_t google_protobuf_FieldDescriptorProto_number(const google_protobuf_FieldDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 12), int32_t); }
+UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_label(const google_protobuf_FieldDescriptorProto *msg) { return _upb_hasbit(msg, 4); }
+UPB_INLINE int32_t google_protobuf_FieldDescriptorProto_label(const google_protobuf_FieldDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t); }
+UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_type(const google_protobuf_FieldDescriptorProto *msg) { return _upb_hasbit(msg, 5); }
+UPB_INLINE int32_t google_protobuf_FieldDescriptorProto_type(const google_protobuf_FieldDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t); }
+UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_type_name(const google_protobuf_FieldDescriptorProto *msg) { return _upb_hasbit(msg, 6); }
+UPB_INLINE upb_strview google_protobuf_FieldDescriptorProto_type_name(const google_protobuf_FieldDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(40, 56), upb_strview); }
+UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_default_value(const google_protobuf_FieldDescriptorProto *msg) { return _upb_hasbit(msg, 7); }
+UPB_INLINE upb_strview google_protobuf_FieldDescriptorProto_default_value(const google_protobuf_FieldDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(48, 72), upb_strview); }
+UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_options(const google_protobuf_FieldDescriptorProto *msg) { return _upb_hasbit(msg, 8); }
+UPB_INLINE const google_protobuf_FieldOptions* google_protobuf_FieldDescriptorProto_options(const google_protobuf_FieldDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(64, 104), const google_protobuf_FieldOptions*); }
+UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_oneof_index(const google_protobuf_FieldDescriptorProto *msg) { return _upb_hasbit(msg, 9); }
+UPB_INLINE int32_t google_protobuf_FieldDescriptorProto_oneof_index(const google_protobuf_FieldDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(16, 16), int32_t); }
+UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_json_name(const google_protobuf_FieldDescriptorProto *msg) { return _upb_hasbit(msg, 10); }
+UPB_INLINE upb_strview google_protobuf_FieldDescriptorProto_json_name(const google_protobuf_FieldDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(56, 88), upb_strview); }
+UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_proto3_optional(const google_protobuf_FieldDescriptorProto *msg) { return _upb_hasbit(msg, 11); }
+UPB_INLINE bool google_protobuf_FieldDescriptorProto_proto3_optional(const google_protobuf_FieldDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(20, 20), bool); }
UPB_INLINE void google_protobuf_FieldDescriptorProto_set_name(google_protobuf_FieldDescriptorProto *msg, upb_strview value) {
- _upb_sethas(msg, 6);
- *UPB_PTR_AT(msg, UPB_SIZE(36, 40), upb_strview) = value;
+ _upb_sethas(msg, 1);
+ *UPB_PTR_AT(msg, UPB_SIZE(24, 24), upb_strview) = value;
}
UPB_INLINE void google_protobuf_FieldDescriptorProto_set_extendee(google_protobuf_FieldDescriptorProto *msg, upb_strview value) {
- _upb_sethas(msg, 7);
- *UPB_PTR_AT(msg, UPB_SIZE(44, 56), upb_strview) = value;
+ _upb_sethas(msg, 2);
+ *UPB_PTR_AT(msg, UPB_SIZE(32, 40), upb_strview) = value;
}
UPB_INLINE void google_protobuf_FieldDescriptorProto_set_number(google_protobuf_FieldDescriptorProto *msg, int32_t value) {
_upb_sethas(msg, 3);
- *UPB_PTR_AT(msg, UPB_SIZE(24, 24), int32_t) = value;
+ *UPB_PTR_AT(msg, UPB_SIZE(12, 12), int32_t) = value;
}
UPB_INLINE void google_protobuf_FieldDescriptorProto_set_label(google_protobuf_FieldDescriptorProto *msg, int32_t value) {
- _upb_sethas(msg, 1);
- *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t) = value;
+ _upb_sethas(msg, 4);
+ *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = value;
}
UPB_INLINE void google_protobuf_FieldDescriptorProto_set_type(google_protobuf_FieldDescriptorProto *msg, int32_t value) {
- _upb_sethas(msg, 2);
- *UPB_PTR_AT(msg, UPB_SIZE(16, 16), int32_t) = value;
+ _upb_sethas(msg, 5);
+ *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t) = value;
}
UPB_INLINE void google_protobuf_FieldDescriptorProto_set_type_name(google_protobuf_FieldDescriptorProto *msg, upb_strview value) {
- _upb_sethas(msg, 8);
- *UPB_PTR_AT(msg, UPB_SIZE(52, 72), upb_strview) = value;
+ _upb_sethas(msg, 6);
+ *UPB_PTR_AT(msg, UPB_SIZE(40, 56), upb_strview) = value;
}
UPB_INLINE void google_protobuf_FieldDescriptorProto_set_default_value(google_protobuf_FieldDescriptorProto *msg, upb_strview value) {
- _upb_sethas(msg, 9);
- *UPB_PTR_AT(msg, UPB_SIZE(60, 88), upb_strview) = value;
+ _upb_sethas(msg, 7);
+ *UPB_PTR_AT(msg, UPB_SIZE(48, 72), upb_strview) = value;
}
UPB_INLINE void google_protobuf_FieldDescriptorProto_set_options(google_protobuf_FieldDescriptorProto *msg, google_protobuf_FieldOptions* value) {
- _upb_sethas(msg, 11);
- *UPB_PTR_AT(msg, UPB_SIZE(76, 120), google_protobuf_FieldOptions*) = value;
+ _upb_sethas(msg, 8);
+ *UPB_PTR_AT(msg, UPB_SIZE(64, 104), google_protobuf_FieldOptions*) = value;
}
UPB_INLINE struct google_protobuf_FieldOptions* google_protobuf_FieldDescriptorProto_mutable_options(google_protobuf_FieldDescriptorProto *msg, upb_arena *arena) {
struct google_protobuf_FieldOptions* sub = (struct google_protobuf_FieldOptions*)google_protobuf_FieldDescriptorProto_options(msg);
@@ -2032,16 +2720,16 @@ UPB_INLINE struct google_protobuf_FieldOptions* google_protobuf_FieldDescriptorP
return sub;
}
UPB_INLINE void google_protobuf_FieldDescriptorProto_set_oneof_index(google_protobuf_FieldDescriptorProto *msg, int32_t value) {
- _upb_sethas(msg, 4);
- *UPB_PTR_AT(msg, UPB_SIZE(28, 28), int32_t) = value;
+ _upb_sethas(msg, 9);
+ *UPB_PTR_AT(msg, UPB_SIZE(16, 16), int32_t) = value;
}
UPB_INLINE void google_protobuf_FieldDescriptorProto_set_json_name(google_protobuf_FieldDescriptorProto *msg, upb_strview value) {
_upb_sethas(msg, 10);
- *UPB_PTR_AT(msg, UPB_SIZE(68, 104), upb_strview) = value;
+ *UPB_PTR_AT(msg, UPB_SIZE(56, 88), upb_strview) = value;
}
UPB_INLINE void google_protobuf_FieldDescriptorProto_set_proto3_optional(google_protobuf_FieldDescriptorProto *msg, bool value) {
- _upb_sethas(msg, 5);
- *UPB_PTR_AT(msg, UPB_SIZE(32, 32), bool) = value;
+ _upb_sethas(msg, 11);
+ *UPB_PTR_AT(msg, UPB_SIZE(20, 20), bool) = value;
}
/* google.protobuf.OneofDescriptorProto */
@@ -2054,13 +2742,19 @@ UPB_INLINE google_protobuf_OneofDescriptorProto *google_protobuf_OneofDescriptor
google_protobuf_OneofDescriptorProto *ret = google_protobuf_OneofDescriptorProto_new(arena);
return (ret && upb_decode(buf, size, ret, &google_protobuf_OneofDescriptorProto_msginit, arena)) ? ret : NULL;
}
+UPB_INLINE google_protobuf_OneofDescriptorProto *google_protobuf_OneofDescriptorProto_parse_ex(const char *buf, size_t size,
+ upb_arena *arena, int options) {
+ google_protobuf_OneofDescriptorProto *ret = google_protobuf_OneofDescriptorProto_new(arena);
+ return (ret && _upb_decode(buf, size, ret, &google_protobuf_OneofDescriptorProto_msginit, arena, options))
+ ? ret : NULL;
+}
UPB_INLINE char *google_protobuf_OneofDescriptorProto_serialize(const google_protobuf_OneofDescriptorProto *msg, upb_arena *arena, size_t *len) {
return upb_encode(msg, &google_protobuf_OneofDescriptorProto_msginit, arena, len);
}
-UPB_INLINE bool google_protobuf_OneofDescriptorProto_has_name(const google_protobuf_OneofDescriptorProto *msg) { return _upb_has_field(msg, 1); }
+UPB_INLINE bool google_protobuf_OneofDescriptorProto_has_name(const google_protobuf_OneofDescriptorProto *msg) { return _upb_hasbit(msg, 1); }
UPB_INLINE upb_strview google_protobuf_OneofDescriptorProto_name(const google_protobuf_OneofDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview); }
-UPB_INLINE bool google_protobuf_OneofDescriptorProto_has_options(const google_protobuf_OneofDescriptorProto *msg) { return _upb_has_field(msg, 2); }
+UPB_INLINE bool google_protobuf_OneofDescriptorProto_has_options(const google_protobuf_OneofDescriptorProto *msg) { return _upb_hasbit(msg, 2); }
UPB_INLINE const google_protobuf_OneofOptions* google_protobuf_OneofDescriptorProto_options(const google_protobuf_OneofDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), const google_protobuf_OneofOptions*); }
UPB_INLINE void google_protobuf_OneofDescriptorProto_set_name(google_protobuf_OneofDescriptorProto *msg, upb_strview value) {
@@ -2091,15 +2785,21 @@ UPB_INLINE google_protobuf_EnumDescriptorProto *google_protobuf_EnumDescriptorPr
google_protobuf_EnumDescriptorProto *ret = google_protobuf_EnumDescriptorProto_new(arena);
return (ret && upb_decode(buf, size, ret, &google_protobuf_EnumDescriptorProto_msginit, arena)) ? ret : NULL;
}
+UPB_INLINE google_protobuf_EnumDescriptorProto *google_protobuf_EnumDescriptorProto_parse_ex(const char *buf, size_t size,
+ upb_arena *arena, int options) {
+ google_protobuf_EnumDescriptorProto *ret = google_protobuf_EnumDescriptorProto_new(arena);
+ return (ret && _upb_decode(buf, size, ret, &google_protobuf_EnumDescriptorProto_msginit, arena, options))
+ ? ret : NULL;
+}
UPB_INLINE char *google_protobuf_EnumDescriptorProto_serialize(const google_protobuf_EnumDescriptorProto *msg, upb_arena *arena, size_t *len) {
return upb_encode(msg, &google_protobuf_EnumDescriptorProto_msginit, arena, len);
}
-UPB_INLINE bool google_protobuf_EnumDescriptorProto_has_name(const google_protobuf_EnumDescriptorProto *msg) { return _upb_has_field(msg, 1); }
+UPB_INLINE bool google_protobuf_EnumDescriptorProto_has_name(const google_protobuf_EnumDescriptorProto *msg) { return _upb_hasbit(msg, 1); }
UPB_INLINE upb_strview google_protobuf_EnumDescriptorProto_name(const google_protobuf_EnumDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview); }
UPB_INLINE bool google_protobuf_EnumDescriptorProto_has_value(const google_protobuf_EnumDescriptorProto *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(16, 32)); }
UPB_INLINE const google_protobuf_EnumValueDescriptorProto* const* google_protobuf_EnumDescriptorProto_value(const google_protobuf_EnumDescriptorProto *msg, size_t *len) { return (const google_protobuf_EnumValueDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(16, 32), len); }
-UPB_INLINE bool google_protobuf_EnumDescriptorProto_has_options(const google_protobuf_EnumDescriptorProto *msg) { return _upb_has_field(msg, 2); }
+UPB_INLINE bool google_protobuf_EnumDescriptorProto_has_options(const google_protobuf_EnumDescriptorProto *msg) { return _upb_hasbit(msg, 2); }
UPB_INLINE const google_protobuf_EnumOptions* google_protobuf_EnumDescriptorProto_options(const google_protobuf_EnumDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), const google_protobuf_EnumOptions*); }
UPB_INLINE bool google_protobuf_EnumDescriptorProto_has_reserved_range(const google_protobuf_EnumDescriptorProto *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(20, 40)); }
UPB_INLINE const google_protobuf_EnumDescriptorProto_EnumReservedRange* const* google_protobuf_EnumDescriptorProto_reserved_range(const google_protobuf_EnumDescriptorProto *msg, size_t *len) { return (const google_protobuf_EnumDescriptorProto_EnumReservedRange* const*)_upb_array_accessor(msg, UPB_SIZE(20, 40), len); }
@@ -2113,12 +2813,12 @@ UPB_INLINE google_protobuf_EnumValueDescriptorProto** google_protobuf_EnumDescri
return (google_protobuf_EnumValueDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(16, 32), len);
}
UPB_INLINE google_protobuf_EnumValueDescriptorProto** google_protobuf_EnumDescriptorProto_resize_value(google_protobuf_EnumDescriptorProto *msg, size_t len, upb_arena *arena) {
- return (google_protobuf_EnumValueDescriptorProto**)_upb_array_resize_accessor(msg, UPB_SIZE(16, 32), len, UPB_TYPE_MESSAGE, arena);
+ return (google_protobuf_EnumValueDescriptorProto**)_upb_array_resize_accessor2(msg, UPB_SIZE(16, 32), len, UPB_SIZE(2, 3), arena);
}
UPB_INLINE struct google_protobuf_EnumValueDescriptorProto* google_protobuf_EnumDescriptorProto_add_value(google_protobuf_EnumDescriptorProto *msg, upb_arena *arena) {
struct google_protobuf_EnumValueDescriptorProto* sub = (struct google_protobuf_EnumValueDescriptorProto*)_upb_msg_new(&google_protobuf_EnumValueDescriptorProto_msginit, arena);
- bool ok = _upb_array_append_accessor(
- msg, UPB_SIZE(16, 32), UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, &sub, arena);
+ bool ok = _upb_array_append_accessor2(
+ msg, UPB_SIZE(16, 32), UPB_SIZE(2, 3), &sub, arena);
if (!ok) return NULL;
return sub;
}
@@ -2139,12 +2839,12 @@ UPB_INLINE google_protobuf_EnumDescriptorProto_EnumReservedRange** google_protob
return (google_protobuf_EnumDescriptorProto_EnumReservedRange**)_upb_array_mutable_accessor(msg, UPB_SIZE(20, 40), len);
}
UPB_INLINE google_protobuf_EnumDescriptorProto_EnumReservedRange** google_protobuf_EnumDescriptorProto_resize_reserved_range(google_protobuf_EnumDescriptorProto *msg, size_t len, upb_arena *arena) {
- return (google_protobuf_EnumDescriptorProto_EnumReservedRange**)_upb_array_resize_accessor(msg, UPB_SIZE(20, 40), len, UPB_TYPE_MESSAGE, arena);
+ return (google_protobuf_EnumDescriptorProto_EnumReservedRange**)_upb_array_resize_accessor2(msg, UPB_SIZE(20, 40), len, UPB_SIZE(2, 3), arena);
}
UPB_INLINE struct google_protobuf_EnumDescriptorProto_EnumReservedRange* google_protobuf_EnumDescriptorProto_add_reserved_range(google_protobuf_EnumDescriptorProto *msg, upb_arena *arena) {
struct google_protobuf_EnumDescriptorProto_EnumReservedRange* sub = (struct google_protobuf_EnumDescriptorProto_EnumReservedRange*)_upb_msg_new(&google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit, arena);
- bool ok = _upb_array_append_accessor(
- msg, UPB_SIZE(20, 40), UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, &sub, arena);
+ bool ok = _upb_array_append_accessor2(
+ msg, UPB_SIZE(20, 40), UPB_SIZE(2, 3), &sub, arena);
if (!ok) return NULL;
return sub;
}
@@ -2152,10 +2852,10 @@ UPB_INLINE upb_strview* google_protobuf_EnumDescriptorProto_mutable_reserved_nam
return (upb_strview*)_upb_array_mutable_accessor(msg, UPB_SIZE(24, 48), len);
}
UPB_INLINE upb_strview* google_protobuf_EnumDescriptorProto_resize_reserved_name(google_protobuf_EnumDescriptorProto *msg, size_t len, upb_arena *arena) {
- return (upb_strview*)_upb_array_resize_accessor(msg, UPB_SIZE(24, 48), len, UPB_TYPE_STRING, arena);
+ return (upb_strview*)_upb_array_resize_accessor2(msg, UPB_SIZE(24, 48), len, UPB_SIZE(3, 4), arena);
}
UPB_INLINE bool google_protobuf_EnumDescriptorProto_add_reserved_name(google_protobuf_EnumDescriptorProto *msg, upb_strview val, upb_arena *arena) {
- return _upb_array_append_accessor(msg, UPB_SIZE(24, 48), UPB_SIZE(8, 16), UPB_TYPE_STRING, &val,
+ return _upb_array_append_accessor2(msg, UPB_SIZE(24, 48), UPB_SIZE(3, 4), &val,
arena);
}
@@ -2169,13 +2869,19 @@ UPB_INLINE google_protobuf_EnumDescriptorProto_EnumReservedRange *google_protobu
google_protobuf_EnumDescriptorProto_EnumReservedRange *ret = google_protobuf_EnumDescriptorProto_EnumReservedRange_new(arena);
return (ret && upb_decode(buf, size, ret, &google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit, arena)) ? ret : NULL;
}
+UPB_INLINE google_protobuf_EnumDescriptorProto_EnumReservedRange *google_protobuf_EnumDescriptorProto_EnumReservedRange_parse_ex(const char *buf, size_t size,
+ upb_arena *arena, int options) {
+ google_protobuf_EnumDescriptorProto_EnumReservedRange *ret = google_protobuf_EnumDescriptorProto_EnumReservedRange_new(arena);
+ return (ret && _upb_decode(buf, size, ret, &google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit, arena, options))
+ ? ret : NULL;
+}
UPB_INLINE char *google_protobuf_EnumDescriptorProto_EnumReservedRange_serialize(const google_protobuf_EnumDescriptorProto_EnumReservedRange *msg, upb_arena *arena, size_t *len) {
return upb_encode(msg, &google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit, arena, len);
}
-UPB_INLINE bool google_protobuf_EnumDescriptorProto_EnumReservedRange_has_start(const google_protobuf_EnumDescriptorProto_EnumReservedRange *msg) { return _upb_has_field(msg, 1); }
+UPB_INLINE bool google_protobuf_EnumDescriptorProto_EnumReservedRange_has_start(const google_protobuf_EnumDescriptorProto_EnumReservedRange *msg) { return _upb_hasbit(msg, 1); }
UPB_INLINE int32_t google_protobuf_EnumDescriptorProto_EnumReservedRange_start(const google_protobuf_EnumDescriptorProto_EnumReservedRange *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t); }
-UPB_INLINE bool google_protobuf_EnumDescriptorProto_EnumReservedRange_has_end(const google_protobuf_EnumDescriptorProto_EnumReservedRange *msg) { return _upb_has_field(msg, 2); }
+UPB_INLINE bool google_protobuf_EnumDescriptorProto_EnumReservedRange_has_end(const google_protobuf_EnumDescriptorProto_EnumReservedRange *msg) { return _upb_hasbit(msg, 2); }
UPB_INLINE int32_t google_protobuf_EnumDescriptorProto_EnumReservedRange_end(const google_protobuf_EnumDescriptorProto_EnumReservedRange *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t); }
UPB_INLINE void google_protobuf_EnumDescriptorProto_EnumReservedRange_set_start(google_protobuf_EnumDescriptorProto_EnumReservedRange *msg, int32_t value) {
@@ -2197,23 +2903,29 @@ UPB_INLINE google_protobuf_EnumValueDescriptorProto *google_protobuf_EnumValueDe
google_protobuf_EnumValueDescriptorProto *ret = google_protobuf_EnumValueDescriptorProto_new(arena);
return (ret && upb_decode(buf, size, ret, &google_protobuf_EnumValueDescriptorProto_msginit, arena)) ? ret : NULL;
}
+UPB_INLINE google_protobuf_EnumValueDescriptorProto *google_protobuf_EnumValueDescriptorProto_parse_ex(const char *buf, size_t size,
+ upb_arena *arena, int options) {
+ google_protobuf_EnumValueDescriptorProto *ret = google_protobuf_EnumValueDescriptorProto_new(arena);
+ return (ret && _upb_decode(buf, size, ret, &google_protobuf_EnumValueDescriptorProto_msginit, arena, options))
+ ? ret : NULL;
+}
UPB_INLINE char *google_protobuf_EnumValueDescriptorProto_serialize(const google_protobuf_EnumValueDescriptorProto *msg, upb_arena *arena, size_t *len) {
return upb_encode(msg, &google_protobuf_EnumValueDescriptorProto_msginit, arena, len);
}
-UPB_INLINE bool google_protobuf_EnumValueDescriptorProto_has_name(const google_protobuf_EnumValueDescriptorProto *msg) { return _upb_has_field(msg, 2); }
+UPB_INLINE bool google_protobuf_EnumValueDescriptorProto_has_name(const google_protobuf_EnumValueDescriptorProto *msg) { return _upb_hasbit(msg, 1); }
UPB_INLINE upb_strview google_protobuf_EnumValueDescriptorProto_name(const google_protobuf_EnumValueDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), upb_strview); }
-UPB_INLINE bool google_protobuf_EnumValueDescriptorProto_has_number(const google_protobuf_EnumValueDescriptorProto *msg) { return _upb_has_field(msg, 1); }
+UPB_INLINE bool google_protobuf_EnumValueDescriptorProto_has_number(const google_protobuf_EnumValueDescriptorProto *msg) { return _upb_hasbit(msg, 2); }
UPB_INLINE int32_t google_protobuf_EnumValueDescriptorProto_number(const google_protobuf_EnumValueDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t); }
-UPB_INLINE bool google_protobuf_EnumValueDescriptorProto_has_options(const google_protobuf_EnumValueDescriptorProto *msg) { return _upb_has_field(msg, 3); }
+UPB_INLINE bool google_protobuf_EnumValueDescriptorProto_has_options(const google_protobuf_EnumValueDescriptorProto *msg) { return _upb_hasbit(msg, 3); }
UPB_INLINE const google_protobuf_EnumValueOptions* google_protobuf_EnumValueDescriptorProto_options(const google_protobuf_EnumValueDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(16, 24), const google_protobuf_EnumValueOptions*); }
UPB_INLINE void google_protobuf_EnumValueDescriptorProto_set_name(google_protobuf_EnumValueDescriptorProto *msg, upb_strview value) {
- _upb_sethas(msg, 2);
+ _upb_sethas(msg, 1);
*UPB_PTR_AT(msg, UPB_SIZE(8, 8), upb_strview) = value;
}
UPB_INLINE void google_protobuf_EnumValueDescriptorProto_set_number(google_protobuf_EnumValueDescriptorProto *msg, int32_t value) {
- _upb_sethas(msg, 1);
+ _upb_sethas(msg, 2);
*UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = value;
}
UPB_INLINE void google_protobuf_EnumValueDescriptorProto_set_options(google_protobuf_EnumValueDescriptorProto *msg, google_protobuf_EnumValueOptions* value) {
@@ -2240,15 +2952,21 @@ UPB_INLINE google_protobuf_ServiceDescriptorProto *google_protobuf_ServiceDescri
google_protobuf_ServiceDescriptorProto *ret = google_protobuf_ServiceDescriptorProto_new(arena);
return (ret && upb_decode(buf, size, ret, &google_protobuf_ServiceDescriptorProto_msginit, arena)) ? ret : NULL;
}
+UPB_INLINE google_protobuf_ServiceDescriptorProto *google_protobuf_ServiceDescriptorProto_parse_ex(const char *buf, size_t size,
+ upb_arena *arena, int options) {
+ google_protobuf_ServiceDescriptorProto *ret = google_protobuf_ServiceDescriptorProto_new(arena);
+ return (ret && _upb_decode(buf, size, ret, &google_protobuf_ServiceDescriptorProto_msginit, arena, options))
+ ? ret : NULL;
+}
UPB_INLINE char *google_protobuf_ServiceDescriptorProto_serialize(const google_protobuf_ServiceDescriptorProto *msg, upb_arena *arena, size_t *len) {
return upb_encode(msg, &google_protobuf_ServiceDescriptorProto_msginit, arena, len);
}
-UPB_INLINE bool google_protobuf_ServiceDescriptorProto_has_name(const google_protobuf_ServiceDescriptorProto *msg) { return _upb_has_field(msg, 1); }
+UPB_INLINE bool google_protobuf_ServiceDescriptorProto_has_name(const google_protobuf_ServiceDescriptorProto *msg) { return _upb_hasbit(msg, 1); }
UPB_INLINE upb_strview google_protobuf_ServiceDescriptorProto_name(const google_protobuf_ServiceDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview); }
UPB_INLINE bool google_protobuf_ServiceDescriptorProto_has_method(const google_protobuf_ServiceDescriptorProto *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(16, 32)); }
UPB_INLINE const google_protobuf_MethodDescriptorProto* const* google_protobuf_ServiceDescriptorProto_method(const google_protobuf_ServiceDescriptorProto *msg, size_t *len) { return (const google_protobuf_MethodDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(16, 32), len); }
-UPB_INLINE bool google_protobuf_ServiceDescriptorProto_has_options(const google_protobuf_ServiceDescriptorProto *msg) { return _upb_has_field(msg, 2); }
+UPB_INLINE bool google_protobuf_ServiceDescriptorProto_has_options(const google_protobuf_ServiceDescriptorProto *msg) { return _upb_hasbit(msg, 2); }
UPB_INLINE const google_protobuf_ServiceOptions* google_protobuf_ServiceDescriptorProto_options(const google_protobuf_ServiceDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), const google_protobuf_ServiceOptions*); }
UPB_INLINE void google_protobuf_ServiceDescriptorProto_set_name(google_protobuf_ServiceDescriptorProto *msg, upb_strview value) {
@@ -2259,12 +2977,12 @@ UPB_INLINE google_protobuf_MethodDescriptorProto** google_protobuf_ServiceDescri
return (google_protobuf_MethodDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(16, 32), len);
}
UPB_INLINE google_protobuf_MethodDescriptorProto** google_protobuf_ServiceDescriptorProto_resize_method(google_protobuf_ServiceDescriptorProto *msg, size_t len, upb_arena *arena) {
- return (google_protobuf_MethodDescriptorProto**)_upb_array_resize_accessor(msg, UPB_SIZE(16, 32), len, UPB_TYPE_MESSAGE, arena);
+ return (google_protobuf_MethodDescriptorProto**)_upb_array_resize_accessor2(msg, UPB_SIZE(16, 32), len, UPB_SIZE(2, 3), arena);
}
UPB_INLINE struct google_protobuf_MethodDescriptorProto* google_protobuf_ServiceDescriptorProto_add_method(google_protobuf_ServiceDescriptorProto *msg, upb_arena *arena) {
struct google_protobuf_MethodDescriptorProto* sub = (struct google_protobuf_MethodDescriptorProto*)_upb_msg_new(&google_protobuf_MethodDescriptorProto_msginit, arena);
- bool ok = _upb_array_append_accessor(
- msg, UPB_SIZE(16, 32), UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, &sub, arena);
+ bool ok = _upb_array_append_accessor2(
+ msg, UPB_SIZE(16, 32), UPB_SIZE(2, 3), &sub, arena);
if (!ok) return NULL;
return sub;
}
@@ -2292,37 +3010,43 @@ UPB_INLINE google_protobuf_MethodDescriptorProto *google_protobuf_MethodDescript
google_protobuf_MethodDescriptorProto *ret = google_protobuf_MethodDescriptorProto_new(arena);
return (ret && upb_decode(buf, size, ret, &google_protobuf_MethodDescriptorProto_msginit, arena)) ? ret : NULL;
}
+UPB_INLINE google_protobuf_MethodDescriptorProto *google_protobuf_MethodDescriptorProto_parse_ex(const char *buf, size_t size,
+ upb_arena *arena, int options) {
+ google_protobuf_MethodDescriptorProto *ret = google_protobuf_MethodDescriptorProto_new(arena);
+ return (ret && _upb_decode(buf, size, ret, &google_protobuf_MethodDescriptorProto_msginit, arena, options))
+ ? ret : NULL;
+}
UPB_INLINE char *google_protobuf_MethodDescriptorProto_serialize(const google_protobuf_MethodDescriptorProto *msg, upb_arena *arena, size_t *len) {
return upb_encode(msg, &google_protobuf_MethodDescriptorProto_msginit, arena, len);
}
-UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_name(const google_protobuf_MethodDescriptorProto *msg) { return _upb_has_field(msg, 3); }
+UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_name(const google_protobuf_MethodDescriptorProto *msg) { return _upb_hasbit(msg, 1); }
UPB_INLINE upb_strview google_protobuf_MethodDescriptorProto_name(const google_protobuf_MethodDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview); }
-UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_input_type(const google_protobuf_MethodDescriptorProto *msg) { return _upb_has_field(msg, 4); }
+UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_input_type(const google_protobuf_MethodDescriptorProto *msg) { return _upb_hasbit(msg, 2); }
UPB_INLINE upb_strview google_protobuf_MethodDescriptorProto_input_type(const google_protobuf_MethodDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_strview); }
-UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_output_type(const google_protobuf_MethodDescriptorProto *msg) { return _upb_has_field(msg, 5); }
+UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_output_type(const google_protobuf_MethodDescriptorProto *msg) { return _upb_hasbit(msg, 3); }
UPB_INLINE upb_strview google_protobuf_MethodDescriptorProto_output_type(const google_protobuf_MethodDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(20, 40), upb_strview); }
-UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_options(const google_protobuf_MethodDescriptorProto *msg) { return _upb_has_field(msg, 6); }
+UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_options(const google_protobuf_MethodDescriptorProto *msg) { return _upb_hasbit(msg, 4); }
UPB_INLINE const google_protobuf_MethodOptions* google_protobuf_MethodDescriptorProto_options(const google_protobuf_MethodDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(28, 56), const google_protobuf_MethodOptions*); }
-UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_client_streaming(const google_protobuf_MethodDescriptorProto *msg) { return _upb_has_field(msg, 1); }
+UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_client_streaming(const google_protobuf_MethodDescriptorProto *msg) { return _upb_hasbit(msg, 5); }
UPB_INLINE bool google_protobuf_MethodDescriptorProto_client_streaming(const google_protobuf_MethodDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool); }
-UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_server_streaming(const google_protobuf_MethodDescriptorProto *msg) { return _upb_has_field(msg, 2); }
+UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_server_streaming(const google_protobuf_MethodDescriptorProto *msg) { return _upb_hasbit(msg, 6); }
UPB_INLINE bool google_protobuf_MethodDescriptorProto_server_streaming(const google_protobuf_MethodDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(2, 2), bool); }
UPB_INLINE void google_protobuf_MethodDescriptorProto_set_name(google_protobuf_MethodDescriptorProto *msg, upb_strview value) {
- _upb_sethas(msg, 3);
+ _upb_sethas(msg, 1);
*UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview) = value;
}
UPB_INLINE void google_protobuf_MethodDescriptorProto_set_input_type(google_protobuf_MethodDescriptorProto *msg, upb_strview value) {
- _upb_sethas(msg, 4);
+ _upb_sethas(msg, 2);
*UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_strview) = value;
}
UPB_INLINE void google_protobuf_MethodDescriptorProto_set_output_type(google_protobuf_MethodDescriptorProto *msg, upb_strview value) {
- _upb_sethas(msg, 5);
+ _upb_sethas(msg, 3);
*UPB_PTR_AT(msg, UPB_SIZE(20, 40), upb_strview) = value;
}
UPB_INLINE void google_protobuf_MethodDescriptorProto_set_options(google_protobuf_MethodDescriptorProto *msg, google_protobuf_MethodOptions* value) {
- _upb_sethas(msg, 6);
+ _upb_sethas(msg, 4);
*UPB_PTR_AT(msg, UPB_SIZE(28, 56), google_protobuf_MethodOptions*) = value;
}
UPB_INLINE struct google_protobuf_MethodOptions* google_protobuf_MethodDescriptorProto_mutable_options(google_protobuf_MethodDescriptorProto *msg, upb_arena *arena) {
@@ -2335,11 +3059,11 @@ UPB_INLINE struct google_protobuf_MethodOptions* google_protobuf_MethodDescripto
return sub;
}
UPB_INLINE void google_protobuf_MethodDescriptorProto_set_client_streaming(google_protobuf_MethodDescriptorProto *msg, bool value) {
- _upb_sethas(msg, 1);
+ _upb_sethas(msg, 5);
*UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool) = value;
}
UPB_INLINE void google_protobuf_MethodDescriptorProto_set_server_streaming(google_protobuf_MethodDescriptorProto *msg, bool value) {
- _upb_sethas(msg, 2);
+ _upb_sethas(msg, 6);
*UPB_PTR_AT(msg, UPB_SIZE(2, 2), bool) = value;
}
@@ -2353,143 +3077,149 @@ UPB_INLINE google_protobuf_FileOptions *google_protobuf_FileOptions_parse(const
google_protobuf_FileOptions *ret = google_protobuf_FileOptions_new(arena);
return (ret && upb_decode(buf, size, ret, &google_protobuf_FileOptions_msginit, arena)) ? ret : NULL;
}
+UPB_INLINE google_protobuf_FileOptions *google_protobuf_FileOptions_parse_ex(const char *buf, size_t size,
+ upb_arena *arena, int options) {
+ google_protobuf_FileOptions *ret = google_protobuf_FileOptions_new(arena);
+ return (ret && _upb_decode(buf, size, ret, &google_protobuf_FileOptions_msginit, arena, options))
+ ? ret : NULL;
+}
UPB_INLINE char *google_protobuf_FileOptions_serialize(const google_protobuf_FileOptions *msg, upb_arena *arena, size_t *len) {
return upb_encode(msg, &google_protobuf_FileOptions_msginit, arena, len);
}
-UPB_INLINE bool google_protobuf_FileOptions_has_java_package(const google_protobuf_FileOptions *msg) { return _upb_has_field(msg, 11); }
-UPB_INLINE upb_strview google_protobuf_FileOptions_java_package(const google_protobuf_FileOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(28, 32), upb_strview); }
-UPB_INLINE bool google_protobuf_FileOptions_has_java_outer_classname(const google_protobuf_FileOptions *msg) { return _upb_has_field(msg, 12); }
-UPB_INLINE upb_strview google_protobuf_FileOptions_java_outer_classname(const google_protobuf_FileOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(36, 48), upb_strview); }
-UPB_INLINE bool google_protobuf_FileOptions_has_optimize_for(const google_protobuf_FileOptions *msg) { return _upb_has_field(msg, 1); }
-UPB_INLINE int32_t google_protobuf_FileOptions_optimize_for(const google_protobuf_FileOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t); }
-UPB_INLINE bool google_protobuf_FileOptions_has_java_multiple_files(const google_protobuf_FileOptions *msg) { return _upb_has_field(msg, 2); }
-UPB_INLINE bool google_protobuf_FileOptions_java_multiple_files(const google_protobuf_FileOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(16, 16), bool); }
-UPB_INLINE bool google_protobuf_FileOptions_has_go_package(const google_protobuf_FileOptions *msg) { return _upb_has_field(msg, 13); }
-UPB_INLINE upb_strview google_protobuf_FileOptions_go_package(const google_protobuf_FileOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(44, 64), upb_strview); }
-UPB_INLINE bool google_protobuf_FileOptions_has_cc_generic_services(const google_protobuf_FileOptions *msg) { return _upb_has_field(msg, 3); }
-UPB_INLINE bool google_protobuf_FileOptions_cc_generic_services(const google_protobuf_FileOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(17, 17), bool); }
-UPB_INLINE bool google_protobuf_FileOptions_has_java_generic_services(const google_protobuf_FileOptions *msg) { return _upb_has_field(msg, 4); }
-UPB_INLINE bool google_protobuf_FileOptions_java_generic_services(const google_protobuf_FileOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(18, 18), bool); }
-UPB_INLINE bool google_protobuf_FileOptions_has_py_generic_services(const google_protobuf_FileOptions *msg) { return _upb_has_field(msg, 5); }
-UPB_INLINE bool google_protobuf_FileOptions_py_generic_services(const google_protobuf_FileOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(19, 19), bool); }
-UPB_INLINE bool google_protobuf_FileOptions_has_java_generate_equals_and_hash(const google_protobuf_FileOptions *msg) { return _upb_has_field(msg, 6); }
-UPB_INLINE bool google_protobuf_FileOptions_java_generate_equals_and_hash(const google_protobuf_FileOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(20, 20), bool); }
-UPB_INLINE bool google_protobuf_FileOptions_has_deprecated(const google_protobuf_FileOptions *msg) { return _upb_has_field(msg, 7); }
-UPB_INLINE bool google_protobuf_FileOptions_deprecated(const google_protobuf_FileOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(21, 21), bool); }
-UPB_INLINE bool google_protobuf_FileOptions_has_java_string_check_utf8(const google_protobuf_FileOptions *msg) { return _upb_has_field(msg, 8); }
-UPB_INLINE bool google_protobuf_FileOptions_java_string_check_utf8(const google_protobuf_FileOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(22, 22), bool); }
-UPB_INLINE bool google_protobuf_FileOptions_has_cc_enable_arenas(const google_protobuf_FileOptions *msg) { return _upb_has_field(msg, 9); }
-UPB_INLINE bool google_protobuf_FileOptions_cc_enable_arenas(const google_protobuf_FileOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(23, 23), bool); }
-UPB_INLINE bool google_protobuf_FileOptions_has_objc_class_prefix(const google_protobuf_FileOptions *msg) { return _upb_has_field(msg, 14); }
-UPB_INLINE upb_strview google_protobuf_FileOptions_objc_class_prefix(const google_protobuf_FileOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(52, 80), upb_strview); }
-UPB_INLINE bool google_protobuf_FileOptions_has_csharp_namespace(const google_protobuf_FileOptions *msg) { return _upb_has_field(msg, 15); }
-UPB_INLINE upb_strview google_protobuf_FileOptions_csharp_namespace(const google_protobuf_FileOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(60, 96), upb_strview); }
-UPB_INLINE bool google_protobuf_FileOptions_has_swift_prefix(const google_protobuf_FileOptions *msg) { return _upb_has_field(msg, 16); }
-UPB_INLINE upb_strview google_protobuf_FileOptions_swift_prefix(const google_protobuf_FileOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(68, 112), upb_strview); }
-UPB_INLINE bool google_protobuf_FileOptions_has_php_class_prefix(const google_protobuf_FileOptions *msg) { return _upb_has_field(msg, 17); }
-UPB_INLINE upb_strview google_protobuf_FileOptions_php_class_prefix(const google_protobuf_FileOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(76, 128), upb_strview); }
-UPB_INLINE bool google_protobuf_FileOptions_has_php_namespace(const google_protobuf_FileOptions *msg) { return _upb_has_field(msg, 18); }
-UPB_INLINE upb_strview google_protobuf_FileOptions_php_namespace(const google_protobuf_FileOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(84, 144), upb_strview); }
-UPB_INLINE bool google_protobuf_FileOptions_has_php_generic_services(const google_protobuf_FileOptions *msg) { return _upb_has_field(msg, 10); }
-UPB_INLINE bool google_protobuf_FileOptions_php_generic_services(const google_protobuf_FileOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(24, 24), bool); }
-UPB_INLINE bool google_protobuf_FileOptions_has_php_metadata_namespace(const google_protobuf_FileOptions *msg) { return _upb_has_field(msg, 19); }
-UPB_INLINE upb_strview google_protobuf_FileOptions_php_metadata_namespace(const google_protobuf_FileOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(92, 160), upb_strview); }
-UPB_INLINE bool google_protobuf_FileOptions_has_ruby_package(const google_protobuf_FileOptions *msg) { return _upb_has_field(msg, 20); }
-UPB_INLINE upb_strview google_protobuf_FileOptions_ruby_package(const google_protobuf_FileOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(100, 176), upb_strview); }
-UPB_INLINE bool google_protobuf_FileOptions_has_uninterpreted_option(const google_protobuf_FileOptions *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(108, 192)); }
-UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_FileOptions_uninterpreted_option(const google_protobuf_FileOptions *msg, size_t *len) { return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(108, 192), len); }
+UPB_INLINE bool google_protobuf_FileOptions_has_java_package(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 1); }
+UPB_INLINE upb_strview google_protobuf_FileOptions_java_package(const google_protobuf_FileOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(20, 24), upb_strview); }
+UPB_INLINE bool google_protobuf_FileOptions_has_java_outer_classname(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 2); }
+UPB_INLINE upb_strview google_protobuf_FileOptions_java_outer_classname(const google_protobuf_FileOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(28, 40), upb_strview); }
+UPB_INLINE bool google_protobuf_FileOptions_has_optimize_for(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 3); }
+UPB_INLINE int32_t google_protobuf_FileOptions_optimize_for(const google_protobuf_FileOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t); }
+UPB_INLINE bool google_protobuf_FileOptions_has_java_multiple_files(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 4); }
+UPB_INLINE bool google_protobuf_FileOptions_java_multiple_files(const google_protobuf_FileOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), bool); }
+UPB_INLINE bool google_protobuf_FileOptions_has_go_package(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 5); }
+UPB_INLINE upb_strview google_protobuf_FileOptions_go_package(const google_protobuf_FileOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(36, 56), upb_strview); }
+UPB_INLINE bool google_protobuf_FileOptions_has_cc_generic_services(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 6); }
+UPB_INLINE bool google_protobuf_FileOptions_cc_generic_services(const google_protobuf_FileOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(9, 9), bool); }
+UPB_INLINE bool google_protobuf_FileOptions_has_java_generic_services(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 7); }
+UPB_INLINE bool google_protobuf_FileOptions_java_generic_services(const google_protobuf_FileOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(10, 10), bool); }
+UPB_INLINE bool google_protobuf_FileOptions_has_py_generic_services(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 8); }
+UPB_INLINE bool google_protobuf_FileOptions_py_generic_services(const google_protobuf_FileOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(11, 11), bool); }
+UPB_INLINE bool google_protobuf_FileOptions_has_java_generate_equals_and_hash(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 9); }
+UPB_INLINE bool google_protobuf_FileOptions_java_generate_equals_and_hash(const google_protobuf_FileOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 12), bool); }
+UPB_INLINE bool google_protobuf_FileOptions_has_deprecated(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 10); }
+UPB_INLINE bool google_protobuf_FileOptions_deprecated(const google_protobuf_FileOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(13, 13), bool); }
+UPB_INLINE bool google_protobuf_FileOptions_has_java_string_check_utf8(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 11); }
+UPB_INLINE bool google_protobuf_FileOptions_java_string_check_utf8(const google_protobuf_FileOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(14, 14), bool); }
+UPB_INLINE bool google_protobuf_FileOptions_has_cc_enable_arenas(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 12); }
+UPB_INLINE bool google_protobuf_FileOptions_cc_enable_arenas(const google_protobuf_FileOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(15, 15), bool); }
+UPB_INLINE bool google_protobuf_FileOptions_has_objc_class_prefix(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 13); }
+UPB_INLINE upb_strview google_protobuf_FileOptions_objc_class_prefix(const google_protobuf_FileOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(44, 72), upb_strview); }
+UPB_INLINE bool google_protobuf_FileOptions_has_csharp_namespace(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 14); }
+UPB_INLINE upb_strview google_protobuf_FileOptions_csharp_namespace(const google_protobuf_FileOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(52, 88), upb_strview); }
+UPB_INLINE bool google_protobuf_FileOptions_has_swift_prefix(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 15); }
+UPB_INLINE upb_strview google_protobuf_FileOptions_swift_prefix(const google_protobuf_FileOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(60, 104), upb_strview); }
+UPB_INLINE bool google_protobuf_FileOptions_has_php_class_prefix(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 16); }
+UPB_INLINE upb_strview google_protobuf_FileOptions_php_class_prefix(const google_protobuf_FileOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(68, 120), upb_strview); }
+UPB_INLINE bool google_protobuf_FileOptions_has_php_namespace(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 17); }
+UPB_INLINE upb_strview google_protobuf_FileOptions_php_namespace(const google_protobuf_FileOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(76, 136), upb_strview); }
+UPB_INLINE bool google_protobuf_FileOptions_has_php_generic_services(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 18); }
+UPB_INLINE bool google_protobuf_FileOptions_php_generic_services(const google_protobuf_FileOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(16, 16), bool); }
+UPB_INLINE bool google_protobuf_FileOptions_has_php_metadata_namespace(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 19); }
+UPB_INLINE upb_strview google_protobuf_FileOptions_php_metadata_namespace(const google_protobuf_FileOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(84, 152), upb_strview); }
+UPB_INLINE bool google_protobuf_FileOptions_has_ruby_package(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 20); }
+UPB_INLINE upb_strview google_protobuf_FileOptions_ruby_package(const google_protobuf_FileOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(92, 168), upb_strview); }
+UPB_INLINE bool google_protobuf_FileOptions_has_uninterpreted_option(const google_protobuf_FileOptions *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(100, 184)); }
+UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_FileOptions_uninterpreted_option(const google_protobuf_FileOptions *msg, size_t *len) { return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(100, 184), len); }
UPB_INLINE void google_protobuf_FileOptions_set_java_package(google_protobuf_FileOptions *msg, upb_strview value) {
- _upb_sethas(msg, 11);
- *UPB_PTR_AT(msg, UPB_SIZE(28, 32), upb_strview) = value;
+ _upb_sethas(msg, 1);
+ *UPB_PTR_AT(msg, UPB_SIZE(20, 24), upb_strview) = value;
}
UPB_INLINE void google_protobuf_FileOptions_set_java_outer_classname(google_protobuf_FileOptions *msg, upb_strview value) {
- _upb_sethas(msg, 12);
- *UPB_PTR_AT(msg, UPB_SIZE(36, 48), upb_strview) = value;
+ _upb_sethas(msg, 2);
+ *UPB_PTR_AT(msg, UPB_SIZE(28, 40), upb_strview) = value;
}
UPB_INLINE void google_protobuf_FileOptions_set_optimize_for(google_protobuf_FileOptions *msg, int32_t value) {
- _upb_sethas(msg, 1);
- *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t) = value;
+ _upb_sethas(msg, 3);
+ *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = value;
}
UPB_INLINE void google_protobuf_FileOptions_set_java_multiple_files(google_protobuf_FileOptions *msg, bool value) {
- _upb_sethas(msg, 2);
- *UPB_PTR_AT(msg, UPB_SIZE(16, 16), bool) = value;
+ _upb_sethas(msg, 4);
+ *UPB_PTR_AT(msg, UPB_SIZE(8, 8), bool) = value;
}
UPB_INLINE void google_protobuf_FileOptions_set_go_package(google_protobuf_FileOptions *msg, upb_strview value) {
- _upb_sethas(msg, 13);
- *UPB_PTR_AT(msg, UPB_SIZE(44, 64), upb_strview) = value;
+ _upb_sethas(msg, 5);
+ *UPB_PTR_AT(msg, UPB_SIZE(36, 56), upb_strview) = value;
}
UPB_INLINE void google_protobuf_FileOptions_set_cc_generic_services(google_protobuf_FileOptions *msg, bool value) {
- _upb_sethas(msg, 3);
- *UPB_PTR_AT(msg, UPB_SIZE(17, 17), bool) = value;
+ _upb_sethas(msg, 6);
+ *UPB_PTR_AT(msg, UPB_SIZE(9, 9), bool) = value;
}
UPB_INLINE void google_protobuf_FileOptions_set_java_generic_services(google_protobuf_FileOptions *msg, bool value) {
- _upb_sethas(msg, 4);
- *UPB_PTR_AT(msg, UPB_SIZE(18, 18), bool) = value;
+ _upb_sethas(msg, 7);
+ *UPB_PTR_AT(msg, UPB_SIZE(10, 10), bool) = value;
}
UPB_INLINE void google_protobuf_FileOptions_set_py_generic_services(google_protobuf_FileOptions *msg, bool value) {
- _upb_sethas(msg, 5);
- *UPB_PTR_AT(msg, UPB_SIZE(19, 19), bool) = value;
+ _upb_sethas(msg, 8);
+ *UPB_PTR_AT(msg, UPB_SIZE(11, 11), bool) = value;
}
UPB_INLINE void google_protobuf_FileOptions_set_java_generate_equals_and_hash(google_protobuf_FileOptions *msg, bool value) {
- _upb_sethas(msg, 6);
- *UPB_PTR_AT(msg, UPB_SIZE(20, 20), bool) = value;
+ _upb_sethas(msg, 9);
+ *UPB_PTR_AT(msg, UPB_SIZE(12, 12), bool) = value;
}
UPB_INLINE void google_protobuf_FileOptions_set_deprecated(google_protobuf_FileOptions *msg, bool value) {
- _upb_sethas(msg, 7);
- *UPB_PTR_AT(msg, UPB_SIZE(21, 21), bool) = value;
+ _upb_sethas(msg, 10);
+ *UPB_PTR_AT(msg, UPB_SIZE(13, 13), bool) = value;
}
UPB_INLINE void google_protobuf_FileOptions_set_java_string_check_utf8(google_protobuf_FileOptions *msg, bool value) {
- _upb_sethas(msg, 8);
- *UPB_PTR_AT(msg, UPB_SIZE(22, 22), bool) = value;
+ _upb_sethas(msg, 11);
+ *UPB_PTR_AT(msg, UPB_SIZE(14, 14), bool) = value;
}
UPB_INLINE void google_protobuf_FileOptions_set_cc_enable_arenas(google_protobuf_FileOptions *msg, bool value) {
- _upb_sethas(msg, 9);
- *UPB_PTR_AT(msg, UPB_SIZE(23, 23), bool) = value;
+ _upb_sethas(msg, 12);
+ *UPB_PTR_AT(msg, UPB_SIZE(15, 15), bool) = value;
}
UPB_INLINE void google_protobuf_FileOptions_set_objc_class_prefix(google_protobuf_FileOptions *msg, upb_strview value) {
- _upb_sethas(msg, 14);
- *UPB_PTR_AT(msg, UPB_SIZE(52, 80), upb_strview) = value;
+ _upb_sethas(msg, 13);
+ *UPB_PTR_AT(msg, UPB_SIZE(44, 72), upb_strview) = value;
}
UPB_INLINE void google_protobuf_FileOptions_set_csharp_namespace(google_protobuf_FileOptions *msg, upb_strview value) {
- _upb_sethas(msg, 15);
- *UPB_PTR_AT(msg, UPB_SIZE(60, 96), upb_strview) = value;
+ _upb_sethas(msg, 14);
+ *UPB_PTR_AT(msg, UPB_SIZE(52, 88), upb_strview) = value;
}
UPB_INLINE void google_protobuf_FileOptions_set_swift_prefix(google_protobuf_FileOptions *msg, upb_strview value) {
- _upb_sethas(msg, 16);
- *UPB_PTR_AT(msg, UPB_SIZE(68, 112), upb_strview) = value;
+ _upb_sethas(msg, 15);
+ *UPB_PTR_AT(msg, UPB_SIZE(60, 104), upb_strview) = value;
}
UPB_INLINE void google_protobuf_FileOptions_set_php_class_prefix(google_protobuf_FileOptions *msg, upb_strview value) {
- _upb_sethas(msg, 17);
- *UPB_PTR_AT(msg, UPB_SIZE(76, 128), upb_strview) = value;
+ _upb_sethas(msg, 16);
+ *UPB_PTR_AT(msg, UPB_SIZE(68, 120), upb_strview) = value;
}
UPB_INLINE void google_protobuf_FileOptions_set_php_namespace(google_protobuf_FileOptions *msg, upb_strview value) {
- _upb_sethas(msg, 18);
- *UPB_PTR_AT(msg, UPB_SIZE(84, 144), upb_strview) = value;
+ _upb_sethas(msg, 17);
+ *UPB_PTR_AT(msg, UPB_SIZE(76, 136), upb_strview) = value;
}
UPB_INLINE void google_protobuf_FileOptions_set_php_generic_services(google_protobuf_FileOptions *msg, bool value) {
- _upb_sethas(msg, 10);
- *UPB_PTR_AT(msg, UPB_SIZE(24, 24), bool) = value;
+ _upb_sethas(msg, 18);
+ *UPB_PTR_AT(msg, UPB_SIZE(16, 16), bool) = value;
}
UPB_INLINE void google_protobuf_FileOptions_set_php_metadata_namespace(google_protobuf_FileOptions *msg, upb_strview value) {
_upb_sethas(msg, 19);
- *UPB_PTR_AT(msg, UPB_SIZE(92, 160), upb_strview) = value;
+ *UPB_PTR_AT(msg, UPB_SIZE(84, 152), upb_strview) = value;
}
UPB_INLINE void google_protobuf_FileOptions_set_ruby_package(google_protobuf_FileOptions *msg, upb_strview value) {
_upb_sethas(msg, 20);
- *UPB_PTR_AT(msg, UPB_SIZE(100, 176), upb_strview) = value;
+ *UPB_PTR_AT(msg, UPB_SIZE(92, 168), upb_strview) = value;
}
UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_FileOptions_mutable_uninterpreted_option(google_protobuf_FileOptions *msg, size_t *len) {
- return (google_protobuf_UninterpretedOption**)_upb_array_mutable_accessor(msg, UPB_SIZE(108, 192), len);
+ return (google_protobuf_UninterpretedOption**)_upb_array_mutable_accessor(msg, UPB_SIZE(100, 184), len);
}
UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_FileOptions_resize_uninterpreted_option(google_protobuf_FileOptions *msg, size_t len, upb_arena *arena) {
- return (google_protobuf_UninterpretedOption**)_upb_array_resize_accessor(msg, UPB_SIZE(108, 192), len, UPB_TYPE_MESSAGE, arena);
+ return (google_protobuf_UninterpretedOption**)_upb_array_resize_accessor2(msg, UPB_SIZE(100, 184), len, UPB_SIZE(2, 3), arena);
}
UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_FileOptions_add_uninterpreted_option(google_protobuf_FileOptions *msg, upb_arena *arena) {
struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_msg_new(&google_protobuf_UninterpretedOption_msginit, arena);
- bool ok = _upb_array_append_accessor(
- msg, UPB_SIZE(108, 192), UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, &sub, arena);
+ bool ok = _upb_array_append_accessor2(
+ msg, UPB_SIZE(100, 184), UPB_SIZE(2, 3), &sub, arena);
if (!ok) return NULL;
return sub;
}
@@ -2504,17 +3234,23 @@ UPB_INLINE google_protobuf_MessageOptions *google_protobuf_MessageOptions_parse(
google_protobuf_MessageOptions *ret = google_protobuf_MessageOptions_new(arena);
return (ret && upb_decode(buf, size, ret, &google_protobuf_MessageOptions_msginit, arena)) ? ret : NULL;
}
+UPB_INLINE google_protobuf_MessageOptions *google_protobuf_MessageOptions_parse_ex(const char *buf, size_t size,
+ upb_arena *arena, int options) {
+ google_protobuf_MessageOptions *ret = google_protobuf_MessageOptions_new(arena);
+ return (ret && _upb_decode(buf, size, ret, &google_protobuf_MessageOptions_msginit, arena, options))
+ ? ret : NULL;
+}
UPB_INLINE char *google_protobuf_MessageOptions_serialize(const google_protobuf_MessageOptions *msg, upb_arena *arena, size_t *len) {
return upb_encode(msg, &google_protobuf_MessageOptions_msginit, arena, len);
}
-UPB_INLINE bool google_protobuf_MessageOptions_has_message_set_wire_format(const google_protobuf_MessageOptions *msg) { return _upb_has_field(msg, 1); }
+UPB_INLINE bool google_protobuf_MessageOptions_has_message_set_wire_format(const google_protobuf_MessageOptions *msg) { return _upb_hasbit(msg, 1); }
UPB_INLINE bool google_protobuf_MessageOptions_message_set_wire_format(const google_protobuf_MessageOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool); }
-UPB_INLINE bool google_protobuf_MessageOptions_has_no_standard_descriptor_accessor(const google_protobuf_MessageOptions *msg) { return _upb_has_field(msg, 2); }
+UPB_INLINE bool google_protobuf_MessageOptions_has_no_standard_descriptor_accessor(const google_protobuf_MessageOptions *msg) { return _upb_hasbit(msg, 2); }
UPB_INLINE bool google_protobuf_MessageOptions_no_standard_descriptor_accessor(const google_protobuf_MessageOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(2, 2), bool); }
-UPB_INLINE bool google_protobuf_MessageOptions_has_deprecated(const google_protobuf_MessageOptions *msg) { return _upb_has_field(msg, 3); }
+UPB_INLINE bool google_protobuf_MessageOptions_has_deprecated(const google_protobuf_MessageOptions *msg) { return _upb_hasbit(msg, 3); }
UPB_INLINE bool google_protobuf_MessageOptions_deprecated(const google_protobuf_MessageOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(3, 3), bool); }
-UPB_INLINE bool google_protobuf_MessageOptions_has_map_entry(const google_protobuf_MessageOptions *msg) { return _upb_has_field(msg, 4); }
+UPB_INLINE bool google_protobuf_MessageOptions_has_map_entry(const google_protobuf_MessageOptions *msg) { return _upb_hasbit(msg, 4); }
UPB_INLINE bool google_protobuf_MessageOptions_map_entry(const google_protobuf_MessageOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), bool); }
UPB_INLINE bool google_protobuf_MessageOptions_has_uninterpreted_option(const google_protobuf_MessageOptions *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(8, 8)); }
UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_MessageOptions_uninterpreted_option(const google_protobuf_MessageOptions *msg, size_t *len) { return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(8, 8), len); }
@@ -2539,12 +3275,12 @@ UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_MessageOptions_
return (google_protobuf_UninterpretedOption**)_upb_array_mutable_accessor(msg, UPB_SIZE(8, 8), len);
}
UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_MessageOptions_resize_uninterpreted_option(google_protobuf_MessageOptions *msg, size_t len, upb_arena *arena) {
- return (google_protobuf_UninterpretedOption**)_upb_array_resize_accessor(msg, UPB_SIZE(8, 8), len, UPB_TYPE_MESSAGE, arena);
+ return (google_protobuf_UninterpretedOption**)_upb_array_resize_accessor2(msg, UPB_SIZE(8, 8), len, UPB_SIZE(2, 3), arena);
}
UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_MessageOptions_add_uninterpreted_option(google_protobuf_MessageOptions *msg, upb_arena *arena) {
struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_msg_new(&google_protobuf_UninterpretedOption_msginit, arena);
- bool ok = _upb_array_append_accessor(
- msg, UPB_SIZE(8, 8), UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, &sub, arena);
+ bool ok = _upb_array_append_accessor2(
+ msg, UPB_SIZE(8, 8), UPB_SIZE(2, 3), &sub, arena);
if (!ok) return NULL;
return sub;
}
@@ -2559,59 +3295,65 @@ UPB_INLINE google_protobuf_FieldOptions *google_protobuf_FieldOptions_parse(cons
google_protobuf_FieldOptions *ret = google_protobuf_FieldOptions_new(arena);
return (ret && upb_decode(buf, size, ret, &google_protobuf_FieldOptions_msginit, arena)) ? ret : NULL;
}
+UPB_INLINE google_protobuf_FieldOptions *google_protobuf_FieldOptions_parse_ex(const char *buf, size_t size,
+ upb_arena *arena, int options) {
+ google_protobuf_FieldOptions *ret = google_protobuf_FieldOptions_new(arena);
+ return (ret && _upb_decode(buf, size, ret, &google_protobuf_FieldOptions_msginit, arena, options))
+ ? ret : NULL;
+}
UPB_INLINE char *google_protobuf_FieldOptions_serialize(const google_protobuf_FieldOptions *msg, upb_arena *arena, size_t *len) {
return upb_encode(msg, &google_protobuf_FieldOptions_msginit, arena, len);
}
-UPB_INLINE bool google_protobuf_FieldOptions_has_ctype(const google_protobuf_FieldOptions *msg) { return _upb_has_field(msg, 1); }
-UPB_INLINE int32_t google_protobuf_FieldOptions_ctype(const google_protobuf_FieldOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t); }
-UPB_INLINE bool google_protobuf_FieldOptions_has_packed(const google_protobuf_FieldOptions *msg) { return _upb_has_field(msg, 3); }
-UPB_INLINE bool google_protobuf_FieldOptions_packed(const google_protobuf_FieldOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(24, 24), bool); }
-UPB_INLINE bool google_protobuf_FieldOptions_has_deprecated(const google_protobuf_FieldOptions *msg) { return _upb_has_field(msg, 4); }
-UPB_INLINE bool google_protobuf_FieldOptions_deprecated(const google_protobuf_FieldOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(25, 25), bool); }
-UPB_INLINE bool google_protobuf_FieldOptions_has_lazy(const google_protobuf_FieldOptions *msg) { return _upb_has_field(msg, 5); }
-UPB_INLINE bool google_protobuf_FieldOptions_lazy(const google_protobuf_FieldOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(26, 26), bool); }
-UPB_INLINE bool google_protobuf_FieldOptions_has_jstype(const google_protobuf_FieldOptions *msg) { return _upb_has_field(msg, 2); }
-UPB_INLINE int32_t google_protobuf_FieldOptions_jstype(const google_protobuf_FieldOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(16, 16), int32_t); }
-UPB_INLINE bool google_protobuf_FieldOptions_has_weak(const google_protobuf_FieldOptions *msg) { return _upb_has_field(msg, 6); }
-UPB_INLINE bool google_protobuf_FieldOptions_weak(const google_protobuf_FieldOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(27, 27), bool); }
-UPB_INLINE bool google_protobuf_FieldOptions_has_uninterpreted_option(const google_protobuf_FieldOptions *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(28, 32)); }
-UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_FieldOptions_uninterpreted_option(const google_protobuf_FieldOptions *msg, size_t *len) { return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(28, 32), len); }
+UPB_INLINE bool google_protobuf_FieldOptions_has_ctype(const google_protobuf_FieldOptions *msg) { return _upb_hasbit(msg, 1); }
+UPB_INLINE int32_t google_protobuf_FieldOptions_ctype(const google_protobuf_FieldOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t); }
+UPB_INLINE bool google_protobuf_FieldOptions_has_packed(const google_protobuf_FieldOptions *msg) { return _upb_hasbit(msg, 2); }
+UPB_INLINE bool google_protobuf_FieldOptions_packed(const google_protobuf_FieldOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 12), bool); }
+UPB_INLINE bool google_protobuf_FieldOptions_has_deprecated(const google_protobuf_FieldOptions *msg) { return _upb_hasbit(msg, 3); }
+UPB_INLINE bool google_protobuf_FieldOptions_deprecated(const google_protobuf_FieldOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(13, 13), bool); }
+UPB_INLINE bool google_protobuf_FieldOptions_has_lazy(const google_protobuf_FieldOptions *msg) { return _upb_hasbit(msg, 4); }
+UPB_INLINE bool google_protobuf_FieldOptions_lazy(const google_protobuf_FieldOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(14, 14), bool); }
+UPB_INLINE bool google_protobuf_FieldOptions_has_jstype(const google_protobuf_FieldOptions *msg) { return _upb_hasbit(msg, 5); }
+UPB_INLINE int32_t google_protobuf_FieldOptions_jstype(const google_protobuf_FieldOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t); }
+UPB_INLINE bool google_protobuf_FieldOptions_has_weak(const google_protobuf_FieldOptions *msg) { return _upb_hasbit(msg, 6); }
+UPB_INLINE bool google_protobuf_FieldOptions_weak(const google_protobuf_FieldOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(15, 15), bool); }
+UPB_INLINE bool google_protobuf_FieldOptions_has_uninterpreted_option(const google_protobuf_FieldOptions *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(16, 16)); }
+UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_FieldOptions_uninterpreted_option(const google_protobuf_FieldOptions *msg, size_t *len) { return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(16, 16), len); }
UPB_INLINE void google_protobuf_FieldOptions_set_ctype(google_protobuf_FieldOptions *msg, int32_t value) {
_upb_sethas(msg, 1);
- *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t) = value;
+ *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = value;
}
UPB_INLINE void google_protobuf_FieldOptions_set_packed(google_protobuf_FieldOptions *msg, bool value) {
- _upb_sethas(msg, 3);
- *UPB_PTR_AT(msg, UPB_SIZE(24, 24), bool) = value;
+ _upb_sethas(msg, 2);
+ *UPB_PTR_AT(msg, UPB_SIZE(12, 12), bool) = value;
}
UPB_INLINE void google_protobuf_FieldOptions_set_deprecated(google_protobuf_FieldOptions *msg, bool value) {
- _upb_sethas(msg, 4);
- *UPB_PTR_AT(msg, UPB_SIZE(25, 25), bool) = value;
+ _upb_sethas(msg, 3);
+ *UPB_PTR_AT(msg, UPB_SIZE(13, 13), bool) = value;
}
UPB_INLINE void google_protobuf_FieldOptions_set_lazy(google_protobuf_FieldOptions *msg, bool value) {
- _upb_sethas(msg, 5);
- *UPB_PTR_AT(msg, UPB_SIZE(26, 26), bool) = value;
+ _upb_sethas(msg, 4);
+ *UPB_PTR_AT(msg, UPB_SIZE(14, 14), bool) = value;
}
UPB_INLINE void google_protobuf_FieldOptions_set_jstype(google_protobuf_FieldOptions *msg, int32_t value) {
- _upb_sethas(msg, 2);
- *UPB_PTR_AT(msg, UPB_SIZE(16, 16), int32_t) = value;
+ _upb_sethas(msg, 5);
+ *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t) = value;
}
UPB_INLINE void google_protobuf_FieldOptions_set_weak(google_protobuf_FieldOptions *msg, bool value) {
_upb_sethas(msg, 6);
- *UPB_PTR_AT(msg, UPB_SIZE(27, 27), bool) = value;
+ *UPB_PTR_AT(msg, UPB_SIZE(15, 15), bool) = value;
}
UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_FieldOptions_mutable_uninterpreted_option(google_protobuf_FieldOptions *msg, size_t *len) {
- return (google_protobuf_UninterpretedOption**)_upb_array_mutable_accessor(msg, UPB_SIZE(28, 32), len);
+ return (google_protobuf_UninterpretedOption**)_upb_array_mutable_accessor(msg, UPB_SIZE(16, 16), len);
}
UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_FieldOptions_resize_uninterpreted_option(google_protobuf_FieldOptions *msg, size_t len, upb_arena *arena) {
- return (google_protobuf_UninterpretedOption**)_upb_array_resize_accessor(msg, UPB_SIZE(28, 32), len, UPB_TYPE_MESSAGE, arena);
+ return (google_protobuf_UninterpretedOption**)_upb_array_resize_accessor2(msg, UPB_SIZE(16, 16), len, UPB_SIZE(2, 3), arena);
}
UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_FieldOptions_add_uninterpreted_option(google_protobuf_FieldOptions *msg, upb_arena *arena) {
struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_msg_new(&google_protobuf_UninterpretedOption_msginit, arena);
- bool ok = _upb_array_append_accessor(
- msg, UPB_SIZE(28, 32), UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, &sub, arena);
+ bool ok = _upb_array_append_accessor2(
+ msg, UPB_SIZE(16, 16), UPB_SIZE(2, 3), &sub, arena);
if (!ok) return NULL;
return sub;
}
@@ -2626,6 +3368,12 @@ UPB_INLINE google_protobuf_OneofOptions *google_protobuf_OneofOptions_parse(cons
google_protobuf_OneofOptions *ret = google_protobuf_OneofOptions_new(arena);
return (ret && upb_decode(buf, size, ret, &google_protobuf_OneofOptions_msginit, arena)) ? ret : NULL;
}
+UPB_INLINE google_protobuf_OneofOptions *google_protobuf_OneofOptions_parse_ex(const char *buf, size_t size,
+ upb_arena *arena, int options) {
+ google_protobuf_OneofOptions *ret = google_protobuf_OneofOptions_new(arena);
+ return (ret && _upb_decode(buf, size, ret, &google_protobuf_OneofOptions_msginit, arena, options))
+ ? ret : NULL;
+}
UPB_INLINE char *google_protobuf_OneofOptions_serialize(const google_protobuf_OneofOptions *msg, upb_arena *arena, size_t *len) {
return upb_encode(msg, &google_protobuf_OneofOptions_msginit, arena, len);
}
@@ -2637,12 +3385,12 @@ UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_OneofOptions_mu
return (google_protobuf_UninterpretedOption**)_upb_array_mutable_accessor(msg, UPB_SIZE(0, 0), len);
}
UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_OneofOptions_resize_uninterpreted_option(google_protobuf_OneofOptions *msg, size_t len, upb_arena *arena) {
- return (google_protobuf_UninterpretedOption**)_upb_array_resize_accessor(msg, UPB_SIZE(0, 0), len, UPB_TYPE_MESSAGE, arena);
+ return (google_protobuf_UninterpretedOption**)_upb_array_resize_accessor2(msg, UPB_SIZE(0, 0), len, UPB_SIZE(2, 3), arena);
}
UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_OneofOptions_add_uninterpreted_option(google_protobuf_OneofOptions *msg, upb_arena *arena) {
struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_msg_new(&google_protobuf_UninterpretedOption_msginit, arena);
- bool ok = _upb_array_append_accessor(
- msg, UPB_SIZE(0, 0), UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, &sub, arena);
+ bool ok = _upb_array_append_accessor2(
+ msg, UPB_SIZE(0, 0), UPB_SIZE(2, 3), &sub, arena);
if (!ok) return NULL;
return sub;
}
@@ -2657,13 +3405,19 @@ UPB_INLINE google_protobuf_EnumOptions *google_protobuf_EnumOptions_parse(const
google_protobuf_EnumOptions *ret = google_protobuf_EnumOptions_new(arena);
return (ret && upb_decode(buf, size, ret, &google_protobuf_EnumOptions_msginit, arena)) ? ret : NULL;
}
+UPB_INLINE google_protobuf_EnumOptions *google_protobuf_EnumOptions_parse_ex(const char *buf, size_t size,
+ upb_arena *arena, int options) {
+ google_protobuf_EnumOptions *ret = google_protobuf_EnumOptions_new(arena);
+ return (ret && _upb_decode(buf, size, ret, &google_protobuf_EnumOptions_msginit, arena, options))
+ ? ret : NULL;
+}
UPB_INLINE char *google_protobuf_EnumOptions_serialize(const google_protobuf_EnumOptions *msg, upb_arena *arena, size_t *len) {
return upb_encode(msg, &google_protobuf_EnumOptions_msginit, arena, len);
}
-UPB_INLINE bool google_protobuf_EnumOptions_has_allow_alias(const google_protobuf_EnumOptions *msg) { return _upb_has_field(msg, 1); }
+UPB_INLINE bool google_protobuf_EnumOptions_has_allow_alias(const google_protobuf_EnumOptions *msg) { return _upb_hasbit(msg, 1); }
UPB_INLINE bool google_protobuf_EnumOptions_allow_alias(const google_protobuf_EnumOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool); }
-UPB_INLINE bool google_protobuf_EnumOptions_has_deprecated(const google_protobuf_EnumOptions *msg) { return _upb_has_field(msg, 2); }
+UPB_INLINE bool google_protobuf_EnumOptions_has_deprecated(const google_protobuf_EnumOptions *msg) { return _upb_hasbit(msg, 2); }
UPB_INLINE bool google_protobuf_EnumOptions_deprecated(const google_protobuf_EnumOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(2, 2), bool); }
UPB_INLINE bool google_protobuf_EnumOptions_has_uninterpreted_option(const google_protobuf_EnumOptions *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(4, 8)); }
UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_EnumOptions_uninterpreted_option(const google_protobuf_EnumOptions *msg, size_t *len) { return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(4, 8), len); }
@@ -2680,12 +3434,12 @@ UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_EnumOptions_mut
return (google_protobuf_UninterpretedOption**)_upb_array_mutable_accessor(msg, UPB_SIZE(4, 8), len);
}
UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_EnumOptions_resize_uninterpreted_option(google_protobuf_EnumOptions *msg, size_t len, upb_arena *arena) {
- return (google_protobuf_UninterpretedOption**)_upb_array_resize_accessor(msg, UPB_SIZE(4, 8), len, UPB_TYPE_MESSAGE, arena);
+ return (google_protobuf_UninterpretedOption**)_upb_array_resize_accessor2(msg, UPB_SIZE(4, 8), len, UPB_SIZE(2, 3), arena);
}
UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_EnumOptions_add_uninterpreted_option(google_protobuf_EnumOptions *msg, upb_arena *arena) {
struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_msg_new(&google_protobuf_UninterpretedOption_msginit, arena);
- bool ok = _upb_array_append_accessor(
- msg, UPB_SIZE(4, 8), UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, &sub, arena);
+ bool ok = _upb_array_append_accessor2(
+ msg, UPB_SIZE(4, 8), UPB_SIZE(2, 3), &sub, arena);
if (!ok) return NULL;
return sub;
}
@@ -2700,11 +3454,17 @@ UPB_INLINE google_protobuf_EnumValueOptions *google_protobuf_EnumValueOptions_pa
google_protobuf_EnumValueOptions *ret = google_protobuf_EnumValueOptions_new(arena);
return (ret && upb_decode(buf, size, ret, &google_protobuf_EnumValueOptions_msginit, arena)) ? ret : NULL;
}
+UPB_INLINE google_protobuf_EnumValueOptions *google_protobuf_EnumValueOptions_parse_ex(const char *buf, size_t size,
+ upb_arena *arena, int options) {
+ google_protobuf_EnumValueOptions *ret = google_protobuf_EnumValueOptions_new(arena);
+ return (ret && _upb_decode(buf, size, ret, &google_protobuf_EnumValueOptions_msginit, arena, options))
+ ? ret : NULL;
+}
UPB_INLINE char *google_protobuf_EnumValueOptions_serialize(const google_protobuf_EnumValueOptions *msg, upb_arena *arena, size_t *len) {
return upb_encode(msg, &google_protobuf_EnumValueOptions_msginit, arena, len);
}
-UPB_INLINE bool google_protobuf_EnumValueOptions_has_deprecated(const google_protobuf_EnumValueOptions *msg) { return _upb_has_field(msg, 1); }
+UPB_INLINE bool google_protobuf_EnumValueOptions_has_deprecated(const google_protobuf_EnumValueOptions *msg) { return _upb_hasbit(msg, 1); }
UPB_INLINE bool google_protobuf_EnumValueOptions_deprecated(const google_protobuf_EnumValueOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool); }
UPB_INLINE bool google_protobuf_EnumValueOptions_has_uninterpreted_option(const google_protobuf_EnumValueOptions *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(4, 8)); }
UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_EnumValueOptions_uninterpreted_option(const google_protobuf_EnumValueOptions *msg, size_t *len) { return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(4, 8), len); }
@@ -2717,12 +3477,12 @@ UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_EnumValueOption
return (google_protobuf_UninterpretedOption**)_upb_array_mutable_accessor(msg, UPB_SIZE(4, 8), len);
}
UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_EnumValueOptions_resize_uninterpreted_option(google_protobuf_EnumValueOptions *msg, size_t len, upb_arena *arena) {
- return (google_protobuf_UninterpretedOption**)_upb_array_resize_accessor(msg, UPB_SIZE(4, 8), len, UPB_TYPE_MESSAGE, arena);
+ return (google_protobuf_UninterpretedOption**)_upb_array_resize_accessor2(msg, UPB_SIZE(4, 8), len, UPB_SIZE(2, 3), arena);
}
UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_EnumValueOptions_add_uninterpreted_option(google_protobuf_EnumValueOptions *msg, upb_arena *arena) {
struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_msg_new(&google_protobuf_UninterpretedOption_msginit, arena);
- bool ok = _upb_array_append_accessor(
- msg, UPB_SIZE(4, 8), UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, &sub, arena);
+ bool ok = _upb_array_append_accessor2(
+ msg, UPB_SIZE(4, 8), UPB_SIZE(2, 3), &sub, arena);
if (!ok) return NULL;
return sub;
}
@@ -2737,11 +3497,17 @@ UPB_INLINE google_protobuf_ServiceOptions *google_protobuf_ServiceOptions_parse(
google_protobuf_ServiceOptions *ret = google_protobuf_ServiceOptions_new(arena);
return (ret && upb_decode(buf, size, ret, &google_protobuf_ServiceOptions_msginit, arena)) ? ret : NULL;
}
+UPB_INLINE google_protobuf_ServiceOptions *google_protobuf_ServiceOptions_parse_ex(const char *buf, size_t size,
+ upb_arena *arena, int options) {
+ google_protobuf_ServiceOptions *ret = google_protobuf_ServiceOptions_new(arena);
+ return (ret && _upb_decode(buf, size, ret, &google_protobuf_ServiceOptions_msginit, arena, options))
+ ? ret : NULL;
+}
UPB_INLINE char *google_protobuf_ServiceOptions_serialize(const google_protobuf_ServiceOptions *msg, upb_arena *arena, size_t *len) {
return upb_encode(msg, &google_protobuf_ServiceOptions_msginit, arena, len);
}
-UPB_INLINE bool google_protobuf_ServiceOptions_has_deprecated(const google_protobuf_ServiceOptions *msg) { return _upb_has_field(msg, 1); }
+UPB_INLINE bool google_protobuf_ServiceOptions_has_deprecated(const google_protobuf_ServiceOptions *msg) { return _upb_hasbit(msg, 1); }
UPB_INLINE bool google_protobuf_ServiceOptions_deprecated(const google_protobuf_ServiceOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool); }
UPB_INLINE bool google_protobuf_ServiceOptions_has_uninterpreted_option(const google_protobuf_ServiceOptions *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(4, 8)); }
UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_ServiceOptions_uninterpreted_option(const google_protobuf_ServiceOptions *msg, size_t *len) { return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(4, 8), len); }
@@ -2754,12 +3520,12 @@ UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_ServiceOptions_
return (google_protobuf_UninterpretedOption**)_upb_array_mutable_accessor(msg, UPB_SIZE(4, 8), len);
}
UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_ServiceOptions_resize_uninterpreted_option(google_protobuf_ServiceOptions *msg, size_t len, upb_arena *arena) {
- return (google_protobuf_UninterpretedOption**)_upb_array_resize_accessor(msg, UPB_SIZE(4, 8), len, UPB_TYPE_MESSAGE, arena);
+ return (google_protobuf_UninterpretedOption**)_upb_array_resize_accessor2(msg, UPB_SIZE(4, 8), len, UPB_SIZE(2, 3), arena);
}
UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_ServiceOptions_add_uninterpreted_option(google_protobuf_ServiceOptions *msg, upb_arena *arena) {
struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_msg_new(&google_protobuf_UninterpretedOption_msginit, arena);
- bool ok = _upb_array_append_accessor(
- msg, UPB_SIZE(4, 8), UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, &sub, arena);
+ bool ok = _upb_array_append_accessor2(
+ msg, UPB_SIZE(4, 8), UPB_SIZE(2, 3), &sub, arena);
if (!ok) return NULL;
return sub;
}
@@ -2774,35 +3540,41 @@ UPB_INLINE google_protobuf_MethodOptions *google_protobuf_MethodOptions_parse(co
google_protobuf_MethodOptions *ret = google_protobuf_MethodOptions_new(arena);
return (ret && upb_decode(buf, size, ret, &google_protobuf_MethodOptions_msginit, arena)) ? ret : NULL;
}
+UPB_INLINE google_protobuf_MethodOptions *google_protobuf_MethodOptions_parse_ex(const char *buf, size_t size,
+ upb_arena *arena, int options) {
+ google_protobuf_MethodOptions *ret = google_protobuf_MethodOptions_new(arena);
+ return (ret && _upb_decode(buf, size, ret, &google_protobuf_MethodOptions_msginit, arena, options))
+ ? ret : NULL;
+}
UPB_INLINE char *google_protobuf_MethodOptions_serialize(const google_protobuf_MethodOptions *msg, upb_arena *arena, size_t *len) {
return upb_encode(msg, &google_protobuf_MethodOptions_msginit, arena, len);
}
-UPB_INLINE bool google_protobuf_MethodOptions_has_deprecated(const google_protobuf_MethodOptions *msg) { return _upb_has_field(msg, 2); }
-UPB_INLINE bool google_protobuf_MethodOptions_deprecated(const google_protobuf_MethodOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(16, 16), bool); }
-UPB_INLINE bool google_protobuf_MethodOptions_has_idempotency_level(const google_protobuf_MethodOptions *msg) { return _upb_has_field(msg, 1); }
-UPB_INLINE int32_t google_protobuf_MethodOptions_idempotency_level(const google_protobuf_MethodOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t); }
-UPB_INLINE bool google_protobuf_MethodOptions_has_uninterpreted_option(const google_protobuf_MethodOptions *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(20, 24)); }
-UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_MethodOptions_uninterpreted_option(const google_protobuf_MethodOptions *msg, size_t *len) { return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(20, 24), len); }
+UPB_INLINE bool google_protobuf_MethodOptions_has_deprecated(const google_protobuf_MethodOptions *msg) { return _upb_hasbit(msg, 1); }
+UPB_INLINE bool google_protobuf_MethodOptions_deprecated(const google_protobuf_MethodOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), bool); }
+UPB_INLINE bool google_protobuf_MethodOptions_has_idempotency_level(const google_protobuf_MethodOptions *msg) { return _upb_hasbit(msg, 2); }
+UPB_INLINE int32_t google_protobuf_MethodOptions_idempotency_level(const google_protobuf_MethodOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t); }
+UPB_INLINE bool google_protobuf_MethodOptions_has_uninterpreted_option(const google_protobuf_MethodOptions *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(12, 16)); }
+UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_MethodOptions_uninterpreted_option(const google_protobuf_MethodOptions *msg, size_t *len) { return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(12, 16), len); }
UPB_INLINE void google_protobuf_MethodOptions_set_deprecated(google_protobuf_MethodOptions *msg, bool value) {
- _upb_sethas(msg, 2);
- *UPB_PTR_AT(msg, UPB_SIZE(16, 16), bool) = value;
+ _upb_sethas(msg, 1);
+ *UPB_PTR_AT(msg, UPB_SIZE(8, 8), bool) = value;
}
UPB_INLINE void google_protobuf_MethodOptions_set_idempotency_level(google_protobuf_MethodOptions *msg, int32_t value) {
- _upb_sethas(msg, 1);
- *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t) = value;
+ _upb_sethas(msg, 2);
+ *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = value;
}
UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_MethodOptions_mutable_uninterpreted_option(google_protobuf_MethodOptions *msg, size_t *len) {
- return (google_protobuf_UninterpretedOption**)_upb_array_mutable_accessor(msg, UPB_SIZE(20, 24), len);
+ return (google_protobuf_UninterpretedOption**)_upb_array_mutable_accessor(msg, UPB_SIZE(12, 16), len);
}
UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_MethodOptions_resize_uninterpreted_option(google_protobuf_MethodOptions *msg, size_t len, upb_arena *arena) {
- return (google_protobuf_UninterpretedOption**)_upb_array_resize_accessor(msg, UPB_SIZE(20, 24), len, UPB_TYPE_MESSAGE, arena);
+ return (google_protobuf_UninterpretedOption**)_upb_array_resize_accessor2(msg, UPB_SIZE(12, 16), len, UPB_SIZE(2, 3), arena);
}
UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_MethodOptions_add_uninterpreted_option(google_protobuf_MethodOptions *msg, upb_arena *arena) {
struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_msg_new(&google_protobuf_UninterpretedOption_msginit, arena);
- bool ok = _upb_array_append_accessor(
- msg, UPB_SIZE(20, 24), UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, &sub, arena);
+ bool ok = _upb_array_append_accessor2(
+ msg, UPB_SIZE(12, 16), UPB_SIZE(2, 3), &sub, arena);
if (!ok) return NULL;
return sub;
}
@@ -2817,52 +3589,58 @@ UPB_INLINE google_protobuf_UninterpretedOption *google_protobuf_UninterpretedOpt
google_protobuf_UninterpretedOption *ret = google_protobuf_UninterpretedOption_new(arena);
return (ret && upb_decode(buf, size, ret, &google_protobuf_UninterpretedOption_msginit, arena)) ? ret : NULL;
}
+UPB_INLINE google_protobuf_UninterpretedOption *google_protobuf_UninterpretedOption_parse_ex(const char *buf, size_t size,
+ upb_arena *arena, int options) {
+ google_protobuf_UninterpretedOption *ret = google_protobuf_UninterpretedOption_new(arena);
+ return (ret && _upb_decode(buf, size, ret, &google_protobuf_UninterpretedOption_msginit, arena, options))
+ ? ret : NULL;
+}
UPB_INLINE char *google_protobuf_UninterpretedOption_serialize(const google_protobuf_UninterpretedOption *msg, upb_arena *arena, size_t *len) {
return upb_encode(msg, &google_protobuf_UninterpretedOption_msginit, arena, len);
}
UPB_INLINE bool google_protobuf_UninterpretedOption_has_name(const google_protobuf_UninterpretedOption *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(56, 80)); }
UPB_INLINE const google_protobuf_UninterpretedOption_NamePart* const* google_protobuf_UninterpretedOption_name(const google_protobuf_UninterpretedOption *msg, size_t *len) { return (const google_protobuf_UninterpretedOption_NamePart* const*)_upb_array_accessor(msg, UPB_SIZE(56, 80), len); }
-UPB_INLINE bool google_protobuf_UninterpretedOption_has_identifier_value(const google_protobuf_UninterpretedOption *msg) { return _upb_has_field(msg, 4); }
+UPB_INLINE bool google_protobuf_UninterpretedOption_has_identifier_value(const google_protobuf_UninterpretedOption *msg) { return _upb_hasbit(msg, 1); }
UPB_INLINE upb_strview google_protobuf_UninterpretedOption_identifier_value(const google_protobuf_UninterpretedOption *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(32, 32), upb_strview); }
-UPB_INLINE bool google_protobuf_UninterpretedOption_has_positive_int_value(const google_protobuf_UninterpretedOption *msg) { return _upb_has_field(msg, 1); }
+UPB_INLINE bool google_protobuf_UninterpretedOption_has_positive_int_value(const google_protobuf_UninterpretedOption *msg) { return _upb_hasbit(msg, 2); }
UPB_INLINE uint64_t google_protobuf_UninterpretedOption_positive_int_value(const google_protobuf_UninterpretedOption *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), uint64_t); }
-UPB_INLINE bool google_protobuf_UninterpretedOption_has_negative_int_value(const google_protobuf_UninterpretedOption *msg) { return _upb_has_field(msg, 2); }
+UPB_INLINE bool google_protobuf_UninterpretedOption_has_negative_int_value(const google_protobuf_UninterpretedOption *msg) { return _upb_hasbit(msg, 3); }
UPB_INLINE int64_t google_protobuf_UninterpretedOption_negative_int_value(const google_protobuf_UninterpretedOption *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(16, 16), int64_t); }
-UPB_INLINE bool google_protobuf_UninterpretedOption_has_double_value(const google_protobuf_UninterpretedOption *msg) { return _upb_has_field(msg, 3); }
+UPB_INLINE bool google_protobuf_UninterpretedOption_has_double_value(const google_protobuf_UninterpretedOption *msg) { return _upb_hasbit(msg, 4); }
UPB_INLINE double google_protobuf_UninterpretedOption_double_value(const google_protobuf_UninterpretedOption *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(24, 24), double); }
-UPB_INLINE bool google_protobuf_UninterpretedOption_has_string_value(const google_protobuf_UninterpretedOption *msg) { return _upb_has_field(msg, 5); }
+UPB_INLINE bool google_protobuf_UninterpretedOption_has_string_value(const google_protobuf_UninterpretedOption *msg) { return _upb_hasbit(msg, 5); }
UPB_INLINE upb_strview google_protobuf_UninterpretedOption_string_value(const google_protobuf_UninterpretedOption *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(40, 48), upb_strview); }
-UPB_INLINE bool google_protobuf_UninterpretedOption_has_aggregate_value(const google_protobuf_UninterpretedOption *msg) { return _upb_has_field(msg, 6); }
+UPB_INLINE bool google_protobuf_UninterpretedOption_has_aggregate_value(const google_protobuf_UninterpretedOption *msg) { return _upb_hasbit(msg, 6); }
UPB_INLINE upb_strview google_protobuf_UninterpretedOption_aggregate_value(const google_protobuf_UninterpretedOption *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(48, 64), upb_strview); }
UPB_INLINE google_protobuf_UninterpretedOption_NamePart** google_protobuf_UninterpretedOption_mutable_name(google_protobuf_UninterpretedOption *msg, size_t *len) {
return (google_protobuf_UninterpretedOption_NamePart**)_upb_array_mutable_accessor(msg, UPB_SIZE(56, 80), len);
}
UPB_INLINE google_protobuf_UninterpretedOption_NamePart** google_protobuf_UninterpretedOption_resize_name(google_protobuf_UninterpretedOption *msg, size_t len, upb_arena *arena) {
- return (google_protobuf_UninterpretedOption_NamePart**)_upb_array_resize_accessor(msg, UPB_SIZE(56, 80), len, UPB_TYPE_MESSAGE, arena);
+ return (google_protobuf_UninterpretedOption_NamePart**)_upb_array_resize_accessor2(msg, UPB_SIZE(56, 80), len, UPB_SIZE(2, 3), arena);
}
UPB_INLINE struct google_protobuf_UninterpretedOption_NamePart* google_protobuf_UninterpretedOption_add_name(google_protobuf_UninterpretedOption *msg, upb_arena *arena) {
struct google_protobuf_UninterpretedOption_NamePart* sub = (struct google_protobuf_UninterpretedOption_NamePart*)_upb_msg_new(&google_protobuf_UninterpretedOption_NamePart_msginit, arena);
- bool ok = _upb_array_append_accessor(
- msg, UPB_SIZE(56, 80), UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, &sub, arena);
+ bool ok = _upb_array_append_accessor2(
+ msg, UPB_SIZE(56, 80), UPB_SIZE(2, 3), &sub, arena);
if (!ok) return NULL;
return sub;
}
UPB_INLINE void google_protobuf_UninterpretedOption_set_identifier_value(google_protobuf_UninterpretedOption *msg, upb_strview value) {
- _upb_sethas(msg, 4);
+ _upb_sethas(msg, 1);
*UPB_PTR_AT(msg, UPB_SIZE(32, 32), upb_strview) = value;
}
UPB_INLINE void google_protobuf_UninterpretedOption_set_positive_int_value(google_protobuf_UninterpretedOption *msg, uint64_t value) {
- _upb_sethas(msg, 1);
+ _upb_sethas(msg, 2);
*UPB_PTR_AT(msg, UPB_SIZE(8, 8), uint64_t) = value;
}
UPB_INLINE void google_protobuf_UninterpretedOption_set_negative_int_value(google_protobuf_UninterpretedOption *msg, int64_t value) {
- _upb_sethas(msg, 2);
+ _upb_sethas(msg, 3);
*UPB_PTR_AT(msg, UPB_SIZE(16, 16), int64_t) = value;
}
UPB_INLINE void google_protobuf_UninterpretedOption_set_double_value(google_protobuf_UninterpretedOption *msg, double value) {
- _upb_sethas(msg, 3);
+ _upb_sethas(msg, 4);
*UPB_PTR_AT(msg, UPB_SIZE(24, 24), double) = value;
}
UPB_INLINE void google_protobuf_UninterpretedOption_set_string_value(google_protobuf_UninterpretedOption *msg, upb_strview value) {
@@ -2884,21 +3662,27 @@ UPB_INLINE google_protobuf_UninterpretedOption_NamePart *google_protobuf_Uninter
google_protobuf_UninterpretedOption_NamePart *ret = google_protobuf_UninterpretedOption_NamePart_new(arena);
return (ret && upb_decode(buf, size, ret, &google_protobuf_UninterpretedOption_NamePart_msginit, arena)) ? ret : NULL;
}
+UPB_INLINE google_protobuf_UninterpretedOption_NamePart *google_protobuf_UninterpretedOption_NamePart_parse_ex(const char *buf, size_t size,
+ upb_arena *arena, int options) {
+ google_protobuf_UninterpretedOption_NamePart *ret = google_protobuf_UninterpretedOption_NamePart_new(arena);
+ return (ret && _upb_decode(buf, size, ret, &google_protobuf_UninterpretedOption_NamePart_msginit, arena, options))
+ ? ret : NULL;
+}
UPB_INLINE char *google_protobuf_UninterpretedOption_NamePart_serialize(const google_protobuf_UninterpretedOption_NamePart *msg, upb_arena *arena, size_t *len) {
return upb_encode(msg, &google_protobuf_UninterpretedOption_NamePart_msginit, arena, len);
}
-UPB_INLINE bool google_protobuf_UninterpretedOption_NamePart_has_name_part(const google_protobuf_UninterpretedOption_NamePart *msg) { return _upb_has_field(msg, 2); }
+UPB_INLINE bool google_protobuf_UninterpretedOption_NamePart_has_name_part(const google_protobuf_UninterpretedOption_NamePart *msg) { return _upb_hasbit(msg, 1); }
UPB_INLINE upb_strview google_protobuf_UninterpretedOption_NamePart_name_part(const google_protobuf_UninterpretedOption_NamePart *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview); }
-UPB_INLINE bool google_protobuf_UninterpretedOption_NamePart_has_is_extension(const google_protobuf_UninterpretedOption_NamePart *msg) { return _upb_has_field(msg, 1); }
+UPB_INLINE bool google_protobuf_UninterpretedOption_NamePart_has_is_extension(const google_protobuf_UninterpretedOption_NamePart *msg) { return _upb_hasbit(msg, 2); }
UPB_INLINE bool google_protobuf_UninterpretedOption_NamePart_is_extension(const google_protobuf_UninterpretedOption_NamePart *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool); }
UPB_INLINE void google_protobuf_UninterpretedOption_NamePart_set_name_part(google_protobuf_UninterpretedOption_NamePart *msg, upb_strview value) {
- _upb_sethas(msg, 2);
+ _upb_sethas(msg, 1);
*UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview) = value;
}
UPB_INLINE void google_protobuf_UninterpretedOption_NamePart_set_is_extension(google_protobuf_UninterpretedOption_NamePart *msg, bool value) {
- _upb_sethas(msg, 1);
+ _upb_sethas(msg, 2);
*UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool) = value;
}
@@ -2912,6 +3696,12 @@ UPB_INLINE google_protobuf_SourceCodeInfo *google_protobuf_SourceCodeInfo_parse(
google_protobuf_SourceCodeInfo *ret = google_protobuf_SourceCodeInfo_new(arena);
return (ret && upb_decode(buf, size, ret, &google_protobuf_SourceCodeInfo_msginit, arena)) ? ret : NULL;
}
+UPB_INLINE google_protobuf_SourceCodeInfo *google_protobuf_SourceCodeInfo_parse_ex(const char *buf, size_t size,
+ upb_arena *arena, int options) {
+ google_protobuf_SourceCodeInfo *ret = google_protobuf_SourceCodeInfo_new(arena);
+ return (ret && _upb_decode(buf, size, ret, &google_protobuf_SourceCodeInfo_msginit, arena, options))
+ ? ret : NULL;
+}
UPB_INLINE char *google_protobuf_SourceCodeInfo_serialize(const google_protobuf_SourceCodeInfo *msg, upb_arena *arena, size_t *len) {
return upb_encode(msg, &google_protobuf_SourceCodeInfo_msginit, arena, len);
}
@@ -2923,12 +3713,12 @@ UPB_INLINE google_protobuf_SourceCodeInfo_Location** google_protobuf_SourceCodeI
return (google_protobuf_SourceCodeInfo_Location**)_upb_array_mutable_accessor(msg, UPB_SIZE(0, 0), len);
}
UPB_INLINE google_protobuf_SourceCodeInfo_Location** google_protobuf_SourceCodeInfo_resize_location(google_protobuf_SourceCodeInfo *msg, size_t len, upb_arena *arena) {
- return (google_protobuf_SourceCodeInfo_Location**)_upb_array_resize_accessor(msg, UPB_SIZE(0, 0), len, UPB_TYPE_MESSAGE, arena);
+ return (google_protobuf_SourceCodeInfo_Location**)_upb_array_resize_accessor2(msg, UPB_SIZE(0, 0), len, UPB_SIZE(2, 3), arena);
}
UPB_INLINE struct google_protobuf_SourceCodeInfo_Location* google_protobuf_SourceCodeInfo_add_location(google_protobuf_SourceCodeInfo *msg, upb_arena *arena) {
struct google_protobuf_SourceCodeInfo_Location* sub = (struct google_protobuf_SourceCodeInfo_Location*)_upb_msg_new(&google_protobuf_SourceCodeInfo_Location_msginit, arena);
- bool ok = _upb_array_append_accessor(
- msg, UPB_SIZE(0, 0), UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, &sub, arena);
+ bool ok = _upb_array_append_accessor2(
+ msg, UPB_SIZE(0, 0), UPB_SIZE(2, 3), &sub, arena);
if (!ok) return NULL;
return sub;
}
@@ -2943,15 +3733,21 @@ UPB_INLINE google_protobuf_SourceCodeInfo_Location *google_protobuf_SourceCodeIn
google_protobuf_SourceCodeInfo_Location *ret = google_protobuf_SourceCodeInfo_Location_new(arena);
return (ret && upb_decode(buf, size, ret, &google_protobuf_SourceCodeInfo_Location_msginit, arena)) ? ret : NULL;
}
+UPB_INLINE google_protobuf_SourceCodeInfo_Location *google_protobuf_SourceCodeInfo_Location_parse_ex(const char *buf, size_t size,
+ upb_arena *arena, int options) {
+ google_protobuf_SourceCodeInfo_Location *ret = google_protobuf_SourceCodeInfo_Location_new(arena);
+ return (ret && _upb_decode(buf, size, ret, &google_protobuf_SourceCodeInfo_Location_msginit, arena, options))
+ ? ret : NULL;
+}
UPB_INLINE char *google_protobuf_SourceCodeInfo_Location_serialize(const google_protobuf_SourceCodeInfo_Location *msg, upb_arena *arena, size_t *len) {
return upb_encode(msg, &google_protobuf_SourceCodeInfo_Location_msginit, arena, len);
}
UPB_INLINE int32_t const* google_protobuf_SourceCodeInfo_Location_path(const google_protobuf_SourceCodeInfo_Location *msg, size_t *len) { return (int32_t const*)_upb_array_accessor(msg, UPB_SIZE(20, 40), len); }
UPB_INLINE int32_t const* google_protobuf_SourceCodeInfo_Location_span(const google_protobuf_SourceCodeInfo_Location *msg, size_t *len) { return (int32_t const*)_upb_array_accessor(msg, UPB_SIZE(24, 48), len); }
-UPB_INLINE bool google_protobuf_SourceCodeInfo_Location_has_leading_comments(const google_protobuf_SourceCodeInfo_Location *msg) { return _upb_has_field(msg, 1); }
+UPB_INLINE bool google_protobuf_SourceCodeInfo_Location_has_leading_comments(const google_protobuf_SourceCodeInfo_Location *msg) { return _upb_hasbit(msg, 1); }
UPB_INLINE upb_strview google_protobuf_SourceCodeInfo_Location_leading_comments(const google_protobuf_SourceCodeInfo_Location *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview); }
-UPB_INLINE bool google_protobuf_SourceCodeInfo_Location_has_trailing_comments(const google_protobuf_SourceCodeInfo_Location *msg) { return _upb_has_field(msg, 2); }
+UPB_INLINE bool google_protobuf_SourceCodeInfo_Location_has_trailing_comments(const google_protobuf_SourceCodeInfo_Location *msg) { return _upb_hasbit(msg, 2); }
UPB_INLINE upb_strview google_protobuf_SourceCodeInfo_Location_trailing_comments(const google_protobuf_SourceCodeInfo_Location *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_strview); }
UPB_INLINE upb_strview const* google_protobuf_SourceCodeInfo_Location_leading_detached_comments(const google_protobuf_SourceCodeInfo_Location *msg, size_t *len) { return (upb_strview const*)_upb_array_accessor(msg, UPB_SIZE(28, 56), len); }
@@ -2959,20 +3755,20 @@ UPB_INLINE int32_t* google_protobuf_SourceCodeInfo_Location_mutable_path(google_
return (int32_t*)_upb_array_mutable_accessor(msg, UPB_SIZE(20, 40), len);
}
UPB_INLINE int32_t* google_protobuf_SourceCodeInfo_Location_resize_path(google_protobuf_SourceCodeInfo_Location *msg, size_t len, upb_arena *arena) {
- return (int32_t*)_upb_array_resize_accessor(msg, UPB_SIZE(20, 40), len, UPB_TYPE_INT32, arena);
+ return (int32_t*)_upb_array_resize_accessor2(msg, UPB_SIZE(20, 40), len, 2, arena);
}
UPB_INLINE bool google_protobuf_SourceCodeInfo_Location_add_path(google_protobuf_SourceCodeInfo_Location *msg, int32_t val, upb_arena *arena) {
- return _upb_array_append_accessor(msg, UPB_SIZE(20, 40), UPB_SIZE(4, 4), UPB_TYPE_INT32, &val,
+ return _upb_array_append_accessor2(msg, UPB_SIZE(20, 40), 2, &val,
arena);
}
UPB_INLINE int32_t* google_protobuf_SourceCodeInfo_Location_mutable_span(google_protobuf_SourceCodeInfo_Location *msg, size_t *len) {
return (int32_t*)_upb_array_mutable_accessor(msg, UPB_SIZE(24, 48), len);
}
UPB_INLINE int32_t* google_protobuf_SourceCodeInfo_Location_resize_span(google_protobuf_SourceCodeInfo_Location *msg, size_t len, upb_arena *arena) {
- return (int32_t*)_upb_array_resize_accessor(msg, UPB_SIZE(24, 48), len, UPB_TYPE_INT32, arena);
+ return (int32_t*)_upb_array_resize_accessor2(msg, UPB_SIZE(24, 48), len, 2, arena);
}
UPB_INLINE bool google_protobuf_SourceCodeInfo_Location_add_span(google_protobuf_SourceCodeInfo_Location *msg, int32_t val, upb_arena *arena) {
- return _upb_array_append_accessor(msg, UPB_SIZE(24, 48), UPB_SIZE(4, 4), UPB_TYPE_INT32, &val,
+ return _upb_array_append_accessor2(msg, UPB_SIZE(24, 48), 2, &val,
arena);
}
UPB_INLINE void google_protobuf_SourceCodeInfo_Location_set_leading_comments(google_protobuf_SourceCodeInfo_Location *msg, upb_strview value) {
@@ -2987,10 +3783,10 @@ UPB_INLINE upb_strview* google_protobuf_SourceCodeInfo_Location_mutable_leading_
return (upb_strview*)_upb_array_mutable_accessor(msg, UPB_SIZE(28, 56), len);
}
UPB_INLINE upb_strview* google_protobuf_SourceCodeInfo_Location_resize_leading_detached_comments(google_protobuf_SourceCodeInfo_Location *msg, size_t len, upb_arena *arena) {
- return (upb_strview*)_upb_array_resize_accessor(msg, UPB_SIZE(28, 56), len, UPB_TYPE_STRING, arena);
+ return (upb_strview*)_upb_array_resize_accessor2(msg, UPB_SIZE(28, 56), len, UPB_SIZE(3, 4), arena);
}
UPB_INLINE bool google_protobuf_SourceCodeInfo_Location_add_leading_detached_comments(google_protobuf_SourceCodeInfo_Location *msg, upb_strview val, upb_arena *arena) {
- return _upb_array_append_accessor(msg, UPB_SIZE(28, 56), UPB_SIZE(8, 16), UPB_TYPE_STRING, &val,
+ return _upb_array_append_accessor2(msg, UPB_SIZE(28, 56), UPB_SIZE(3, 4), &val,
arena);
}
@@ -3004,6 +3800,12 @@ UPB_INLINE google_protobuf_GeneratedCodeInfo *google_protobuf_GeneratedCodeInfo_
google_protobuf_GeneratedCodeInfo *ret = google_protobuf_GeneratedCodeInfo_new(arena);
return (ret && upb_decode(buf, size, ret, &google_protobuf_GeneratedCodeInfo_msginit, arena)) ? ret : NULL;
}
+UPB_INLINE google_protobuf_GeneratedCodeInfo *google_protobuf_GeneratedCodeInfo_parse_ex(const char *buf, size_t size,
+ upb_arena *arena, int options) {
+ google_protobuf_GeneratedCodeInfo *ret = google_protobuf_GeneratedCodeInfo_new(arena);
+ return (ret && _upb_decode(buf, size, ret, &google_protobuf_GeneratedCodeInfo_msginit, arena, options))
+ ? ret : NULL;
+}
UPB_INLINE char *google_protobuf_GeneratedCodeInfo_serialize(const google_protobuf_GeneratedCodeInfo *msg, upb_arena *arena, size_t *len) {
return upb_encode(msg, &google_protobuf_GeneratedCodeInfo_msginit, arena, len);
}
@@ -3015,12 +3817,12 @@ UPB_INLINE google_protobuf_GeneratedCodeInfo_Annotation** google_protobuf_Genera
return (google_protobuf_GeneratedCodeInfo_Annotation**)_upb_array_mutable_accessor(msg, UPB_SIZE(0, 0), len);
}
UPB_INLINE google_protobuf_GeneratedCodeInfo_Annotation** google_protobuf_GeneratedCodeInfo_resize_annotation(google_protobuf_GeneratedCodeInfo *msg, size_t len, upb_arena *arena) {
- return (google_protobuf_GeneratedCodeInfo_Annotation**)_upb_array_resize_accessor(msg, UPB_SIZE(0, 0), len, UPB_TYPE_MESSAGE, arena);
+ return (google_protobuf_GeneratedCodeInfo_Annotation**)_upb_array_resize_accessor2(msg, UPB_SIZE(0, 0), len, UPB_SIZE(2, 3), arena);
}
UPB_INLINE struct google_protobuf_GeneratedCodeInfo_Annotation* google_protobuf_GeneratedCodeInfo_add_annotation(google_protobuf_GeneratedCodeInfo *msg, upb_arena *arena) {
struct google_protobuf_GeneratedCodeInfo_Annotation* sub = (struct google_protobuf_GeneratedCodeInfo_Annotation*)_upb_msg_new(&google_protobuf_GeneratedCodeInfo_Annotation_msginit, arena);
- bool ok = _upb_array_append_accessor(
- msg, UPB_SIZE(0, 0), UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, &sub, arena);
+ bool ok = _upb_array_append_accessor2(
+ msg, UPB_SIZE(0, 0), UPB_SIZE(2, 3), &sub, arena);
if (!ok) return NULL;
return sub;
}
@@ -3035,38 +3837,44 @@ UPB_INLINE google_protobuf_GeneratedCodeInfo_Annotation *google_protobuf_Generat
google_protobuf_GeneratedCodeInfo_Annotation *ret = google_protobuf_GeneratedCodeInfo_Annotation_new(arena);
return (ret && upb_decode(buf, size, ret, &google_protobuf_GeneratedCodeInfo_Annotation_msginit, arena)) ? ret : NULL;
}
+UPB_INLINE google_protobuf_GeneratedCodeInfo_Annotation *google_protobuf_GeneratedCodeInfo_Annotation_parse_ex(const char *buf, size_t size,
+ upb_arena *arena, int options) {
+ google_protobuf_GeneratedCodeInfo_Annotation *ret = google_protobuf_GeneratedCodeInfo_Annotation_new(arena);
+ return (ret && _upb_decode(buf, size, ret, &google_protobuf_GeneratedCodeInfo_Annotation_msginit, arena, options))
+ ? ret : NULL;
+}
UPB_INLINE char *google_protobuf_GeneratedCodeInfo_Annotation_serialize(const google_protobuf_GeneratedCodeInfo_Annotation *msg, upb_arena *arena, size_t *len) {
return upb_encode(msg, &google_protobuf_GeneratedCodeInfo_Annotation_msginit, arena, len);
}
UPB_INLINE int32_t const* google_protobuf_GeneratedCodeInfo_Annotation_path(const google_protobuf_GeneratedCodeInfo_Annotation *msg, size_t *len) { return (int32_t const*)_upb_array_accessor(msg, UPB_SIZE(20, 32), len); }
-UPB_INLINE bool google_protobuf_GeneratedCodeInfo_Annotation_has_source_file(const google_protobuf_GeneratedCodeInfo_Annotation *msg) { return _upb_has_field(msg, 3); }
+UPB_INLINE bool google_protobuf_GeneratedCodeInfo_Annotation_has_source_file(const google_protobuf_GeneratedCodeInfo_Annotation *msg) { return _upb_hasbit(msg, 1); }
UPB_INLINE upb_strview google_protobuf_GeneratedCodeInfo_Annotation_source_file(const google_protobuf_GeneratedCodeInfo_Annotation *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 16), upb_strview); }
-UPB_INLINE bool google_protobuf_GeneratedCodeInfo_Annotation_has_begin(const google_protobuf_GeneratedCodeInfo_Annotation *msg) { return _upb_has_field(msg, 1); }
+UPB_INLINE bool google_protobuf_GeneratedCodeInfo_Annotation_has_begin(const google_protobuf_GeneratedCodeInfo_Annotation *msg) { return _upb_hasbit(msg, 2); }
UPB_INLINE int32_t google_protobuf_GeneratedCodeInfo_Annotation_begin(const google_protobuf_GeneratedCodeInfo_Annotation *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t); }
-UPB_INLINE bool google_protobuf_GeneratedCodeInfo_Annotation_has_end(const google_protobuf_GeneratedCodeInfo_Annotation *msg) { return _upb_has_field(msg, 2); }
+UPB_INLINE bool google_protobuf_GeneratedCodeInfo_Annotation_has_end(const google_protobuf_GeneratedCodeInfo_Annotation *msg) { return _upb_hasbit(msg, 3); }
UPB_INLINE int32_t google_protobuf_GeneratedCodeInfo_Annotation_end(const google_protobuf_GeneratedCodeInfo_Annotation *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t); }
UPB_INLINE int32_t* google_protobuf_GeneratedCodeInfo_Annotation_mutable_path(google_protobuf_GeneratedCodeInfo_Annotation *msg, size_t *len) {
return (int32_t*)_upb_array_mutable_accessor(msg, UPB_SIZE(20, 32), len);
}
UPB_INLINE int32_t* google_protobuf_GeneratedCodeInfo_Annotation_resize_path(google_protobuf_GeneratedCodeInfo_Annotation *msg, size_t len, upb_arena *arena) {
- return (int32_t*)_upb_array_resize_accessor(msg, UPB_SIZE(20, 32), len, UPB_TYPE_INT32, arena);
+ return (int32_t*)_upb_array_resize_accessor2(msg, UPB_SIZE(20, 32), len, 2, arena);
}
UPB_INLINE bool google_protobuf_GeneratedCodeInfo_Annotation_add_path(google_protobuf_GeneratedCodeInfo_Annotation *msg, int32_t val, upb_arena *arena) {
- return _upb_array_append_accessor(msg, UPB_SIZE(20, 32), UPB_SIZE(4, 4), UPB_TYPE_INT32, &val,
+ return _upb_array_append_accessor2(msg, UPB_SIZE(20, 32), 2, &val,
arena);
}
UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_set_source_file(google_protobuf_GeneratedCodeInfo_Annotation *msg, upb_strview value) {
- _upb_sethas(msg, 3);
+ _upb_sethas(msg, 1);
*UPB_PTR_AT(msg, UPB_SIZE(12, 16), upb_strview) = value;
}
UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_set_begin(google_protobuf_GeneratedCodeInfo_Annotation *msg, int32_t value) {
- _upb_sethas(msg, 1);
+ _upb_sethas(msg, 2);
*UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = value;
}
UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_set_end(google_protobuf_GeneratedCodeInfo_Annotation *msg, int32_t value) {
- _upb_sethas(msg, 2);
+ _upb_sethas(msg, 3);
*UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t) = value;
}
@@ -3093,6 +3901,7 @@ UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_set_end(google_prot
#define UPB_DEF_H_
+/* Must be last. */
#ifdef __cplusplus
extern "C" {
@@ -3191,9 +4000,10 @@ typedef upb_inttable_iter upb_oneof_iter;
const char *upb_oneofdef_name(const upb_oneofdef *o);
const upb_msgdef *upb_oneofdef_containingtype(const upb_oneofdef *o);
-int upb_oneofdef_numfields(const upb_oneofdef *o);
uint32_t upb_oneofdef_index(const upb_oneofdef *o);
bool upb_oneofdef_issynthetic(const upb_oneofdef *o);
+int upb_oneofdef_fieldcount(const upb_oneofdef *o);
+const upb_fielddef *upb_oneofdef_field(const upb_oneofdef *o, int i);
/* Oneof lookups:
* - ntof: look up a field by name.
@@ -3207,11 +4017,8 @@ UPB_INLINE const upb_fielddef *upb_oneofdef_ntofz(const upb_oneofdef *o,
}
const upb_fielddef *upb_oneofdef_itof(const upb_oneofdef *o, uint32_t num);
-/* upb_oneof_iter i;
- * for(upb_oneof_begin(&i, e); !upb_oneof_done(&i); upb_oneof_next(&i)) {
- * // ...
- * }
- */
+/* DEPRECATED, slated for removal. */
+int upb_oneofdef_numfields(const upb_oneofdef *o);
void upb_oneof_begin(upb_oneof_iter *iter, const upb_oneofdef *o);
void upb_oneof_next(upb_oneof_iter *iter);
bool upb_oneof_done(upb_oneof_iter *iter);
@@ -3219,6 +4026,7 @@ upb_fielddef *upb_oneof_iter_field(const upb_oneof_iter *iter);
void upb_oneof_iter_setdone(upb_oneof_iter *iter);
bool upb_oneof_iter_isequal(const upb_oneof_iter *iter1,
const upb_oneof_iter *iter2);
+/* END DEPRECATED */
/* upb_msgdef *****************************************************************/
@@ -3244,20 +4052,21 @@ typedef upb_strtable_iter upb_msg_oneof_iter;
const char *upb_msgdef_fullname(const upb_msgdef *m);
const upb_filedef *upb_msgdef_file(const upb_msgdef *m);
const char *upb_msgdef_name(const upb_msgdef *m);
-int upb_msgdef_numfields(const upb_msgdef *m);
-int upb_msgdef_numoneofs(const upb_msgdef *m);
-int upb_msgdef_numrealoneofs(const upb_msgdef *m);
upb_syntax_t upb_msgdef_syntax(const upb_msgdef *m);
bool upb_msgdef_mapentry(const upb_msgdef *m);
upb_wellknowntype_t upb_msgdef_wellknowntype(const upb_msgdef *m);
+bool upb_msgdef_iswrapper(const upb_msgdef *m);
bool upb_msgdef_isnumberwrapper(const upb_msgdef *m);
+int upb_msgdef_fieldcount(const upb_msgdef *m);
+int upb_msgdef_oneofcount(const upb_msgdef *m);
+const upb_fielddef *upb_msgdef_field(const upb_msgdef *m, int i);
+const upb_oneofdef *upb_msgdef_oneof(const upb_msgdef *m, int i);
const upb_fielddef *upb_msgdef_itof(const upb_msgdef *m, uint32_t i);
const upb_fielddef *upb_msgdef_ntof(const upb_msgdef *m, const char *name,
size_t len);
const upb_oneofdef *upb_msgdef_ntoo(const upb_msgdef *m, const char *name,
size_t len);
const upb_msglayout *upb_msgdef_layout(const upb_msgdef *m);
-const upb_fielddef *_upb_msgdef_field(const upb_msgdef *m, int i);
UPB_INLINE const upb_oneofdef *upb_msgdef_ntooz(const upb_msgdef *m,
const char *name) {
@@ -3289,19 +4098,10 @@ UPB_INLINE bool upb_msgdef_lookupnamez(const upb_msgdef *m, const char *name,
const upb_fielddef *upb_msgdef_lookupjsonname(const upb_msgdef *m,
const char *name, size_t len);
-/* Iteration over fields and oneofs. For example:
- *
- * upb_msg_field_iter i;
- * for(upb_msg_field_begin(&i, m);
- * !upb_msg_field_done(&i);
- * upb_msg_field_next(&i)) {
- * upb_fielddef *f = upb_msg_iter_field(&i);
- * // ...
- * }
- *
- * For C we don't have separate iterators for const and non-const.
- * It is the caller's responsibility to cast the upb_fielddef* to
- * const if the upb_msgdef* is const. */
+/* DEPRECATED, slated for removal */
+int upb_msgdef_numfields(const upb_msgdef *m);
+int upb_msgdef_numoneofs(const upb_msgdef *m);
+int upb_msgdef_numrealoneofs(const upb_msgdef *m);
void upb_msg_field_begin(upb_msg_field_iter *iter, const upb_msgdef *m);
void upb_msg_field_next(upb_msg_field_iter *iter);
bool upb_msg_field_done(const upb_msg_field_iter *iter);
@@ -3309,9 +4109,6 @@ upb_fielddef *upb_msg_iter_field(const upb_msg_field_iter *iter);
void upb_msg_field_iter_setdone(upb_msg_field_iter *iter);
bool upb_msg_field_iter_isequal(const upb_msg_field_iter * iter1,
const upb_msg_field_iter * iter2);
-
-/* Similar to above, we also support iterating through the oneofs in a
- * msgdef. */
void upb_msg_oneof_begin(upb_msg_oneof_iter * iter, const upb_msgdef *m);
void upb_msg_oneof_next(upb_msg_oneof_iter * iter);
bool upb_msg_oneof_done(const upb_msg_oneof_iter *iter);
@@ -3319,6 +4116,7 @@ const upb_oneofdef *upb_msg_iter_oneof(const upb_msg_oneof_iter *iter);
void upb_msg_oneof_iter_setdone(upb_msg_oneof_iter * iter);
bool upb_msg_oneof_iter_isequal(const upb_msg_oneof_iter *iter1,
const upb_msg_oneof_iter *iter2);
+/* END DEPRECATED */
/* upb_enumdef ****************************************************************/
@@ -3343,11 +4141,6 @@ UPB_INLINE bool upb_enumdef_ntoiz(const upb_enumdef *e,
}
const char *upb_enumdef_iton(const upb_enumdef *e, int32_t num);
-/* upb_enum_iter i;
- * for(upb_enum_begin(&i, e); !upb_enum_done(&i); upb_enum_next(&i)) {
- * // ...
- * }
- */
void upb_enum_begin(upb_enum_iter *iter, const upb_enumdef *e);
void upb_enum_next(upb_enum_iter *iter);
bool upb_enum_done(upb_enum_iter *iter);
@@ -3367,6 +4160,8 @@ int upb_filedef_enumcount(const upb_filedef *f);
const upb_filedef *upb_filedef_dep(const upb_filedef *f, int i);
const upb_msgdef *upb_filedef_msg(const upb_filedef *f, int i);
const upb_enumdef *upb_filedef_enum(const upb_filedef *f, int i);
+const upb_symtab *upb_filedef_symtab(const upb_filedef *f);
+upb_arena *_upb_symtab_arena(const upb_symtab *s);
/* upb_symtab *****************************************************************/
@@ -3377,10 +4172,13 @@ const upb_msgdef *upb_symtab_lookupmsg2(
const upb_symtab *s, const char *sym, size_t len);
const upb_enumdef *upb_symtab_lookupenum(const upb_symtab *s, const char *sym);
const upb_filedef *upb_symtab_lookupfile(const upb_symtab *s, const char *name);
+const upb_filedef *upb_symtab_lookupfile2(
+ const upb_symtab *s, const char *name, size_t len);
int upb_symtab_filecount(const upb_symtab *s);
const upb_filedef *upb_symtab_addfile(
upb_symtab *s, const google_protobuf_FileDescriptorProto *file,
upb_status *status);
+size_t _upb_symtab_bytesloaded(const upb_symtab *s);
/* For generated code only: loads a generated descriptor. */
typedef struct upb_def_init {
@@ -3404,6 +4202,10 @@ bool _upb_symtab_loaddefinit(upb_symtab *s, const upb_def_init *init);
+#ifdef __cplusplus
+extern "C" {
+#endif
+
typedef union {
bool bool_val;
float float_val;
@@ -3424,6 +4226,8 @@ typedef union {
upb_array* array;
} upb_mutmsgval;
+upb_msgval upb_fielddef_default(const upb_fielddef *f);
+
/** upb_msg *******************************************************************/
/* Creates a new message of the given type in the given arena. */
@@ -3440,8 +4244,9 @@ upb_mutmsgval upb_msg_mutable(upb_msg *msg, const upb_fielddef *f, upb_arena *a)
/* May only be called for fields where upb_fielddef_haspresence(f) == true. */
bool upb_msg_has(const upb_msg *msg, const upb_fielddef *f);
-/* Returns whether any field is set in the oneof. */
-bool upb_msg_hasoneof(const upb_msg *msg, const upb_oneofdef *o);
+/* Returns the field that is set in the oneof, or NULL if none are set. */
+const upb_fielddef *upb_msg_whichoneof(const upb_msg *msg,
+ const upb_oneofdef *o);
/* Sets the given field to the given value. For a msg/array/map/string, the
* value must be in the same arena. */
@@ -3451,6 +4256,9 @@ void upb_msg_set(upb_msg *msg, const upb_fielddef *f, upb_msgval val,
/* Clears any field presence and sets the value back to its default. */
void upb_msg_clearfield(upb_msg *msg, const upb_fielddef *f);
+/* Clear all data and unknown fields. */
+void upb_msg_clear(upb_msg *msg, const upb_msgdef *m);
+
/* Iterate over present fields.
*
* size_t iter = UPB_MSG_BEGIN;
@@ -3475,6 +4283,9 @@ bool upb_msg_next(const upb_msg *msg, const upb_msgdef *m,
void upb_msg_addunknown(upb_msg *msg, const char *data, size_t len,
upb_arena *arena);
+/* Clears all unknown field data from this message and all submessages. */
+bool upb_msg_discardunknown(upb_msg *msg, const upb_msgdef *m, int maxdepth);
+
/* Returns a reference to the message's unknown data. */
const char *upb_msg_getunknown(const upb_msg *msg, size_t *len);
@@ -3539,6 +4350,11 @@ bool upb_map_delete(upb_map *map, upb_msgval key);
/* Advances to the next entry. Returns false if no more entries are present. */
bool upb_mapiter_next(const upb_map *map, size_t *iter);
+/* Returns true if the iterator still points to a valid entry, or false if the
+ * iterator is past the last element. It is an error to call this function with
+ * UPB_MAP_BEGIN (you must call next() at least once first). */
+bool upb_mapiter_done(const upb_map *map, size_t iter);
+
/* Returns the key and value for this entry of the map. */
upb_msgval upb_mapiter_key(const upb_map *map, size_t iter);
upb_msgval upb_mapiter_value(const upb_map *map, size_t iter);
@@ -3547,3211 +4363,69 @@ upb_msgval upb_mapiter_value(const upb_map *map, size_t iter);
* iterator must not have been initialized const. */
void upb_mapiter_setvalue(upb_map *map, size_t iter, upb_msgval value);
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
-#endif /* UPB_REFLECTION_H_ */
-/*
-** upb::Handlers (upb_handlers)
-**
-** A upb_handlers is like a virtual table for a upb_msgdef. Each field of the
-** message can have associated functions that will be called when we are
-** parsing or visiting a stream of data. This is similar to how handlers work
-** in SAX (the Simple API for XML).
-**
-** The handlers have no idea where the data is coming from, so a single set of
-** handlers could be used with two completely different data sources (for
-** example, a parser and a visitor over in-memory objects). This decoupling is
-** the most important feature of upb, because it allows parsers and serializers
-** to be highly reusable.
-**
-** This is a mixed C/C++ interface that offers a full API to both languages.
-** See the top-level README for more information.
-*/
-#ifndef UPB_HANDLERS_H
-#define UPB_HANDLERS_H
+#endif /* UPB_REFLECTION_H_ */
+#ifndef UPB_JSONDECODE_H_
+#define UPB_JSONDECODE_H_
#ifdef __cplusplus
-namespace upb {
-class HandlersPtr;
-class HandlerCache;
-template class Handler;
-template struct CanonicalType;
-} /* namespace upb */
+extern "C" {
#endif
+enum {
+ UPB_JSONDEC_IGNOREUNKNOWN = 1
+};
-/* The maximum depth that the handler graph can have. This is a resource limit
- * for the C stack since we sometimes need to recursively traverse the graph.
- * Cycles are ok; the traversal will stop when it detects a cycle, but we must
- * hit the cycle before the maximum depth is reached.
- *
- * If having a single static limit is too inflexible, we can add another variant
- * of Handlers::Freeze that allows specifying this as a parameter. */
-#define UPB_MAX_HANDLER_DEPTH 64
-
-/* All the different types of handlers that can be registered.
- * Only needed for the advanced functions in upb::Handlers. */
-typedef enum {
- UPB_HANDLER_INT32,
- UPB_HANDLER_INT64,
- UPB_HANDLER_UINT32,
- UPB_HANDLER_UINT64,
- UPB_HANDLER_FLOAT,
- UPB_HANDLER_DOUBLE,
- UPB_HANDLER_BOOL,
- UPB_HANDLER_STARTSTR,
- UPB_HANDLER_STRING,
- UPB_HANDLER_ENDSTR,
- UPB_HANDLER_STARTSUBMSG,
- UPB_HANDLER_ENDSUBMSG,
- UPB_HANDLER_STARTSEQ,
- UPB_HANDLER_ENDSEQ
-} upb_handlertype_t;
-
-#define UPB_HANDLER_MAX (UPB_HANDLER_ENDSEQ+1)
-
-#define UPB_BREAK NULL
-
-/* A convenient definition for when no closure is needed. */
-extern char _upb_noclosure;
-#define UPB_NO_CLOSURE &_upb_noclosure
-
-/* A selector refers to a specific field handler in the Handlers object
- * (for example: the STARTSUBMSG handler for field "field15"). */
-typedef int32_t upb_selector_t;
-
-/* Static selectors for upb::Handlers. */
-#define UPB_STARTMSG_SELECTOR 0
-#define UPB_ENDMSG_SELECTOR 1
-#define UPB_UNKNOWN_SELECTOR 2
-#define UPB_STATIC_SELECTOR_COUNT 3 /* Warning: also in upb/def.c. */
-
-/* Static selectors for upb::BytesHandler. */
-#define UPB_STARTSTR_SELECTOR 0
-#define UPB_STRING_SELECTOR 1
-#define UPB_ENDSTR_SELECTOR 2
+bool upb_json_decode(const char *buf, size_t size, upb_msg *msg,
+ const upb_msgdef *m, const upb_symtab *any_pool,
+ int options, upb_arena *arena, upb_status *status);
#ifdef __cplusplus
-template const void *UniquePtrForType() {
- static const char ch = 0;
- return &ch;
-}
+} /* extern "C" */
#endif
-/* upb_handlers ************************************************************/
-
-/* Handler attributes, to be registered with the handler itself. */
-typedef struct {
- const void *handler_data;
- const void *closure_type;
- const void *return_closure_type;
- bool alwaysok;
-} upb_handlerattr;
-
-#define UPB_HANDLERATTR_INIT {NULL, NULL, NULL, false}
-
-/* Bufhandle, data passed along with a buffer to indicate its provenance. */
-typedef struct {
- /* The beginning of the buffer. This may be different than the pointer
- * passed to a StringBuf handler because the handler may receive data
- * that is from the middle or end of a larger buffer. */
- const char *buf;
-
- /* The offset within the attached object where this buffer begins. Only
- * meaningful if there is an attached object. */
- size_t objofs;
-
- /* The attached object (if any) and a pointer representing its type. */
- const void *obj;
- const void *objtype;
+#endif /* UPB_JSONDECODE_H_ */
-#ifdef __cplusplus
- template
- void SetAttachedObject(const T* _obj) {
- obj = _obj;
- objtype = UniquePtrForType();
- }
+#ifndef UPB_JSONENCODE_H_
+#define UPB_JSONENCODE_H_
- template
- const T *GetAttachedObject() const {
- return objtype == UniquePtrForType() ? static_cast(obj)
- : NULL;
- }
-#endif
-} upb_bufhandle;
-
-#define UPB_BUFHANDLE_INIT {NULL, 0, NULL, NULL}
-
-/* Handler function typedefs. */
-typedef void upb_handlerfree(void *d);
-typedef bool upb_unknown_handlerfunc(void *c, const void *hd, const char *buf,
- size_t n);
-typedef bool upb_startmsg_handlerfunc(void *c, const void*);
-typedef bool upb_endmsg_handlerfunc(void *c, const void *, upb_status *status);
-typedef void* upb_startfield_handlerfunc(void *c, const void *hd);
-typedef bool upb_endfield_handlerfunc(void *c, const void *hd);
-typedef bool upb_int32_handlerfunc(void *c, const void *hd, int32_t val);
-typedef bool upb_int64_handlerfunc(void *c, const void *hd, int64_t val);
-typedef bool upb_uint32_handlerfunc(void *c, const void *hd, uint32_t val);
-typedef bool upb_uint64_handlerfunc(void *c, const void *hd, uint64_t val);
-typedef bool upb_float_handlerfunc(void *c, const void *hd, float val);
-typedef bool upb_double_handlerfunc(void *c, const void *hd, double val);
-typedef bool upb_bool_handlerfunc(void *c, const void *hd, bool val);
-typedef void *upb_startstr_handlerfunc(void *c, const void *hd,
- size_t size_hint);
-typedef size_t upb_string_handlerfunc(void *c, const void *hd, const char *buf,
- size_t n, const upb_bufhandle* handle);
-
-struct upb_handlers;
-typedef struct upb_handlers upb_handlers;
#ifdef __cplusplus
extern "C" {
#endif
-/* Mutating accessors. */
-const upb_status *upb_handlers_status(upb_handlers *h);
-void upb_handlers_clearerr(upb_handlers *h);
-const upb_msgdef *upb_handlers_msgdef(const upb_handlers *h);
-bool upb_handlers_addcleanup(upb_handlers *h, void *p, upb_handlerfree *hfree);
-bool upb_handlers_setunknown(upb_handlers *h, upb_unknown_handlerfunc *func,
- const upb_handlerattr *attr);
-bool upb_handlers_setstartmsg(upb_handlers *h, upb_startmsg_handlerfunc *func,
- const upb_handlerattr *attr);
-bool upb_handlers_setendmsg(upb_handlers *h, upb_endmsg_handlerfunc *func,
- const upb_handlerattr *attr);
-bool upb_handlers_setint32(upb_handlers *h, const upb_fielddef *f,
- upb_int32_handlerfunc *func,
- const upb_handlerattr *attr);
-bool upb_handlers_setint64(upb_handlers *h, const upb_fielddef *f,
- upb_int64_handlerfunc *func,
- const upb_handlerattr *attr);
-bool upb_handlers_setuint32(upb_handlers *h, const upb_fielddef *f,
- upb_uint32_handlerfunc *func,
- const upb_handlerattr *attr);
-bool upb_handlers_setuint64(upb_handlers *h, const upb_fielddef *f,
- upb_uint64_handlerfunc *func,
- const upb_handlerattr *attr);
-bool upb_handlers_setfloat(upb_handlers *h, const upb_fielddef *f,
- upb_float_handlerfunc *func,
- const upb_handlerattr *attr);
-bool upb_handlers_setdouble(upb_handlers *h, const upb_fielddef *f,
- upb_double_handlerfunc *func,
- const upb_handlerattr *attr);
-bool upb_handlers_setbool(upb_handlers *h, const upb_fielddef *f,
- upb_bool_handlerfunc *func,
- const upb_handlerattr *attr);
-bool upb_handlers_setstartstr(upb_handlers *h, const upb_fielddef *f,
- upb_startstr_handlerfunc *func,
- const upb_handlerattr *attr);
-bool upb_handlers_setstring(upb_handlers *h, const upb_fielddef *f,
- upb_string_handlerfunc *func,
- const upb_handlerattr *attr);
-bool upb_handlers_setendstr(upb_handlers *h, const upb_fielddef *f,
- upb_endfield_handlerfunc *func,
- const upb_handlerattr *attr);
-bool upb_handlers_setstartseq(upb_handlers *h, const upb_fielddef *f,
- upb_startfield_handlerfunc *func,
- const upb_handlerattr *attr);
-bool upb_handlers_setstartsubmsg(upb_handlers *h, const upb_fielddef *f,
- upb_startfield_handlerfunc *func,
- const upb_handlerattr *attr);
-bool upb_handlers_setendsubmsg(upb_handlers *h, const upb_fielddef *f,
- upb_endfield_handlerfunc *func,
- const upb_handlerattr *attr);
-bool upb_handlers_setendseq(upb_handlers *h, const upb_fielddef *f,
- upb_endfield_handlerfunc *func,
- const upb_handlerattr *attr);
-
-/* Read-only accessors. */
-const upb_handlers *upb_handlers_getsubhandlers(const upb_handlers *h,
- const upb_fielddef *f);
-const upb_handlers *upb_handlers_getsubhandlers_sel(const upb_handlers *h,
- upb_selector_t sel);
-upb_func *upb_handlers_gethandler(const upb_handlers *h, upb_selector_t s,
- const void **handler_data);
-bool upb_handlers_getattr(const upb_handlers *h, upb_selector_t s,
- upb_handlerattr *attr);
-
-/* "Static" methods */
-upb_handlertype_t upb_handlers_getprimitivehandlertype(const upb_fielddef *f);
-bool upb_handlers_getselector(const upb_fielddef *f, upb_handlertype_t type,
- upb_selector_t *s);
-UPB_INLINE upb_selector_t upb_handlers_getendselector(upb_selector_t start) {
- return start + 1;
-}
-
-#ifdef __cplusplus
-} /* extern "C" */
-
-namespace upb {
-typedef upb_handlers Handlers;
-}
-
-/* Convenience macros for creating a Handler object that is wrapped with a
- * type-safe wrapper function that converts the "void*" parameters/returns
- * of the underlying C API into nice C++ function.
- *
- * Sample usage:
- * void OnValue1(MyClosure* c, const MyHandlerData* d, int32_t val) {
- * // do stuff ...
- * }
- *
- * // Handler that doesn't need any data bound to it.
- * void OnValue2(MyClosure* c, int32_t val) {
- * // do stuff ...
- * }
- *
- * // Handler that returns bool so it can return failure if necessary.
- * bool OnValue3(MyClosure* c, int32_t val) {
- * // do stuff ...
- * return ok;
- * }
- *
- * // Member function handler.
- * class MyClosure {
- * public:
- * void OnValue(int32_t val) {
- * // do stuff ...
- * }
- * };
- *
- * // Takes ownership of the MyHandlerData.
- * handlers->SetInt32Handler(f1, UpbBind(OnValue1, new MyHandlerData(...)));
- * handlers->SetInt32Handler(f2, UpbMakeHandler(OnValue2));
- * handlers->SetInt32Handler(f1, UpbMakeHandler(OnValue3));
- * handlers->SetInt32Handler(f2, UpbMakeHandler(&MyClosure::OnValue));
- */
-
-/* In C++11, the "template" disambiguator can appear even outside templates,
- * so all calls can safely use this pair of macros. */
-
-#define UpbMakeHandler(f) upb::MatchFunc(f).template GetFunc()
-
-/* We have to be careful to only evaluate "d" once. */
-#define UpbBind(f, d) upb::MatchFunc(f).template GetFunc((d))
-
-/* Handler: a struct that contains the (handler, data, deleter) tuple that is
- * used to register all handlers. Users can Make() these directly but it's
- * more convenient to use the UpbMakeHandler/UpbBind macros above. */
-template class upb::Handler {
- public:
- /* The underlying, handler function signature that upb uses internally. */
- typedef T FuncPtr;
-
- /* Intentionally implicit. */
- template Handler(F func);
- ~Handler() { UPB_ASSERT(registered_); }
-
- void AddCleanup(upb_handlers* h) const;
- FuncPtr handler() const { return handler_; }
- const upb_handlerattr& attr() const { return attr_; }
-
- private:
- Handler(const Handler&) = delete;
- Handler& operator=(const Handler&) = delete;
+enum {
+ /* When set, emits 0/default values. TODO(haberman): proto3 only? */
+ UPB_JSONENC_EMITDEFAULTS = 1,
- FuncPtr handler_;
- mutable upb_handlerattr attr_;
- mutable bool registered_;
- void *cleanup_data_;
- upb_handlerfree *cleanup_func_;
+ /* When set, use normal (snake_caes) field names instead of JSON (camelCase)
+ names. */
+ UPB_JSONENC_PROTONAMES = 2
};
-/* A upb::Handlers object represents the set of handlers associated with a
- * message in the graph of messages. You can think of it as a big virtual
- * table with functions corresponding to all the events that can fire while
- * parsing or visiting a message of a specific type.
+/* Encodes the given |msg| to JSON format. The message's reflection is given in
+ * |m|. The symtab in |symtab| is used to find extensions (if NULL, extensions
+ * will not be printed).
*
- * Any handlers that are not set behave as if they had successfully consumed
- * the value. Any unset Start* handlers will propagate their closure to the
- * inner frame.
- *
- * The easiest way to create the *Handler objects needed by the Set* methods is
- * with the UpbBind() and UpbMakeHandler() macros; see below. */
-class upb::HandlersPtr {
- public:
- HandlersPtr(upb_handlers* ptr) : ptr_(ptr) {}
-
- upb_handlers* ptr() const { return ptr_; }
-
- typedef upb_selector_t Selector;
- typedef upb_handlertype_t Type;
-
- typedef Handler StartFieldHandler;
- typedef Handler EndFieldHandler;
- typedef Handler StartMessageHandler;
- typedef Handler
- EndMessageHandler;
- typedef Handler StartStringHandler;
- typedef Handler
- StringHandler;
-
- template struct ValueHandler {
- typedef Handler H;
- };
-
- typedef ValueHandler::H Int32Handler;
- typedef ValueHandler::H Int64Handler;
- typedef ValueHandler::H UInt32Handler;
- typedef ValueHandler::H UInt64Handler;
- typedef ValueHandler::H FloatHandler;
- typedef ValueHandler::H DoubleHandler;
- typedef ValueHandler::H BoolHandler;
-
- /* Any function pointer can be converted to this and converted back to its
- * correct type. */
- typedef void GenericFunction();
-
- typedef void HandlersCallback(const void *closure, upb_handlers *h);
-
- /* Returns the msgdef associated with this handlers object. */
- MessageDefPtr message_def() const {
- return MessageDefPtr(upb_handlers_msgdef(ptr()));
- }
-
- /* Adds the given pointer and function to the list of cleanup functions that
- * will be run when these handlers are freed. If this pointer has previously
- * been registered, the function returns false and does nothing. */
- bool AddCleanup(void *ptr, upb_handlerfree *cleanup) {
- return upb_handlers_addcleanup(ptr_, ptr, cleanup);
- }
-
- /* Sets the startmsg handler for the message, which is defined as follows:
- *
- * bool startmsg(MyType* closure) {
- * // Called when the message begins. Returns true if processing should
- * // continue.
- * return true;
- * }
- */
- bool SetStartMessageHandler(const StartMessageHandler &h) {
- h.AddCleanup(ptr());
- return upb_handlers_setstartmsg(ptr(), h.handler(), &h.attr());
- }
-
- /* Sets the endmsg handler for the message, which is defined as follows:
- *
- * bool endmsg(MyType* closure, upb_status *status) {
- * // Called when processing of this message ends, whether in success or
- * // failure. "status" indicates the final status of processing, and
- * // can also be modified in-place to update the final status.
- * }
- */
- bool SetEndMessageHandler(const EndMessageHandler& h) {
- h.AddCleanup(ptr());
- return upb_handlers_setendmsg(ptr(), h.handler(), &h.attr());
- }
-
- /* Sets the value handler for the given field, which is defined as follows
- * (this is for an int32 field; other field types will pass their native
- * C/C++ type for "val"):
- *
- * bool OnValue(MyClosure* c, const MyHandlerData* d, int32_t val) {
- * // Called when the field's value is encountered. "d" contains
- * // whatever data was bound to this field when it was registered.
- * // Returns true if processing should continue.
- * return true;
- * }
- *
- * handers->SetInt32Handler(f, UpbBind(OnValue, new MyHandlerData(...)));
- *
- * The value type must exactly match f->type().
- * For example, a handler that takes an int32_t parameter may only be used for
- * fields of type UPB_TYPE_INT32 and UPB_TYPE_ENUM.
- *
- * Returns false if the handler failed to register; in this case the cleanup
- * handler (if any) will be called immediately.
- */
- bool SetInt32Handler(FieldDefPtr f, const Int32Handler &h) {
- h.AddCleanup(ptr());
- return upb_handlers_setint32(ptr(), f.ptr(), h.handler(), &h.attr());
- }
-
- bool SetInt64Handler (FieldDefPtr f, const Int64Handler& h) {
- h.AddCleanup(ptr());
- return upb_handlers_setint64(ptr(), f.ptr(), h.handler(), &h.attr());
- }
-
- bool SetUInt32Handler(FieldDefPtr f, const UInt32Handler& h) {
- h.AddCleanup(ptr());
- return upb_handlers_setuint32(ptr(), f.ptr(), h.handler(), &h.attr());
- }
-
- bool SetUInt64Handler(FieldDefPtr f, const UInt64Handler& h) {
- h.AddCleanup(ptr());
- return upb_handlers_setuint64(ptr(), f.ptr(), h.handler(), &h.attr());
- }
-
- bool SetFloatHandler (FieldDefPtr f, const FloatHandler& h) {
- h.AddCleanup(ptr());
- return upb_handlers_setfloat(ptr(), f.ptr(), h.handler(), &h.attr());
- }
-
- bool SetDoubleHandler(FieldDefPtr f, const DoubleHandler& h) {
- h.AddCleanup(ptr());
- return upb_handlers_setdouble(ptr(), f.ptr(), h.handler(), &h.attr());
- }
-
- bool SetBoolHandler(FieldDefPtr f, const BoolHandler &h) {
- h.AddCleanup(ptr());
- return upb_handlers_setbool(ptr(), f.ptr(), h.handler(), &h.attr());
- }
-
- /* Like the previous, but templated on the type on the value (ie. int32).
- * This is mostly useful to call from other templates. To call this you must
- * specify the template parameter explicitly, ie:
- * h->SetValueHandler(f, UpbBind(MyHandler, MyData)); */
- template
- bool SetValueHandler(
- FieldDefPtr f,
- const typename ValueHandler::Type>::H &handler);
-
- /* Sets handlers for a string field, which are defined as follows:
- *
- * MySubClosure* startstr(MyClosure* c, const MyHandlerData* d,
- * size_t size_hint) {
- * // Called when a string value begins. The return value indicates the
- * // closure for the string. "size_hint" indicates the size of the
- * // string if it is known, however if the string is length-delimited
- * // and the end-of-string is not available size_hint will be zero.
- * // This case is indistinguishable from the case where the size is
- * // known to be zero.
- * //
- * // TODO(haberman): is it important to distinguish these cases?
- * // If we had ssize_t as a type we could make -1 "unknown", but
- * // ssize_t is POSIX (not ANSI) and therefore less portable.
- * // In practice I suspect it won't be important to distinguish.
- * return closure;
- * }
- *
- * size_t str(MyClosure* closure, const MyHandlerData* d,
- * const char *str, size_t len) {
- * // Called for each buffer of string data; the multiple physical buffers
- * // are all part of the same logical string. The return value indicates
- * // how many bytes were consumed. If this number is less than "len",
- * // this will also indicate that processing should be halted for now,
- * // like returning false or UPB_BREAK from any other callback. If
- * // number is greater than "len", the excess bytes will be skipped over
- * // and not passed to the callback.
- * return len;
- * }
- *
- * bool endstr(MyClosure* c, const MyHandlerData* d) {
- * // Called when a string value ends. Return value indicates whether
- * // processing should continue.
- * return true;
- * }
- */
- bool SetStartStringHandler(FieldDefPtr f, const StartStringHandler &h) {
- h.AddCleanup(ptr());
- return upb_handlers_setstartstr(ptr(), f.ptr(), h.handler(), &h.attr());
- }
-
- bool SetStringHandler(FieldDefPtr f, const StringHandler& h) {
- h.AddCleanup(ptr());
- return upb_handlers_setstring(ptr(), f.ptr(), h.handler(), &h.attr());
- }
-
- bool SetEndStringHandler(FieldDefPtr f, const EndFieldHandler& h) {
- h.AddCleanup(ptr());
- return upb_handlers_setendstr(ptr(), f.ptr(), h.handler(), &h.attr());
- }
-
- /* Sets the startseq handler, which is defined as follows:
- *
- * MySubClosure *startseq(MyClosure* c, const MyHandlerData* d) {
- * // Called when a sequence (repeated field) begins. The returned
- * // pointer indicates the closure for the sequence (or UPB_BREAK
- * // to interrupt processing).
- * return closure;
- * }
- *
- * h->SetStartSequenceHandler(f, UpbBind(startseq, new MyHandlerData(...)));
- *
- * Returns "false" if "f" does not belong to this message or is not a
- * repeated field.
- */
- bool SetStartSequenceHandler(FieldDefPtr f, const StartFieldHandler &h) {
- h.AddCleanup(ptr());
- return upb_handlers_setstartseq(ptr(), f.ptr(), h.handler(), &h.attr());
- }
-
- /* Sets the startsubmsg handler for the given field, which is defined as
- * follows:
- *
- * MySubClosure* startsubmsg(MyClosure* c, const MyHandlerData* d) {
- * // Called when a submessage begins. The returned pointer indicates the
- * // closure for the sequence (or UPB_BREAK to interrupt processing).
- * return closure;
- * }
- *
- * h->SetStartSubMessageHandler(f, UpbBind(startsubmsg,
- * new MyHandlerData(...)));
- *
- * Returns "false" if "f" does not belong to this message or is not a
- * submessage/group field.
- */
- bool SetStartSubMessageHandler(FieldDefPtr f, const StartFieldHandler& h) {
- h.AddCleanup(ptr());
- return upb_handlers_setstartsubmsg(ptr(), f.ptr(), h.handler(), &h.attr());
- }
-
- /* Sets the endsubmsg handler for the given field, which is defined as
- * follows:
- *
- * bool endsubmsg(MyClosure* c, const MyHandlerData* d) {
- * // Called when a submessage ends. Returns true to continue processing.
- * return true;
- * }
- *
- * Returns "false" if "f" does not belong to this message or is not a
- * submessage/group field.
- */
- bool SetEndSubMessageHandler(FieldDefPtr f, const EndFieldHandler &h) {
- h.AddCleanup(ptr());
- return upb_handlers_setendsubmsg(ptr(), f.ptr(), h.handler(), &h.attr());
- }
-
- /* Starts the endsubseq handler for the given field, which is defined as
- * follows:
- *
- * bool endseq(MyClosure* c, const MyHandlerData* d) {
- * // Called when a sequence ends. Returns true continue processing.
- * return true;
- * }
- *
- * Returns "false" if "f" does not belong to this message or is not a
- * repeated field.
- */
- bool SetEndSequenceHandler(FieldDefPtr f, const EndFieldHandler &h) {
- h.AddCleanup(ptr());
- return upb_handlers_setendseq(ptr(), f.ptr(), h.handler(), &h.attr());
- }
-
- private:
- upb_handlers* ptr_;
-};
-
-#endif /* __cplusplus */
-
-/* upb_handlercache ***********************************************************/
-
-/* A upb_handlercache lazily builds and caches upb_handlers. You pass it a
- * function (with optional closure) that can build handlers for a given
- * message on-demand, and the cache maintains a map of msgdef->handlers. */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct upb_handlercache;
-typedef struct upb_handlercache upb_handlercache;
-
-typedef void upb_handlers_callback(const void *closure, upb_handlers *h);
-
-upb_handlercache *upb_handlercache_new(upb_handlers_callback *callback,
- const void *closure);
-void upb_handlercache_free(upb_handlercache *cache);
-const upb_handlers *upb_handlercache_get(upb_handlercache *cache,
- const upb_msgdef *md);
-bool upb_handlercache_addcleanup(upb_handlercache *h, void *p,
- upb_handlerfree *hfree);
-
-#ifdef __cplusplus
-} /* extern "C" */
-
-class upb::HandlerCache {
- public:
- HandlerCache(upb_handlers_callback *callback, const void *closure)
- : ptr_(upb_handlercache_new(callback, closure), upb_handlercache_free) {}
- HandlerCache(HandlerCache&&) = default;
- HandlerCache& operator=(HandlerCache&&) = default;
- HandlerCache(upb_handlercache* c) : ptr_(c, upb_handlercache_free) {}
-
- upb_handlercache* ptr() { return ptr_.get(); }
-
- const upb_handlers *Get(MessageDefPtr md) {
- return upb_handlercache_get(ptr_.get(), md.ptr());
- }
-
- private:
- std::unique_ptr ptr_;
-};
-
-#endif /* __cplusplus */
-
-/* upb_byteshandler ***********************************************************/
-
-typedef struct {
- upb_func *func;
-
- /* It is wasteful to include the entire attributes here:
- *
- * * Some of the information is redundant (like storing the closure type
- * separately for each handler that must match).
- * * Some of the info is only needed prior to freeze() (like closure types).
- * * alignment padding wastes a lot of space for alwaysok_.
- *
- * If/when the size and locality of handlers is an issue, we can optimize this
- * not to store the entire attr like this. We do not expose the table's
- * layout to allow this optimization in the future. */
- upb_handlerattr attr;
-} upb_handlers_tabent;
-
-#define UPB_TABENT_INIT {NULL, UPB_HANDLERATTR_INIT}
-
-typedef struct {
- upb_handlers_tabent table[3];
-} upb_byteshandler;
-
-#define UPB_BYTESHANDLER_INIT \
- { \
- { UPB_TABENT_INIT, UPB_TABENT_INIT, UPB_TABENT_INIT } \
- }
-
-UPB_INLINE void upb_byteshandler_init(upb_byteshandler *handler) {
- upb_byteshandler init = UPB_BYTESHANDLER_INIT;
- *handler = init;
-}
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Caller must ensure that "d" outlives the handlers. */
-bool upb_byteshandler_setstartstr(upb_byteshandler *h,
- upb_startstr_handlerfunc *func, void *d);
-bool upb_byteshandler_setstring(upb_byteshandler *h,
- upb_string_handlerfunc *func, void *d);
-bool upb_byteshandler_setendstr(upb_byteshandler *h,
- upb_endfield_handlerfunc *func, void *d);
-
-#ifdef __cplusplus
-} /* extern "C" */
-
-namespace upb {
-typedef upb_byteshandler BytesHandler;
-}
-#endif
-
-/** Message handlers ******************************************************************/
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* These are the handlers used internally by upb_msgfactory_getmergehandlers().
- * They write scalar data to a known offset from the message pointer.
- *
- * These would be trivial for anyone to implement themselves, but it's better
- * to use these because some JITs will recognize and specialize these instead
- * of actually calling the function. */
-
-/* Sets a handler for the given primitive field that will write the data at the
- * given offset. If hasbit > 0, also sets a hasbit at the given bit offset
- * (addressing each byte low to high). */
-bool upb_msg_setscalarhandler(upb_handlers *h,
- const upb_fielddef *f,
- size_t offset,
- int32_t hasbit);
-
-/* If the given handler is a msghandlers_primitive field, returns true and sets
- * *type, *offset and *hasbit. Otherwise returns false. */
-bool upb_msg_getscalarhandlerdata(const upb_handlers *h,
- upb_selector_t s,
- upb_fieldtype_t *type,
- size_t *offset,
- int32_t *hasbit);
-
-
-
-#ifdef __cplusplus
-} /* extern "C" */
-#endif
-
-
-/*
-** Inline definitions for handlers.h, which are particularly long and a bit
-** tricky.
-*/
-
-#ifndef UPB_HANDLERS_INL_H_
-#define UPB_HANDLERS_INL_H_
-
-#include
-#include
-
-
-#ifdef __cplusplus
-
-/* Type detection and typedefs for integer types.
- * For platforms where there are multiple 32-bit or 64-bit types, we need to be
- * able to enumerate them so we can properly create overloads for all variants.
- *
- * If any platform existed where there were three integer types with the same
- * size, this would have to become more complicated. For example, short, int,
- * and long could all be 32-bits. Even more diabolically, short, int, long,
- * and long long could all be 64 bits and still be standard-compliant.
- * However, few platforms are this strange, and it's unlikely that upb will be
- * used on the strangest ones. */
-
-/* Can't count on stdint.h limits like INT32_MAX, because in C++ these are
- * only defined when __STDC_LIMIT_MACROS are defined before the *first* include
- * of stdint.h. We can't guarantee that someone else didn't include these first
- * without defining __STDC_LIMIT_MACROS. */
-#define UPB_INT32_MAX 0x7fffffffLL
-#define UPB_INT32_MIN (-UPB_INT32_MAX - 1)
-#define UPB_INT64_MAX 0x7fffffffffffffffLL
-#define UPB_INT64_MIN (-UPB_INT64_MAX - 1)
-
-#if INT_MAX == UPB_INT32_MAX && INT_MIN == UPB_INT32_MIN
-#define UPB_INT_IS_32BITS 1
-#endif
-
-#if LONG_MAX == UPB_INT32_MAX && LONG_MIN == UPB_INT32_MIN
-#define UPB_LONG_IS_32BITS 1
-#endif
-
-#if LONG_MAX == UPB_INT64_MAX && LONG_MIN == UPB_INT64_MIN
-#define UPB_LONG_IS_64BITS 1
-#endif
-
-#if LLONG_MAX == UPB_INT64_MAX && LLONG_MIN == UPB_INT64_MIN
-#define UPB_LLONG_IS_64BITS 1
-#endif
-
-/* We use macros instead of typedefs so we can undefine them later and avoid
- * leaking them outside this header file. */
-#if UPB_INT_IS_32BITS
-#define UPB_INT32_T int
-#define UPB_UINT32_T unsigned int
-
-#if UPB_LONG_IS_32BITS
-#define UPB_TWO_32BIT_TYPES 1
-#define UPB_INT32ALT_T long
-#define UPB_UINT32ALT_T unsigned long
-#endif /* UPB_LONG_IS_32BITS */
-
-#elif UPB_LONG_IS_32BITS /* && !UPB_INT_IS_32BITS */
-#define UPB_INT32_T long
-#define UPB_UINT32_T unsigned long
-#endif /* UPB_INT_IS_32BITS */
-
-
-#if UPB_LONG_IS_64BITS
-#define UPB_INT64_T long
-#define UPB_UINT64_T unsigned long
-
-#if UPB_LLONG_IS_64BITS
-#define UPB_TWO_64BIT_TYPES 1
-#define UPB_INT64ALT_T long long
-#define UPB_UINT64ALT_T unsigned long long
-#endif /* UPB_LLONG_IS_64BITS */
-
-#elif UPB_LLONG_IS_64BITS /* && !UPB_LONG_IS_64BITS */
-#define UPB_INT64_T long long
-#define UPB_UINT64_T unsigned long long
-#endif /* UPB_LONG_IS_64BITS */
-
-#undef UPB_INT32_MAX
-#undef UPB_INT32_MIN
-#undef UPB_INT64_MAX
-#undef UPB_INT64_MIN
-#undef UPB_INT_IS_32BITS
-#undef UPB_LONG_IS_32BITS
-#undef UPB_LONG_IS_64BITS
-#undef UPB_LLONG_IS_64BITS
-
-
-namespace upb {
-
-typedef void CleanupFunc(void *ptr);
-
-/* Template to remove "const" from "const T*" and just return "T*".
- *
- * We define a nonsense default because otherwise it will fail to instantiate as
- * a function parameter type even in cases where we don't expect any caller to
- * actually match the overload. */
-class CouldntRemoveConst {};
-template struct remove_constptr { typedef CouldntRemoveConst type; };
-template struct remove_constptr { typedef T *type; };
-
-/* Template that we use below to remove a template specialization from
- * consideration if it matches a specific type. */
-template struct disable_if_same { typedef void Type; };
-template struct disable_if_same {};
-
-template void DeletePointer(void *p) { delete static_cast(p); }
-
-template
-struct FirstUnlessVoidOrBool {
- typedef T1 value;
-};
-
-template
-struct FirstUnlessVoidOrBool {
- typedef T2 value;
-};
-
-template
-struct FirstUnlessVoidOrBool {
- typedef T2 value;
-};
-
-template
-struct is_same {
- static bool value;
-};
-
-template
-struct is_same {
- static bool value;
-};
-
-template
-bool is_same::value = false;
-
-template
-bool is_same::value = true;
-
-/* FuncInfo *******************************************************************/
-
-/* Info about the user's original, pre-wrapped function. */
-template
-struct FuncInfo {
- /* The type of the closure that the function takes (its first param). */
- typedef C Closure;
-
- /* The return type. */
- typedef R Return;
-};
-
-/* Func ***********************************************************************/
-
-/* Func1, Func2, Func3: Template classes representing a function and its
- * signature.
- *
- * Since the function is a template parameter, calling the function can be
- * inlined at compile-time and does not require a function pointer at runtime.
- * These functions are not bound to a handler data so have no data or cleanup
- * handler. */
-struct UnboundFunc {
- CleanupFunc *GetCleanup() { return nullptr; }
- void *GetData() { return nullptr; }
-};
-
-template
-struct Func1 : public UnboundFunc {
- typedef R Return;
- typedef I FuncInfo;
- static R Call(P1 p1) { return F(p1); }
-};
-
-template
-struct Func2 : public UnboundFunc {
- typedef R Return;
- typedef I FuncInfo;
- static R Call(P1 p1, P2 p2) { return F(p1, p2); }
-};
-
-template
-struct Func3 : public UnboundFunc {
- typedef R Return;
- typedef I FuncInfo;
- static R Call(P1 p1, P2 p2, P3 p3) { return F(p1, p2, p3); }
-};
-
-template
-struct Func4 : public UnboundFunc {
- typedef R Return;
- typedef I FuncInfo;
- static R Call(P1 p1, P2 p2, P3 p3, P4 p4) { return F(p1, p2, p3, p4); }
-};
-
-template
-struct Func5 : public UnboundFunc {
- typedef R Return;
- typedef I FuncInfo;
- static R Call(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) {
- return F(p1, p2, p3, p4, p5);
- }
-};
-
-/* BoundFunc ******************************************************************/
-
-/* BoundFunc2, BoundFunc3: Like Func2/Func3 except also contains a value that
- * shall be bound to the function's second parameter.
- *
- * Note that the second parameter is a const pointer, but our stored bound value
- * is non-const so we can free it when the handlers are destroyed. */
-template
-struct BoundFunc {
- typedef typename remove_constptr::type MutableP2;
- explicit BoundFunc(MutableP2 data_) : data(data_) {}
- CleanupFunc *GetCleanup() { return &DeletePointer; }
- MutableP2 GetData() { return data; }
- MutableP2 data;
-};
-
-template
-struct BoundFunc2 : public BoundFunc {
- typedef BoundFunc Base;
- typedef I FuncInfo;
- explicit BoundFunc2(typename Base::MutableP2 arg) : Base(arg) {}
-};
-
-template
-struct BoundFunc3 : public BoundFunc {
- typedef BoundFunc Base;
- typedef I FuncInfo;
- explicit BoundFunc3(typename Base::MutableP2 arg) : Base(arg) {}
-};
-
-template
-struct BoundFunc4 : public BoundFunc {
- typedef BoundFunc Base;
- typedef I FuncInfo;
- explicit BoundFunc4(typename Base::MutableP2 arg) : Base(arg) {}
-};
-
-template
-struct BoundFunc5 : public BoundFunc {
- typedef BoundFunc Base;
- typedef I FuncInfo;
- explicit BoundFunc5(typename Base::MutableP2 arg) : Base(arg) {}
-};
-
-/* FuncSig ********************************************************************/
-
-/* FuncSig1, FuncSig2, FuncSig3: template classes reflecting a function
- * *signature*, but without a specific function attached.
- *
- * These classes contain member functions that can be invoked with a
- * specific function to return a Func/BoundFunc class. */
-template
-struct FuncSig1 {
- template
- Func1 > GetFunc() {
- return Func1 >();
- }
-};
-
-template
-struct FuncSig2 {
- template
- Func2 > GetFunc() {
- return Func2 >();
- }
-
- template
- BoundFunc2 > GetFunc(
- typename remove_constptr::type param2) {
- return BoundFunc2 >(param2);
- }
-};
-
-template
-struct FuncSig3 {
- template
- Func3 > GetFunc() {
- return Func3 >();
- }
-
- template
- BoundFunc3 > GetFunc(
- typename remove_constptr::type param2) {
- return BoundFunc3 >(param2);
- }
-};
-
-template
-struct FuncSig4 {
- template
- Func4 > GetFunc() {
- return Func4 >();
- }
-
- template
- BoundFunc4 > GetFunc(
- typename remove_constptr::type param2) {
- return BoundFunc4 >(param2);
- }
-};
-
-template
-struct FuncSig5 {
- template
- Func5 > GetFunc() {
- return Func5 >();
- }
-
- template