Add dependencies locally
This commit is contained in:
9
deps/protobuf/ruby/.gitignore
vendored
Normal file
9
deps/protobuf/ruby/.gitignore
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
*.bundle
|
||||
tags
|
||||
.idea/
|
||||
lib/google/protobuf_java.jar
|
||||
protobuf-jruby.iml
|
||||
target/
|
||||
pkg/
|
||||
tmp/
|
||||
tests/google/
|
3
deps/protobuf/ruby/Gemfile
vendored
Normal file
3
deps/protobuf/ruby/Gemfile
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
source 'https://rubygems.org'
|
||||
|
||||
gemspec
|
111
deps/protobuf/ruby/README.md
vendored
Normal file
111
deps/protobuf/ruby/README.md
vendored
Normal file
@ -0,0 +1,111 @@
|
||||
This directory contains the Ruby extension that implements Protocol Buffers
|
||||
functionality in Ruby.
|
||||
|
||||
The Ruby extension makes use of generated Ruby code that defines message and
|
||||
enum types in a Ruby DSL. You may write definitions in this DSL directly, but
|
||||
we recommend using protoc's Ruby generation support with .proto files. The
|
||||
build process in this directory only installs the extension; you need to
|
||||
install protoc as well to have Ruby code generation functionality.
|
||||
|
||||
Installation from Gem
|
||||
---------------------
|
||||
In Gemfile (Please check a version of Protocol Buffers you needed [RubyGems](https://rubygems.org/gems/google-protobuf)):
|
||||
|
||||
gem 'google-protobuf'
|
||||
|
||||
Or for using this pre-packaged gem, simply install it as you would any other gem:
|
||||
|
||||
$ gem install [--prerelease] google-protobuf
|
||||
|
||||
Once the gem is installed, you may or may not need `protoc`. If you write your
|
||||
message type descriptions directly in the Ruby DSL, you do not need it.
|
||||
However, if you wish to generate the Ruby DSL from a `.proto` file, you will
|
||||
also want to install Protocol Buffers itself, as described in this repository's
|
||||
main `README` file. The version of `protoc` included in the latest release
|
||||
supports the `--ruby_out` option to generate Ruby code.
|
||||
|
||||
A simple example of using the Ruby extension follows. More extensive
|
||||
documentation may be found in the RubyDoc comments (`call-seq` tags) in the
|
||||
source, and we plan to release separate, more detailed, documentation at a
|
||||
later date.
|
||||
|
||||
```ruby
|
||||
require 'google/protobuf'
|
||||
|
||||
# generated from my_proto_types.proto with protoc:
|
||||
# $ protoc --ruby_out=. my_proto_types.proto
|
||||
require 'my_proto_types'
|
||||
|
||||
mymessage = MyTestMessage.new(:field1 => 42, :field2 => ["a", "b", "c"])
|
||||
mymessage.field1 = 43
|
||||
mymessage.field2.push("d")
|
||||
mymessage.field3 = SubMessage.new(:foo => 100)
|
||||
|
||||
encoded_data = MyTestMessage.encode(mymessage)
|
||||
decoded = MyTestMessage.decode(encoded_data)
|
||||
assert decoded == mymessage
|
||||
|
||||
puts "JSON:"
|
||||
puts MyTestMessage.encode_json(mymessage)
|
||||
```
|
||||
|
||||
Installation from Source (Building Gem)
|
||||
---------------------------------------
|
||||
|
||||
To build this Ruby extension, you will need:
|
||||
|
||||
* Rake
|
||||
* Bundler
|
||||
* Ruby development headers
|
||||
* a C compiler
|
||||
|
||||
To Build the JRuby extension, you will need:
|
||||
|
||||
* Maven
|
||||
* The latest version of the protobuf java library (see ../java/README.md)
|
||||
* Install JRuby via rbenv or RVM
|
||||
|
||||
First switch to the desired platform with rbenv or RVM.
|
||||
|
||||
Then install the required Ruby gems:
|
||||
|
||||
$ gem install bundler
|
||||
$ bundle
|
||||
|
||||
Then build the Gem:
|
||||
|
||||
$ rake
|
||||
$ rake clobber_package gem
|
||||
$ gem install `ls pkg/google-protobuf-*.gem`
|
||||
|
||||
To run the specs:
|
||||
|
||||
$ rake test
|
||||
|
||||
This gem includes the upb parsing and serialization library as a single-file
|
||||
amalgamation. It is up-to-date with upb git commit
|
||||
`535bc2fe2f2b467f59347ffc9449e11e47791257`.
|
||||
|
||||
Version Number Scheme
|
||||
---------------------
|
||||
|
||||
We are using a version number scheme that is a hybrid of Protocol Buffers'
|
||||
overall version number and some Ruby-specific rules. Gem does not allow
|
||||
re-uploads of a gem with the same version number, so we add a sequence number
|
||||
("upload version") to the version. We also format alphabetical tags (alpha,
|
||||
pre, ...) slightly differently, and we avoid hyphens. In more detail:
|
||||
|
||||
* First, we determine the prefix: a Protocol Buffers version "3.0.0-alpha-2"
|
||||
becomes "3.0.0.alpha.2". When we release 3.0.0, this prefix will be simply
|
||||
"3.0.0".
|
||||
* We then append the upload version: "3.0.0.alpha.2.0" or "3.0.0.0". If we need
|
||||
to upload a new version of the gem to fix an issue, the version becomes
|
||||
"3.0.0.alpha.2.1" or "3.0.0.1".
|
||||
* If we are working on a prerelease version, we append a prerelease tag:
|
||||
"3.0.0.alpha.3.0.pre". The prerelease tag comes at the end so that when
|
||||
version numbers are sorted, any prerelease builds are ordered between the
|
||||
prior version and current version.
|
||||
|
||||
These rules are designed to work with the sorting rules for
|
||||
[Gem::Version](http://ruby-doc.org/stdlib-2.0/libdoc/rubygems/rdoc/Gem/Version.html):
|
||||
release numbers should sort in actual release order.
|
167
deps/protobuf/ruby/Rakefile
vendored
Normal file
167
deps/protobuf/ruby/Rakefile
vendored
Normal file
@ -0,0 +1,167 @@
|
||||
require "rubygems"
|
||||
require "rubygems/package_task"
|
||||
require "rake/extensiontask" unless RUBY_PLATFORM == "java"
|
||||
require "rake/testtask"
|
||||
|
||||
spec = Gem::Specification.load("google-protobuf.gemspec")
|
||||
|
||||
well_known_protos = %w[
|
||||
google/protobuf/any.proto
|
||||
google/protobuf/api.proto
|
||||
google/protobuf/descriptor.proto
|
||||
google/protobuf/duration.proto
|
||||
google/protobuf/empty.proto
|
||||
google/protobuf/field_mask.proto
|
||||
google/protobuf/source_context.proto
|
||||
google/protobuf/struct.proto
|
||||
google/protobuf/timestamp.proto
|
||||
google/protobuf/type.proto
|
||||
google/protobuf/wrappers.proto
|
||||
]
|
||||
|
||||
test_protos = %w[
|
||||
tests/basic_test.proto
|
||||
tests/basic_test_proto2.proto
|
||||
tests/generated_code.proto
|
||||
tests/generated_code_proto2.proto
|
||||
tests/multi_level_nesting_test.proto
|
||||
tests/test_import.proto
|
||||
tests/test_import_proto2.proto
|
||||
tests/test_ruby_package.proto
|
||||
tests/test_ruby_package_proto2.proto
|
||||
]
|
||||
|
||||
# These are omitted for now because we don't support proto2.
|
||||
proto2_protos = %w[
|
||||
google/protobuf/descriptor.proto
|
||||
google/protobuf/compiler/plugin.proto
|
||||
]
|
||||
|
||||
if system('../src/protoc --version')
|
||||
protoc_command = '../src/protoc'
|
||||
else
|
||||
protoc_command = 'protoc'
|
||||
end
|
||||
|
||||
genproto_output = []
|
||||
|
||||
# We won't have access to .. from within docker, but the proto files
|
||||
# will be there, thanks to the :genproto rule dependency for gem:native.
|
||||
unless ENV['IN_DOCKER'] == 'true'
|
||||
well_known_protos.each do |proto_file|
|
||||
input_file = "../src/" + proto_file
|
||||
output_file = "lib/" + proto_file.sub(/\.proto$/, "_pb.rb")
|
||||
genproto_output << output_file
|
||||
file output_file => input_file do |file_task|
|
||||
sh "#{protoc_command} -I../src --ruby_out=lib #{input_file}"
|
||||
end
|
||||
end
|
||||
|
||||
test_protos.each do |proto_file|
|
||||
output_file = proto_file.sub(/\.proto$/, "_pb.rb")
|
||||
genproto_output << output_file
|
||||
file output_file => proto_file do |file_task|
|
||||
sh "#{protoc_command} -I../src -I. -I./tests --ruby_out=. #{proto_file}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if RUBY_PLATFORM == "java"
|
||||
task :clean => :require_mvn do
|
||||
system("mvn --batch-mode clean")
|
||||
end
|
||||
|
||||
task :compile => :require_mvn do
|
||||
system("mvn --batch-mode package")
|
||||
end
|
||||
|
||||
task :require_mvn do
|
||||
raise ArgumentError, "maven needs to be installed" if `which mvn` == ''
|
||||
end
|
||||
|
||||
else
|
||||
unless ENV['IN_DOCKER'] == 'true'
|
||||
# We need utf8_range in-tree.
|
||||
FileUtils.mkdir_p("ext/google/protobuf_c/third_party/utf8_range")
|
||||
FileUtils.cp("../third_party/utf8_range/utf8_range.h", "ext/google/protobuf_c/third_party/utf8_range")
|
||||
FileUtils.cp("../third_party/utf8_range/naive.c", "ext/google/protobuf_c/third_party/utf8_range")
|
||||
FileUtils.cp("../third_party/utf8_range/range2-neon.c", "ext/google/protobuf_c/third_party/utf8_range")
|
||||
FileUtils.cp("../third_party/utf8_range/range2-sse.c", "ext/google/protobuf_c/third_party/utf8_range")
|
||||
FileUtils.cp("../third_party/utf8_range/LICENSE", "ext/google/protobuf_c/third_party/utf8_range")
|
||||
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,
|
||||
# "no_native" can only be set if the RUBY_PLATFORM doing
|
||||
# cross-compilation is contained in the "ext.cross_platform" array.
|
||||
ext.no_native = true
|
||||
end
|
||||
ext.ext_dir = "ext/google/protobuf_c"
|
||||
ext.lib_dir = "lib/google"
|
||||
ext.cross_compile = true
|
||||
ext.cross_platform = [
|
||||
'x86-mingw32', 'x64-mingw32',
|
||||
'x86_64-linux', 'x86-linux',
|
||||
'x86_64-darwin', 'arm64-darwin',
|
||||
]
|
||||
end
|
||||
|
||||
task 'gem:java' do
|
||||
sh "rm Gemfile.lock"
|
||||
require 'rake_compiler_dock'
|
||||
# Specify the repo root as the working and mount directory to provide access
|
||||
# to the java directory
|
||||
repo_root = File.realdirpath File.join(Dir.pwd, '..')
|
||||
RakeCompilerDock.sh <<-"EOT", platform: 'jruby', rubyvm: :jruby, mountdir: repo_root, workdir: repo_root
|
||||
sudo apt-get install maven -y && \
|
||||
cd java && mvn install -Dmaven.test.skip=true && cd ../ruby && \
|
||||
bundle && \
|
||||
IN_DOCKER=true rake compile gem
|
||||
EOT
|
||||
end
|
||||
|
||||
task 'gem:windows' do
|
||||
sh "rm Gemfile.lock"
|
||||
require 'rake_compiler_dock'
|
||||
['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=3.1.0:3.0.0:2.7.0:2.6.0:2.5.0
|
||||
EOT
|
||||
end
|
||||
end
|
||||
|
||||
if RUBY_PLATFORM =~ /darwin/
|
||||
task 'gem:native' do
|
||||
system "rake genproto"
|
||||
system "rake cross native gem RUBY_CC_VERSION=3.1.0:3.0.0:2.7.0:2.6.0:2.5.1"
|
||||
end
|
||||
else
|
||||
task 'gem:native' => [:genproto, 'gem:windows', 'gem:java']
|
||||
end
|
||||
end
|
||||
|
||||
task :genproto => genproto_output
|
||||
|
||||
task :clean do
|
||||
sh "rm -f #{genproto_output.join(' ')}"
|
||||
end
|
||||
|
||||
Gem::PackageTask.new(spec) do |pkg|
|
||||
end
|
||||
|
||||
Rake::TestTask.new(:test => [:build, :genproto]) do |t|
|
||||
t.test_files = FileList["tests/*.rb"].exclude("tests/gc_test.rb", "tests/common_tests.rb")
|
||||
end
|
||||
|
||||
# gc_test needs to be split out to ensure the generated file hasn't been
|
||||
# imported by other tests.
|
||||
Rake::TestTask.new(:gc_test => :build) do |t|
|
||||
t.test_files = FileList["tests/gc_test.rb"]
|
||||
end
|
||||
|
||||
task :build => [:clean, :genproto, :compile]
|
||||
task :default => [:build]
|
||||
|
||||
# vim:sw=2:et
|
5
deps/protobuf/ruby/compatibility_tests/v3.0.0/README.md
vendored
Normal file
5
deps/protobuf/ruby/compatibility_tests/v3.0.0/README.md
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
# Protobuf Ruby Compatibility Tests
|
||||
|
||||
This directory contains a snapshot of protobuf ruby 3.0.0 unittest code and
|
||||
test scripts used to verifies whether the latest version of protobuf is
|
||||
still compatible with 3.0.0 generated code.
|
25
deps/protobuf/ruby/compatibility_tests/v3.0.0/Rakefile
vendored
Normal file
25
deps/protobuf/ruby/compatibility_tests/v3.0.0/Rakefile
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
require "rake/testtask"
|
||||
|
||||
# Proto for tests.
|
||||
genproto_output = []
|
||||
genproto_output << "tests/generated_code.rb"
|
||||
genproto_output << "tests/test_import.rb"
|
||||
file "tests/generated_code.rb" => "tests/generated_code.proto" do |file_task|
|
||||
sh "./protoc --ruby_out=. tests/generated_code.proto"
|
||||
end
|
||||
|
||||
file "tests/test_import.rb" => "tests/test_import.proto" do |file_task|
|
||||
sh "./protoc --ruby_out=. tests/test_import.proto"
|
||||
end
|
||||
|
||||
task :genproto => genproto_output
|
||||
|
||||
task :clean do
|
||||
sh "rm -f #{genproto_output.join(' ')}"
|
||||
end
|
||||
|
||||
Rake::TestTask.new(:test => :genproto) do |t|
|
||||
t.test_files = FileList["tests/*.rb"]
|
||||
end
|
||||
|
||||
task :default => [:test]
|
17
deps/protobuf/ruby/compatibility_tests/v3.0.0/test.sh
vendored
Normal file
17
deps/protobuf/ruby/compatibility_tests/v3.0.0/test.sh
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -ex
|
||||
|
||||
# Change to the script's directory
|
||||
cd $(dirname $0)
|
||||
|
||||
# Download 3.0.0 version of protoc
|
||||
PROTOC_BINARY_NAME="protoc-3.0.0-linux-x86_64.exe"
|
||||
if [ `uname` = "Darwin" ]; then
|
||||
PROTOC_BINARY_NAME="protoc-3.0.0-osx-x86_64.exe"
|
||||
fi
|
||||
wget https://repo1.maven.org/maven2/com/google/protobuf/protoc/3.0.0/${PROTOC_BINARY_NAME} -O protoc
|
||||
chmod +x protoc
|
||||
|
||||
# Run tests
|
||||
RUBYLIB=../../lib:. rake test
|
1276
deps/protobuf/ruby/compatibility_tests/v3.0.0/tests/basic.rb
vendored
Normal file
1276
deps/protobuf/ruby/compatibility_tests/v3.0.0/tests/basic.rb
vendored
Normal file
File diff suppressed because it is too large
Load Diff
67
deps/protobuf/ruby/compatibility_tests/v3.0.0/tests/generated_code.proto
vendored
Normal file
67
deps/protobuf/ruby/compatibility_tests/v3.0.0/tests/generated_code.proto
vendored
Normal file
@ -0,0 +1,67 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package a.b.c;
|
||||
|
||||
message TestMessage {
|
||||
int32 optional_int32 = 1;
|
||||
int64 optional_int64 = 2;
|
||||
uint32 optional_uint32 = 3;
|
||||
uint64 optional_uint64 = 4;
|
||||
bool optional_bool = 5;
|
||||
double optional_double = 6;
|
||||
float optional_float = 7;
|
||||
string optional_string = 8;
|
||||
bytes optional_bytes = 9;
|
||||
TestEnum optional_enum = 10;
|
||||
TestMessage optional_msg = 11;
|
||||
|
||||
repeated int32 repeated_int32 = 21;
|
||||
repeated int64 repeated_int64 = 22;
|
||||
repeated uint32 repeated_uint32 = 23;
|
||||
repeated uint64 repeated_uint64 = 24;
|
||||
repeated bool repeated_bool = 25;
|
||||
repeated double repeated_double = 26;
|
||||
repeated float repeated_float = 27;
|
||||
repeated string repeated_string = 28;
|
||||
repeated bytes repeated_bytes = 29;
|
||||
repeated TestEnum repeated_enum = 30;
|
||||
repeated TestMessage repeated_msg = 31;
|
||||
|
||||
oneof my_oneof {
|
||||
int32 oneof_int32 = 41;
|
||||
int64 oneof_int64 = 42;
|
||||
uint32 oneof_uint32 = 43;
|
||||
uint64 oneof_uint64 = 44;
|
||||
bool oneof_bool = 45;
|
||||
double oneof_double = 46;
|
||||
float oneof_float = 47;
|
||||
string oneof_string = 48;
|
||||
bytes oneof_bytes = 49;
|
||||
TestEnum oneof_enum = 50;
|
||||
TestMessage oneof_msg = 51;
|
||||
}
|
||||
|
||||
map<int32, string> map_int32_string = 61;
|
||||
map<int64, string> map_int64_string = 62;
|
||||
map<uint32, string> map_uint32_string = 63;
|
||||
map<uint64, string> map_uint64_string = 64;
|
||||
map<bool, string> map_bool_string = 65;
|
||||
map<string, string> map_string_string = 66;
|
||||
map<string, TestMessage> map_string_msg = 67;
|
||||
map<string, TestEnum> map_string_enum = 68;
|
||||
map<string, int32> map_string_int32 = 69;
|
||||
map<string, bool> map_string_bool = 70;
|
||||
|
||||
message NestedMessage {
|
||||
int32 foo = 1;
|
||||
}
|
||||
|
||||
NestedMessage nested_message = 80;
|
||||
}
|
||||
|
||||
enum TestEnum {
|
||||
Default = 0;
|
||||
A = 1;
|
||||
B = 2;
|
||||
C = 3;
|
||||
}
|
19
deps/protobuf/ruby/compatibility_tests/v3.0.0/tests/generated_code_test.rb
vendored
Normal file
19
deps/protobuf/ruby/compatibility_tests/v3.0.0/tests/generated_code_test.rb
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
#!/usr/bin/ruby
|
||||
|
||||
# generated_code.rb is in the same directory as this test.
|
||||
$LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__)))
|
||||
|
||||
require 'generated_code_pb'
|
||||
require 'test_import_pb'
|
||||
require 'test/unit'
|
||||
|
||||
class GeneratedCodeTest < Test::Unit::TestCase
|
||||
def test_generated_msg
|
||||
# just test that we can instantiate the message. The purpose of this test
|
||||
# is to ensure that the output of the code generator is valid Ruby and
|
||||
# successfully creates message definitions and classes, not to test every
|
||||
# aspect of the extension (basic.rb is for that).
|
||||
m = A::B::C::TestMessage.new()
|
||||
m2 = FooBar::TestImportedMessage.new()
|
||||
end
|
||||
end
|
631
deps/protobuf/ruby/compatibility_tests/v3.0.0/tests/repeated_field_test.rb
vendored
Normal file
631
deps/protobuf/ruby/compatibility_tests/v3.0.0/tests/repeated_field_test.rb
vendored
Normal file
@ -0,0 +1,631 @@
|
||||
#!/usr/bin/ruby
|
||||
|
||||
require 'google/protobuf'
|
||||
require 'test/unit'
|
||||
|
||||
class RepeatedFieldTest < Test::Unit::TestCase
|
||||
|
||||
def test_acts_like_enumerator
|
||||
m = TestMessage.new
|
||||
(Enumerable.instance_methods - TestMessage.new.repeated_string.methods).each do |method_name|
|
||||
assert m.repeated_string.respond_to?(method_name) == true, "does not respond to #{method_name}"
|
||||
end
|
||||
end
|
||||
|
||||
def test_acts_like_an_array
|
||||
m = TestMessage.new
|
||||
arr_methods = ([].methods - TestMessage.new.repeated_string.methods)
|
||||
# jRuby additions to the Array class that we can ignore
|
||||
arr_methods -= [ :indices, :iter_for_each, :iter_for_each_index,
|
||||
:iter_for_each_with_index, :dimensions, :copy_data, :copy_data_simple,
|
||||
:nitems, :iter_for_reverse_each, :indexes, :append, :prepend]
|
||||
arr_methods -= [:union, :difference, :filter!]
|
||||
arr_methods -= [:intersection, :deconstruct] # ruby 2.7 methods we can ignore
|
||||
arr_methods -= [:intersect?] # ruby 3.1 methods we can ignore
|
||||
arr_methods.each do |method_name|
|
||||
assert m.repeated_string.respond_to?(method_name) == true, "does not respond to #{method_name}"
|
||||
end
|
||||
end
|
||||
|
||||
def test_first
|
||||
m = TestMessage.new
|
||||
repeated_field_names(TestMessage).each do |field_name|
|
||||
assert_nil m.send(field_name).first
|
||||
end
|
||||
fill_test_msg(m)
|
||||
assert_equal -10, m.repeated_int32.first
|
||||
assert_equal -1_000_000, m.repeated_int64.first
|
||||
assert_equal 10, m.repeated_uint32.first
|
||||
assert_equal 1_000_000, m.repeated_uint64.first
|
||||
assert_equal true, m.repeated_bool.first
|
||||
assert_equal -1.01, m.repeated_float.first.round(2)
|
||||
assert_equal -1.0000000000001, m.repeated_double.first
|
||||
assert_equal 'foo', m.repeated_string.first
|
||||
assert_equal "bar".encode!('ASCII-8BIT'), m.repeated_bytes.first
|
||||
assert_equal TestMessage2.new(:foo => 1), m.repeated_msg.first
|
||||
assert_equal :A, m.repeated_enum.first
|
||||
end
|
||||
|
||||
|
||||
def test_last
|
||||
m = TestMessage.new
|
||||
repeated_field_names(TestMessage).each do |field_name|
|
||||
assert_nil m.send(field_name).first
|
||||
end
|
||||
fill_test_msg(m)
|
||||
assert_equal -11, m.repeated_int32.last
|
||||
assert_equal -1_000_001, m.repeated_int64.last
|
||||
assert_equal 11, m.repeated_uint32.last
|
||||
assert_equal 1_000_001, m.repeated_uint64.last
|
||||
assert_equal false, m.repeated_bool.last
|
||||
assert_equal -1.02, m.repeated_float.last.round(2)
|
||||
assert_equal -1.0000000000002, m.repeated_double.last
|
||||
assert_equal 'bar', m.repeated_string.last
|
||||
assert_equal "foo".encode!('ASCII-8BIT'), m.repeated_bytes.last
|
||||
assert_equal TestMessage2.new(:foo => 2), m.repeated_msg.last
|
||||
assert_equal :B, m.repeated_enum.last
|
||||
end
|
||||
|
||||
|
||||
def test_pop
|
||||
m = TestMessage.new
|
||||
repeated_field_names(TestMessage).each do |field_name|
|
||||
assert_nil m.send(field_name).pop
|
||||
end
|
||||
fill_test_msg(m)
|
||||
|
||||
assert_equal -11, m.repeated_int32.pop
|
||||
assert_equal -10, m.repeated_int32.pop
|
||||
assert_equal -1_000_001, m.repeated_int64.pop
|
||||
assert_equal -1_000_000, m.repeated_int64.pop
|
||||
assert_equal 11, m.repeated_uint32.pop
|
||||
assert_equal 10, m.repeated_uint32.pop
|
||||
assert_equal 1_000_001, m.repeated_uint64.pop
|
||||
assert_equal 1_000_000, m.repeated_uint64.pop
|
||||
assert_equal false, m.repeated_bool.pop
|
||||
assert_equal true, m.repeated_bool.pop
|
||||
assert_equal -1.02, m.repeated_float.pop.round(2)
|
||||
assert_equal -1.01, m.repeated_float.pop.round(2)
|
||||
assert_equal -1.0000000000002, m.repeated_double.pop
|
||||
assert_equal -1.0000000000001, m.repeated_double.pop
|
||||
assert_equal 'bar', m.repeated_string.pop
|
||||
assert_equal 'foo', m.repeated_string.pop
|
||||
assert_equal "foo".encode!('ASCII-8BIT'), m.repeated_bytes.pop
|
||||
assert_equal "bar".encode!('ASCII-8BIT'), m.repeated_bytes.pop
|
||||
assert_equal TestMessage2.new(:foo => 2), m.repeated_msg.pop
|
||||
assert_equal TestMessage2.new(:foo => 1), m.repeated_msg.pop
|
||||
assert_equal :B, m.repeated_enum.pop
|
||||
assert_equal :A, m.repeated_enum.pop
|
||||
repeated_field_names(TestMessage).each do |field_name|
|
||||
assert_nil m.send(field_name).pop
|
||||
end
|
||||
|
||||
fill_test_msg(m)
|
||||
assert_equal ['bar', 'foo'], m.repeated_string.pop(2)
|
||||
assert_nil m.repeated_string.pop
|
||||
end
|
||||
|
||||
|
||||
def test_each
|
||||
m = TestMessage.new
|
||||
5.times{|i| m.repeated_string << 'string' }
|
||||
count = 0
|
||||
m.repeated_string.each do |val|
|
||||
assert_equal 'string', val
|
||||
count += 1
|
||||
end
|
||||
assert_equal 5, count
|
||||
result = m.repeated_string.each{|val| val + '_junk'}
|
||||
assert_equal ['string'] * 5, result
|
||||
end
|
||||
|
||||
|
||||
def test_empty?
|
||||
m = TestMessage.new
|
||||
assert_equal true, m.repeated_string.empty?
|
||||
m.repeated_string << 'foo'
|
||||
assert_equal false, m.repeated_string.empty?
|
||||
m.repeated_string << 'bar'
|
||||
assert_equal false, m.repeated_string.empty?
|
||||
end
|
||||
|
||||
def test_array_accessor
|
||||
m = TestMessage.new
|
||||
reference_arr = %w(foo bar baz)
|
||||
m.repeated_string += reference_arr.clone
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr[1]
|
||||
end
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr[-2]
|
||||
end
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr[20]
|
||||
end
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr[1, 2]
|
||||
end
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr[0..2]
|
||||
end
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr[-1, 1]
|
||||
end
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr[10, 12]
|
||||
end
|
||||
end
|
||||
|
||||
def test_array_settor
|
||||
m = TestMessage.new
|
||||
reference_arr = %w(foo bar baz)
|
||||
m.repeated_string += reference_arr.clone
|
||||
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr[1] = 'junk'
|
||||
end
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr[-2] = 'snappy'
|
||||
end
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr[3] = ''
|
||||
end
|
||||
# slight deviation; we are strongly typed, and nil is not allowed
|
||||
# for string types;
|
||||
m.repeated_string[5] = 'spacious'
|
||||
assert_equal ["foo", "snappy", "baz", "", "", "spacious"], m.repeated_string
|
||||
|
||||
#make sure it sests the default types for other fields besides strings
|
||||
%w(repeated_int32 repeated_int64 repeated_uint32 repeated_uint64).each do |field_name|
|
||||
m.send(field_name)[3] = 10
|
||||
assert_equal [0,0,0,10], m.send(field_name)
|
||||
end
|
||||
m.repeated_float[3] = 10.1
|
||||
#wonky mri float handling
|
||||
assert_equal [0,0,0], m.repeated_float.to_a[0..2]
|
||||
assert_equal 10.1, m.repeated_float[3].round(1)
|
||||
m.repeated_double[3] = 10.1
|
||||
assert_equal [0,0,0,10.1], m.repeated_double
|
||||
m.repeated_bool[3] = true
|
||||
assert_equal [false, false, false, true], m.repeated_bool
|
||||
m.repeated_bytes[3] = "bar".encode!('ASCII-8BIT')
|
||||
assert_equal ['', '', '', "bar".encode!('ASCII-8BIT')], m.repeated_bytes
|
||||
m.repeated_msg[3] = TestMessage2.new(:foo => 1)
|
||||
assert_equal [nil, nil, nil, TestMessage2.new(:foo => 1)], m.repeated_msg
|
||||
m.repeated_enum[3] = :A
|
||||
assert_equal [:Default, :Default, :Default, :A], m.repeated_enum
|
||||
|
||||
# check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
# arr[20] = 'spacious'
|
||||
# end
|
||||
# TODO: accessor doesn't allow other ruby-like methods
|
||||
# check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
# arr[1, 2] = 'fizz'
|
||||
# end
|
||||
# check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
# arr[0..2] = 'buzz'
|
||||
# end
|
||||
end
|
||||
|
||||
def test_push
|
||||
m = TestMessage.new
|
||||
reference_arr = %w(foo bar baz)
|
||||
m.repeated_string += reference_arr.clone
|
||||
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr.push('fizz')
|
||||
end
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr << 'fizz'
|
||||
end
|
||||
#TODO: push should support multiple
|
||||
# check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
# arr.push('fizz', 'buzz')
|
||||
# end
|
||||
end
|
||||
|
||||
def test_clear
|
||||
m = TestMessage.new
|
||||
reference_arr = %w(foo bar baz)
|
||||
m.repeated_string += reference_arr.clone
|
||||
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr.clear
|
||||
end
|
||||
end
|
||||
|
||||
def test_concat
|
||||
m = TestMessage.new
|
||||
reference_arr = %w(foo bar baz)
|
||||
m.repeated_string += reference_arr.clone
|
||||
m.repeated_string.concat(['fizz', 'buzz'])
|
||||
assert_equal %w(foo bar baz fizz buzz), m.repeated_string
|
||||
#TODO: concat should return the orig array
|
||||
# check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
# arr.concat(['fizz', 'buzz'])
|
||||
# end
|
||||
end
|
||||
|
||||
def test_equal
|
||||
m = TestMessage.new
|
||||
reference_arr = %w(foo bar baz)
|
||||
m.repeated_string += reference_arr.clone
|
||||
assert_equal reference_arr, m.repeated_string
|
||||
reference_arr << 'fizz'
|
||||
assert_not_equal reference_arr, m.repeated_string
|
||||
m.repeated_string << 'fizz'
|
||||
assert_equal reference_arr, m.repeated_string
|
||||
end
|
||||
|
||||
def test_hash
|
||||
# just a sanity check
|
||||
m = TestMessage.new
|
||||
reference_arr = %w(foo bar baz)
|
||||
m.repeated_string += reference_arr.clone
|
||||
assert m.repeated_string.hash.is_a?(Integer)
|
||||
hash = m.repeated_string.hash
|
||||
assert_equal hash, m.repeated_string.hash
|
||||
m.repeated_string << 'j'
|
||||
assert_not_equal hash, m.repeated_string.hash
|
||||
end
|
||||
|
||||
def test_plus
|
||||
m = TestMessage.new
|
||||
reference_arr = %w(foo bar baz)
|
||||
m.repeated_string += reference_arr.clone
|
||||
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr + ['fizz', 'buzz']
|
||||
end
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr += ['fizz', 'buzz']
|
||||
end
|
||||
end
|
||||
|
||||
def test_replace
|
||||
m = TestMessage.new
|
||||
reference_arr = %w(foo bar baz)
|
||||
m.repeated_string += reference_arr.clone
|
||||
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr.replace(['fizz', 'buzz'])
|
||||
end
|
||||
end
|
||||
|
||||
def test_to_a
|
||||
m = TestMessage.new
|
||||
reference_arr = %w(foo bar baz)
|
||||
m.repeated_string += reference_arr.clone
|
||||
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr.to_a
|
||||
end
|
||||
end
|
||||
|
||||
def test_to_ary
|
||||
m = TestMessage.new
|
||||
reference_arr = %w(foo bar baz)
|
||||
m.repeated_string += reference_arr.clone
|
||||
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr.to_ary
|
||||
end
|
||||
end
|
||||
|
||||
# emulate Array behavior
|
||||
##########################
|
||||
|
||||
def test_collect!
|
||||
m = TestMessage.new
|
||||
reference_arr = %w(foo bar baz)
|
||||
m.repeated_string += reference_arr.clone
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr.collect!{|x| x + "!" }
|
||||
end
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr.collect!.with_index{|x, i| x[0...i] }
|
||||
end
|
||||
end
|
||||
|
||||
def test_delete
|
||||
m = TestMessage.new
|
||||
reference_arr = %w(foo bar baz)
|
||||
m.repeated_string += reference_arr.clone
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr.delete('bar')
|
||||
end
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr.delete('nope')
|
||||
end
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr.delete('nope'){'within'}
|
||||
end
|
||||
end
|
||||
|
||||
def test_delete_at
|
||||
m = TestMessage.new
|
||||
reference_arr = %w(foo bar baz)
|
||||
m.repeated_string += reference_arr.clone
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr.delete_at(2)
|
||||
end
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr.delete_at(10)
|
||||
end
|
||||
end
|
||||
|
||||
def test_fill
|
||||
m = TestMessage.new
|
||||
reference_arr = %w(foo bar baz)
|
||||
m.repeated_string += reference_arr.clone
|
||||
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr.fill("x")
|
||||
end
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr.fill("z", 2, 2)
|
||||
end
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr.fill("y", 0..1)
|
||||
end
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr.fill { |i| (i*i).to_s }
|
||||
end
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr.fill(-2) { |i| (i*i*i).to_s }
|
||||
end
|
||||
end
|
||||
|
||||
def test_flatten!
|
||||
m = TestMessage.new
|
||||
reference_arr = %w(foo bar baz)
|
||||
m.repeated_string += reference_arr.clone
|
||||
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr.flatten!
|
||||
end
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr.flatten!(1)
|
||||
end
|
||||
end
|
||||
|
||||
def test_insert
|
||||
m = TestMessage.new
|
||||
reference_arr = %w(foo bar baz)
|
||||
m.repeated_string += reference_arr.clone
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr.insert(2, 'fizz')
|
||||
end
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr.insert(3, 'fizz', 'buzz', 'bazz')
|
||||
end
|
||||
end
|
||||
|
||||
def test_inspect
|
||||
m = TestMessage.new
|
||||
assert_equal '[]', m.repeated_string.inspect
|
||||
m.repeated_string << 'foo'
|
||||
assert_equal m.repeated_string.to_a.inspect, m.repeated_string.inspect
|
||||
m.repeated_string << 'bar'
|
||||
assert_equal m.repeated_string.to_a.inspect, m.repeated_string.inspect
|
||||
end
|
||||
|
||||
def test_reverse!
|
||||
m = TestMessage.new
|
||||
reference_arr = %w(foo bar baz)
|
||||
m.repeated_string += reference_arr.clone
|
||||
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr.reverse!
|
||||
end
|
||||
end
|
||||
|
||||
def test_rotate!
|
||||
m = TestMessage.new
|
||||
reference_arr = %w(foo bar baz)
|
||||
m.repeated_string += reference_arr.clone
|
||||
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr.rotate!
|
||||
end
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr.rotate!(2)
|
||||
end
|
||||
end
|
||||
|
||||
def test_select!
|
||||
m = TestMessage.new
|
||||
reference_arr = %w(foo bar baz)
|
||||
m.repeated_string += reference_arr.clone
|
||||
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr.select! { |v| v =~ /[aeiou]/ }
|
||||
end
|
||||
end
|
||||
|
||||
def test_shift
|
||||
m = TestMessage.new
|
||||
reference_arr = %w(foo bar baz)
|
||||
m.repeated_string += reference_arr.clone
|
||||
|
||||
# should return an element
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr.shift
|
||||
end
|
||||
# should return an array
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr.shift(2)
|
||||
end
|
||||
# should return nil
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr.shift
|
||||
end
|
||||
end
|
||||
|
||||
def test_shuffle!
|
||||
m = TestMessage.new
|
||||
m.repeated_string += %w(foo bar baz)
|
||||
orig_repeated_string = m.repeated_string.clone
|
||||
result = m.repeated_string.shuffle!
|
||||
assert_equal m.repeated_string, result
|
||||
# NOTE: sometimes it doesn't change the order...
|
||||
# assert_not_equal m.repeated_string.to_a, orig_repeated_string.to_a
|
||||
end
|
||||
|
||||
def test_slice!
|
||||
m = TestMessage.new
|
||||
reference_arr = %w(foo bar baz bar fizz buzz)
|
||||
m.repeated_string += reference_arr.clone
|
||||
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr.slice!(2)
|
||||
end
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr.slice!(1,2)
|
||||
end
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr.slice!(0..1)
|
||||
end
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr.slice!(10)
|
||||
end
|
||||
end
|
||||
|
||||
def test_sort!
|
||||
m = TestMessage.new
|
||||
reference_arr = %w(foo bar baz)
|
||||
m.repeated_string += reference_arr.clone
|
||||
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr.sort!
|
||||
end
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr.sort! { |x,y| y <=> x }
|
||||
end
|
||||
end
|
||||
|
||||
def test_sort_by!
|
||||
m = TestMessage.new
|
||||
reference_arr = %w(foo bar baz)
|
||||
m.repeated_string += reference_arr.clone
|
||||
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr.sort_by!
|
||||
end
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr.sort_by!(&:hash)
|
||||
end
|
||||
end
|
||||
|
||||
def test_uniq!
|
||||
m = TestMessage.new
|
||||
reference_arr = %w(foo bar baz)
|
||||
m.repeated_string += reference_arr.clone
|
||||
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr.uniq!
|
||||
end
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr.uniq!{|s| s[0] }
|
||||
end
|
||||
end
|
||||
|
||||
def test_unshift
|
||||
m = TestMessage.new
|
||||
reference_arr = %w(foo bar baz)
|
||||
m.repeated_string += reference_arr.clone
|
||||
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr.unshift('1')
|
||||
end
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr.unshift('a', 'b')
|
||||
end
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr.unshift('')
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
##### HELPER METHODS
|
||||
|
||||
def check_self_modifying_method(repeated_field, ref_array)
|
||||
expected_result = yield(ref_array)
|
||||
actual_result = yield(repeated_field)
|
||||
if expected_result.is_a?(Enumerator)
|
||||
assert_equal expected_result.to_a, actual_result.to_a
|
||||
else
|
||||
assert_equal expected_result, actual_result
|
||||
end
|
||||
assert_equal ref_array, repeated_field
|
||||
end
|
||||
|
||||
|
||||
def repeated_field_names(klass)
|
||||
klass.descriptor.find_all{|f| f.label == :repeated}.map(&:name)
|
||||
end
|
||||
|
||||
|
||||
def fill_test_msg(test_msg)
|
||||
test_msg.repeated_int32 += [-10, -11]
|
||||
test_msg.repeated_int64 += [-1_000_000, -1_000_001]
|
||||
test_msg.repeated_uint32 += [10, 11]
|
||||
test_msg.repeated_uint64 += [1_000_000, 1_000_001]
|
||||
test_msg.repeated_bool += [true, false]
|
||||
test_msg.repeated_float += [-1.01, -1.02]
|
||||
test_msg.repeated_double += [-1.0000000000001, -1.0000000000002]
|
||||
test_msg.repeated_string += %w(foo bar)
|
||||
test_msg.repeated_bytes += ["bar".encode!('ASCII-8BIT'), "foo".encode!('ASCII-8BIT')]
|
||||
test_msg.repeated_msg << TestMessage2.new(:foo => 1)
|
||||
test_msg.repeated_msg << TestMessage2.new(:foo => 2)
|
||||
test_msg.repeated_enum << :A
|
||||
test_msg.repeated_enum << :B
|
||||
end
|
||||
|
||||
|
||||
pool = Google::Protobuf::DescriptorPool.new
|
||||
pool.build do
|
||||
|
||||
add_message "TestMessage" do
|
||||
optional :optional_int32, :int32, 1
|
||||
optional :optional_int64, :int64, 2
|
||||
optional :optional_uint32, :uint32, 3
|
||||
optional :optional_uint64, :uint64, 4
|
||||
optional :optional_bool, :bool, 5
|
||||
optional :optional_float, :float, 6
|
||||
optional :optional_double, :double, 7
|
||||
optional :optional_string, :string, 8
|
||||
optional :optional_bytes, :bytes, 9
|
||||
optional :optional_msg, :message, 10, "TestMessage2"
|
||||
optional :optional_enum, :enum, 11, "TestEnum"
|
||||
|
||||
repeated :repeated_int32, :int32, 12
|
||||
repeated :repeated_int64, :int64, 13
|
||||
repeated :repeated_uint32, :uint32, 14
|
||||
repeated :repeated_uint64, :uint64, 15
|
||||
repeated :repeated_bool, :bool, 16
|
||||
repeated :repeated_float, :float, 17
|
||||
repeated :repeated_double, :double, 18
|
||||
repeated :repeated_string, :string, 19
|
||||
repeated :repeated_bytes, :bytes, 20
|
||||
repeated :repeated_msg, :message, 21, "TestMessage2"
|
||||
repeated :repeated_enum, :enum, 22, "TestEnum"
|
||||
end
|
||||
add_message "TestMessage2" do
|
||||
optional :foo, :int32, 1
|
||||
end
|
||||
|
||||
add_enum "TestEnum" do
|
||||
value :Default, 0
|
||||
value :A, 1
|
||||
value :B, 2
|
||||
value :C, 3
|
||||
end
|
||||
end
|
||||
|
||||
TestMessage = pool.lookup("TestMessage").msgclass
|
||||
TestMessage2 = pool.lookup("TestMessage2").msgclass
|
||||
TestEnum = pool.lookup("TestEnum").enummodule
|
||||
|
||||
|
||||
end
|
38
deps/protobuf/ruby/compatibility_tests/v3.0.0/tests/stress.rb
vendored
Normal file
38
deps/protobuf/ruby/compatibility_tests/v3.0.0/tests/stress.rb
vendored
Normal file
@ -0,0 +1,38 @@
|
||||
#!/usr/bin/ruby
|
||||
|
||||
require 'google/protobuf'
|
||||
require 'test/unit'
|
||||
|
||||
module StressTest
|
||||
pool = Google::Protobuf::DescriptorPool.new
|
||||
pool.build do
|
||||
add_message "TestMessage" do
|
||||
optional :a, :int32, 1
|
||||
repeated :b, :message, 2, "M"
|
||||
end
|
||||
add_message "M" do
|
||||
optional :foo, :string, 1
|
||||
end
|
||||
end
|
||||
|
||||
TestMessage = pool.lookup("TestMessage").msgclass
|
||||
M = pool.lookup("M").msgclass
|
||||
|
||||
class StressTest < Test::Unit::TestCase
|
||||
def get_msg
|
||||
TestMessage.new(:a => 1000,
|
||||
:b => [M.new(:foo => "hello"),
|
||||
M.new(:foo => "world")])
|
||||
end
|
||||
def test_stress
|
||||
m = get_msg
|
||||
data = TestMessage.encode(m)
|
||||
100_000.times do
|
||||
mnew = TestMessage.decode(data)
|
||||
mnew = mnew.dup
|
||||
assert_equal mnew.inspect, m.inspect
|
||||
assert TestMessage.encode(mnew) == data
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
5
deps/protobuf/ruby/compatibility_tests/v3.0.0/tests/test_import.proto
vendored
Normal file
5
deps/protobuf/ruby/compatibility_tests/v3.0.0/tests/test_import.proto
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package foo_bar;
|
||||
|
||||
message TestImportedMessage {}
|
361
deps/protobuf/ruby/ext/google/protobuf_c/convert.c
vendored
Normal file
361
deps/protobuf/ruby/ext/google/protobuf_c/convert.c
vendored
Normal file
@ -0,0 +1,361 @@
|
||||
// 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_MessageValue.
|
||||
//
|
||||
// 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"
|
||||
|
||||
static upb_StringView Convert_StringData(VALUE str, upb_Arena* arena) {
|
||||
upb_StringView 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_CType 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 == kUpb_CType_UInt32 || type == kUpb_CType_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, kUpb_CType_Int32, value);
|
||||
val = NUM2INT(value);
|
||||
break;
|
||||
case T_STRING: {
|
||||
const upb_EnumValueDef* ev = upb_EnumDef_FindValueByNameWithSize(
|
||||
e, RSTRING_PTR(value), RSTRING_LEN(value));
|
||||
if (!ev) goto unknownval;
|
||||
val = upb_EnumValueDef_Number(ev);
|
||||
break;
|
||||
}
|
||||
case T_SYMBOL: {
|
||||
const upb_EnumValueDef* ev =
|
||||
upb_EnumDef_FindValueByName(e, rb_id2name(SYM2ID(value)));
|
||||
if (!ev)
|
||||
goto unknownval;
|
||||
val = upb_EnumValueDef_Number(ev);
|
||||
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_MessageValue Convert_RubyToUpb(VALUE value, const char* name,
|
||||
TypeInfo type_info, upb_Arena* arena) {
|
||||
upb_MessageValue ret;
|
||||
|
||||
switch (type_info.type) {
|
||||
case kUpb_CType_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 kUpb_CType_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 kUpb_CType_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 kUpb_CType_String: {
|
||||
VALUE utf8 = rb_enc_from_encoding(rb_utf8_encoding());
|
||||
if (rb_obj_class(value) == rb_cSymbol) {
|
||||
value = rb_funcall(value, rb_intern("to_s"), 0);
|
||||
} else if (rb_obj_class(value) != rb_cString) {
|
||||
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 kUpb_CType_Bytes: {
|
||||
VALUE bytes = rb_enc_from_encoding(rb_ascii8bit_encoding());
|
||||
if (rb_obj_class(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 kUpb_CType_Message:
|
||||
ret.msg_val =
|
||||
Message_GetUpbMessage(value, type_info.def.msgdef, name, arena);
|
||||
break;
|
||||
case kUpb_CType_Enum:
|
||||
ret.int32_val = Convert_ToEnum(value, name, type_info.def.enumdef);
|
||||
break;
|
||||
case kUpb_CType_Int32:
|
||||
case kUpb_CType_Int64:
|
||||
case kUpb_CType_UInt32:
|
||||
case kUpb_CType_UInt64:
|
||||
Convert_CheckInt(name, type_info.type, value);
|
||||
switch (type_info.type) {
|
||||
case kUpb_CType_Int32:
|
||||
ret.int32_val = NUM2INT(value);
|
||||
break;
|
||||
case kUpb_CType_Int64:
|
||||
ret.int64_val = NUM2LL(value);
|
||||
break;
|
||||
case kUpb_CType_UInt32:
|
||||
ret.uint32_val = NUM2UINT(value);
|
||||
break;
|
||||
case kUpb_CType_UInt64:
|
||||
ret.uint64_val = NUM2ULL(value);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
VALUE Convert_UpbToRuby(upb_MessageValue upb_val, TypeInfo type_info,
|
||||
VALUE arena) {
|
||||
switch (type_info.type) {
|
||||
case kUpb_CType_Float:
|
||||
return DBL2NUM(upb_val.float_val);
|
||||
case kUpb_CType_Double:
|
||||
return DBL2NUM(upb_val.double_val);
|
||||
case kUpb_CType_Bool:
|
||||
return upb_val.bool_val ? Qtrue : Qfalse;
|
||||
case kUpb_CType_Int32:
|
||||
return INT2NUM(upb_val.int32_val);
|
||||
case kUpb_CType_Int64:
|
||||
return LL2NUM(upb_val.int64_val);
|
||||
case kUpb_CType_UInt32:
|
||||
return UINT2NUM(upb_val.uint32_val);
|
||||
case kUpb_CType_UInt64:
|
||||
return ULL2NUM(upb_val.int64_val);
|
||||
case kUpb_CType_Enum: {
|
||||
const upb_EnumValueDef *ev = upb_EnumDef_FindValueByNumber(
|
||||
type_info.def.enumdef, upb_val.int32_val);
|
||||
if (ev) {
|
||||
return ID2SYM(rb_intern(upb_EnumValueDef_Name(ev)));
|
||||
} else {
|
||||
return INT2NUM(upb_val.int32_val);
|
||||
}
|
||||
}
|
||||
case kUpb_CType_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 kUpb_CType_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 kUpb_CType_Message:
|
||||
return Message_GetRubyWrapper((upb_Message*)upb_val.msg_val,
|
||||
type_info.def.msgdef, arena);
|
||||
default:
|
||||
rb_raise(rb_eRuntimeError, "Convert_UpbToRuby(): Unexpected type %d",
|
||||
(int)type_info.type);
|
||||
}
|
||||
}
|
||||
|
||||
upb_MessageValue Msgval_DeepCopy(upb_MessageValue msgval, TypeInfo type_info,
|
||||
upb_Arena* arena) {
|
||||
upb_MessageValue new_msgval;
|
||||
|
||||
switch (type_info.type) {
|
||||
default:
|
||||
memcpy(&new_msgval, &msgval, sizeof(msgval));
|
||||
break;
|
||||
case kUpb_CType_String:
|
||||
case kUpb_CType_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 kUpb_CType_Message:
|
||||
new_msgval.msg_val =
|
||||
Message_deep_copy(msgval.msg_val, type_info.def.msgdef, arena);
|
||||
break;
|
||||
}
|
||||
|
||||
return new_msgval;
|
||||
}
|
||||
|
||||
bool Msgval_IsEqual(upb_MessageValue val1, upb_MessageValue val2,
|
||||
TypeInfo type_info) {
|
||||
switch (type_info.type) {
|
||||
case kUpb_CType_Bool:
|
||||
return memcmp(&val1, &val2, 1) == 0;
|
||||
case kUpb_CType_Float:
|
||||
case kUpb_CType_Int32:
|
||||
case kUpb_CType_UInt32:
|
||||
case kUpb_CType_Enum:
|
||||
return memcmp(&val1, &val2, 4) == 0;
|
||||
case kUpb_CType_Double:
|
||||
case kUpb_CType_Int64:
|
||||
case kUpb_CType_UInt64:
|
||||
return memcmp(&val1, &val2, 8) == 0;
|
||||
case kUpb_CType_String:
|
||||
case kUpb_CType_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 kUpb_CType_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_MessageValue val, TypeInfo type_info,
|
||||
uint64_t seed) {
|
||||
switch (type_info.type) {
|
||||
case kUpb_CType_Bool:
|
||||
return _upb_Hash(&val, 1, seed);
|
||||
case kUpb_CType_Float:
|
||||
case kUpb_CType_Int32:
|
||||
case kUpb_CType_UInt32:
|
||||
case kUpb_CType_Enum:
|
||||
return _upb_Hash(&val, 4, seed);
|
||||
case kUpb_CType_Double:
|
||||
case kUpb_CType_Int64:
|
||||
case kUpb_CType_UInt64:
|
||||
return _upb_Hash(&val, 8, seed);
|
||||
case kUpb_CType_String:
|
||||
case kUpb_CType_Bytes:
|
||||
return _upb_Hash(val.str_val.data, val.str_val.size, seed);
|
||||
case kUpb_CType_Message:
|
||||
return Message_Hash(val.msg_val, type_info.def.msgdef, seed);
|
||||
default:
|
||||
rb_raise(rb_eRuntimeError, "Internal error, unexpected type");
|
||||
}
|
||||
}
|
75
deps/protobuf/ruby/ext/google/protobuf_c/convert.h
vendored
Normal file
75
deps/protobuf/ruby/ext/google/protobuf_c/convert.h
vendored
Normal file
@ -0,0 +1,75 @@
|
||||
// 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 <ruby/ruby.h>
|
||||
|
||||
#include "protobuf.h"
|
||||
#include "ruby-upb.h"
|
||||
|
||||
// Converts |ruby_val| to a upb_MessageValue 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_MessageValue 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_MessageValue upb_val, TypeInfo type_info,
|
||||
VALUE arena);
|
||||
|
||||
// Creates a deep copy of |msgval| in |arena|.
|
||||
upb_MessageValue Msgval_DeepCopy(upb_MessageValue 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_MessageValue val1, upb_MessageValue val2,
|
||||
TypeInfo type_info);
|
||||
|
||||
// Returns a hash value for the given upb_MessageValue.
|
||||
uint64_t Msgval_GetHash(upb_MessageValue val, TypeInfo type_info,
|
||||
uint64_t seed);
|
||||
|
||||
#endif // RUBY_PROTOBUF_CONVERT_H_
|
1280
deps/protobuf/ruby/ext/google/protobuf_c/defs.c
vendored
Normal file
1280
deps/protobuf/ruby/ext/google/protobuf_c/defs.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
107
deps/protobuf/ruby/ext/google/protobuf_c/defs.h
vendored
Normal file
107
deps/protobuf/ruby/ext/google/protobuf_c/defs.h
vendored
Normal file
@ -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 <ruby/ruby.h>
|
||||
|
||||
#include "protobuf.h"
|
||||
#include "ruby-upb.h"
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// TypeInfo
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// This bundles a upb_CType 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_CType type;
|
||||
union {
|
||||
const upb_MessageDef* msgdef; // When type == kUpb_CType_Message
|
||||
const upb_EnumDef* enumdef; // When type == kUpb_CType_Enum
|
||||
} def;
|
||||
} TypeInfo;
|
||||
|
||||
static inline TypeInfo TypeInfo_get(const upb_FieldDef* f) {
|
||||
TypeInfo ret = {upb_FieldDef_CType(f), {NULL}};
|
||||
switch (ret.type) {
|
||||
case kUpb_CType_Message:
|
||||
ret.def.msgdef = upb_FieldDef_MessageSubDef(f);
|
||||
break;
|
||||
case kUpb_CType_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_CType type) {
|
||||
TypeInfo ret = {type};
|
||||
assert(type != kUpb_CType_Message && type != kUpb_CType_Enum);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Other utilities
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
VALUE Descriptor_DefToClass(const upb_MessageDef* 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_DefPool* DescriptorPool_GetSymtab(VALUE desc_pool_rb);
|
||||
const upb_MessageDef* Descriptor_GetMsgDef(VALUE desc_rb);
|
||||
|
||||
// Returns a upb field type for the given Ruby symbol
|
||||
// (eg. :float => kUpb_CType_Float).
|
||||
upb_CType 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_
|
28
deps/protobuf/ruby/ext/google/protobuf_c/extconf.rb
vendored
Normal file
28
deps/protobuf/ruby/ext/google/protobuf_c/extconf.rb
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
#!/usr/bin/ruby
|
||||
|
||||
require 'mkmf'
|
||||
|
||||
ext_name = "google/protobuf_c"
|
||||
|
||||
dir_config(ext_name)
|
||||
|
||||
if RUBY_PLATFORM =~ /darwin/ || RUBY_PLATFORM =~ /linux/
|
||||
$CFLAGS += " -std=gnu99 -O3 -DNDEBUG -fvisibility=hidden -Wall -Wsign-compare -Wno-declaration-after-statement"
|
||||
else
|
||||
$CFLAGS += " -std=gnu99 -O3 -DNDEBUG"
|
||||
end
|
||||
|
||||
|
||||
if RUBY_PLATFORM =~ /linux/
|
||||
# Instruct the linker to point memcpy calls at our __wrap_memcpy wrapper.
|
||||
$LDFLAGS += " -Wl,-wrap,memcpy"
|
||||
end
|
||||
|
||||
$VPATH << "$(srcdir)/third_party/utf8_range"
|
||||
$INCFLAGS << "$(srcdir)/third_party/utf8_range"
|
||||
|
||||
$srcs = ["protobuf.c", "convert.c", "defs.c", "message.c",
|
||||
"repeated_field.c", "map.c", "ruby-upb.c", "wrap_memcpy.c",
|
||||
"naive.c", "range2-neon.c", "range2-sse.c"]
|
||||
|
||||
create_makefile(ext_name)
|
702
deps/protobuf/ruby/ext/google/protobuf_c/map.c
vendored
Normal file
702
deps/protobuf/ruby/ext/google/protobuf_c/map.c
vendored
Normal file
@ -0,0 +1,702 @@
|
||||
// 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 "convert.h"
|
||||
#include "defs.h"
|
||||
#include "message.h"
|
||||
#include "protobuf.h"
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// 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).
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Map container type.
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
typedef struct {
|
||||
const upb_Map* map; // Can convert to mutable when non-frozen.
|
||||
upb_CType 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, RUBY_DEFAULT_FREE, NULL},
|
||||
.flags = RUBY_TYPED_FREE_IMMEDIATELY,
|
||||
};
|
||||
|
||||
VALUE cMap;
|
||||
|
||||
static Map* ruby_to_Map(VALUE _self) {
|
||||
Map* self;
|
||||
TypedData_Get_Struct(_self, Map, &Map_type, self);
|
||||
return 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);
|
||||
}
|
||||
|
||||
VALUE Map_GetRubyWrapper(upb_Map* map, upb_CType 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);
|
||||
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 == kUpb_CType_Message) {
|
||||
const upb_MessageDef* val_m = self->value_type_info.def.msgdef;
|
||||
self->value_type_class = Descriptor_DefToClass(val_m);
|
||||
}
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static TypeInfo Map_keyinfo(Map* self) {
|
||||
TypeInfo ret;
|
||||
ret.type = self->key_type;
|
||||
ret.def.msgdef = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static upb_Map* Map_GetMutable(VALUE _self) {
|
||||
rb_check_frozen(_self);
|
||||
return (upb_Map*)ruby_to_Map(_self)->map;
|
||||
}
|
||||
|
||||
VALUE Map_CreateHash(const upb_Map* map, upb_CType key_type,
|
||||
TypeInfo val_info) {
|
||||
VALUE hash = rb_hash_new();
|
||||
size_t iter = kUpb_Map_Begin;
|
||||
TypeInfo key_info = TypeInfo_from_type(key_type);
|
||||
|
||||
if (!map) return hash;
|
||||
|
||||
while (upb_MapIterator_Next(map, &iter)) {
|
||||
upb_MessageValue key = upb_MapIterator_Key(map, iter);
|
||||
upb_MessageValue val = upb_MapIterator_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 = kUpb_Map_Begin;
|
||||
while (upb_MapIterator_Next(self->map, &iter)) {
|
||||
upb_MessageValue key = upb_MapIterator_Key(self->map, iter);
|
||||
upb_MessageValue val = upb_MapIterator_Value(self->map, iter);
|
||||
upb_MessageValue 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,
|
||||
upb_Arena* arena) {
|
||||
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_CType(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");
|
||||
}
|
||||
|
||||
Arena_fuse(self->arena, arena);
|
||||
return self->map;
|
||||
}
|
||||
|
||||
void Map_Inspect(StringBuilder* b, const upb_Map* map, upb_CType key_type,
|
||||
TypeInfo val_type) {
|
||||
bool first = true;
|
||||
TypeInfo key_type_info = {key_type};
|
||||
StringBuilder_Printf(b, "{");
|
||||
if (map) {
|
||||
size_t iter = kUpb_Map_Begin;
|
||||
while (upb_MapIterator_Next(map, &iter)) {
|
||||
upb_MessageValue key = upb_MapIterator_Key(map, iter);
|
||||
upb_MessageValue val = upb_MapIterator_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_MessageValue key_val =
|
||||
Convert_RubyToUpb(key, "", Map_keyinfo(self), arena);
|
||||
upb_MessageValue 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_Message* self_msg = Map_GetMutable(_self);
|
||||
size_t iter = kUpb_Map_Begin;
|
||||
|
||||
Arena_fuse(other->arena, 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_MapIterator_Next(other->map, &iter)) {
|
||||
upb_MessageValue key = upb_MapIterator_Key(other->map, iter);
|
||||
upb_MessageValue val = upb_MapIterator_Value(other->map, iter);
|
||||
upb_Map_Set(self_msg, key, val, arena);
|
||||
}
|
||||
} else {
|
||||
rb_raise(rb_eArgError, "Unknown type merging into Map");
|
||||
}
|
||||
return _self;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Map.new(key_type, value_type, value_typeclass = nil, init_hashmap = {})
|
||||
* => new map
|
||||
*
|
||||
* Allocates a new Map container. This constructor may be called with 2, 3, or 4
|
||||
* arguments. The first two arguments are always present and are symbols (taking
|
||||
* on the same values as field-type symbols in message descriptors) that
|
||||
* indicate the type of the map key and value fields.
|
||||
*
|
||||
* The supported key types are: :int32, :int64, :uint32, :uint64, :bool,
|
||||
* :string, :bytes.
|
||||
*
|
||||
* The supported value types are: :int32, :int64, :uint32, :uint64, :bool,
|
||||
* :string, :bytes, :enum, :message.
|
||||
*
|
||||
* The third argument, value_typeclass, must be present if value_type is :enum
|
||||
* or :message. As in RepeatedField#new, this argument must be a message class
|
||||
* (for :message) or enum module (for :enum).
|
||||
*
|
||||
* The last argument, if present, provides initial content for map. Note that
|
||||
* this may be an ordinary Ruby hashmap or another Map instance with identical
|
||||
* key and value types. Also note that this argument may be present whether or
|
||||
* not value_typeclass is present (and it is unambiguously separate from
|
||||
* value_typeclass because value_typeclass's presence is strictly determined by
|
||||
* value_type). The contents of this initial hashmap or Map instance are
|
||||
* shallow-copied into the new Map: the original map is unmodified, but
|
||||
* references to underlying objects will be shared if the value type is a
|
||||
* message type.
|
||||
*/
|
||||
static VALUE Map_init(int argc, VALUE* argv, VALUE _self) {
|
||||
Map* self = ruby_to_Map(_self);
|
||||
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
|
||||
// hashmap).
|
||||
if (argc < 2 || argc > 4) {
|
||||
rb_raise(rb_eArgError, "Map constructor expects 2, 3 or 4 arguments.");
|
||||
}
|
||||
|
||||
self->key_type = ruby_to_fieldtype(argv[0]);
|
||||
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) {
|
||||
case kUpb_CType_Int32:
|
||||
case kUpb_CType_Int64:
|
||||
case kUpb_CType_UInt32:
|
||||
case kUpb_CType_UInt64:
|
||||
case kUpb_CType_Bool:
|
||||
case kUpb_CType_String:
|
||||
case kUpb_CType_Bytes:
|
||||
// These are OK.
|
||||
break;
|
||||
default:
|
||||
rb_raise(rb_eArgError, "Invalid key type for map.");
|
||||
}
|
||||
|
||||
self->map = upb_Map_New(Arena_get(self->arena), self->key_type,
|
||||
self->value_type_info.type);
|
||||
ObjectCache_Add(self->map, _self);
|
||||
|
||||
if (init_arg != Qnil) {
|
||||
Map_merge_into_self(_self, init_arg);
|
||||
}
|
||||
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Map.each(&block)
|
||||
*
|
||||
* Invokes &block on each |key, value| pair in the map, in unspecified order.
|
||||
* Note that Map also includes Enumerable; map thus acts like a normal Ruby
|
||||
* sequence.
|
||||
*/
|
||||
static VALUE Map_each(VALUE _self) {
|
||||
Map* self = ruby_to_Map(_self);
|
||||
size_t iter = kUpb_Map_Begin;
|
||||
|
||||
while (upb_MapIterator_Next(self->map, &iter)) {
|
||||
upb_MessageValue key = upb_MapIterator_Key(self->map, iter);
|
||||
upb_MessageValue val = upb_MapIterator_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;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Map.keys => [list_of_keys]
|
||||
*
|
||||
* Returns the list of keys contained in the map, in unspecified order.
|
||||
*/
|
||||
static VALUE Map_keys(VALUE _self) {
|
||||
Map* self = ruby_to_Map(_self);
|
||||
size_t iter = kUpb_Map_Begin;
|
||||
VALUE ret = rb_ary_new();
|
||||
|
||||
while (upb_MapIterator_Next(self->map, &iter)) {
|
||||
upb_MessageValue key = upb_MapIterator_Key(self->map, iter);
|
||||
VALUE key_val = Convert_UpbToRuby(key, Map_keyinfo(self), self->arena);
|
||||
rb_ary_push(ret, key_val);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Map.values => [list_of_values]
|
||||
*
|
||||
* Returns the list of values contained in the map, in unspecified order.
|
||||
*/
|
||||
static VALUE Map_values(VALUE _self) {
|
||||
Map* self = ruby_to_Map(_self);
|
||||
size_t iter = kUpb_Map_Begin;
|
||||
VALUE ret = rb_ary_new();
|
||||
|
||||
while (upb_MapIterator_Next(self->map, &iter)) {
|
||||
upb_MessageValue val = upb_MapIterator_Value(self->map, iter);
|
||||
VALUE val_val = Convert_UpbToRuby(val, self->value_type_info, self->arena);
|
||||
rb_ary_push(ret, val_val);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Map.[](key) => value
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
static VALUE Map_index(VALUE _self, VALUE key) {
|
||||
Map* self = ruby_to_Map(_self);
|
||||
upb_MessageValue key_upb =
|
||||
Convert_RubyToUpb(key, "", Map_keyinfo(self), NULL);
|
||||
upb_MessageValue val;
|
||||
|
||||
if (upb_Map_Get(self->map, key_upb, &val)) {
|
||||
return Convert_UpbToRuby(val, self->value_type_info, self->arena);
|
||||
} else {
|
||||
return Qnil;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Map.[]=(key, value) => value
|
||||
*
|
||||
* Inserts or overwrites the value at the given key with the given new value.
|
||||
* Throws an exception if the key type is incorrect. Returns the new value that
|
||||
* was just inserted.
|
||||
*/
|
||||
static VALUE Map_index_set(VALUE _self, VALUE key, VALUE val) {
|
||||
Map* self = ruby_to_Map(_self);
|
||||
upb_Arena* arena = Arena_get(self->arena);
|
||||
upb_MessageValue key_upb =
|
||||
Convert_RubyToUpb(key, "", Map_keyinfo(self), NULL);
|
||||
upb_MessageValue val_upb =
|
||||
Convert_RubyToUpb(val, "", self->value_type_info, arena);
|
||||
|
||||
upb_Map_Set(Map_GetMutable(_self), key_upb, val_upb, arena);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Map.has_key?(key) => bool
|
||||
*
|
||||
* Returns true if the given key is present in the map. Throws an exception if
|
||||
* the key has the wrong type.
|
||||
*/
|
||||
static VALUE Map_has_key(VALUE _self, VALUE key) {
|
||||
Map* self = ruby_to_Map(_self);
|
||||
upb_MessageValue key_upb =
|
||||
Convert_RubyToUpb(key, "", Map_keyinfo(self), NULL);
|
||||
|
||||
if (upb_Map_Get(self->map, key_upb, NULL)) {
|
||||
return Qtrue;
|
||||
} else {
|
||||
return Qfalse;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Map.delete(key) => old_value
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
static VALUE Map_delete(VALUE _self, VALUE key) {
|
||||
Map* self = ruby_to_Map(_self);
|
||||
upb_MessageValue key_upb =
|
||||
Convert_RubyToUpb(key, "", Map_keyinfo(self), NULL);
|
||||
upb_MessageValue val_upb;
|
||||
VALUE ret;
|
||||
|
||||
rb_check_frozen(_self);
|
||||
|
||||
// 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 {
|
||||
ret = Qnil;
|
||||
}
|
||||
|
||||
upb_Map_Delete(Map_GetMutable(_self), key_upb);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Map.clear
|
||||
*
|
||||
* Removes all entries from the map.
|
||||
*/
|
||||
static VALUE Map_clear(VALUE _self) {
|
||||
upb_Map_Clear(Map_GetMutable(_self));
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Map.length
|
||||
*
|
||||
* Returns the number of entries (key-value pairs) in the map.
|
||||
*/
|
||||
static VALUE Map_length(VALUE _self) {
|
||||
Map* self = ruby_to_Map(_self);
|
||||
return ULL2NUM(upb_Map_Size(self->map));
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Map.dup => new_map
|
||||
*
|
||||
* Duplicates this map with a shallow copy. References to all non-primitive
|
||||
* element objects (e.g., submessages) are shared.
|
||||
*/
|
||||
static VALUE Map_dup(VALUE _self) {
|
||||
Map* self = ruby_to_Map(_self);
|
||||
VALUE new_map_rb = Map_new_this_type(self);
|
||||
Map* new_self = ruby_to_Map(new_map_rb);
|
||||
size_t iter = kUpb_Map_Begin;
|
||||
upb_Arena* arena = Arena_get(new_self->arena);
|
||||
upb_Map* new_map = Map_GetMutable(new_map_rb);
|
||||
|
||||
Arena_fuse(self->arena, arena);
|
||||
|
||||
while (upb_MapIterator_Next(self->map, &iter)) {
|
||||
upb_MessageValue key = upb_MapIterator_Key(self->map, iter);
|
||||
upb_MessageValue val = upb_MapIterator_Value(self->map, iter);
|
||||
upb_Map_Set(new_map, key, val, arena);
|
||||
}
|
||||
|
||||
return new_map_rb;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Map.==(other) => boolean
|
||||
*
|
||||
* Compares this map to another. Maps are equal if they have identical key sets,
|
||||
* and for each key, the values in both maps compare equal. Elements are
|
||||
* compared as per normal Ruby semantics, by calling their :== methods (or
|
||||
* performing a more efficient comparison for primitive types).
|
||||
*
|
||||
* Maps with dissimilar key types or value types/typeclasses are never equal,
|
||||
* even if value comparison (for example, between integers and floats) would
|
||||
* have otherwise indicated that every element has equal value.
|
||||
*/
|
||||
VALUE Map_eq(VALUE _self, VALUE _other) {
|
||||
Map* self = ruby_to_Map(_self);
|
||||
Map* other;
|
||||
|
||||
// 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);
|
||||
Map_merge_into_self(other_map, _other);
|
||||
_other = other_map;
|
||||
}
|
||||
|
||||
other = ruby_to_Map(_other);
|
||||
|
||||
if (self == other) {
|
||||
return Qtrue;
|
||||
}
|
||||
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) {
|
||||
return Qfalse;
|
||||
}
|
||||
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.
|
||||
size_t iter = kUpb_Map_Begin;
|
||||
while (upb_MapIterator_Next(self->map, &iter)) {
|
||||
upb_MessageValue key = upb_MapIterator_Key(self->map, iter);
|
||||
upb_MessageValue val = upb_MapIterator_Value(self->map, iter);
|
||||
upb_MessageValue other_val;
|
||||
if (!upb_Map_Get(other->map, key, &other_val)) {
|
||||
// Not present in other map.
|
||||
return Qfalse;
|
||||
}
|
||||
if (!Msgval_IsEqual(val, other_val, self->value_type_info)) {
|
||||
// Present but different value.
|
||||
return Qfalse;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
if (!RB_OBJ_FROZEN(_self)) {
|
||||
Arena_Pin(self->arena, _self);
|
||||
RB_OBJ_FREEZE(_self);
|
||||
}
|
||||
return _self;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Map.hash => hash_value
|
||||
*
|
||||
* Returns a hash value based on this map's contents.
|
||||
*/
|
||||
VALUE Map_hash(VALUE _self) {
|
||||
Map* self = ruby_to_Map(_self);
|
||||
uint64_t hash = 0;
|
||||
|
||||
size_t iter = kUpb_Map_Begin;
|
||||
TypeInfo key_info = {self->key_type};
|
||||
while (upb_MapIterator_Next(self->map, &iter)) {
|
||||
upb_MessageValue key = upb_MapIterator_Key(self->map, iter);
|
||||
upb_MessageValue val = upb_MapIterator_Value(self->map, iter);
|
||||
hash = Msgval_GetHash(key, key_info, hash);
|
||||
hash = Msgval_GetHash(val, self->value_type_info, hash);
|
||||
}
|
||||
|
||||
return LL2NUM(hash);
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Map.to_h => {}
|
||||
*
|
||||
* Returns a Ruby Hash object containing all the values within the map
|
||||
*/
|
||||
VALUE Map_to_h(VALUE _self) {
|
||||
Map* self = ruby_to_Map(_self);
|
||||
return Map_CreateHash(self->map, self->key_type, self->value_type_info);
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Map.inspect => string
|
||||
*
|
||||
* Returns a string representing this map's elements. It will be formatted as
|
||||
* "{key => value, key => value, ...}", with each key and value string
|
||||
* representation computed by its own #inspect method.
|
||||
*/
|
||||
VALUE Map_inspect(VALUE _self) {
|
||||
Map* self = ruby_to_Map(_self);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Map.merge(other_map) => map
|
||||
*
|
||||
* Copies key/value pairs from other_map into a copy of this map. If a key is
|
||||
* set in other_map and this map, the value from other_map overwrites the value
|
||||
* in the new copy of this map. Returns the new copy of this map with merged
|
||||
* contents.
|
||||
*/
|
||||
static VALUE Map_merge(VALUE _self, VALUE hashmap) {
|
||||
VALUE dupped = Map_dup(_self);
|
||||
return Map_merge_into_self(dupped, hashmap);
|
||||
}
|
||||
|
||||
void Map_register(VALUE module) {
|
||||
VALUE klass = rb_define_class_under(module, "Map", rb_cObject);
|
||||
rb_define_alloc_func(klass, Map_alloc);
|
||||
rb_gc_register_address(&cMap);
|
||||
cMap = klass;
|
||||
|
||||
rb_define_method(klass, "initialize", Map_init, -1);
|
||||
rb_define_method(klass, "each", Map_each, 0);
|
||||
rb_define_method(klass, "keys", Map_keys, 0);
|
||||
rb_define_method(klass, "values", Map_values, 0);
|
||||
rb_define_method(klass, "[]", Map_index, 1);
|
||||
rb_define_method(klass, "[]=", Map_index_set, 2);
|
||||
rb_define_method(klass, "has_key?", Map_has_key, 1);
|
||||
rb_define_method(klass, "delete", Map_delete, 1);
|
||||
rb_define_method(klass, "clear", Map_clear, 0);
|
||||
rb_define_method(klass, "length", Map_length, 0);
|
||||
rb_define_method(klass, "size", Map_length, 0);
|
||||
rb_define_method(klass, "dup", Map_dup, 0);
|
||||
// Also define #clone so that we don't inherit Object#clone.
|
||||
rb_define_method(klass, "clone", 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);
|
||||
rb_define_method(klass, "merge", Map_merge, 1);
|
||||
rb_include_module(klass, rb_mEnumerable);
|
||||
}
|
66
deps/protobuf/ruby/ext/google/protobuf_c/map.h
vendored
Normal file
66
deps/protobuf/ruby/ext/google/protobuf_c/map.h
vendored
Normal file
@ -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 <ruby/ruby.h>
|
||||
|
||||
#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_CType 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,
|
||||
upb_Arena *arena);
|
||||
|
||||
// Implements #inspect for this map by appending its contents to |b|.
|
||||
void Map_Inspect(StringBuilder *b, const upb_Map *map, upb_CType key_type,
|
||||
TypeInfo val_type);
|
||||
|
||||
// Returns a new Hash object containing the contents of this Map.
|
||||
VALUE Map_CreateHash(const upb_Map *map, upb_CType 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_
|
1402
deps/protobuf/ruby/ext/google/protobuf_c/message.c
vendored
Normal file
1402
deps/protobuf/ruby/ext/google/protobuf_c/message.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
104
deps/protobuf/ruby/ext/google/protobuf_c/message.h
vendored
Normal file
104
deps/protobuf/ruby/ext/google/protobuf_c/message.h
vendored
Normal file
@ -0,0 +1,104 @@
|
||||
// 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 <ruby/ruby.h>
|
||||
|
||||
#include "protobuf.h"
|
||||
#include "ruby-upb.h"
|
||||
|
||||
// Gets the underlying upb_Message* and upb_MessageDef for the given Ruby
|
||||
// message wrapper. Requires that |value| is indeed a message object.
|
||||
const upb_Message* Message_Get(VALUE value, const upb_MessageDef** m);
|
||||
|
||||
// Like Message_Get(), but checks that the object is not frozen and returns a
|
||||
// mutable pointer.
|
||||
upb_Message* Message_GetMutable(VALUE value, const upb_MessageDef** m);
|
||||
|
||||
// Returns the Arena object for this message.
|
||||
VALUE Message_GetArena(VALUE value);
|
||||
|
||||
// Converts |value| into a upb_Message value of the expected upb_MessageDef
|
||||
// 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_Message* Message_GetUpbMessage(VALUE value, const upb_MessageDef* 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_Message* msg, const upb_MessageDef* m,
|
||||
VALUE arena);
|
||||
|
||||
// Gets the given field from this message.
|
||||
VALUE Message_getfield(VALUE _self, const upb_FieldDef* f);
|
||||
|
||||
// Implements #inspect for this message, printing the text to |b|.
|
||||
void Message_PrintMessage(StringBuilder* b, const upb_Message* msg,
|
||||
const upb_MessageDef* m);
|
||||
|
||||
// Returns a hash value for the given message.
|
||||
uint64_t Message_Hash(const upb_Message* msg, const upb_MessageDef* m,
|
||||
uint64_t seed);
|
||||
|
||||
// Returns a deep copy of the given message.
|
||||
upb_Message* Message_deep_copy(const upb_Message* msg, const upb_MessageDef* m,
|
||||
upb_Arena* arena);
|
||||
|
||||
// Returns true if these two messages are equal.
|
||||
bool Message_Equal(const upb_Message* m1, const upb_Message* m2,
|
||||
const upb_MessageDef* 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_MessageValue 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_
|
480
deps/protobuf/ruby/ext/google/protobuf_c/protobuf.c
vendored
Normal file
480
deps/protobuf/ruby/ext/google/protobuf_c/protobuf.c
vendored
Normal file
@ -0,0 +1,480 @@
|
||||
// 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"
|
||||
|
||||
#include <ruby/version.h>
|
||||
|
||||
#include "defs.h"
|
||||
#include "map.h"
|
||||
#include "message.h"
|
||||
#include "repeated_field.h"
|
||||
|
||||
VALUE cParseError;
|
||||
VALUE cTypeError;
|
||||
|
||||
const upb_FieldDef *map_field_key(const upb_FieldDef *field) {
|
||||
const upb_MessageDef *entry = upb_FieldDef_MessageSubDef(field);
|
||||
return upb_MessageDef_FindFieldByNumber(entry, 1);
|
||||
}
|
||||
|
||||
const upb_FieldDef *map_field_value(const upb_FieldDef *field) {
|
||||
const upb_MessageDef *entry = upb_FieldDef_MessageSubDef(field);
|
||||
return upb_MessageDef_FindFieldByNumber(entry, 2);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// 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;
|
||||
}
|
||||
|
||||
VALUE StringBuilder_ToRubyString(StringBuilder *b) {
|
||||
VALUE ret = rb_str_new(b->data, b->size);
|
||||
rb_enc_associate(ret, rb_utf8_encoding());
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void StringBuilder_PrintEnum(StringBuilder *b, int32_t val,
|
||||
const upb_EnumDef *e) {
|
||||
const upb_EnumValueDef *ev = upb_EnumDef_FindValueByNumber(e, val);
|
||||
if (ev) {
|
||||
StringBuilder_Printf(b, ":%s", upb_EnumValueDef_Name(ev));
|
||||
} else {
|
||||
StringBuilder_Printf(b, "%" PRId32, val);
|
||||
}
|
||||
}
|
||||
|
||||
void StringBuilder_PrintMsgval(StringBuilder *b, upb_MessageValue val,
|
||||
TypeInfo info) {
|
||||
switch (info.type) {
|
||||
case kUpb_CType_Bool:
|
||||
StringBuilder_Printf(b, "%s", val.bool_val ? "true" : "false");
|
||||
break;
|
||||
case kUpb_CType_Float: {
|
||||
VALUE str = rb_inspect(DBL2NUM(val.float_val));
|
||||
StringBuilder_Printf(b, "%s", RSTRING_PTR(str));
|
||||
break;
|
||||
}
|
||||
case kUpb_CType_Double: {
|
||||
VALUE str = rb_inspect(DBL2NUM(val.double_val));
|
||||
StringBuilder_Printf(b, "%s", RSTRING_PTR(str));
|
||||
break;
|
||||
}
|
||||
case kUpb_CType_Int32:
|
||||
StringBuilder_Printf(b, "%" PRId32, val.int32_val);
|
||||
break;
|
||||
case kUpb_CType_UInt32:
|
||||
StringBuilder_Printf(b, "%" PRIu32, val.uint32_val);
|
||||
break;
|
||||
case kUpb_CType_Int64:
|
||||
StringBuilder_Printf(b, "%" PRId64, val.int64_val);
|
||||
break;
|
||||
case kUpb_CType_UInt64:
|
||||
StringBuilder_Printf(b, "%" PRIu64, val.uint64_val);
|
||||
break;
|
||||
case kUpb_CType_String:
|
||||
StringBuilder_Printf(b, "\"%.*s\"", (int)val.str_val.size,
|
||||
val.str_val.data);
|
||||
break;
|
||||
case kUpb_CType_Bytes:
|
||||
StringBuilder_Printf(b, "\"%.*s\"", (int)val.str_val.size,
|
||||
val.str_val.data);
|
||||
break;
|
||||
case kUpb_CType_Enum:
|
||||
StringBuilder_PrintEnum(b, val.int32_val, info.def.enumdef);
|
||||
break;
|
||||
case kUpb_CType_Message:
|
||||
Message_PrintMessage(b, val.msg_val, info.def.msgdef);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Arena
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
typedef struct {
|
||||
upb_Arena *arena;
|
||||
VALUE pinned_objs;
|
||||
} Arena;
|
||||
|
||||
static void Arena_mark(void *data) {
|
||||
Arena *arena = data;
|
||||
rb_gc_mark(arena->pinned_objs);
|
||||
}
|
||||
|
||||
static void Arena_free(void *data) {
|
||||
Arena *arena = data;
|
||||
upb_Arena_Free(arena->arena);
|
||||
xfree(arena);
|
||||
}
|
||||
|
||||
static VALUE cArena;
|
||||
|
||||
const rb_data_type_t Arena_type = {
|
||||
"Google::Protobuf::Internal::Arena",
|
||||
{Arena_mark, Arena_free, NULL},
|
||||
.flags = RUBY_TYPED_FREE_IMMEDIATELY,
|
||||
};
|
||||
|
||||
static void* ruby_upb_allocfunc(upb_alloc* alloc, void* ptr, size_t oldsize, size_t size) {
|
||||
if (size == 0) {
|
||||
xfree(ptr);
|
||||
return NULL;
|
||||
} else {
|
||||
return xrealloc(ptr, size);
|
||||
}
|
||||
}
|
||||
|
||||
upb_alloc ruby_upb_alloc = {&ruby_upb_allocfunc};
|
||||
|
||||
static VALUE Arena_alloc(VALUE klass) {
|
||||
Arena *arena = ALLOC(Arena);
|
||||
arena->arena = upb_Arena_Init(NULL, 0, &ruby_upb_alloc);
|
||||
arena->pinned_objs = Qnil;
|
||||
return TypedData_Wrap_Struct(klass, &Arena_type, arena);
|
||||
}
|
||||
|
||||
upb_Arena *Arena_get(VALUE _arena) {
|
||||
Arena *arena;
|
||||
TypedData_Get_Struct(_arena, Arena, &Arena_type, arena);
|
||||
return arena->arena;
|
||||
}
|
||||
|
||||
void Arena_fuse(VALUE _arena, upb_Arena *other) {
|
||||
Arena *arena;
|
||||
TypedData_Get_Struct(_arena, Arena, &Arena_type, arena);
|
||||
if (!upb_Arena_Fuse(arena->arena, other)) {
|
||||
rb_raise(rb_eRuntimeError,
|
||||
"Unable to fuse arenas. This should never happen since Ruby does "
|
||||
"not use initial blocks");
|
||||
}
|
||||
}
|
||||
|
||||
VALUE Arena_new() { return Arena_alloc(cArena); }
|
||||
|
||||
void Arena_Pin(VALUE _arena, VALUE obj) {
|
||||
Arena *arena;
|
||||
TypedData_Get_Struct(_arena, Arena, &Arena_type, arena);
|
||||
if (arena->pinned_objs == Qnil) {
|
||||
arena->pinned_objs = rb_ary_new();
|
||||
}
|
||||
rb_ary_push(arena->pinned_objs, obj);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Object Cache
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// 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 use WeakMap for the cache. For Ruby <2.7 we also need a secondary Hash
|
||||
// to store WeakMap keys because Ruby <2.7 WeakMap doesn't allow non-finalizable
|
||||
// keys.
|
||||
//
|
||||
// We also need the secondary Hash if sizeof(long) < sizeof(VALUE), because this
|
||||
// means it may not be possible to fit a pointer into a Fixnum. Keys are
|
||||
// pointers, and if they fit into a Fixnum, Ruby doesn't collect them, but if
|
||||
// they overflow and require allocating a Bignum, they could get collected
|
||||
// prematurely, thus removing the cache entry. This happens on 64-bit Windows,
|
||||
// on which pointers are 64 bits but longs are 32 bits. In this case, we enable
|
||||
// the secondary Hash to hold the keys and prevent them from being collected.
|
||||
|
||||
#if RUBY_API_VERSION_CODE >= 20700 && SIZEOF_LONG >= SIZEOF_VALUE
|
||||
#define USE_SECONDARY_MAP 0
|
||||
#else
|
||||
#define USE_SECONDARY_MAP 1
|
||||
#endif
|
||||
|
||||
#if USE_SECONDARY_MAP
|
||||
|
||||
// Maps Numeric -> Object. The object is then used as a key into the WeakMap.
|
||||
// This is needed for Ruby <2.7 where a number cannot be a key to WeakMap.
|
||||
// The object is used only for its identity; it does not contain any data.
|
||||
VALUE secondary_map = Qnil;
|
||||
|
||||
// Mutations to the map are under a mutex, because SeconaryMap_MaybeGC()
|
||||
// iterates over the map which cannot happen in parallel with insertions, or
|
||||
// Ruby will throw:
|
||||
// can't add a new key into hash during iteration (RuntimeError)
|
||||
VALUE secondary_map_mutex = Qnil;
|
||||
|
||||
// Lambda that will GC entries from the secondary map that are no longer present
|
||||
// in the primary map.
|
||||
VALUE gc_secondary_map_lambda = Qnil;
|
||||
ID length;
|
||||
|
||||
extern VALUE weak_obj_cache;
|
||||
|
||||
static void SecondaryMap_Init() {
|
||||
rb_gc_register_address(&secondary_map);
|
||||
rb_gc_register_address(&gc_secondary_map_lambda);
|
||||
rb_gc_register_address(&secondary_map_mutex);
|
||||
secondary_map = rb_hash_new();
|
||||
gc_secondary_map_lambda = rb_eval_string(
|
||||
"->(secondary, weak) {\n"
|
||||
" secondary.delete_if { |k, v| !weak.key?(v) }\n"
|
||||
"}\n");
|
||||
secondary_map_mutex = rb_mutex_new();
|
||||
length = rb_intern("length");
|
||||
}
|
||||
|
||||
// The secondary map is a regular Hash, and will never shrink on its own.
|
||||
// The main object cache is a WeakMap that will automatically remove entries
|
||||
// when the target object is no longer reachable, but unless we manually
|
||||
// remove the corresponding entries from the secondary map, it will grow
|
||||
// without bound.
|
||||
//
|
||||
// To avoid this unbounded growth we periodically remove entries from the
|
||||
// secondary map that are no longer present in the WeakMap. The logic of
|
||||
// how often to perform this GC is an artbirary tuning parameter that
|
||||
// represents a straightforward CPU/memory tradeoff.
|
||||
//
|
||||
// Requires: secondary_map_mutex is held.
|
||||
static void SecondaryMap_MaybeGC() {
|
||||
PBRUBY_ASSERT(rb_mutex_locked_p(secondary_map_mutex) == Qtrue);
|
||||
size_t weak_len = NUM2ULL(rb_funcall(weak_obj_cache, length, 0));
|
||||
size_t secondary_len = RHASH_SIZE(secondary_map);
|
||||
if (secondary_len < weak_len) {
|
||||
// Logically this case should not be possible: a valid entry cannot exist in
|
||||
// the weak table unless there is a corresponding entry in the secondary
|
||||
// table. It should *always* be the case that secondary_len >= weak_len.
|
||||
//
|
||||
// However ObjectSpace::WeakMap#length (and therefore weak_len) is
|
||||
// unreliable: it overreports its true length by including non-live objects.
|
||||
// However these non-live objects are not yielded in iteration, so we may
|
||||
// have previously deleted them from the secondary map in a previous
|
||||
// invocation of SecondaryMap_MaybeGC().
|
||||
//
|
||||
// In this case, we can't measure any waste, so we just return.
|
||||
return;
|
||||
}
|
||||
size_t waste = secondary_len - weak_len;
|
||||
// GC if we could remove at least 2000 entries or 20% of the table size
|
||||
// (whichever is greater). Since the cost of the GC pass is O(N), we
|
||||
// want to make sure that we condition this on overall table size, to
|
||||
// avoid O(N^2) CPU costs.
|
||||
size_t threshold = PBRUBY_MAX(secondary_len * 0.2, 2000);
|
||||
if (waste > threshold) {
|
||||
rb_funcall(gc_secondary_map_lambda, rb_intern("call"), 2, secondary_map,
|
||||
weak_obj_cache);
|
||||
}
|
||||
}
|
||||
|
||||
// Requires: secondary_map_mutex is held by this thread iff create == true.
|
||||
static VALUE SecondaryMap_Get(VALUE key, bool create) {
|
||||
PBRUBY_ASSERT(!create || rb_mutex_locked_p(secondary_map_mutex) == Qtrue);
|
||||
VALUE ret = rb_hash_lookup(secondary_map, key);
|
||||
if (ret == Qnil && create) {
|
||||
SecondaryMap_MaybeGC();
|
||||
ret = rb_class_new_instance(0, NULL, rb_cObject);
|
||||
rb_hash_aset(secondary_map, key, ret);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// Requires: secondary_map_mutex is held by this thread iff create == true.
|
||||
static VALUE ObjectCache_GetKey(const void *key, bool create) {
|
||||
VALUE key_val = (VALUE)key;
|
||||
PBRUBY_ASSERT((key_val & 3) == 0);
|
||||
VALUE ret = LL2NUM(key_val >> 2);
|
||||
#if USE_SECONDARY_MAP
|
||||
ret = SecondaryMap_Get(ret, create);
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Public ObjectCache API.
|
||||
|
||||
VALUE weak_obj_cache = Qnil;
|
||||
ID item_get;
|
||||
ID item_set;
|
||||
|
||||
static void ObjectCache_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);
|
||||
item_get = rb_intern("[]");
|
||||
item_set = rb_intern("[]=");
|
||||
#if USE_SECONDARY_MAP
|
||||
SecondaryMap_Init();
|
||||
#endif
|
||||
}
|
||||
|
||||
void ObjectCache_Add(const void *key, VALUE val) {
|
||||
PBRUBY_ASSERT(ObjectCache_Get(key) == Qnil);
|
||||
#if USE_SECONDARY_MAP
|
||||
rb_mutex_lock(secondary_map_mutex);
|
||||
#endif
|
||||
VALUE key_rb = ObjectCache_GetKey(key, true);
|
||||
rb_funcall(weak_obj_cache, item_set, 2, key_rb, val);
|
||||
#if USE_SECONDARY_MAP
|
||||
rb_mutex_unlock(secondary_map_mutex);
|
||||
#endif
|
||||
PBRUBY_ASSERT(ObjectCache_Get(key) == val);
|
||||
}
|
||||
|
||||
// Returns the cached object for this key, if any. Otherwise returns Qnil.
|
||||
VALUE ObjectCache_Get(const void *key) {
|
||||
VALUE key_rb = ObjectCache_GetKey(key, false);
|
||||
return rb_funcall(weak_obj_cache, item_get, 1, key_rb);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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_MessageDef *m;
|
||||
upb_Message *msg = Message_GetMutable(msg_rb, &m);
|
||||
if (!upb_Message_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_MessageDef *m;
|
||||
const upb_Message *msg = Message_Get(obj, &m);
|
||||
upb_Message *new_msg = Message_deep_copy(msg, m, new_arena);
|
||||
return Message_GetRubyWrapper(new_msg, m, new_arena_rb);
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Initialization/entry point.
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// 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");
|
||||
|
||||
Arena_register(protobuf);
|
||||
Defs_register(protobuf);
|
||||
RepeatedField_register(protobuf);
|
||||
Map_register(protobuf);
|
||||
Message_register(protobuf);
|
||||
|
||||
cParseError = rb_const_get(protobuf, rb_intern("ParseError"));
|
||||
rb_gc_register_mark_object(cParseError);
|
||||
cTypeError = rb_const_get(protobuf, rb_intern("TypeError"));
|
||||
rb_gc_register_mark_object(cTypeError);
|
||||
|
||||
rb_define_singleton_method(protobuf, "discard_unknown",
|
||||
Google_Protobuf_discard_unknown, 1);
|
||||
rb_define_singleton_method(protobuf, "deep_copy", Google_Protobuf_deep_copy,
|
||||
1);
|
||||
}
|
120
deps/protobuf/ruby/ext/google/protobuf_c/protobuf.h
vendored
Normal file
120
deps/protobuf/ruby/ext/google/protobuf_c/protobuf.h
vendored
Normal file
@ -0,0 +1,120 @@
|
||||
// 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.
|
||||
|
||||
#ifndef __GOOGLE_PROTOBUF_RUBY_PROTOBUF_H__
|
||||
#define __GOOGLE_PROTOBUF_RUBY_PROTOBUF_H__
|
||||
|
||||
#include <ruby/encoding.h>
|
||||
#include <ruby/ruby.h>
|
||||
#include <ruby/vm.h>
|
||||
|
||||
#include "defs.h"
|
||||
#include "ruby-upb.h"
|
||||
|
||||
// These operate on a map field (i.e., a repeated field of submessages whose
|
||||
// submessage type is a map-entry msgdef).
|
||||
const upb_FieldDef* map_field_key(const upb_FieldDef* field);
|
||||
const upb_FieldDef* map_field_value(const upb_FieldDef* field);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Arena
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// 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.
|
||||
|
||||
VALUE Arena_new();
|
||||
upb_Arena* Arena_get(VALUE arena);
|
||||
|
||||
// Fuses this arena to another, throwing a Ruby exception if this is not
|
||||
// possible.
|
||||
void Arena_fuse(VALUE arena, upb_Arena* other);
|
||||
|
||||
// Pins this Ruby object to the lifetime of this arena, so that as long as the
|
||||
// arena is alive this object will not be collected.
|
||||
//
|
||||
// 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.
|
||||
void Arena_Pin(VALUE arena, VALUE obj);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// ObjectCache
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// 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);
|
||||
|
||||
// Returns the cached object for this key, if any. Otherwise returns Qnil.
|
||||
VALUE ObjectCache_Get(const void* key);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// StringBuilder, for inspect
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
struct StringBuilder;
|
||||
typedef struct StringBuilder StringBuilder;
|
||||
|
||||
StringBuilder* StringBuilder_New();
|
||||
void StringBuilder_Free(StringBuilder* b);
|
||||
void StringBuilder_Printf(StringBuilder* b, const char* fmt, ...);
|
||||
VALUE StringBuilder_ToRubyString(StringBuilder* b);
|
||||
|
||||
void StringBuilder_PrintMsgval(StringBuilder* b, upb_MessageValue val,
|
||||
TypeInfo info);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Utilities.
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
extern VALUE cTypeError;
|
||||
|
||||
#ifdef NDEBUG
|
||||
#define PBRUBY_ASSERT(expr) \
|
||||
do { \
|
||||
} while (false && (expr))
|
||||
#else
|
||||
#define PBRUBY_ASSERT(expr) assert(expr)
|
||||
#endif
|
||||
|
||||
#define PBRUBY_MAX(x, y) (((x) > (y)) ? (x) : (y))
|
||||
|
||||
#define UPB_UNUSED(var) (void)var
|
||||
|
||||
#endif // __GOOGLE_PROTOBUF_RUBY_PROTOBUF_H__
|
657
deps/protobuf/ruby/ext/google/protobuf_c/repeated_field.c
vendored
Normal file
657
deps/protobuf/ruby/ext/google/protobuf_c/repeated_field.c
vendored
Normal file
@ -0,0 +1,657 @@
|
||||
// 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 "repeated_field.h"
|
||||
|
||||
#include "convert.h"
|
||||
#include "defs.h"
|
||||
#include "message.h"
|
||||
#include "protobuf.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, RUBY_DEFAULT_FREE, NULL},
|
||||
.flags = RUBY_TYPED_FREE_IMMEDIATELY,
|
||||
};
|
||||
|
||||
static RepeatedField* ruby_to_RepeatedField(VALUE _self) {
|
||||
RepeatedField* self;
|
||||
TypedData_Get_Struct(_self, RepeatedField, &RepeatedField_type, self);
|
||||
return self;
|
||||
}
|
||||
|
||||
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);
|
||||
TypedData_Get_Struct(val, RepeatedField, &RepeatedField_type, self);
|
||||
self->array = array;
|
||||
self->arena = arena;
|
||||
self->type_info = type_info;
|
||||
if (self->type_info.type == kUpb_CType_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_MessageValue msgval = upb_Array_Get(self->array, i);
|
||||
upb_MessageValue 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,
|
||||
upb_Arena* arena) {
|
||||
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");
|
||||
}
|
||||
|
||||
Arena_fuse(self->arena, arena);
|
||||
return self->array;
|
||||
}
|
||||
|
||||
static int index_position(VALUE _index, RepeatedField* repeated_field) {
|
||||
int index = NUM2INT(_index);
|
||||
if (index < 0) index += upb_Array_Size(repeated_field->array);
|
||||
return index;
|
||||
}
|
||||
|
||||
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++) {
|
||||
upb_MessageValue msgval = upb_Array_Get(self->array, i);
|
||||
VALUE elem = Convert_UpbToRuby(msgval, self->type_info, self->arena);
|
||||
rb_ary_push(ary, elem);
|
||||
}
|
||||
return ary;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* RepeatedField.each(&block)
|
||||
*
|
||||
* Invokes the block once for each element of the repeated field. RepeatedField
|
||||
* also includes Enumerable; combined with this method, the repeated field thus
|
||||
* acts like an ordinary Ruby sequence.
|
||||
*/
|
||||
static VALUE RepeatedField_each(VALUE _self) {
|
||||
RepeatedField* self = ruby_to_RepeatedField(_self);
|
||||
int size = upb_Array_Size(self->array);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
upb_MessageValue msgval = upb_Array_Get(self->array, i);
|
||||
VALUE val = Convert_UpbToRuby(msgval, self->type_info, self->arena);
|
||||
rb_yield(val);
|
||||
}
|
||||
return _self;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* RepeatedField.[](index) => value
|
||||
*
|
||||
* Accesses the element at the given index. Returns nil on out-of-bounds
|
||||
*/
|
||||
static VALUE RepeatedField_index(int argc, VALUE* argv, VALUE _self) {
|
||||
RepeatedField* self = ruby_to_RepeatedField(_self);
|
||||
long size = upb_Array_Size(self->array);
|
||||
|
||||
VALUE arg = argv[0];
|
||||
long beg, len;
|
||||
|
||||
if (argc == 1) {
|
||||
if (FIXNUM_P(arg)) {
|
||||
/* standard case */
|
||||
upb_MessageValue msgval;
|
||||
int index = index_position(argv[0], self);
|
||||
if (index < 0 || (size_t)index >= upb_Array_Size(self->array)) {
|
||||
return Qnil;
|
||||
}
|
||||
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, size, 0)) {
|
||||
case Qfalse:
|
||||
break;
|
||||
case Qnil:
|
||||
return Qnil;
|
||||
default:
|
||||
return RepeatedField_subarray(self, beg, len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* assume 2 arguments */
|
||||
beg = NUM2LONG(argv[0]);
|
||||
len = NUM2LONG(argv[1]);
|
||||
if (beg < 0) {
|
||||
beg += size;
|
||||
}
|
||||
if (beg >= size) {
|
||||
return Qnil;
|
||||
}
|
||||
return RepeatedField_subarray(self, beg, len);
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* RepeatedField.[]=(index, value)
|
||||
*
|
||||
* Sets the element at the given index. On out-of-bounds assignments, extends
|
||||
* the array and fills the hole (if any) with default values.
|
||||
*/
|
||||
static VALUE RepeatedField_index_set(VALUE _self, VALUE _index, VALUE val) {
|
||||
RepeatedField* self = ruby_to_RepeatedField(_self);
|
||||
int size = upb_Array_Size(self->array);
|
||||
upb_Array* array = RepeatedField_GetMutable(_self);
|
||||
upb_Arena* arena = Arena_get(self->arena);
|
||||
upb_MessageValue 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 >= size) {
|
||||
upb_Array_Resize(array, index + 1, arena);
|
||||
upb_MessageValue 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);
|
||||
}
|
||||
}
|
||||
|
||||
upb_Array_Set(array, index, msgval);
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* RepeatedField.push(value, ...)
|
||||
*
|
||||
* Adds a new element to the repeated field.
|
||||
*/
|
||||
static VALUE RepeatedField_push_vararg(int argc, VALUE* argv, VALUE _self) {
|
||||
RepeatedField* self = ruby_to_RepeatedField(_self);
|
||||
upb_Arena* arena = Arena_get(self->arena);
|
||||
upb_Array* array = RepeatedField_GetMutable(_self);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < argc; i++) {
|
||||
upb_MessageValue msgval =
|
||||
Convert_RubyToUpb(argv[i], "", self->type_info, arena);
|
||||
upb_Array_Append(array, msgval, arena);
|
||||
}
|
||||
|
||||
return _self;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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_Arena* arena = Arena_get(self->arena);
|
||||
upb_Array* array = RepeatedField_GetMutable(_self);
|
||||
|
||||
upb_MessageValue msgval = Convert_RubyToUpb(val, "", self->type_info, arena);
|
||||
upb_Array_Append(array, msgval, arena);
|
||||
|
||||
return _self;
|
||||
}
|
||||
|
||||
/*
|
||||
* Private ruby method, used by RepeatedField.pop
|
||||
*/
|
||||
static VALUE RepeatedField_pop_one(VALUE _self) {
|
||||
RepeatedField* self = ruby_to_RepeatedField(_self);
|
||||
size_t size = upb_Array_Size(self->array);
|
||||
upb_Array* array = RepeatedField_GetMutable(_self);
|
||||
upb_MessageValue last;
|
||||
VALUE ret;
|
||||
|
||||
if (size == 0) {
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* RepeatedField.replace(list)
|
||||
*
|
||||
* Replaces the contents of the repeated field with the given list of elements.
|
||||
*/
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* RepeatedField.clear
|
||||
*
|
||||
* Clears (removes all elements from) this repeated field.
|
||||
*/
|
||||
static VALUE RepeatedField_clear(VALUE _self) {
|
||||
RepeatedField* self = ruby_to_RepeatedField(_self);
|
||||
upb_Array* array = RepeatedField_GetMutable(_self);
|
||||
upb_Array_Resize(array, 0, Arena_get(self->arena));
|
||||
return _self;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* RepeatedField.length
|
||||
*
|
||||
* Returns the length of this repeated field.
|
||||
*/
|
||||
static VALUE RepeatedField_length(VALUE _self) {
|
||||
RepeatedField* self = ruby_to_RepeatedField(_self);
|
||||
return INT2NUM(upb_Array_Size(self->array));
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* RepeatedField.dup => repeated_field
|
||||
*
|
||||
* Duplicates this repeated field with a shallow copy. References to all
|
||||
* non-primitive element objects (e.g., submessages) are shared.
|
||||
*/
|
||||
static VALUE RepeatedField_dup(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_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;
|
||||
|
||||
Arena_fuse(self->arena, arena);
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
upb_MessageValue msgval = upb_Array_Get(self->array, i);
|
||||
upb_Array_Append(new_array, msgval, arena);
|
||||
}
|
||||
|
||||
return new_rptfield;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* RepeatedField.to_ary => array
|
||||
*
|
||||
* Used when converted implicitly into array, e.g. compared to an Array.
|
||||
* Also called as a fallback of Object#to_a
|
||||
*/
|
||||
VALUE RepeatedField_to_ary(VALUE _self) {
|
||||
RepeatedField* self = ruby_to_RepeatedField(_self);
|
||||
int size = upb_Array_Size(self->array);
|
||||
VALUE ary = rb_ary_new2(size);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
upb_MessageValue msgval = upb_Array_Get(self->array, i);
|
||||
VALUE val = Convert_UpbToRuby(msgval, self->type_info, self->arena);
|
||||
rb_ary_push(ary, val);
|
||||
}
|
||||
|
||||
return ary;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* RepeatedField.==(other) => boolean
|
||||
*
|
||||
* Compares this repeated field to another. Repeated fields are equal if their
|
||||
* element types are equal, their lengths are equal, and each element is equal.
|
||||
* Elements are compared as per normal Ruby semantics, by calling their :==
|
||||
* methods (or performing a more efficient comparison for primitive types).
|
||||
*
|
||||
* Repeated fields with dissimilar element types are never equal, even if value
|
||||
* comparison (for example, between integers and floats) would have otherwise
|
||||
* indicated that every element has equal value.
|
||||
*/
|
||||
VALUE RepeatedField_eq(VALUE _self, VALUE _other) {
|
||||
RepeatedField* self;
|
||||
RepeatedField* other;
|
||||
|
||||
if (_self == _other) {
|
||||
return Qtrue;
|
||||
}
|
||||
|
||||
if (TYPE(_other) == T_ARRAY) {
|
||||
VALUE self_ary = RepeatedField_to_ary(_self);
|
||||
return rb_equal(self_ary, _other);
|
||||
}
|
||||
|
||||
self = ruby_to_RepeatedField(_self);
|
||||
other = ruby_to_RepeatedField(_other);
|
||||
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;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
upb_MessageValue val1 = upb_Array_Get(self->array, i);
|
||||
upb_MessageValue val2 = upb_Array_Get(other->array, i);
|
||||
if (!Msgval_IsEqual(val1, val2, self->type_info)) {
|
||||
return Qfalse;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
if (!RB_OBJ_FROZEN(_self)) {
|
||||
Arena_Pin(self->arena, _self);
|
||||
RB_OBJ_FREEZE(_self);
|
||||
}
|
||||
return _self;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* RepeatedField.hash => hash_value
|
||||
*
|
||||
* Returns a hash value computed from this repeated field's elements.
|
||||
*/
|
||||
VALUE RepeatedField_hash(VALUE _self) {
|
||||
RepeatedField* self = ruby_to_RepeatedField(_self);
|
||||
uint64_t hash = 0;
|
||||
size_t n = upb_Array_Size(self->array);
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
upb_MessageValue val = upb_Array_Get(self->array, i);
|
||||
hash = Msgval_GetHash(val, self->type_info, hash);
|
||||
}
|
||||
|
||||
return LL2NUM(hash);
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* RepeatedField.+(other) => repeated field
|
||||
*
|
||||
* Returns a new repeated field that contains the concatenated list of this
|
||||
* repeated field's elements and other's elements. The other (second) list may
|
||||
* be either another repeated field or a Ruby array.
|
||||
*/
|
||||
VALUE RepeatedField_plus(VALUE _self, VALUE list) {
|
||||
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);
|
||||
}
|
||||
} 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);
|
||||
Arena_fuse(list_rptfield->arena, arena);
|
||||
int size = upb_Array_Size(list_rptfield->array);
|
||||
int i;
|
||||
|
||||
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 < size; i++) {
|
||||
upb_MessageValue 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_;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* RepeatedField.concat(other) => self
|
||||
*
|
||||
* concats the passed in array to self. Returns a Ruby array.
|
||||
*/
|
||||
VALUE RepeatedField_concat(VALUE _self, VALUE list) {
|
||||
int i;
|
||||
|
||||
Check_Type(list, T_ARRAY);
|
||||
for (i = 0; i < RARRAY_LEN(list); i++) {
|
||||
RepeatedField_push(_self, rb_ary_entry(list, i));
|
||||
}
|
||||
return _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->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);
|
||||
|
||||
if (ary != Qnil) {
|
||||
if (!RB_TYPE_P(ary, T_ARRAY)) {
|
||||
rb_raise(rb_eArgError, "Expected array as initialize argument");
|
||||
}
|
||||
for (int i = 0; i < RARRAY_LEN(ary); i++) {
|
||||
RepeatedField_push(_self, rb_ary_entry(ary, i));
|
||||
}
|
||||
}
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
void RepeatedField_register(VALUE module) {
|
||||
VALUE klass = rb_define_class_under(module, "RepeatedField", rb_cObject);
|
||||
rb_define_alloc_func(klass, RepeatedField_alloc);
|
||||
rb_gc_register_address(&cRepeatedField);
|
||||
cRepeatedField = klass;
|
||||
|
||||
rb_define_method(klass, "initialize", RepeatedField_init, -1);
|
||||
rb_define_method(klass, "each", RepeatedField_each, 0);
|
||||
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, -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);
|
||||
rb_define_method(klass, "clear", RepeatedField_clear, 0);
|
||||
rb_define_method(klass, "length", RepeatedField_length, 0);
|
||||
rb_define_method(klass, "size", RepeatedField_length, 0);
|
||||
rb_define_method(klass, "dup", RepeatedField_dup, 0);
|
||||
// Also define #clone so that we don't inherit Object#clone.
|
||||
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);
|
||||
rb_include_module(klass, rb_mEnumerable);
|
||||
}
|
63
deps/protobuf/ruby/ext/google/protobuf_c/repeated_field.h
vendored
Normal file
63
deps/protobuf/ruby/ext/google/protobuf_c/repeated_field.h
vendored
Normal file
@ -0,0 +1,63 @@
|
||||
// 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 <ruby/ruby.h>
|
||||
|
||||
#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,
|
||||
upb_Arena* arena);
|
||||
|
||||
// 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_
|
11115
deps/protobuf/ruby/ext/google/protobuf_c/ruby-upb.c
vendored
Normal file
11115
deps/protobuf/ruby/ext/google/protobuf_c/ruby-upb.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
5612
deps/protobuf/ruby/ext/google/protobuf_c/ruby-upb.h
vendored
Normal file
5612
deps/protobuf/ruby/ext/google/protobuf_c/ruby-upb.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
52
deps/protobuf/ruby/ext/google/protobuf_c/wrap_memcpy.c
vendored
Normal file
52
deps/protobuf/ruby/ext/google/protobuf_c/wrap_memcpy.c
vendored
Normal file
@ -0,0 +1,52 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2017 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 <string.h>
|
||||
|
||||
// On x86-64 Linux with glibc, we link against the 2.2.5 version of memcpy so
|
||||
// that we avoid depending on the 2.14 version of the symbol. This way,
|
||||
// distributions that are using pre-2.14 versions of glibc can successfully use
|
||||
// the gem we distribute
|
||||
// (https://github.com/protocolbuffers/protobuf/issues/2783).
|
||||
//
|
||||
// This wrapper is enabled by passing the linker flags -Wl,-wrap,memcpy in
|
||||
// extconf.rb.
|
||||
#ifdef __linux__
|
||||
#if defined(__x86_64__) && defined(__GNU_LIBRARY__)
|
||||
__asm__(".symver memcpy,memcpy@GLIBC_2.2.5");
|
||||
void *__wrap_memcpy(void *dest, const void *src, size_t n) {
|
||||
return memcpy(dest, src, n);
|
||||
}
|
||||
#else
|
||||
void *__wrap_memcpy(void *dest, const void *src, size_t n) {
|
||||
return memmove(dest, src, n);
|
||||
}
|
||||
#endif
|
||||
#endif
|
27
deps/protobuf/ruby/google-protobuf.gemspec
vendored
Normal file
27
deps/protobuf/ruby/google-protobuf.gemspec
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
Gem::Specification.new do |s|
|
||||
s.name = "google-protobuf"
|
||||
s.version = "3.20.3"
|
||||
git_tag = "v#{s.version.to_s.sub('.rc.', '-rc')}" # Converts X.Y.Z.rc.N to vX.Y.Z-rcN, used for the git tag
|
||||
s.licenses = ["BSD-3-Clause"]
|
||||
s.summary = "Protocol Buffers"
|
||||
s.description = "Protocol Buffers are Google's data interchange format."
|
||||
s.homepage = "https://developers.google.com/protocol-buffers"
|
||||
s.authors = ["Protobuf Authors"]
|
||||
s.email = "protobuf@googlegroups.com"
|
||||
s.metadata = { "source_code_uri" => "https://github.com/protocolbuffers/protobuf/tree/#{git_tag}/ruby" }
|
||||
s.require_paths = ["lib"]
|
||||
s.files = Dir.glob('lib/**/*.rb')
|
||||
if RUBY_PLATFORM == "java"
|
||||
s.platform = "java"
|
||||
s.files += ["lib/google/protobuf_java.jar"]
|
||||
else
|
||||
s.files += Dir.glob('ext/**/*')
|
||||
s.extensions= ["ext/google/protobuf_c/extconf.rb"]
|
||||
s.add_development_dependency "rake-compiler-dock", "= 1.2.1" end
|
||||
s.test_files = ["tests/basic.rb",
|
||||
"tests/stress.rb",
|
||||
"tests/generated_code_test.rb"]
|
||||
s.required_ruby_version = '>= 2.3'
|
||||
s.add_development_dependency "rake-compiler", "~> 1.1.0"
|
||||
s.add_development_dependency "test-unit", '~> 3.0', '>= 3.0.9'
|
||||
end
|
79
deps/protobuf/ruby/lib/google/protobuf.rb
vendored
Normal file
79
deps/protobuf/ruby/lib/google/protobuf.rb
vendored
Normal file
@ -0,0 +1,79 @@
|
||||
# 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.
|
||||
|
||||
# require mixins before we hook them into the java & c code
|
||||
require 'google/protobuf/message_exts'
|
||||
|
||||
# We define these before requiring the platform-specific modules.
|
||||
# That way the module init can grab references to these.
|
||||
module Google
|
||||
module Protobuf
|
||||
class Error < StandardError; end
|
||||
class ParseError < Error; end
|
||||
class TypeError < ::TypeError; end
|
||||
end
|
||||
end
|
||||
|
||||
if RUBY_PLATFORM == "java"
|
||||
require 'json'
|
||||
require 'google/protobuf_java'
|
||||
else
|
||||
begin
|
||||
require "google/#{RUBY_VERSION.sub(/\.\d+$/, '')}/protobuf_c"
|
||||
rescue LoadError
|
||||
require 'google/protobuf_c'
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
require 'google/protobuf/descriptor_dsl'
|
||||
require 'google/protobuf/repeated_field'
|
||||
|
||||
module Google
|
||||
module Protobuf
|
||||
|
||||
def self.encode(msg, options = {})
|
||||
msg.to_proto(options)
|
||||
end
|
||||
|
||||
def self.encode_json(msg, options = {})
|
||||
msg.to_json(options)
|
||||
end
|
||||
|
||||
def self.decode(klass, proto, options = {})
|
||||
klass.decode(proto, options)
|
||||
end
|
||||
|
||||
def self.decode_json(klass, json, options = {})
|
||||
klass.decode_json(json, options)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
465
deps/protobuf/ruby/lib/google/protobuf/descriptor_dsl.rb
vendored
Normal file
465
deps/protobuf/ruby/lib/google/protobuf/descriptor_dsl.rb
vendored
Normal file
@ -0,0 +1,465 @@
|
||||
#!/usr/bin/ruby
|
||||
#
|
||||
# Code that implements the DSL for defining proto messages.
|
||||
|
||||
# Suppress warning: loading in progress, circular require considered harmful.
|
||||
# This circular require is intentional to avoid missing dependency.
|
||||
begin
|
||||
old_verbose, $VERBOSE = $VERBOSE, nil
|
||||
require 'google/protobuf/descriptor_pb'
|
||||
ensure
|
||||
$VERBOSE = old_verbose
|
||||
end
|
||||
|
||||
module Google
|
||||
module Protobuf
|
||||
module Internal
|
||||
class AtomicCounter
|
||||
def initialize
|
||||
@n = 0
|
||||
@mu = Mutex.new
|
||||
end
|
||||
|
||||
def get_and_increment
|
||||
n = @n
|
||||
@mu.synchronize {
|
||||
@n += 1
|
||||
}
|
||||
return n
|
||||
end
|
||||
end
|
||||
|
||||
class Builder
|
||||
@@file_number = AtomicCounter.new
|
||||
|
||||
def initialize(pool)
|
||||
@pool = pool
|
||||
@default_file = nil # Constructed lazily
|
||||
end
|
||||
|
||||
def add_file(name, options={}, &block)
|
||||
builder = FileBuilder.new(@pool, name, options)
|
||||
builder.instance_eval(&block)
|
||||
internal_add_file(builder)
|
||||
end
|
||||
|
||||
def add_message(name, &block)
|
||||
internal_default_file.add_message(name, &block)
|
||||
end
|
||||
|
||||
def add_enum(name, &block)
|
||||
internal_default_file.add_enum(name, &block)
|
||||
end
|
||||
|
||||
# ---- Internal methods, not part of the DSL ----
|
||||
|
||||
def build
|
||||
if @default_file
|
||||
internal_add_file(@default_file)
|
||||
end
|
||||
end
|
||||
|
||||
private def internal_add_file(file_builder)
|
||||
proto = file_builder.build
|
||||
serialized = Google::Protobuf::FileDescriptorProto.encode(proto)
|
||||
@pool.add_serialized_file(serialized)
|
||||
end
|
||||
|
||||
private def internal_default_file
|
||||
number = @@file_number.get_and_increment
|
||||
filename = "ruby_default_file#{number}.proto"
|
||||
@default_file ||= FileBuilder.new(@pool, filename)
|
||||
end
|
||||
end
|
||||
|
||||
class FileBuilder
|
||||
def initialize(pool, name, options={})
|
||||
@pool = pool
|
||||
@file_proto = Google::Protobuf::FileDescriptorProto.new(
|
||||
name: name,
|
||||
syntax: options.fetch(:syntax, "proto3")
|
||||
)
|
||||
end
|
||||
|
||||
def add_message(name, &block)
|
||||
builder = MessageBuilder.new(name, self, @file_proto)
|
||||
builder.instance_eval(&block)
|
||||
builder.internal_add_synthetic_oneofs
|
||||
end
|
||||
|
||||
def add_enum(name, &block)
|
||||
EnumBuilder.new(name, @file_proto).instance_eval(&block)
|
||||
end
|
||||
|
||||
# ---- Internal methods, not part of the DSL ----
|
||||
|
||||
# These methods fix up the file descriptor to account for differences
|
||||
# between the DSL and FileDescriptorProto.
|
||||
|
||||
# The DSL can omit a package name; here we infer what the package is if
|
||||
# was not specified.
|
||||
def infer_package(names)
|
||||
# Package is longest common prefix ending in '.', if any.
|
||||
if not names.empty?
|
||||
min, max = names.minmax
|
||||
last_common_dot = nil
|
||||
min.size.times { |i|
|
||||
if min[i] != max[i] then break end
|
||||
if min[i] == "." then last_common_dot = i end
|
||||
}
|
||||
if last_common_dot
|
||||
return min.slice(0, last_common_dot)
|
||||
end
|
||||
end
|
||||
|
||||
nil
|
||||
end
|
||||
|
||||
def rewrite_enum_default(field)
|
||||
if field.type != :TYPE_ENUM or !field.has_default_value? or !field.has_type_name?
|
||||
return
|
||||
end
|
||||
|
||||
value = field.default_value
|
||||
type_name = field.type_name
|
||||
|
||||
if value.empty? or value[0].ord < "0".ord or value[0].ord > "9".ord
|
||||
return
|
||||
end
|
||||
|
||||
if type_name.empty? || type_name[0] != "."
|
||||
return
|
||||
end
|
||||
|
||||
type_name = type_name[1..-1]
|
||||
as_int = Integer(value) rescue return
|
||||
|
||||
enum_desc = @pool.lookup(type_name)
|
||||
if enum_desc.is_a?(Google::Protobuf::EnumDescriptor)
|
||||
# Enum was defined in a previous file.
|
||||
name = enum_desc.lookup_value(as_int)
|
||||
if name
|
||||
# Update the default value in the proto.
|
||||
field.default_value = name
|
||||
end
|
||||
else
|
||||
# See if enum was defined in this file.
|
||||
@file_proto.enum_type.each { |enum_proto|
|
||||
if enum_proto.name == type_name
|
||||
enum_proto.value.each { |enum_value_proto|
|
||||
if enum_value_proto.number == as_int
|
||||
# Update the default value in the proto.
|
||||
field.default_value = enum_value_proto.name
|
||||
return
|
||||
end
|
||||
}
|
||||
# We found the right enum, but no value matched.
|
||||
return
|
||||
end
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
# Historically we allowed enum defaults to be specified as a number.
|
||||
# In retrospect this was a mistake as descriptors require defaults to
|
||||
# be specified as a label. This can make a difference if multiple
|
||||
# labels have the same number.
|
||||
#
|
||||
# Here we do a pass over all enum defaults and rewrite numeric defaults
|
||||
# by looking up their labels. This is complicated by the fact that the
|
||||
# enum definition can live in either the symtab or the file_proto.
|
||||
#
|
||||
# We take advantage of the fact that this is called *before* enums or
|
||||
# messages are nested in other messages, so we only have to iterate
|
||||
# one level deep.
|
||||
def rewrite_enum_defaults
|
||||
@file_proto.message_type.each { |msg|
|
||||
msg.field.each { |field|
|
||||
rewrite_enum_default(field)
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
# 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. */
|
||||
|
||||
def split_parent_name(msg_or_enum)
|
||||
name = msg_or_enum.name
|
||||
idx = name.rindex(?.)
|
||||
if idx
|
||||
return name[0...idx], name[idx+1..-1]
|
||||
else
|
||||
return nil, name
|
||||
end
|
||||
end
|
||||
|
||||
def get_parent_msg(msgs_by_name, name, parent_name)
|
||||
parent_msg = msgs_by_name[parent_name]
|
||||
if parent_msg.nil?
|
||||
raise "To define name #{name}, there must be a message named #{parent_name} to enclose it"
|
||||
end
|
||||
return parent_msg
|
||||
end
|
||||
|
||||
def fix_nesting
|
||||
# Calculate and update package.
|
||||
msgs_by_name = @file_proto.message_type.map { |msg| [msg.name, msg] }.to_h
|
||||
enum_names = @file_proto.enum_type.map { |enum_proto| enum_proto.name }
|
||||
|
||||
package = infer_package(msgs_by_name.keys + enum_names)
|
||||
if package
|
||||
@file_proto.package = package
|
||||
end
|
||||
|
||||
# Update nesting based on package.
|
||||
final_msgs = Google::Protobuf::RepeatedField.new(:message, Google::Protobuf::DescriptorProto)
|
||||
final_enums = Google::Protobuf::RepeatedField.new(:message, Google::Protobuf::EnumDescriptorProto)
|
||||
|
||||
# Note: We don't iterate over msgs_by_name.values because we want to
|
||||
# preserve order as listed in the DSL.
|
||||
@file_proto.message_type.each { |msg|
|
||||
parent_name, msg.name = split_parent_name(msg)
|
||||
if parent_name == package
|
||||
final_msgs << msg
|
||||
else
|
||||
get_parent_msg(msgs_by_name, msg.name, parent_name).nested_type << msg
|
||||
end
|
||||
}
|
||||
|
||||
@file_proto.enum_type.each { |enum|
|
||||
parent_name, enum.name = split_parent_name(enum)
|
||||
if parent_name == package
|
||||
final_enums << enum
|
||||
else
|
||||
get_parent_msg(msgs_by_name, enum.name, parent_name).enum_type << enum
|
||||
end
|
||||
}
|
||||
|
||||
@file_proto.message_type = final_msgs
|
||||
@file_proto.enum_type = final_enums
|
||||
end
|
||||
|
||||
def internal_file_proto
|
||||
@file_proto
|
||||
end
|
||||
|
||||
def build
|
||||
rewrite_enum_defaults
|
||||
fix_nesting
|
||||
return @file_proto
|
||||
end
|
||||
end
|
||||
|
||||
class MessageBuilder
|
||||
def initialize(name, file_builder, file_proto)
|
||||
@file_builder = file_builder
|
||||
@msg_proto = Google::Protobuf::DescriptorProto.new(
|
||||
:name => name
|
||||
)
|
||||
file_proto.message_type << @msg_proto
|
||||
end
|
||||
|
||||
def optional(name, type, number, type_class=nil, options=nil)
|
||||
internal_add_field(:LABEL_OPTIONAL, name, type, number, type_class, options)
|
||||
end
|
||||
|
||||
def proto3_optional(name, type, number, type_class=nil, options=nil)
|
||||
internal_add_field(:LABEL_OPTIONAL, name, type, number, type_class, options,
|
||||
proto3_optional: true)
|
||||
end
|
||||
|
||||
def required(name, type, number, type_class=nil, options=nil)
|
||||
internal_add_field(:LABEL_REQUIRED, name, type, number, type_class, options)
|
||||
end
|
||||
|
||||
def repeated(name, type, number, type_class = nil, options=nil)
|
||||
internal_add_field(:LABEL_REPEATED, name, type, number, type_class, options)
|
||||
end
|
||||
|
||||
def oneof(name, &block)
|
||||
OneofBuilder.new(name, self).instance_eval(&block)
|
||||
end
|
||||
|
||||
# Defines a new map field on this message type with the given key and
|
||||
# value types, tag number, and type class (for message and enum value
|
||||
# types). The key type must be :int32/:uint32/:int64/:uint64, :bool, or
|
||||
# :string. The value type type must be a Ruby symbol (as accepted by
|
||||
# FieldDescriptor#type=) and the type_class must be a string, if
|
||||
# present (as accepted by FieldDescriptor#submsg_name=).
|
||||
def map(name, key_type, value_type, number, value_type_class = nil)
|
||||
if key_type == :float or key_type == :double or key_type == :enum or
|
||||
key_type == :message
|
||||
raise ArgError, "Not an acceptable key type: " + key_type
|
||||
end
|
||||
entry_name = "#{@msg_proto.name}_MapEntry_#{name}"
|
||||
|
||||
@file_builder.add_message entry_name do
|
||||
optional :key, key_type, 1
|
||||
optional :value, value_type, 2, value_type_class
|
||||
end
|
||||
options = @file_builder.internal_file_proto.message_type.last.options ||= MessageOptions.new
|
||||
options.map_entry = true
|
||||
repeated name, :message, number, entry_name
|
||||
end
|
||||
|
||||
# ---- Internal methods, not part of the DSL ----
|
||||
|
||||
def internal_add_synthetic_oneofs
|
||||
# We have to build a set of all names, to ensure that synthetic oneofs
|
||||
# are not creating conflicts
|
||||
names = {}
|
||||
@msg_proto.field.each { |field| names[field.name] = true }
|
||||
@msg_proto.oneof_decl.each { |oneof| names[oneof.name] = true }
|
||||
|
||||
@msg_proto.field.each { |field|
|
||||
if field.proto3_optional
|
||||
# Prepend '_' until we are no longer conflicting.
|
||||
oneof_name = field.name
|
||||
while names[oneof_name]
|
||||
oneof_name = "_" + oneof_name
|
||||
end
|
||||
names[oneof_name] = true
|
||||
field.oneof_index = @msg_proto.oneof_decl.size
|
||||
@msg_proto.oneof_decl << Google::Protobuf::OneofDescriptorProto.new(
|
||||
name: oneof_name
|
||||
)
|
||||
end
|
||||
}
|
||||
end
|
||||
|
||||
def internal_add_field(label, name, type, number, type_class, options,
|
||||
oneof_index: nil, proto3_optional: false)
|
||||
# Allow passing either:
|
||||
# - (name, type, number, options) or
|
||||
# - (name, type, number, type_class, options)
|
||||
if options.nil? and type_class.instance_of?(Hash)
|
||||
options = type_class;
|
||||
type_class = nil;
|
||||
end
|
||||
|
||||
field_proto = Google::Protobuf::FieldDescriptorProto.new(
|
||||
:label => label,
|
||||
:name => name,
|
||||
:type => ("TYPE_" + type.to_s.upcase).to_sym,
|
||||
:number => number
|
||||
)
|
||||
|
||||
if type_class
|
||||
# Make it an absolute type name by prepending a dot.
|
||||
field_proto.type_name = "." + type_class
|
||||
end
|
||||
|
||||
if oneof_index
|
||||
field_proto.oneof_index = oneof_index
|
||||
end
|
||||
|
||||
if proto3_optional
|
||||
field_proto.proto3_optional = true
|
||||
end
|
||||
|
||||
if options
|
||||
if options.key?(:default)
|
||||
default = options[:default]
|
||||
if !default.instance_of?(String)
|
||||
# Call #to_s since all defaults are strings in the descriptor.
|
||||
default = default.to_s
|
||||
end
|
||||
# XXX: we should be C-escaping bytes defaults.
|
||||
field_proto.default_value = default.dup.force_encoding("UTF-8")
|
||||
end
|
||||
if options.key?(:json_name)
|
||||
field_proto.json_name = options[:json_name]
|
||||
end
|
||||
end
|
||||
|
||||
@msg_proto.field << field_proto
|
||||
end
|
||||
|
||||
def internal_msg_proto
|
||||
@msg_proto
|
||||
end
|
||||
end
|
||||
|
||||
class OneofBuilder
|
||||
def initialize(name, msg_builder)
|
||||
@msg_builder = msg_builder
|
||||
oneof_proto = Google::Protobuf::OneofDescriptorProto.new(
|
||||
:name => name
|
||||
)
|
||||
msg_proto = msg_builder.internal_msg_proto
|
||||
@oneof_index = msg_proto.oneof_decl.size
|
||||
msg_proto.oneof_decl << oneof_proto
|
||||
end
|
||||
|
||||
def optional(name, type, number, type_class=nil, options=nil)
|
||||
@msg_builder.internal_add_field(
|
||||
:LABEL_OPTIONAL, name, type, number, type_class, options,
|
||||
oneof_index: @oneof_index)
|
||||
end
|
||||
end
|
||||
|
||||
class EnumBuilder
|
||||
def initialize(name, file_proto)
|
||||
@enum_proto = Google::Protobuf::EnumDescriptorProto.new(
|
||||
:name => name
|
||||
)
|
||||
file_proto.enum_type << @enum_proto
|
||||
end
|
||||
|
||||
def value(name, number)
|
||||
enum_value_proto = Google::Protobuf::EnumValueDescriptorProto.new(
|
||||
name: name,
|
||||
number: number
|
||||
)
|
||||
@enum_proto.value << enum_value_proto
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# Re-open the class (the rest of the class is implemented in C)
|
||||
class DescriptorPool
|
||||
def build(&block)
|
||||
builder = Internal::Builder.new(self)
|
||||
builder.instance_eval(&block)
|
||||
builder.build
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
53
deps/protobuf/ruby/lib/google/protobuf/message_exts.rb
vendored
Normal file
53
deps/protobuf/ruby/lib/google/protobuf/message_exts.rb
vendored
Normal file
@ -0,0 +1,53 @@
|
||||
# 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.
|
||||
|
||||
module Google
|
||||
module Protobuf
|
||||
module MessageExts
|
||||
|
||||
#this is only called in jruby; mri loades the ClassMethods differently
|
||||
def self.included(klass)
|
||||
klass.extend(ClassMethods)
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
end
|
||||
|
||||
def to_json(options = {})
|
||||
self.class.encode_json(self, options)
|
||||
end
|
||||
|
||||
def to_proto(options = {})
|
||||
self.class.encode(self, options)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
188
deps/protobuf/ruby/lib/google/protobuf/repeated_field.rb
vendored
Normal file
188
deps/protobuf/ruby/lib/google/protobuf/repeated_field.rb
vendored
Normal file
@ -0,0 +1,188 @@
|
||||
# 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.
|
||||
|
||||
require 'forwardable'
|
||||
|
||||
#
|
||||
# This class makes RepeatedField act (almost-) like a Ruby Array.
|
||||
# It has convenience methods that extend the core C or Java based
|
||||
# methods.
|
||||
#
|
||||
# This is a best-effort to mirror Array behavior. Two comments:
|
||||
# 1) patches always welcome :)
|
||||
# 2) if performance is an issue, feel free to rewrite the method
|
||||
# in jruby and C. The source code has plenty of examples
|
||||
#
|
||||
# KNOWN ISSUES
|
||||
# - #[]= doesn't allow less used approaches such as `arr[1, 2] = 'fizz'`
|
||||
# - #concat should return the orig array
|
||||
# - #push should accept multiple arguments and push them all at the same time
|
||||
#
|
||||
module Google
|
||||
module Protobuf
|
||||
class RepeatedField
|
||||
extend Forwardable
|
||||
|
||||
# methods defined in C or Java:
|
||||
# +
|
||||
# [], at
|
||||
# []=
|
||||
# concat
|
||||
# clear
|
||||
# dup, clone
|
||||
# each
|
||||
# push, <<
|
||||
# replace
|
||||
# length, size
|
||||
# ==
|
||||
# to_ary, to_a
|
||||
# also all enumerable
|
||||
#
|
||||
# NOTE: using delegators rather than method_missing to make the
|
||||
# relationship explicit instead of implicit
|
||||
def_delegators :to_ary,
|
||||
:&, :*, :-, :'<=>',
|
||||
:assoc, :bsearch, :bsearch_index, :combination, :compact, :count,
|
||||
:cycle, :dig, :drop, :drop_while, :eql?, :fetch, :find_index, :flatten,
|
||||
:include?, :index, :inspect, :join,
|
||||
:pack, :permutation, :product, :pretty_print, :pretty_print_cycle,
|
||||
:rassoc, :repeated_combination, :repeated_permutation, :reverse,
|
||||
:rindex, :rotate, :sample, :shuffle, :shelljoin,
|
||||
:to_s, :transpose, :uniq, :|
|
||||
|
||||
|
||||
def first(n=nil)
|
||||
n ? self[0...n] : self[0]
|
||||
end
|
||||
|
||||
|
||||
def last(n=nil)
|
||||
n ? self[(self.size-n-1)..-1] : self[-1]
|
||||
end
|
||||
|
||||
|
||||
def pop(n=nil)
|
||||
if n
|
||||
results = []
|
||||
n.times{ results << pop_one }
|
||||
return results
|
||||
else
|
||||
return pop_one
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def empty?
|
||||
self.size == 0
|
||||
end
|
||||
|
||||
# array aliases into enumerable
|
||||
alias_method :each_index, :each_with_index
|
||||
alias_method :slice, :[]
|
||||
alias_method :values_at, :select
|
||||
alias_method :map, :collect
|
||||
|
||||
|
||||
class << self
|
||||
def define_array_wrapper_method(method_name)
|
||||
define_method(method_name) do |*args, &block|
|
||||
arr = self.to_a
|
||||
result = arr.send(method_name, *args)
|
||||
self.replace(arr)
|
||||
return result if result
|
||||
return block ? block.call : result
|
||||
end
|
||||
end
|
||||
private :define_array_wrapper_method
|
||||
|
||||
|
||||
def define_array_wrapper_with_result_method(method_name)
|
||||
define_method(method_name) do |*args, &block|
|
||||
# result can be an Enumerator, Array, or nil
|
||||
# Enumerator can sometimes be returned if a block is an optional argument and it is not passed in
|
||||
# nil usually specifies that no change was made
|
||||
result = self.to_a.send(method_name, *args, &block)
|
||||
if result
|
||||
new_arr = result.to_a
|
||||
self.replace(new_arr)
|
||||
if result.is_a?(Enumerator)
|
||||
# generate a fresh enum; rewinding the exiting one, in Ruby 2.2, will
|
||||
# reset the enum with the same length, but all the #next calls will
|
||||
# return nil
|
||||
result = new_arr.to_enum
|
||||
# generate a wrapper enum so any changes which occur by a chained
|
||||
# enum can be captured
|
||||
ie = ProxyingEnumerator.new(self, result)
|
||||
result = ie.to_enum
|
||||
end
|
||||
end
|
||||
result
|
||||
end
|
||||
end
|
||||
private :define_array_wrapper_with_result_method
|
||||
end
|
||||
|
||||
|
||||
%w(delete delete_at shift slice! unshift).each do |method_name|
|
||||
define_array_wrapper_method(method_name)
|
||||
end
|
||||
|
||||
|
||||
%w(collect! compact! delete_if fill flatten! insert reverse!
|
||||
rotate! select! shuffle! sort! sort_by! uniq!).each do |method_name|
|
||||
define_array_wrapper_with_result_method(method_name)
|
||||
end
|
||||
alias_method :keep_if, :select!
|
||||
alias_method :map!, :collect!
|
||||
alias_method :reject!, :delete_if
|
||||
|
||||
|
||||
# propagates changes made by user of enumerator back to the original repeated field.
|
||||
# This only applies in cases where the calling function which created the enumerator,
|
||||
# such as #sort!, modifies itself rather than a new array, such as #sort
|
||||
class ProxyingEnumerator < Struct.new(:repeated_field, :external_enumerator)
|
||||
def each(*args, &block)
|
||||
results = []
|
||||
external_enumerator.each_with_index do |val, i|
|
||||
result = yield(val)
|
||||
results << result
|
||||
#nil means no change occurred from yield; usually occurs when #to_a is called
|
||||
if result
|
||||
repeated_field[i] = result if result != val
|
||||
end
|
||||
end
|
||||
results
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
end
|
||||
end
|
240
deps/protobuf/ruby/lib/google/protobuf/well_known_types.rb
vendored
Normal file
240
deps/protobuf/ruby/lib/google/protobuf/well_known_types.rb
vendored
Normal file
@ -0,0 +1,240 @@
|
||||
#!/usr/bin/ruby
|
||||
# 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.
|
||||
|
||||
require 'google/protobuf/any_pb'
|
||||
require 'google/protobuf/duration_pb'
|
||||
require 'google/protobuf/field_mask_pb'
|
||||
require 'google/protobuf/struct_pb'
|
||||
require 'google/protobuf/timestamp_pb'
|
||||
|
||||
module Google
|
||||
module Protobuf
|
||||
|
||||
Any.class_eval do
|
||||
def self.pack(msg, type_url_prefix='type.googleapis.com/')
|
||||
any = self.new
|
||||
any.pack(msg, type_url_prefix)
|
||||
any
|
||||
end
|
||||
|
||||
def pack(msg, type_url_prefix='type.googleapis.com/')
|
||||
if type_url_prefix.empty? or type_url_prefix[-1] != '/' then
|
||||
self.type_url = "#{type_url_prefix}/#{msg.class.descriptor.name}"
|
||||
else
|
||||
self.type_url = "#{type_url_prefix}#{msg.class.descriptor.name}"
|
||||
end
|
||||
self.value = msg.to_proto
|
||||
end
|
||||
|
||||
def unpack(klass)
|
||||
if self.is(klass) then
|
||||
klass.decode(self.value)
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
def type_name
|
||||
return self.type_url.split("/")[-1]
|
||||
end
|
||||
|
||||
def is(klass)
|
||||
return self.type_name == klass.descriptor.name
|
||||
end
|
||||
end
|
||||
|
||||
Timestamp.class_eval do
|
||||
if RUBY_VERSION < "2.5"
|
||||
def to_time
|
||||
Time.at(self.to_f)
|
||||
end
|
||||
else
|
||||
def to_time
|
||||
Time.at(seconds, nanos, :nanosecond)
|
||||
end
|
||||
end
|
||||
|
||||
def self.from_time(time)
|
||||
new.from_time(time)
|
||||
end
|
||||
|
||||
def from_time(time)
|
||||
self.seconds = time.to_i
|
||||
self.nanos = time.nsec
|
||||
self
|
||||
end
|
||||
|
||||
def to_i
|
||||
self.seconds
|
||||
end
|
||||
|
||||
def to_f
|
||||
self.seconds + (self.nanos.quo(1_000_000_000))
|
||||
end
|
||||
end
|
||||
|
||||
Duration.class_eval do
|
||||
def to_f
|
||||
self.seconds + (self.nanos.to_f / 1_000_000_000)
|
||||
end
|
||||
end
|
||||
|
||||
class UnexpectedStructType < Google::Protobuf::Error; end
|
||||
|
||||
Value.class_eval do
|
||||
def to_ruby(recursive = false)
|
||||
case self.kind
|
||||
when :struct_value
|
||||
if recursive
|
||||
self.struct_value.to_h
|
||||
else
|
||||
self.struct_value
|
||||
end
|
||||
when :list_value
|
||||
if recursive
|
||||
self.list_value.to_a
|
||||
else
|
||||
self.list_value
|
||||
end
|
||||
when :null_value
|
||||
nil
|
||||
when :number_value
|
||||
self.number_value
|
||||
when :string_value
|
||||
self.string_value
|
||||
when :bool_value
|
||||
self.bool_value
|
||||
else
|
||||
raise UnexpectedStructType
|
||||
end
|
||||
end
|
||||
|
||||
def self.from_ruby(value)
|
||||
self.new.from_ruby(value)
|
||||
end
|
||||
|
||||
def from_ruby(value)
|
||||
case value
|
||||
when NilClass
|
||||
self.null_value = :NULL_VALUE
|
||||
when Numeric
|
||||
self.number_value = value
|
||||
when String
|
||||
self.string_value = value
|
||||
when TrueClass
|
||||
self.bool_value = true
|
||||
when FalseClass
|
||||
self.bool_value = false
|
||||
when Struct
|
||||
self.struct_value = value
|
||||
when Hash
|
||||
self.struct_value = Struct.from_hash(value)
|
||||
when ListValue
|
||||
self.list_value = value
|
||||
when Array
|
||||
self.list_value = ListValue.from_a(value)
|
||||
else
|
||||
raise UnexpectedStructType
|
||||
end
|
||||
|
||||
self
|
||||
end
|
||||
end
|
||||
|
||||
Struct.class_eval do
|
||||
def [](key)
|
||||
self.fields[key].to_ruby
|
||||
rescue NoMethodError
|
||||
nil
|
||||
end
|
||||
|
||||
def []=(key, value)
|
||||
unless key.is_a?(String)
|
||||
raise UnexpectedStructType, "Struct keys must be strings."
|
||||
end
|
||||
self.fields[key] ||= Google::Protobuf::Value.new
|
||||
self.fields[key].from_ruby(value)
|
||||
end
|
||||
|
||||
def to_h
|
||||
ret = {}
|
||||
self.fields.each { |key, val| ret[key] = val.to_ruby(true) }
|
||||
ret
|
||||
end
|
||||
|
||||
def self.from_hash(hash)
|
||||
ret = Struct.new
|
||||
hash.each { |key, val| ret[key] = val }
|
||||
ret
|
||||
end
|
||||
|
||||
def has_key?(key)
|
||||
self.fields.has_key?(key)
|
||||
end
|
||||
end
|
||||
|
||||
ListValue.class_eval do
|
||||
include Enumerable
|
||||
|
||||
def length
|
||||
self.values.length
|
||||
end
|
||||
|
||||
def [](index)
|
||||
self.values[index].to_ruby
|
||||
end
|
||||
|
||||
def []=(index, value)
|
||||
self.values[index].from_ruby(value)
|
||||
end
|
||||
|
||||
def <<(value)
|
||||
wrapper = Google::Protobuf::Value.new
|
||||
wrapper.from_ruby(value)
|
||||
self.values << wrapper
|
||||
end
|
||||
|
||||
def each
|
||||
self.values.each { |x| yield(x.to_ruby) }
|
||||
end
|
||||
|
||||
def to_a
|
||||
self.values.map { |x| x.to_ruby(true) }
|
||||
end
|
||||
|
||||
def self.from_a(arr)
|
||||
ret = ListValue.new
|
||||
arr.each { |val| ret << val }
|
||||
ret
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
88
deps/protobuf/ruby/pom.xml
vendored
Normal file
88
deps/protobuf/ruby/pom.xml
vendored
Normal file
@ -0,0 +1,88 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.google</groupId>
|
||||
<artifactId>google</artifactId>
|
||||
<version>1</version>
|
||||
</parent>
|
||||
|
||||
<groupId>com.google.protobuf.jruby</groupId>
|
||||
<artifactId>protobuf-jruby</artifactId>
|
||||
<version>3.20.3</version>
|
||||
<name>Protocol Buffer JRuby native extension</name>
|
||||
<description>
|
||||
Protocol Buffers are a way of encoding structured data in an efficient yet
|
||||
extensible format.
|
||||
</description>
|
||||
<inceptionYear>2014</inceptionYear>
|
||||
<url>https://developers.google.com/protocol-buffers/</url>
|
||||
<licenses>
|
||||
<license>
|
||||
<name>BSD-3-Clause</name>
|
||||
<url>https://opensource.org/licenses/BSD-3-Clause</url>
|
||||
<distribution>repo</distribution>
|
||||
</license>
|
||||
</licenses>
|
||||
<scm>
|
||||
<url>https://github.com/protocolbuffers/protobuf</url>
|
||||
<connection>
|
||||
scm:git:https://github.com/protocolbuffers/protobuf.git
|
||||
</connection>
|
||||
</scm>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<ruby.sources>lib/google</ruby.sources>
|
||||
<jar.finalName>protobuf_java</jar.finalName>
|
||||
</properties>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<version>3.3.0</version>
|
||||
<configuration>
|
||||
<finalName>${jar.finalName}</finalName>
|
||||
<outputDirectory>${ruby.sources}</outputDirectory>
|
||||
<appendAssemblyId>false</appendAssemblyId>
|
||||
<descriptorRefs>
|
||||
<descriptorRef>jar-with-dependencies</descriptorRef>
|
||||
</descriptorRefs>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>make-assembly</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>single</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.8.1</version>
|
||||
<configuration>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<dependencies>
|
||||
<!-- Ordering of dependencies matters to update_version.py -->
|
||||
<dependency>
|
||||
<groupId>com.google.protobuf</groupId>
|
||||
<artifactId>protobuf-java-util</artifactId>
|
||||
<version>3.20.3</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jruby</groupId>
|
||||
<artifactId>jruby-complete</artifactId>
|
||||
<version>9.2.20.1</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
225
deps/protobuf/ruby/src/main/java/com/google/protobuf/jruby/RubyDescriptor.java
vendored
Normal file
225
deps/protobuf/ruby/src/main/java/com/google/protobuf/jruby/RubyDescriptor.java
vendored
Normal file
@ -0,0 +1,225 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.google.protobuf.jruby;
|
||||
|
||||
import com.google.protobuf.Descriptors.Descriptor;
|
||||
import com.google.protobuf.Descriptors.FieldDescriptor;
|
||||
import com.google.protobuf.Descriptors.OneofDescriptor;
|
||||
import org.jruby.*;
|
||||
import org.jruby.anno.JRubyClass;
|
||||
import org.jruby.anno.JRubyMethod;
|
||||
import org.jruby.runtime.Block;
|
||||
import org.jruby.runtime.Helpers;
|
||||
import org.jruby.runtime.ObjectAllocator;
|
||||
import org.jruby.runtime.ThreadContext;
|
||||
import org.jruby.runtime.builtin.IRubyObject;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
@JRubyClass(name = "Descriptor", include = "Enumerable")
|
||||
public class RubyDescriptor extends RubyObject {
|
||||
public static void createRubyDescriptor(Ruby runtime) {
|
||||
RubyModule protobuf = runtime.getClassFromPath("Google::Protobuf");
|
||||
RubyClass cDescriptor = protobuf.defineClassUnder("Descriptor", runtime.getObject(), new ObjectAllocator() {
|
||||
@Override
|
||||
public IRubyObject allocate(Ruby runtime, RubyClass klazz) {
|
||||
return new RubyDescriptor(runtime, klazz);
|
||||
}
|
||||
});
|
||||
cDescriptor.includeModule(runtime.getEnumerable());
|
||||
cDescriptor.defineAnnotatedMethods(RubyDescriptor.class);
|
||||
cFieldDescriptor = (RubyClass) runtime.getClassFromPath("Google::Protobuf::FieldDescriptor");
|
||||
cOneofDescriptor = (RubyClass) runtime.getClassFromPath("Google::Protobuf::OneofDescriptor");
|
||||
}
|
||||
|
||||
public RubyDescriptor(Ruby runtime, RubyClass klazz) {
|
||||
super(runtime, klazz);
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Descriptor.name => name
|
||||
*
|
||||
* Returns the name of this message type as a fully-qualified string (e.g.,
|
||||
* My.Package.MessageType).
|
||||
*/
|
||||
@JRubyMethod(name = "name")
|
||||
public IRubyObject getName(ThreadContext context) {
|
||||
return name;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Descriptor.lookup(name) => FieldDescriptor
|
||||
*
|
||||
* Returns the field descriptor for the field with the given name, if present,
|
||||
* or nil if none.
|
||||
*/
|
||||
@JRubyMethod
|
||||
public IRubyObject lookup(ThreadContext context, IRubyObject fieldName) {
|
||||
return Helpers.nullToNil(fieldDescriptors.get(fieldName), context.nil);
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Descriptor.msgclass => message_klass
|
||||
*
|
||||
* Returns the Ruby class created for this message type. Valid only once the
|
||||
* message type has been added to a pool.
|
||||
*/
|
||||
@JRubyMethod
|
||||
public IRubyObject msgclass(ThreadContext context) {
|
||||
return klazz;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Descriptor.each(&block)
|
||||
*
|
||||
* Iterates over fields in this message type, yielding to the block on each one.
|
||||
*/
|
||||
@JRubyMethod
|
||||
public IRubyObject each(ThreadContext context, Block block) {
|
||||
for (Map.Entry<IRubyObject, RubyFieldDescriptor> entry : fieldDescriptors.entrySet()) {
|
||||
block.yield(context, entry.getValue());
|
||||
}
|
||||
return context.nil;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Descriptor.file_descriptor
|
||||
*
|
||||
* Returns the FileDescriptor object this message belongs to.
|
||||
*/
|
||||
@JRubyMethod(name = "file_descriptor")
|
||||
public IRubyObject getFileDescriptor(ThreadContext context) {
|
||||
return RubyFileDescriptor.getRubyFileDescriptor(context, descriptor);
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Descriptor.each_oneof(&block) => nil
|
||||
*
|
||||
* Invokes the given block for each oneof in this message type, passing the
|
||||
* corresponding OneofDescriptor.
|
||||
*/
|
||||
@JRubyMethod(name = "each_oneof")
|
||||
public IRubyObject eachOneof(ThreadContext context, Block block) {
|
||||
for (RubyOneofDescriptor oneofDescriptor : oneofDescriptors.values()) {
|
||||
block.yieldSpecific(context, oneofDescriptor);
|
||||
}
|
||||
return context.nil;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Descriptor.lookup_oneof(name) => OneofDescriptor
|
||||
*
|
||||
* Returns the oneof descriptor for the oneof with the given name, if present,
|
||||
* or nil if none.
|
||||
*/
|
||||
@JRubyMethod(name = "lookup_oneof")
|
||||
public IRubyObject lookupOneof(ThreadContext context, IRubyObject name) {
|
||||
return Helpers.nullToNil(oneofDescriptors.get(Utils.symToString(name)), context.nil);
|
||||
}
|
||||
|
||||
protected FieldDescriptor getField(String name) {
|
||||
return descriptor.findFieldByName(name);
|
||||
}
|
||||
|
||||
protected void setDescriptor(ThreadContext context, Descriptor descriptor, RubyDescriptorPool pool) {
|
||||
Ruby runtime = context.runtime;
|
||||
Map<FieldDescriptor, RubyFieldDescriptor> cache = new HashMap();
|
||||
this.descriptor = descriptor;
|
||||
|
||||
// Populate the field caches
|
||||
fieldDescriptors = new HashMap<IRubyObject, RubyFieldDescriptor>();
|
||||
oneofDescriptors = new HashMap<IRubyObject, RubyOneofDescriptor>();
|
||||
|
||||
for (FieldDescriptor fieldDescriptor : descriptor.getFields()) {
|
||||
RubyFieldDescriptor fd = (RubyFieldDescriptor) cFieldDescriptor.newInstance(context, Block.NULL_BLOCK);
|
||||
fd.setDescriptor(context, fieldDescriptor, pool);
|
||||
fieldDescriptors.put(runtime.newString(fieldDescriptor.getName()), fd);
|
||||
cache.put(fieldDescriptor, fd);
|
||||
}
|
||||
|
||||
for (OneofDescriptor oneofDescriptor : descriptor.getRealOneofs()) {
|
||||
RubyOneofDescriptor ood = (RubyOneofDescriptor) cOneofDescriptor.newInstance(context, Block.NULL_BLOCK);
|
||||
ood.setDescriptor(context, oneofDescriptor, cache);
|
||||
oneofDescriptors.put(runtime.newString(oneofDescriptor.getName()), ood);
|
||||
}
|
||||
|
||||
// Make sure our class is built
|
||||
this.klazz = buildClassFromDescriptor(context);
|
||||
}
|
||||
|
||||
protected void setName(IRubyObject name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
private RubyClass buildClassFromDescriptor(ThreadContext context) {
|
||||
Ruby runtime = context.runtime;
|
||||
|
||||
ObjectAllocator allocator = new ObjectAllocator() {
|
||||
@Override
|
||||
public IRubyObject allocate(Ruby runtime, RubyClass klazz) {
|
||||
return new RubyMessage(runtime, klazz, descriptor);
|
||||
}
|
||||
};
|
||||
|
||||
// rb_define_class_id
|
||||
RubyClass klass = RubyClass.newClass(runtime, runtime.getObject());
|
||||
klass.setAllocator(allocator);
|
||||
klass.makeMetaClass(runtime.getObject().getMetaClass());
|
||||
klass.inherit(runtime.getObject());
|
||||
RubyModule messageExts = runtime.getClassFromPath("Google::Protobuf::MessageExts");
|
||||
klass.include(new IRubyObject[] {messageExts});
|
||||
klass.instance_variable_set(runtime.newString(Utils.DESCRIPTOR_INSTANCE_VAR), this);
|
||||
klass.defineAnnotatedMethods(RubyMessage.class);
|
||||
// Workaround for https://github.com/jruby/jruby/issues/7154
|
||||
klass.searchMethod("respond_to?").setIsBuiltin(false);
|
||||
return klass;
|
||||
}
|
||||
|
||||
private static RubyClass cFieldDescriptor;
|
||||
private static RubyClass cOneofDescriptor;
|
||||
|
||||
private Descriptor descriptor;
|
||||
private IRubyObject name;
|
||||
private Map<IRubyObject, RubyFieldDescriptor> fieldDescriptors;
|
||||
private Map<IRubyObject, RubyOneofDescriptor> oneofDescriptors;
|
||||
private RubyClass klazz;
|
||||
}
|
180
deps/protobuf/ruby/src/main/java/com/google/protobuf/jruby/RubyDescriptorPool.java
vendored
Normal file
180
deps/protobuf/ruby/src/main/java/com/google/protobuf/jruby/RubyDescriptorPool.java
vendored
Normal file
@ -0,0 +1,180 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.google.protobuf.jruby;
|
||||
|
||||
import com.google.protobuf.DescriptorProtos.FileDescriptorProto;
|
||||
import com.google.protobuf.Descriptors.Descriptor;
|
||||
import com.google.protobuf.Descriptors.DescriptorValidationException;
|
||||
import com.google.protobuf.Descriptors.EnumDescriptor;
|
||||
import com.google.protobuf.Descriptors.FileDescriptor;
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
import org.jruby.*;
|
||||
import org.jruby.anno.JRubyClass;
|
||||
import org.jruby.anno.JRubyMethod;
|
||||
import org.jruby.exceptions.RaiseException;
|
||||
import org.jruby.runtime.*;
|
||||
import org.jruby.runtime.builtin.IRubyObject;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@JRubyClass(name = "DescriptorPool")
|
||||
public class RubyDescriptorPool extends RubyObject {
|
||||
public static void createRubyDescriptorPool(Ruby runtime) {
|
||||
RubyModule protobuf = runtime.getClassFromPath("Google::Protobuf");
|
||||
RubyClass cDescriptorPool = protobuf.defineClassUnder("DescriptorPool", runtime.getObject(), new ObjectAllocator() {
|
||||
@Override
|
||||
public IRubyObject allocate(Ruby runtime, RubyClass klazz) {
|
||||
return new RubyDescriptorPool(runtime, klazz);
|
||||
}
|
||||
});
|
||||
|
||||
cDescriptorPool.defineAnnotatedMethods(RubyDescriptorPool.class);
|
||||
descriptorPool = (RubyDescriptorPool) cDescriptorPool.newInstance(runtime.getCurrentContext(), Block.NULL_BLOCK);
|
||||
cDescriptor = (RubyClass) runtime.getClassFromPath("Google::Protobuf::Descriptor");
|
||||
cEnumDescriptor = (RubyClass) runtime.getClassFromPath("Google::Protobuf::EnumDescriptor");
|
||||
}
|
||||
|
||||
public RubyDescriptorPool(Ruby runtime, RubyClass klazz) {
|
||||
super(runtime, klazz);
|
||||
this.fileDescriptors = new ArrayList<>();
|
||||
this.symtab = new HashMap<IRubyObject, IRubyObject>();
|
||||
}
|
||||
|
||||
@JRubyMethod
|
||||
public IRubyObject build(ThreadContext context, Block block) {
|
||||
RubyClass cBuilder = (RubyClass) context.runtime.getClassFromPath("Google::Protobuf::Internal::Builder");
|
||||
RubyBasicObject ctx = (RubyBasicObject) cBuilder.newInstance(context, this, Block.NULL_BLOCK);
|
||||
ctx.instance_eval(context, block);
|
||||
ctx.callMethod(context, "build"); // Needs to be called to support the deprecated syntax
|
||||
return context.nil;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* DescriptorPool.lookup(name) => descriptor
|
||||
*
|
||||
* Finds a Descriptor or EnumDescriptor by name and returns it, or nil if none
|
||||
* exists with the given name.
|
||||
*
|
||||
* This currently lazy loads the ruby descriptor objects as they are requested.
|
||||
* This allows us to leave the heavy lifting to the java library
|
||||
*/
|
||||
@JRubyMethod
|
||||
public IRubyObject lookup(ThreadContext context, IRubyObject name) {
|
||||
return Helpers.nullToNil(symtab.get(name), context.nil);
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* DescriptorPool.generated_pool => descriptor_pool
|
||||
*
|
||||
* Class method that returns the global DescriptorPool. This is a singleton into
|
||||
* which generated-code message and enum types are registered. The user may also
|
||||
* register types in this pool for convenience so that they do not have to hold
|
||||
* a reference to a private pool instance.
|
||||
*/
|
||||
@JRubyMethod(meta = true, name = "generated_pool")
|
||||
public static IRubyObject generatedPool(ThreadContext context, IRubyObject recv) {
|
||||
return descriptorPool;
|
||||
}
|
||||
|
||||
@JRubyMethod(required = 1)
|
||||
public IRubyObject add_serialized_file (ThreadContext context, IRubyObject data ) {
|
||||
byte[] bin = data.convertToString().getBytes();
|
||||
try {
|
||||
FileDescriptorProto.Builder builder = FileDescriptorProto.newBuilder().mergeFrom(bin);
|
||||
registerFileDescriptor(context, builder);
|
||||
} catch (InvalidProtocolBufferException e) {
|
||||
throw RaiseException.from(context.runtime, (RubyClass) context.runtime.getClassFromPath("Google::Protobuf::ParseError"), e.getMessage());
|
||||
}
|
||||
return context.nil;
|
||||
}
|
||||
|
||||
protected void registerFileDescriptor(ThreadContext context, FileDescriptorProto.Builder builder) {
|
||||
final FileDescriptor fd;
|
||||
try {
|
||||
fd = FileDescriptor.buildFrom(builder.build(), existingFileDescriptors());
|
||||
} catch (DescriptorValidationException e) {
|
||||
throw context.runtime.newRuntimeError(e.getMessage());
|
||||
}
|
||||
|
||||
String packageName = fd.getPackage();
|
||||
if (!packageName.isEmpty()) {
|
||||
packageName = packageName + ".";
|
||||
}
|
||||
|
||||
// Need to make sure enums are registered first in case anything references them
|
||||
for (EnumDescriptor ed : fd.getEnumTypes()) registerEnumDescriptor(context, ed, packageName);
|
||||
for (Descriptor message : fd.getMessageTypes()) registerDescriptor(context, message, packageName);
|
||||
|
||||
// Mark this as a loaded file
|
||||
fileDescriptors.add(fd);
|
||||
}
|
||||
|
||||
private void registerDescriptor(ThreadContext context, Descriptor descriptor, String parentPath) {
|
||||
String fullName = parentPath + descriptor.getName();
|
||||
String fullPath = fullName + ".";
|
||||
RubyString name = context.runtime.newString(fullName);
|
||||
|
||||
RubyDescriptor des = (RubyDescriptor) cDescriptor.newInstance(context, Block.NULL_BLOCK);
|
||||
des.setName(name);
|
||||
des.setDescriptor(context, descriptor, this);
|
||||
symtab.put(name, des);
|
||||
|
||||
// Need to make sure enums are registered first in case anything references them
|
||||
for (EnumDescriptor ed : descriptor.getEnumTypes()) registerEnumDescriptor(context, ed, fullPath);
|
||||
for (Descriptor message : descriptor.getNestedTypes()) registerDescriptor(context, message, fullPath);
|
||||
}
|
||||
|
||||
private void registerEnumDescriptor(ThreadContext context, EnumDescriptor descriptor, String parentPath) {
|
||||
RubyString name = context.runtime.newString(parentPath + descriptor.getName());
|
||||
RubyEnumDescriptor des = (RubyEnumDescriptor) cEnumDescriptor.newInstance(context, Block.NULL_BLOCK);
|
||||
des.setName(name);
|
||||
des.setDescriptor(context, descriptor);
|
||||
symtab.put(name, des);
|
||||
}
|
||||
|
||||
private FileDescriptor[] existingFileDescriptors() {
|
||||
return fileDescriptors.toArray(new FileDescriptor[fileDescriptors.size()]);
|
||||
}
|
||||
|
||||
private static RubyClass cDescriptor;
|
||||
private static RubyClass cEnumDescriptor;
|
||||
private static RubyDescriptorPool descriptorPool;
|
||||
|
||||
private List<FileDescriptor> fileDescriptors;
|
||||
private Map<IRubyObject, IRubyObject> symtab;
|
||||
}
|
78
deps/protobuf/ruby/src/main/java/com/google/protobuf/jruby/RubyEnum.java
vendored
Normal file
78
deps/protobuf/ruby/src/main/java/com/google/protobuf/jruby/RubyEnum.java
vendored
Normal file
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.google.protobuf.jruby;
|
||||
|
||||
import org.jruby.RubyModule;
|
||||
import org.jruby.anno.JRubyMethod;
|
||||
import org.jruby.runtime.ThreadContext;
|
||||
import org.jruby.runtime.builtin.IRubyObject;
|
||||
|
||||
public class RubyEnum {
|
||||
/*
|
||||
* call-seq:
|
||||
* Enum.lookup(number) => name
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
@JRubyMethod(meta = true)
|
||||
public static IRubyObject lookup(ThreadContext context, IRubyObject recv, IRubyObject number) {
|
||||
RubyEnumDescriptor rubyEnumDescriptor = (RubyEnumDescriptor) getDescriptor(context, recv);
|
||||
return rubyEnumDescriptor.numberToName(context, number);
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Enum.resolve(name) => 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.
|
||||
*/
|
||||
@JRubyMethod(meta = true)
|
||||
public static IRubyObject resolve(ThreadContext context, IRubyObject recv, IRubyObject name) {
|
||||
RubyEnumDescriptor rubyEnumDescriptor = (RubyEnumDescriptor) getDescriptor(context, recv);
|
||||
return rubyEnumDescriptor.nameToNumber(context, name);
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Enum.descriptor
|
||||
*
|
||||
* This module method, provided on each generated enum module, returns the
|
||||
* EnumDescriptor corresponding to this enum type.
|
||||
*/
|
||||
@JRubyMethod(meta = true, name = "descriptor")
|
||||
public static IRubyObject getDescriptor(ThreadContext context, IRubyObject recv) {
|
||||
return ((RubyModule) recv).getInstanceVariable(Utils.DESCRIPTOR_INSTANCE_VAR);
|
||||
}
|
||||
}
|
181
deps/protobuf/ruby/src/main/java/com/google/protobuf/jruby/RubyEnumDescriptor.java
vendored
Normal file
181
deps/protobuf/ruby/src/main/java/com/google/protobuf/jruby/RubyEnumDescriptor.java
vendored
Normal file
@ -0,0 +1,181 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.google.protobuf.jruby;
|
||||
|
||||
import com.google.protobuf.DescriptorProtos.EnumDescriptorProto;
|
||||
import com.google.protobuf.Descriptors.EnumDescriptor;
|
||||
import com.google.protobuf.Descriptors.EnumValueDescriptor;
|
||||
import com.google.protobuf.Descriptors.FileDescriptor;
|
||||
import org.jruby.Ruby;
|
||||
import org.jruby.RubyClass;
|
||||
import org.jruby.RubyModule;
|
||||
import org.jruby.RubyObject;
|
||||
import org.jruby.RubyNumeric;
|
||||
import org.jruby.anno.JRubyClass;
|
||||
import org.jruby.anno.JRubyMethod;
|
||||
import org.jruby.runtime.Block;
|
||||
import org.jruby.runtime.ObjectAllocator;
|
||||
import org.jruby.runtime.ThreadContext;
|
||||
import org.jruby.runtime.builtin.IRubyObject;
|
||||
|
||||
@JRubyClass(name = "EnumDescriptor", include = "Enumerable")
|
||||
public class RubyEnumDescriptor extends RubyObject {
|
||||
public static void createRubyEnumDescriptor(Ruby runtime) {
|
||||
RubyModule mProtobuf = runtime.getClassFromPath("Google::Protobuf");
|
||||
RubyClass cEnumDescriptor = mProtobuf.defineClassUnder("EnumDescriptor", runtime.getObject(), new ObjectAllocator() {
|
||||
@Override
|
||||
public IRubyObject allocate(Ruby runtime, RubyClass klazz) {
|
||||
return new RubyEnumDescriptor(runtime, klazz);
|
||||
}
|
||||
});
|
||||
cEnumDescriptor.includeModule(runtime.getEnumerable());
|
||||
cEnumDescriptor.defineAnnotatedMethods(RubyEnumDescriptor.class);
|
||||
}
|
||||
|
||||
public RubyEnumDescriptor(Ruby runtime, RubyClass klazz) {
|
||||
super(runtime, klazz);
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* EnumDescriptor.name => name
|
||||
*
|
||||
* Returns the name of this enum type.
|
||||
*/
|
||||
@JRubyMethod(name = "name")
|
||||
public IRubyObject getName(ThreadContext context) {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* EnumDescriptor.each(&block)
|
||||
*
|
||||
* Iterates over key => value mappings in this enum's definition, yielding to
|
||||
* the block with (key, value) arguments for each one.
|
||||
*/
|
||||
@JRubyMethod
|
||||
public IRubyObject each(ThreadContext context, Block block) {
|
||||
Ruby runtime = context.runtime;
|
||||
for (EnumValueDescriptor enumValueDescriptor : descriptor.getValues()) {
|
||||
block.yield(context, runtime.newArray(runtime.newSymbol(enumValueDescriptor.getName()),
|
||||
runtime.newFixnum(enumValueDescriptor.getNumber())));
|
||||
}
|
||||
return context.nil;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* EnumDescriptor.enummodule => module
|
||||
*
|
||||
* Returns the Ruby module corresponding to this enum type. Cannot be called
|
||||
* until the enum descriptor has been added to a pool.
|
||||
*/
|
||||
@JRubyMethod
|
||||
public IRubyObject enummodule(ThreadContext context) {
|
||||
return module;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* EnumDescriptor.file_descriptor
|
||||
*
|
||||
* Returns the FileDescriptor object this enum belongs to.
|
||||
*/
|
||||
@JRubyMethod(name = "file_descriptor")
|
||||
public IRubyObject getFileDescriptor(ThreadContext context) {
|
||||
return RubyFileDescriptor.getRubyFileDescriptor(context, descriptor);
|
||||
}
|
||||
|
||||
public boolean isValidValue(ThreadContext context, IRubyObject value) {
|
||||
EnumValueDescriptor enumValue;
|
||||
|
||||
if (Utils.isRubyNum(value)) {
|
||||
enumValue = descriptor.findValueByNumberCreatingIfUnknown(RubyNumeric.num2int(value));
|
||||
} else {
|
||||
enumValue = descriptor.findValueByName(value.asJavaString());
|
||||
}
|
||||
|
||||
return enumValue != null;
|
||||
}
|
||||
|
||||
protected IRubyObject nameToNumber(ThreadContext context, IRubyObject name) {
|
||||
EnumValueDescriptor value = descriptor.findValueByName(name.asJavaString());
|
||||
return value == null ? context.nil : context.runtime.newFixnum(value.getNumber());
|
||||
}
|
||||
|
||||
protected IRubyObject numberToName(ThreadContext context, IRubyObject number) {
|
||||
EnumValueDescriptor value = descriptor.findValueByNumber(RubyNumeric.num2int(number));
|
||||
return value == null ? context.nil : context.runtime.newSymbol(value.getName());
|
||||
}
|
||||
|
||||
protected void setDescriptor(ThreadContext context, EnumDescriptor descriptor) {
|
||||
this.descriptor = descriptor;
|
||||
this.module = buildModuleFromDescriptor(context);
|
||||
}
|
||||
|
||||
protected void setName(IRubyObject name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
private RubyModule buildModuleFromDescriptor(ThreadContext context) {
|
||||
Ruby runtime = context.runtime;
|
||||
|
||||
RubyModule enumModule = RubyModule.newModule(runtime);
|
||||
boolean defaultValueRequiredButNotFound = descriptor.getFile().getSyntax() == FileDescriptor.Syntax.PROTO3;
|
||||
for (EnumValueDescriptor value : descriptor.getValues()) {
|
||||
String name = value.getName();
|
||||
// Make sure its a valid constant name before trying to create it
|
||||
if (Character.isUpperCase(name.codePointAt(0))) {
|
||||
enumModule.defineConstant(name, runtime.newFixnum(value.getNumber()));
|
||||
} else {
|
||||
runtime.getWarnings().warn("Enum value " + name + " does not start with an uppercase letter as is required for Ruby constants.");
|
||||
}
|
||||
if (value.getNumber() == 0) {
|
||||
defaultValueRequiredButNotFound = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (defaultValueRequiredButNotFound) {
|
||||
throw Utils.createTypeError(context, "Enum definition " + name + " does not contain a value for '0'");
|
||||
}
|
||||
enumModule.instance_variable_set(runtime.newString(Utils.DESCRIPTOR_INSTANCE_VAR), this);
|
||||
enumModule.defineAnnotatedMethods(RubyEnum.class);
|
||||
return enumModule;
|
||||
}
|
||||
|
||||
private EnumDescriptor descriptor;
|
||||
private EnumDescriptorProto.Builder builder;
|
||||
private IRubyObject name;
|
||||
private RubyModule module;
|
||||
}
|
270
deps/protobuf/ruby/src/main/java/com/google/protobuf/jruby/RubyFieldDescriptor.java
vendored
Normal file
270
deps/protobuf/ruby/src/main/java/com/google/protobuf/jruby/RubyFieldDescriptor.java
vendored
Normal file
@ -0,0 +1,270 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.google.protobuf.jruby;
|
||||
|
||||
import com.google.protobuf.Descriptors.FieldDescriptor;
|
||||
import com.google.protobuf.Descriptors.FileDescriptor;
|
||||
import org.jruby.*;
|
||||
import org.jruby.anno.JRubyClass;
|
||||
import org.jruby.anno.JRubyMethod;
|
||||
import org.jruby.runtime.ObjectAllocator;
|
||||
import org.jruby.runtime.ThreadContext;
|
||||
import org.jruby.runtime.builtin.IRubyObject;
|
||||
|
||||
@JRubyClass(name = "FieldDescriptor")
|
||||
public class RubyFieldDescriptor extends RubyObject {
|
||||
public static void createRubyFieldDescriptor(Ruby runtime) {
|
||||
RubyModule mProtobuf = runtime.getClassFromPath("Google::Protobuf");
|
||||
RubyClass cFieldDescriptor = mProtobuf.defineClassUnder("FieldDescriptor", runtime.getObject(), new ObjectAllocator() {
|
||||
@Override
|
||||
public IRubyObject allocate(Ruby runtime, RubyClass klazz) {
|
||||
return new RubyFieldDescriptor(runtime, klazz);
|
||||
}
|
||||
});
|
||||
cFieldDescriptor.defineAnnotatedMethods(RubyFieldDescriptor.class);
|
||||
}
|
||||
|
||||
public RubyFieldDescriptor(Ruby runtime, RubyClass klazz) {
|
||||
super(runtime, klazz);
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* FieldDescriptor.default => default
|
||||
*
|
||||
* 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);
|
||||
// }
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* FieldDescriptor.label => label
|
||||
*
|
||||
* Returns this field's label (i.e., plurality), as a Ruby symbol.
|
||||
*
|
||||
* Valid field labels are:
|
||||
* :optional, :repeated
|
||||
*/
|
||||
@JRubyMethod(name = "label")
|
||||
public IRubyObject getLabel(ThreadContext context) {
|
||||
if (label == null) {
|
||||
calculateLabel(context);
|
||||
}
|
||||
return label;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* FieldDescriptor.name => name
|
||||
*
|
||||
* Returns the name of this field as a Ruby String, or nil if it is not set.
|
||||
*/
|
||||
@JRubyMethod(name = "name")
|
||||
public IRubyObject getName(ThreadContext context) {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* FieldDescriptor.subtype => message_or_enum_descriptor
|
||||
*
|
||||
* Returns the message or enum descriptor corresponding to this field's type if
|
||||
* it is a message or enum field, respectively, or nil otherwise. Cannot be
|
||||
* called *until* the containing message type is added to a pool (and thus
|
||||
* resolved).
|
||||
*/
|
||||
@JRubyMethod(name = "subtype")
|
||||
public IRubyObject getSubtype(ThreadContext context) {
|
||||
if (subtype == null) {
|
||||
calculateSubtype(context);
|
||||
}
|
||||
return subtype;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* FieldDescriptor.type => type
|
||||
*
|
||||
* Returns this field's type, as a Ruby symbol, or nil if not yet set.
|
||||
*
|
||||
* Valid field types are:
|
||||
* :int32, :int64, :uint32, :uint64, :float, :double, :bool, :string,
|
||||
* :bytes, :message.
|
||||
*/
|
||||
@JRubyMethod(name = "type")
|
||||
public IRubyObject getType(ThreadContext context) {
|
||||
return Utils.fieldTypeToRuby(context, descriptor.getType());
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* FieldDescriptor.number => number
|
||||
*
|
||||
* Returns the tag number for this field.
|
||||
*/
|
||||
@JRubyMethod(name = "number")
|
||||
public IRubyObject getNumber(ThreadContext context) {
|
||||
return this.number;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* FieldDescriptor.submsg_name => submsg_name
|
||||
*
|
||||
* Returns the name of the message or enum type corresponding to this field, if
|
||||
* it is a message or enum field (respectively), or nil otherwise. This type
|
||||
* 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);
|
||||
// switch (upb_fielddef_type(self->fielddef)) {
|
||||
// case UPB_TYPE_ENUM:
|
||||
// return rb_str_new2(
|
||||
// upb_enumdef_fullname(upb_fielddef_enumsubdef(self->fielddef)));
|
||||
// case UPB_TYPE_MESSAGE:
|
||||
// return rb_str_new2(
|
||||
// upb_msgdef_fullname(upb_fielddef_msgsubdef(self->fielddef)));
|
||||
// default:
|
||||
// return Qnil;
|
||||
// }
|
||||
// }
|
||||
/*
|
||||
* call-seq:
|
||||
* FieldDescriptor.submsg_name = submsg_name
|
||||
*
|
||||
* Sets the name of the message or enum type corresponding to this field, if it
|
||||
* is a message or enum field (respectively). This type name will be resolved
|
||||
* within the context of the pool to which the containing message type is added.
|
||||
* Cannot be called on field that are not of message or enum type, or on fields
|
||||
* that are part of a message type already added to a pool.
|
||||
*/
|
||||
// @JRubyMethod(name = "submsg_name=")
|
||||
// public IRubyObject setSubmsgName(ThreadContext context, IRubyObject name) {
|
||||
// this.builder.setTypeName("." + Utils.escapeIdentifier(name.asJavaString()));
|
||||
// return context.runtime.getNil();
|
||||
// }
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* FieldDescriptor.clear(message)
|
||||
*
|
||||
* Clears the field from the message if it's set.
|
||||
*/
|
||||
@JRubyMethod(name = "clear")
|
||||
public IRubyObject clearValue(ThreadContext context, IRubyObject message) {
|
||||
return ((RubyMessage) message).clearField(context, descriptor);
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* FieldDescriptor.get(message) => value
|
||||
*
|
||||
* Returns the value set for this field on the given message. Raises an
|
||||
* exception if message is of the wrong type.
|
||||
*/
|
||||
@JRubyMethod(name = "get")
|
||||
public IRubyObject getValue(ThreadContext context, IRubyObject message) {
|
||||
return ((RubyMessage) message).getField(context, descriptor);
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* FieldDescriptor.has?(message) => boolean
|
||||
*
|
||||
* Returns whether the value is set on the given message. Raises an
|
||||
* exception when calling for fields that do not have presence.
|
||||
*/
|
||||
@JRubyMethod(name = "has?")
|
||||
public IRubyObject has(ThreadContext context, IRubyObject message) {
|
||||
return ((RubyMessage) message).hasField(context, descriptor);
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* FieldDescriptor.set(message, value)
|
||||
*
|
||||
* Sets the value corresponding to this field to the given value on the given
|
||||
* message. Raises an exception if message is of the wrong type. Performs the
|
||||
* ordinary type-checks for field setting.
|
||||
*/
|
||||
@JRubyMethod(name = "set")
|
||||
public IRubyObject setValue(ThreadContext context, IRubyObject message, IRubyObject value) {
|
||||
((RubyMessage) message).setField(context, descriptor, value);
|
||||
return context.nil;
|
||||
}
|
||||
|
||||
protected void setDescriptor(ThreadContext context, FieldDescriptor descriptor, RubyDescriptorPool pool) {
|
||||
if (descriptor.isRequired() && descriptor.getFile().getSyntax() == FileDescriptor.Syntax.PROTO3) {
|
||||
throw Utils.createTypeError(context, descriptor.getName() + " is labeled required but required fields are unsupported in proto3");
|
||||
}
|
||||
this.descriptor = descriptor;
|
||||
this.name = context.runtime.newString(descriptor.getName());
|
||||
this.pool = pool;
|
||||
}
|
||||
|
||||
private void calculateLabel(ThreadContext context) {
|
||||
if (descriptor.isRepeated()) {
|
||||
this.label = context.runtime.newSymbol("repeated");
|
||||
} else if (descriptor.isOptional()) {
|
||||
this.label = context.runtime.newSymbol("optional");
|
||||
} else {
|
||||
this.label = context.nil;
|
||||
}
|
||||
}
|
||||
|
||||
private void calculateSubtype(ThreadContext context) {
|
||||
FieldDescriptor.Type fdType = descriptor.getType();
|
||||
if (fdType == FieldDescriptor.Type.MESSAGE) {
|
||||
RubyString messageName = context.runtime.newString(descriptor.getMessageType().getFullName());
|
||||
this.subtype = pool.lookup(context, messageName);
|
||||
} else if (fdType == FieldDescriptor.Type.ENUM) {
|
||||
RubyString enumName = context.runtime.newString(descriptor.getEnumType().getFullName());
|
||||
this.subtype = pool.lookup(context, enumName);
|
||||
} else {
|
||||
this.subtype = context.nil;
|
||||
}
|
||||
}
|
||||
|
||||
private static final String DOT = ".";
|
||||
|
||||
private FieldDescriptor descriptor;
|
||||
private IRubyObject name;
|
||||
private IRubyObject label;
|
||||
private IRubyObject number;
|
||||
private IRubyObject subtype;
|
||||
private RubyDescriptorPool pool;
|
||||
}
|
106
deps/protobuf/ruby/src/main/java/com/google/protobuf/jruby/RubyFileDescriptor.java
vendored
Normal file
106
deps/protobuf/ruby/src/main/java/com/google/protobuf/jruby/RubyFileDescriptor.java
vendored
Normal file
@ -0,0 +1,106 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.google.protobuf.jruby;
|
||||
|
||||
import com.google.protobuf.Descriptors.Descriptor;
|
||||
import com.google.protobuf.Descriptors.FileDescriptor;
|
||||
import com.google.protobuf.Descriptors.FileDescriptor.Syntax.*;
|
||||
import com.google.protobuf.Descriptors.GenericDescriptor;
|
||||
import org.jruby.*;
|
||||
import org.jruby.anno.JRubyClass;
|
||||
import org.jruby.anno.JRubyMethod;
|
||||
import org.jruby.runtime.Block;
|
||||
import org.jruby.runtime.ObjectAllocator;
|
||||
import org.jruby.runtime.ThreadContext;
|
||||
import org.jruby.runtime.builtin.IRubyObject;
|
||||
|
||||
@JRubyClass(name = "FileDescriptor")
|
||||
public class RubyFileDescriptor extends RubyObject {
|
||||
public static void createRubyFileDescriptor(Ruby runtime) {
|
||||
RubyModule mProtobuf = runtime.getClassFromPath("Google::Protobuf");
|
||||
cFileDescriptor = mProtobuf.defineClassUnder("FileDescriptor", runtime.getObject(), new ObjectAllocator() {
|
||||
@Override
|
||||
public IRubyObject allocate(Ruby runtime, RubyClass klazz) {
|
||||
return new RubyFileDescriptor(runtime, klazz);
|
||||
}
|
||||
});
|
||||
cFileDescriptor.defineAnnotatedMethods(RubyFileDescriptor.class);
|
||||
}
|
||||
|
||||
public static RubyFileDescriptor getRubyFileDescriptor(ThreadContext context, GenericDescriptor descriptor) {
|
||||
RubyFileDescriptor rfd = (RubyFileDescriptor) cFileDescriptor.newInstance(context, Block.NULL_BLOCK);
|
||||
rfd.fileDescriptor = descriptor.getFile();
|
||||
return rfd;
|
||||
}
|
||||
|
||||
public RubyFileDescriptor(Ruby runtime, RubyClass klazz) {
|
||||
super(runtime, klazz);
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* FileDescriptor.name => name
|
||||
*
|
||||
* Returns the name of the file.
|
||||
*/
|
||||
@JRubyMethod(name = "name")
|
||||
public IRubyObject getName(ThreadContext context) {
|
||||
String name = fileDescriptor.getName();
|
||||
return name == null ? context.nil : context.runtime.newString(name);
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* FileDescriptor.syntax => syntax
|
||||
*
|
||||
* Returns this file descriptors syntax.
|
||||
*
|
||||
* Valid syntax versions are:
|
||||
* :proto2 or :proto3.
|
||||
*/
|
||||
@JRubyMethod(name = "syntax")
|
||||
public IRubyObject getSyntax(ThreadContext context) {
|
||||
switch (fileDescriptor.getSyntax()) {
|
||||
case PROTO2:
|
||||
return context.runtime.newSymbol("proto2");
|
||||
case PROTO3:
|
||||
return context.runtime.newSymbol("proto3");
|
||||
default:
|
||||
return context.nil;
|
||||
}
|
||||
}
|
||||
|
||||
private static RubyClass cFileDescriptor;
|
||||
|
||||
private FileDescriptor fileDescriptor;
|
||||
}
|
474
deps/protobuf/ruby/src/main/java/com/google/protobuf/jruby/RubyMap.java
vendored
Normal file
474
deps/protobuf/ruby/src/main/java/com/google/protobuf/jruby/RubyMap.java
vendored
Normal file
@ -0,0 +1,474 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.google.protobuf.jruby;
|
||||
|
||||
import com.google.protobuf.Descriptors.FieldDescriptor;
|
||||
import com.google.protobuf.DynamicMessage;
|
||||
import org.jruby.*;
|
||||
import org.jruby.anno.JRubyClass;
|
||||
import org.jruby.anno.JRubyMethod;
|
||||
import org.jruby.runtime.Block;
|
||||
import org.jruby.runtime.Helpers;
|
||||
import org.jruby.runtime.ObjectAllocator;
|
||||
import org.jruby.runtime.ThreadContext;
|
||||
import org.jruby.runtime.builtin.IRubyObject;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@JRubyClass(name = "Map", include = "Enumerable")
|
||||
public class RubyMap extends RubyObject {
|
||||
public static void createRubyMap(Ruby runtime) {
|
||||
RubyModule protobuf = runtime.getClassFromPath("Google::Protobuf");
|
||||
RubyClass cMap = protobuf.defineClassUnder("Map", runtime.getObject(), new ObjectAllocator() {
|
||||
@Override
|
||||
public IRubyObject allocate(Ruby ruby, RubyClass rubyClass) {
|
||||
return new RubyMap(ruby, rubyClass);
|
||||
}
|
||||
});
|
||||
cMap.includeModule(runtime.getEnumerable());
|
||||
cMap.defineAnnotatedMethods(RubyMap.class);
|
||||
}
|
||||
|
||||
public RubyMap(Ruby ruby, RubyClass rubyClass) {
|
||||
super(ruby, rubyClass);
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Map.new(key_type, value_type, value_typeclass = nil, init_hashmap = {})
|
||||
* => new map
|
||||
*
|
||||
* Allocates a new Map container. This constructor may be called with 2, 3, or 4
|
||||
* arguments. The first two arguments are always present and are symbols (taking
|
||||
* on the same values as field-type symbols in message descriptors) that
|
||||
* indicate the type of the map key and value fields.
|
||||
*
|
||||
* The supported key types are: :int32, :int64, :uint32, :uint64, :fixed32,
|
||||
* :fixed64, :sfixed32, :sfixed64, :sint32, :sint64, :bool, :string, :bytes.
|
||||
*
|
||||
* The supported value types are: :int32, :int64, :uint32, :uint64, :fixed32,
|
||||
* :fixed64, :sfixed32, :sfixed64, :sint32, :sint64, :bool, :string, :bytes,
|
||||
* :enum, :message.
|
||||
*
|
||||
* The third argument, value_typeclass, must be present if value_type is :enum
|
||||
* or :message. As in RepeatedField#new, this argument must be a message class
|
||||
* (for :message) or enum module (for :enum).
|
||||
*
|
||||
* The last argument, if present, provides initial content for map. Note that
|
||||
* this may be an ordinary Ruby hashmap or another Map instance with identical
|
||||
* key and value types. Also note that this argument may be present whether or
|
||||
* not value_typeclass is present (and it is unambiguously separate from
|
||||
* value_typeclass because value_typeclass's presence is strictly determined by
|
||||
* value_type). The contents of this initial hashmap or Map instance are
|
||||
* shallow-copied into the new Map: the original map is unmodified, but
|
||||
* references to underlying objects will be shared if the value type is a
|
||||
* message type.
|
||||
*/
|
||||
@JRubyMethod(required = 2, optional = 2)
|
||||
public IRubyObject initialize(ThreadContext context, IRubyObject[] args) {
|
||||
this.table = new HashMap<IRubyObject, IRubyObject>();
|
||||
this.keyType = Utils.rubyToFieldType(args[0]);
|
||||
this.valueType = Utils.rubyToFieldType(args[1]);
|
||||
|
||||
switch(keyType) {
|
||||
case STRING:
|
||||
case BYTES:
|
||||
this.keyTypeIsString = true;
|
||||
break;
|
||||
case INT32:
|
||||
case INT64:
|
||||
case SINT32:
|
||||
case SINT64:
|
||||
case UINT32:
|
||||
case UINT64:
|
||||
case FIXED32:
|
||||
case FIXED64:
|
||||
case SFIXED32:
|
||||
case SFIXED64:
|
||||
case BOOL:
|
||||
// These are OK.
|
||||
break;
|
||||
default:
|
||||
throw context.runtime.newArgumentError("Invalid key type for map.");
|
||||
}
|
||||
|
||||
int initValueArg = 2;
|
||||
if (needTypeclass(this.valueType) && args.length > 2) {
|
||||
this.valueTypeClass = args[2];
|
||||
Utils.validateTypeClass(context, this.valueType, this.valueTypeClass);
|
||||
initValueArg = 3;
|
||||
} else {
|
||||
this.valueTypeClass = context.runtime.getNilClass();
|
||||
}
|
||||
|
||||
if (args.length > initValueArg) {
|
||||
mergeIntoSelf(context, args[initValueArg]);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Map.[]=(key, value) => value
|
||||
*
|
||||
* Inserts or overwrites the value at the given key with the given new value.
|
||||
* Throws an exception if the key type is incorrect. Returns the new value that
|
||||
* was just inserted.
|
||||
*/
|
||||
@JRubyMethod(name = "[]=")
|
||||
public IRubyObject indexSet(ThreadContext context, IRubyObject key, IRubyObject value) {
|
||||
checkFrozen();
|
||||
|
||||
/*
|
||||
* String types for keys return a different error than
|
||||
* other types for keys, so deal with them specifically first
|
||||
*/
|
||||
if (keyTypeIsString && !(key instanceof RubySymbol || key instanceof RubyString)) {
|
||||
throw Utils.createTypeError(context, "Expected string for map key");
|
||||
}
|
||||
key = Utils.checkType(context, keyType, "key", key, (RubyModule) valueTypeClass);
|
||||
value = Utils.checkType(context, valueType, "value", value, (RubyModule) valueTypeClass);
|
||||
IRubyObject symbol;
|
||||
if (valueType == FieldDescriptor.Type.ENUM &&
|
||||
Utils.isRubyNum(value) &&
|
||||
! (symbol = RubyEnum.lookup(context, valueTypeClass, value)).isNil()) {
|
||||
value = symbol;
|
||||
}
|
||||
this.table.put(key, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Map.[](key) => value
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
@JRubyMethod(name = "[]")
|
||||
public IRubyObject index(ThreadContext context, IRubyObject key) {
|
||||
key = Utils.symToString(key);
|
||||
return Helpers.nullToNil(table.get(key), context.nil);
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Map.==(other) => boolean
|
||||
*
|
||||
* Compares this map to another. Maps are equal if they have identical key sets,
|
||||
* and for each key, the values in both maps compare equal. Elements are
|
||||
* compared as per normal Ruby semantics, by calling their :== methods (or
|
||||
* performing a more efficient comparison for primitive types).
|
||||
*
|
||||
* Maps with dissimilar key types or value types/typeclasses are never equal,
|
||||
* even if value comparison (for example, between integers and floats) would
|
||||
* have otherwise indicated that every element has equal value.
|
||||
*/
|
||||
@JRubyMethod(name = "==")
|
||||
public IRubyObject eq(ThreadContext context, IRubyObject _other) {
|
||||
if (_other instanceof RubyHash)
|
||||
return singleLevelHash(context).op_equal(context, _other);
|
||||
RubyMap other = (RubyMap) _other;
|
||||
if (this == other) return context.runtime.getTrue();
|
||||
if (!typeCompatible(other) || this.table.size() != other.table.size())
|
||||
return context.runtime.getFalse();
|
||||
for (IRubyObject key : table.keySet()) {
|
||||
if (! other.table.containsKey(key))
|
||||
return context.runtime.getFalse();
|
||||
if (! other.table.get(key).equals(table.get(key)))
|
||||
return context.runtime.getFalse();
|
||||
}
|
||||
return context.runtime.getTrue();
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Map.inspect => string
|
||||
*
|
||||
* Returns a string representing this map's elements. It will be formatted as
|
||||
* "{key => value, key => value, ...}", with each key and value string
|
||||
* representation computed by its own #inspect method.
|
||||
*/
|
||||
@JRubyMethod
|
||||
public IRubyObject inspect() {
|
||||
return singleLevelHash(getRuntime().getCurrentContext()).inspect();
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Map.hash => hash_value
|
||||
*
|
||||
* Returns a hash value based on this map's contents.
|
||||
*/
|
||||
@JRubyMethod
|
||||
public IRubyObject hash(ThreadContext context) {
|
||||
try {
|
||||
MessageDigest digest = MessageDigest.getInstance("SHA-256");
|
||||
for (IRubyObject key : table.keySet()) {
|
||||
digest.update((byte) key.hashCode());
|
||||
digest.update((byte) table.get(key).hashCode());
|
||||
}
|
||||
return context.runtime.newFixnum(ByteBuffer.wrap(digest.digest()).getLong());
|
||||
} catch (NoSuchAlgorithmException ignore) {
|
||||
return context.runtime.newFixnum(System.identityHashCode(table));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Map.keys => [list_of_keys]
|
||||
*
|
||||
* Returns the list of keys contained in the map, in unspecified order.
|
||||
*/
|
||||
@JRubyMethod
|
||||
public IRubyObject keys(ThreadContext context) {
|
||||
return RubyArray.newArray(context.runtime, table.keySet());
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Map.values => [list_of_values]
|
||||
*
|
||||
* Returns the list of values contained in the map, in unspecified order.
|
||||
*/
|
||||
@JRubyMethod
|
||||
public IRubyObject values(ThreadContext context) {
|
||||
return RubyArray.newArray(context.runtime, table.values());
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Map.clear
|
||||
*
|
||||
* Removes all entries from the map.
|
||||
*/
|
||||
@JRubyMethod
|
||||
public IRubyObject clear(ThreadContext context) {
|
||||
checkFrozen();
|
||||
table.clear();
|
||||
return context.nil;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Map.each(&block)
|
||||
*
|
||||
* Invokes &block on each |key, value| pair in the map, in unspecified order.
|
||||
* Note that Map also includes Enumerable; map thus acts like a normal Ruby
|
||||
* sequence.
|
||||
*/
|
||||
@JRubyMethod
|
||||
public IRubyObject each(ThreadContext context, Block block) {
|
||||
for (IRubyObject key : table.keySet()) {
|
||||
block.yieldSpecific(context, key, table.get(key));
|
||||
}
|
||||
return context.nil;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Map.delete(key) => old_value
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
@JRubyMethod
|
||||
public IRubyObject delete(ThreadContext context, IRubyObject key) {
|
||||
checkFrozen();
|
||||
return table.remove(key);
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Map.has_key?(key) => bool
|
||||
*
|
||||
* Returns true if the given key is present in the map. Throws an exception if
|
||||
* the key has the wrong type.
|
||||
*/
|
||||
@JRubyMethod(name = "has_key?")
|
||||
public IRubyObject hasKey(ThreadContext context, IRubyObject key) {
|
||||
return this.table.containsKey(key) ? context.runtime.getTrue() : context.runtime.getFalse();
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Map.length
|
||||
*
|
||||
* Returns the number of entries (key-value pairs) in the map.
|
||||
*/
|
||||
@JRubyMethod(name = {"length", "size"})
|
||||
public IRubyObject length(ThreadContext context) {
|
||||
return context.runtime.newFixnum(this.table.size());
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Map.dup => new_map
|
||||
*
|
||||
* Duplicates this map with a shallow copy. References to all non-primitive
|
||||
* element objects (e.g., submessages) are shared.
|
||||
*/
|
||||
@JRubyMethod
|
||||
public IRubyObject dup(ThreadContext context) {
|
||||
RubyMap newMap = newThisType(context);
|
||||
for (Map.Entry<IRubyObject, IRubyObject> entry : table.entrySet()) {
|
||||
newMap.table.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
return newMap;
|
||||
}
|
||||
|
||||
@JRubyMethod(name = "to_h")
|
||||
public RubyHash toHash(ThreadContext context) {
|
||||
Map<IRubyObject, IRubyObject> mapForHash = new HashMap();
|
||||
|
||||
table.forEach((key, value) -> {
|
||||
if (!value.isNil()) {
|
||||
if (value.respondsTo("to_h")) {
|
||||
value = Helpers.invoke(context, value, "to_h");
|
||||
} else if (value.respondsTo("to_a")) {
|
||||
value = Helpers.invoke(context, value, "to_a");
|
||||
}
|
||||
mapForHash.put(key, value);
|
||||
}
|
||||
});
|
||||
|
||||
return RubyHash.newHash(context.runtime, mapForHash, context.nil);
|
||||
}
|
||||
|
||||
// Used by Google::Protobuf.deep_copy but not exposed directly.
|
||||
protected IRubyObject deepCopy(ThreadContext context) {
|
||||
RubyMap newMap = newThisType(context);
|
||||
switch (valueType) {
|
||||
case MESSAGE:
|
||||
for (IRubyObject key : table.keySet()) {
|
||||
RubyMessage message = (RubyMessage) table.get(key);
|
||||
newMap.table.put(key.dup(), message.deepCopy(context));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
for (IRubyObject key : table.keySet()) {
|
||||
newMap.table.put(key.dup(), table.get(key).dup());
|
||||
}
|
||||
}
|
||||
return newMap;
|
||||
}
|
||||
|
||||
protected List<DynamicMessage> build(ThreadContext context, RubyDescriptor descriptor, int depth, int recursionLimit) {
|
||||
List<DynamicMessage> list = new ArrayList<DynamicMessage>();
|
||||
RubyClass rubyClass = (RubyClass) descriptor.msgclass(context);
|
||||
FieldDescriptor keyField = descriptor.getField("key");
|
||||
FieldDescriptor valueField = descriptor.getField("value");
|
||||
for (IRubyObject key : table.keySet()) {
|
||||
RubyMessage mapMessage = (RubyMessage) rubyClass.newInstance(context, Block.NULL_BLOCK);
|
||||
mapMessage.setField(context, keyField, key);
|
||||
mapMessage.setField(context, valueField, table.get(key));
|
||||
list.add(mapMessage.build(context, depth + 1, recursionLimit));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
protected RubyMap mergeIntoSelf(final ThreadContext context, IRubyObject hashmap) {
|
||||
if (hashmap instanceof RubyHash) {
|
||||
((RubyHash) hashmap).visitAll(context, new RubyHash.Visitor() {
|
||||
@Override
|
||||
public void visit(IRubyObject key, IRubyObject val) {
|
||||
if (val instanceof RubyHash && !valueTypeClass.isNil()) {
|
||||
val = ((RubyClass) valueTypeClass).newInstance(context, val, Block.NULL_BLOCK);
|
||||
}
|
||||
indexSet(context, key, val);
|
||||
}
|
||||
}, null);
|
||||
} else if (hashmap instanceof RubyMap) {
|
||||
RubyMap other = (RubyMap) hashmap;
|
||||
if (!typeCompatible(other)) {
|
||||
throw Utils.createTypeError(context, "Attempt to merge Map with mismatching types");
|
||||
}
|
||||
} else {
|
||||
throw Utils.createTypeError(context, "Unknown type merging into Map");
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
protected boolean typeCompatible(RubyMap other) {
|
||||
return this.keyType == other.keyType &&
|
||||
this.valueType == other.valueType &&
|
||||
this.valueTypeClass == other.valueTypeClass;
|
||||
}
|
||||
|
||||
private RubyMap newThisType(ThreadContext context) {
|
||||
RubyMap newMap;
|
||||
if (needTypeclass(valueType)) {
|
||||
newMap = (RubyMap) metaClass.newInstance(context,
|
||||
Utils.fieldTypeToRuby(context, keyType),
|
||||
Utils.fieldTypeToRuby(context, valueType),
|
||||
valueTypeClass, Block.NULL_BLOCK);
|
||||
} else {
|
||||
newMap = (RubyMap) metaClass.newInstance(context,
|
||||
Utils.fieldTypeToRuby(context, keyType),
|
||||
Utils.fieldTypeToRuby(context, valueType),
|
||||
Block.NULL_BLOCK);
|
||||
}
|
||||
newMap.table = new HashMap<IRubyObject, IRubyObject>();
|
||||
return newMap;
|
||||
}
|
||||
|
||||
/*
|
||||
* toHash calls toHash on values, for some camparisons we only need
|
||||
* a hash with the original objects still as values
|
||||
*/
|
||||
private RubyHash singleLevelHash(ThreadContext context) {
|
||||
return RubyHash.newHash(context.runtime, table, context.nil);
|
||||
}
|
||||
|
||||
private boolean needTypeclass(FieldDescriptor.Type type) {
|
||||
switch(type) {
|
||||
case MESSAGE:
|
||||
case ENUM:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private FieldDescriptor.Type keyType;
|
||||
private FieldDescriptor.Type valueType;
|
||||
private IRubyObject valueTypeClass;
|
||||
private Map<IRubyObject, IRubyObject> table;
|
||||
private boolean keyTypeIsString = false;
|
||||
}
|
1350
deps/protobuf/ruby/src/main/java/com/google/protobuf/jruby/RubyMessage.java
vendored
Normal file
1350
deps/protobuf/ruby/src/main/java/com/google/protobuf/jruby/RubyMessage.java
vendored
Normal file
File diff suppressed because it is too large
Load Diff
86
deps/protobuf/ruby/src/main/java/com/google/protobuf/jruby/RubyOneofDescriptor.java
vendored
Normal file
86
deps/protobuf/ruby/src/main/java/com/google/protobuf/jruby/RubyOneofDescriptor.java
vendored
Normal file
@ -0,0 +1,86 @@
|
||||
package com.google.protobuf.jruby;
|
||||
|
||||
import com.google.protobuf.Descriptors.FieldDescriptor;
|
||||
import com.google.protobuf.Descriptors.OneofDescriptor;
|
||||
import org.jruby.Ruby;
|
||||
import org.jruby.RubyClass;
|
||||
import org.jruby.RubyModule;
|
||||
import org.jruby.RubyObject;
|
||||
import org.jruby.anno.JRubyClass;
|
||||
import org.jruby.anno.JRubyMethod;
|
||||
import org.jruby.runtime.Block;
|
||||
import org.jruby.runtime.ObjectAllocator;
|
||||
import org.jruby.runtime.ThreadContext;
|
||||
import org.jruby.runtime.builtin.IRubyObject;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@JRubyClass(name = "OneofDescriptor", include = "Enumerable")
|
||||
public class RubyOneofDescriptor extends RubyObject {
|
||||
|
||||
public static void createRubyOneofDescriptor(Ruby runtime) {
|
||||
RubyModule protobuf = runtime.getClassFromPath("Google::Protobuf");
|
||||
RubyClass cRubyOneofDescriptor = protobuf.defineClassUnder("OneofDescriptor", runtime.getObject(), new ObjectAllocator() {
|
||||
@Override
|
||||
public IRubyObject allocate(Ruby ruby, RubyClass rubyClass) {
|
||||
return new RubyOneofDescriptor(ruby, rubyClass);
|
||||
}
|
||||
});
|
||||
cRubyOneofDescriptor.defineAnnotatedMethods(RubyOneofDescriptor.class);
|
||||
cRubyOneofDescriptor.includeModule(runtime.getEnumerable());
|
||||
}
|
||||
|
||||
public RubyOneofDescriptor(Ruby ruby, RubyClass rubyClass) {
|
||||
super(ruby, rubyClass);
|
||||
fields = new ArrayList<RubyFieldDescriptor>();
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* OneofDescriptor.name => name
|
||||
*
|
||||
* Returns the name of this oneof.
|
||||
*/
|
||||
@JRubyMethod(name = "name")
|
||||
public IRubyObject getName(ThreadContext context) {
|
||||
return name;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* OneofDescriptor.each(&block) => nil
|
||||
*
|
||||
* Iterates through fields in this oneof, yielding to the block on each one.
|
||||
*/
|
||||
@JRubyMethod
|
||||
public IRubyObject each(ThreadContext context, Block block) {
|
||||
for (RubyFieldDescriptor field : fields) {
|
||||
block.yieldSpecific(context, field);
|
||||
}
|
||||
return context.nil;
|
||||
}
|
||||
|
||||
protected Collection<RubyFieldDescriptor> getFields() {
|
||||
return fields;
|
||||
}
|
||||
|
||||
protected OneofDescriptor getDescriptor() {
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
protected void setDescriptor(ThreadContext context, OneofDescriptor descriptor, Map<FieldDescriptor, RubyFieldDescriptor> fieldCache) {
|
||||
this.descriptor = descriptor;
|
||||
this.name = context.runtime.newString(descriptor.getName());
|
||||
|
||||
for (FieldDescriptor fd : descriptor.getFields()) {
|
||||
fields.add(fieldCache.get(fd));
|
||||
}
|
||||
}
|
||||
|
||||
private IRubyObject name;
|
||||
private List<RubyFieldDescriptor> fields;
|
||||
private OneofDescriptor descriptor;
|
||||
}
|
82
deps/protobuf/ruby/src/main/java/com/google/protobuf/jruby/RubyProtobuf.java
vendored
Normal file
82
deps/protobuf/ruby/src/main/java/com/google/protobuf/jruby/RubyProtobuf.java
vendored
Normal file
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.google.protobuf.jruby;
|
||||
|
||||
import org.jruby.Ruby;
|
||||
import org.jruby.RubyModule;
|
||||
import org.jruby.anno.JRubyMethod;
|
||||
import org.jruby.anno.JRubyModule;
|
||||
import org.jruby.runtime.ThreadContext;
|
||||
import org.jruby.runtime.builtin.IRubyObject;
|
||||
|
||||
@JRubyModule(name = "Protobuf")
|
||||
public class RubyProtobuf {
|
||||
|
||||
public static void createProtobuf(Ruby runtime) {
|
||||
RubyModule mGoogle = runtime.getModule("Google");
|
||||
RubyModule mProtobuf = mGoogle.defineModuleUnder("Protobuf");
|
||||
mProtobuf.defineAnnotatedMethods(RubyProtobuf.class);
|
||||
RubyModule mInternal = mProtobuf.defineModuleUnder("Internal");
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Google::Protobuf.deep_copy(obj) => copy_of_obj
|
||||
*
|
||||
* Performs a deep copy of either a RepeatedField instance or a message object,
|
||||
* recursively copying its members.
|
||||
*/
|
||||
@JRubyMethod(name = "deep_copy", meta = true)
|
||||
public static IRubyObject deepCopy(ThreadContext context, IRubyObject self, IRubyObject message) {
|
||||
if (message instanceof RubyMessage) {
|
||||
return ((RubyMessage) message).deepCopy(context);
|
||||
} else if (message instanceof RubyRepeatedField) {
|
||||
return ((RubyRepeatedField) message).deepCopy(context);
|
||||
} else {
|
||||
return ((RubyMap) message).deepCopy(context);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Google::Protobuf.discard_unknown(msg)
|
||||
*
|
||||
* Discard unknown fields in the given message object and recursively discard
|
||||
* unknown fields in submessages.
|
||||
*/
|
||||
@JRubyMethod(name = "discard_unknown", meta = true)
|
||||
public static IRubyObject discardUnknown(ThreadContext context, IRubyObject self, IRubyObject message) {
|
||||
((RubyMessage) message).discardUnknownFields(context);
|
||||
return context.nil;
|
||||
}
|
||||
}
|
423
deps/protobuf/ruby/src/main/java/com/google/protobuf/jruby/RubyRepeatedField.java
vendored
Normal file
423
deps/protobuf/ruby/src/main/java/com/google/protobuf/jruby/RubyRepeatedField.java
vendored
Normal file
@ -0,0 +1,423 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.google.protobuf.jruby;
|
||||
|
||||
import com.google.protobuf.Descriptors.FieldDescriptor;
|
||||
import org.jruby.*;
|
||||
import org.jruby.anno.JRubyClass;
|
||||
import org.jruby.anno.JRubyMethod;
|
||||
import org.jruby.runtime.Block;
|
||||
import org.jruby.runtime.ObjectAllocator;
|
||||
import org.jruby.runtime.ThreadContext;
|
||||
import org.jruby.runtime.builtin.IRubyObject;
|
||||
import java.util.Arrays;
|
||||
|
||||
@JRubyClass(name = "RepeatedClass", include = "Enumerable")
|
||||
public class RubyRepeatedField extends RubyObject {
|
||||
public static void createRubyRepeatedField(Ruby runtime) {
|
||||
RubyModule mProtobuf = runtime.getClassFromPath("Google::Protobuf");
|
||||
RubyClass cRepeatedField = mProtobuf.defineClassUnder("RepeatedField", runtime.getObject(),
|
||||
new ObjectAllocator() {
|
||||
@Override
|
||||
public IRubyObject allocate(Ruby runtime, RubyClass klazz) {
|
||||
return new RubyRepeatedField(runtime, klazz);
|
||||
}
|
||||
});
|
||||
cRepeatedField.defineAnnotatedMethods(RubyRepeatedField.class);
|
||||
cRepeatedField.includeModule(runtime.getEnumerable());
|
||||
}
|
||||
|
||||
public RubyRepeatedField(Ruby runtime, RubyClass klazz) {
|
||||
super(runtime, klazz);
|
||||
}
|
||||
|
||||
public RubyRepeatedField(Ruby runtime, RubyClass klazz, FieldDescriptor.Type fieldType, IRubyObject typeClass) {
|
||||
this(runtime, klazz);
|
||||
this.fieldType = fieldType;
|
||||
this.storage = runtime.newArray();
|
||||
this.typeClass = typeClass;
|
||||
}
|
||||
|
||||
@JRubyMethod(required = 1, optional = 2)
|
||||
public IRubyObject initialize(ThreadContext context, IRubyObject[] args) {
|
||||
Ruby runtime = context.runtime;
|
||||
this.storage = runtime.newArray();
|
||||
IRubyObject ary = null;
|
||||
if (!(args[0] instanceof RubySymbol)) {
|
||||
throw runtime.newArgumentError("Expected Symbol for type name");
|
||||
}
|
||||
this.fieldType = Utils.rubyToFieldType(args[0]);
|
||||
if (fieldType == FieldDescriptor.Type.MESSAGE
|
||||
|| fieldType == FieldDescriptor.Type.ENUM) {
|
||||
if (args.length < 2)
|
||||
throw runtime.newArgumentError("Expected at least 2 arguments for message/enum");
|
||||
typeClass = args[1];
|
||||
if (args.length > 2)
|
||||
ary = args[2];
|
||||
Utils.validateTypeClass(context, fieldType, typeClass);
|
||||
} else {
|
||||
if (args.length > 2)
|
||||
throw runtime.newArgumentError("Too many arguments: expected 1 or 2");
|
||||
if (args.length > 1)
|
||||
ary = args[1];
|
||||
}
|
||||
if (ary != null) {
|
||||
RubyArray arr = ary.convertToArray();
|
||||
for (int i = 0; i < arr.size(); i++) {
|
||||
this.storage.add(arr.eltInternal(i));
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* RepeatedField.[]=(index, value)
|
||||
*
|
||||
* Sets the element at the given index. On out-of-bounds assignments, extends
|
||||
* the array and fills the hole (if any) with default values.
|
||||
*/
|
||||
@JRubyMethod(name = "[]=")
|
||||
public IRubyObject indexSet(ThreadContext context, IRubyObject index, IRubyObject value) {
|
||||
int arrIndex = normalizeArrayIndex(index);
|
||||
value = Utils.checkType(context, fieldType, name, value, (RubyModule) typeClass);
|
||||
IRubyObject defaultValue = defaultValue(context);
|
||||
for (int i = this.storage.size(); i < arrIndex; i++) {
|
||||
this.storage.set(i, defaultValue);
|
||||
}
|
||||
this.storage.set(arrIndex, value);
|
||||
return context.runtime.getNil();
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* RepeatedField.[](index) => value
|
||||
*
|
||||
* Accesses the element at the given index. Returns nil on out-of-bounds
|
||||
*/
|
||||
@JRubyMethod(required=1, optional=1, name = {"at", "[]"})
|
||||
public IRubyObject index(ThreadContext context, IRubyObject[] args) {
|
||||
if (args.length == 1){
|
||||
IRubyObject arg = args[0];
|
||||
if (Utils.isRubyNum(arg)) {
|
||||
/* standard case */
|
||||
int arrIndex = normalizeArrayIndex(arg);
|
||||
if (arrIndex < 0 || arrIndex >= this.storage.size()) {
|
||||
return context.runtime.getNil();
|
||||
}
|
||||
return this.storage.eltInternal(arrIndex);
|
||||
} else if (arg instanceof RubyRange) {
|
||||
RubyRange range = ((RubyRange) arg);
|
||||
|
||||
int beg = RubyNumeric.num2int(range.first(context));
|
||||
int len = RubyNumeric.num2int(range.size(context));
|
||||
|
||||
if (len == 0) return context.runtime.newEmptyArray();
|
||||
|
||||
return this.storage.subseq(beg, len);
|
||||
}
|
||||
}
|
||||
/* assume 2 arguments */
|
||||
int beg = RubyNumeric.num2int(args[0]);
|
||||
int len = RubyNumeric.num2int(args[1]);
|
||||
if (beg < 0) {
|
||||
beg += this.storage.size();
|
||||
}
|
||||
if (beg >= this.storage.size()) {
|
||||
return context.runtime.getNil();
|
||||
}
|
||||
return this.storage.subseq(beg, len);
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* RepeatedField.push(value)
|
||||
*
|
||||
* Adds a new element to the repeated field.
|
||||
*/
|
||||
@JRubyMethod(name = {"push", "<<"}, required = 1, rest = true)
|
||||
public IRubyObject push(ThreadContext context, IRubyObject[] args) {
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
IRubyObject val = args[i];
|
||||
if (fieldType != FieldDescriptor.Type.MESSAGE || !val.isNil()) {
|
||||
val = Utils.checkType(context, fieldType, name, val, (RubyModule) typeClass);
|
||||
}
|
||||
storage.add(val);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/*
|
||||
* private Ruby method used by RepeatedField.pop
|
||||
*/
|
||||
@JRubyMethod(visibility = org.jruby.runtime.Visibility.PRIVATE)
|
||||
public IRubyObject pop_one(ThreadContext context) {
|
||||
IRubyObject ret = this.storage.last();
|
||||
this.storage.remove(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* RepeatedField.replace(list)
|
||||
*
|
||||
* Replaces the contents of the repeated field with the given list of elements.
|
||||
*/
|
||||
@JRubyMethod
|
||||
public IRubyObject replace(ThreadContext context, IRubyObject list) {
|
||||
RubyArray arr = (RubyArray) list;
|
||||
checkArrayElementType(context, arr);
|
||||
this.storage = arr;
|
||||
return this;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* RepeatedField.clear
|
||||
*
|
||||
* Clears (removes all elements from) this repeated field.
|
||||
*/
|
||||
@JRubyMethod
|
||||
public IRubyObject clear(ThreadContext context) {
|
||||
this.storage.clear();
|
||||
return this;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* RepeatedField.length
|
||||
*
|
||||
* Returns the length of this repeated field.
|
||||
*/
|
||||
@JRubyMethod(name = {"length", "size"})
|
||||
public IRubyObject length(ThreadContext context) {
|
||||
return context.runtime.newFixnum(this.storage.size());
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* RepeatedField.+(other) => repeated field
|
||||
*
|
||||
* Returns a new repeated field that contains the concatenated list of this
|
||||
* repeated field's elements and other's elements. The other (second) list may
|
||||
* be either another repeated field or a Ruby array.
|
||||
*/
|
||||
@JRubyMethod(name = {"+"})
|
||||
public IRubyObject plus(ThreadContext context, IRubyObject list) {
|
||||
RubyRepeatedField dup = (RubyRepeatedField) dup(context);
|
||||
if (list instanceof RubyArray) {
|
||||
checkArrayElementType(context, (RubyArray) list);
|
||||
dup.storage.addAll((RubyArray) list);
|
||||
} else {
|
||||
RubyRepeatedField repeatedField = (RubyRepeatedField) list;
|
||||
if (! fieldType.equals(repeatedField.fieldType) || (typeClass != null && !
|
||||
typeClass.equals(repeatedField.typeClass)))
|
||||
throw context.runtime.newArgumentError("Attempt to append RepeatedField with different element type.");
|
||||
dup.storage.addAll((RubyArray) repeatedField.toArray(context));
|
||||
}
|
||||
return dup;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* RepeatedField.concat(other) => self
|
||||
*
|
||||
* concats the passed in array to self. Returns a Ruby array.
|
||||
*/
|
||||
@JRubyMethod
|
||||
public IRubyObject concat(ThreadContext context, IRubyObject list) {
|
||||
if (list instanceof RubyArray) {
|
||||
checkArrayElementType(context, (RubyArray) list);
|
||||
this.storage.addAll((RubyArray) list);
|
||||
} else {
|
||||
RubyRepeatedField repeatedField = (RubyRepeatedField) list;
|
||||
if (! fieldType.equals(repeatedField.fieldType) || (typeClass != null && !
|
||||
typeClass.equals(repeatedField.typeClass)))
|
||||
throw context.runtime.newArgumentError("Attempt to append RepeatedField with different element type.");
|
||||
this.storage.addAll((RubyArray) repeatedField.toArray(context));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* RepeatedField.hash => hash_value
|
||||
*
|
||||
* Returns a hash value computed from this repeated field's elements.
|
||||
*/
|
||||
@JRubyMethod
|
||||
public IRubyObject hash(ThreadContext context) {
|
||||
int hashCode = this.storage.hashCode();
|
||||
return context.runtime.newFixnum(hashCode);
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* RepeatedField.==(other) => boolean
|
||||
*
|
||||
* Compares this repeated field to another. Repeated fields are equal if their
|
||||
* element types are equal, their lengths are equal, and each element is equal.
|
||||
* Elements are compared as per normal Ruby semantics, by calling their :==
|
||||
* methods (or performing a more efficient comparison for primitive types).
|
||||
*/
|
||||
@JRubyMethod(name = "==")
|
||||
public IRubyObject eq(ThreadContext context, IRubyObject other) {
|
||||
return this.toArray(context).op_equal(context, other);
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* RepeatedField.each(&block)
|
||||
*
|
||||
* Invokes the block once for each element of the repeated field. RepeatedField
|
||||
* also includes Enumerable; combined with this method, the repeated field thus
|
||||
* acts like an ordinary Ruby sequence.
|
||||
*/
|
||||
@JRubyMethod
|
||||
public IRubyObject each(ThreadContext context, Block block) {
|
||||
this.storage.each(context, block);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@JRubyMethod(name = {"to_ary", "to_a"})
|
||||
public IRubyObject toArray(ThreadContext context) {
|
||||
return this.storage;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* RepeatedField.dup => repeated_field
|
||||
*
|
||||
* Duplicates this repeated field with a shallow copy. References to all
|
||||
* non-primitive element objects (e.g., submessages) are shared.
|
||||
*/
|
||||
@JRubyMethod
|
||||
public IRubyObject dup(ThreadContext context) {
|
||||
RubyRepeatedField dup = new RubyRepeatedField(context.runtime, metaClass, fieldType, typeClass);
|
||||
dup.push(context, storage.toJavaArray());
|
||||
return dup;
|
||||
}
|
||||
|
||||
@JRubyMethod
|
||||
public IRubyObject inspect() {
|
||||
return storage.inspect();
|
||||
}
|
||||
|
||||
// Java API
|
||||
protected IRubyObject get(int index) {
|
||||
return this.storage.eltInternal(index);
|
||||
}
|
||||
|
||||
protected RubyRepeatedField deepCopy(ThreadContext context) {
|
||||
RubyRepeatedField copy = new RubyRepeatedField(context.runtime, metaClass, fieldType, typeClass);
|
||||
for (int i = 0; i < size(); i++) {
|
||||
IRubyObject value = storage.eltInternal(i);
|
||||
if (fieldType == FieldDescriptor.Type.MESSAGE) {
|
||||
copy.storage.add(((RubyMessage) value).deepCopy(context));
|
||||
} else {
|
||||
copy.storage.add(value);
|
||||
}
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
protected void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
protected int size() {
|
||||
return this.storage.size();
|
||||
}
|
||||
|
||||
private IRubyObject defaultValue(ThreadContext context) {
|
||||
SentinelOuterClass.Sentinel sentinel = SentinelOuterClass.Sentinel.getDefaultInstance();
|
||||
Object value;
|
||||
switch (fieldType) {
|
||||
case INT32:
|
||||
value = sentinel.getDefaultInt32();
|
||||
break;
|
||||
case INT64:
|
||||
value = sentinel.getDefaultInt64();
|
||||
break;
|
||||
case UINT32:
|
||||
value = sentinel.getDefaultUnit32();
|
||||
break;
|
||||
case UINT64:
|
||||
value = sentinel.getDefaultUint64();
|
||||
break;
|
||||
case FLOAT:
|
||||
value = sentinel.getDefaultFloat();
|
||||
break;
|
||||
case DOUBLE:
|
||||
value = sentinel.getDefaultDouble();
|
||||
break;
|
||||
case BOOL:
|
||||
value = sentinel.getDefaultBool();
|
||||
break;
|
||||
case BYTES:
|
||||
value = sentinel.getDefaultBytes();
|
||||
break;
|
||||
case STRING:
|
||||
value = sentinel.getDefaultString();
|
||||
break;
|
||||
case ENUM:
|
||||
IRubyObject defaultEnumLoc = context.runtime.newFixnum(0);
|
||||
return RubyEnum.lookup(context, typeClass, defaultEnumLoc);
|
||||
default:
|
||||
return context.runtime.getNil();
|
||||
}
|
||||
return Utils.wrapPrimaryValue(context, fieldType, value);
|
||||
}
|
||||
|
||||
private void checkArrayElementType(ThreadContext context, RubyArray arr) {
|
||||
for (int i = 0; i < arr.getLength(); i++) {
|
||||
Utils.checkType(context, fieldType, name, arr.eltInternal(i), (RubyModule) typeClass);
|
||||
}
|
||||
}
|
||||
|
||||
private int normalizeArrayIndex(IRubyObject index) {
|
||||
int arrIndex = RubyNumeric.num2int(index);
|
||||
int arrSize = this.storage.size();
|
||||
if (arrIndex < 0 && arrSize > 0) {
|
||||
arrIndex = arrSize + arrIndex;
|
||||
}
|
||||
return arrIndex;
|
||||
}
|
||||
|
||||
private FieldDescriptor.Type fieldType;
|
||||
private IRubyObject typeClass;
|
||||
private RubyArray storage;
|
||||
private String name;
|
||||
}
|
776
deps/protobuf/ruby/src/main/java/com/google/protobuf/jruby/SentinelOuterClass.java
vendored
Normal file
776
deps/protobuf/ruby/src/main/java/com/google/protobuf/jruby/SentinelOuterClass.java
vendored
Normal file
@ -0,0 +1,776 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
// source: sentinel.proto
|
||||
|
||||
package com.google.protobuf.jruby;
|
||||
|
||||
public final class SentinelOuterClass {
|
||||
private SentinelOuterClass() {}
|
||||
public static void registerAllExtensions(
|
||||
com.google.protobuf.ExtensionRegistry registry) {
|
||||
}
|
||||
public interface SentinelOrBuilder extends
|
||||
// @@protoc_insertion_point(interface_extends:com.google.protobuf.jruby.Sentinel)
|
||||
com.google.protobuf.MessageOrBuilder {
|
||||
|
||||
/**
|
||||
* <code>optional int32 default_int32 = 1;</code>
|
||||
*/
|
||||
int getDefaultInt32();
|
||||
|
||||
/**
|
||||
* <code>optional int64 default_int64 = 2;</code>
|
||||
*/
|
||||
long getDefaultInt64();
|
||||
|
||||
/**
|
||||
* <code>optional uint32 default_unit32 = 3;</code>
|
||||
*/
|
||||
int getDefaultUnit32();
|
||||
|
||||
/**
|
||||
* <code>optional uint64 default_uint64 = 4;</code>
|
||||
*/
|
||||
long getDefaultUint64();
|
||||
|
||||
/**
|
||||
* <code>optional string default_string = 5;</code>
|
||||
*/
|
||||
java.lang.String getDefaultString();
|
||||
/**
|
||||
* <code>optional string default_string = 5;</code>
|
||||
*/
|
||||
com.google.protobuf.ByteString
|
||||
getDefaultStringBytes();
|
||||
|
||||
/**
|
||||
* <code>optional bool default_bool = 6;</code>
|
||||
*/
|
||||
boolean getDefaultBool();
|
||||
|
||||
/**
|
||||
* <code>optional float default_float = 7;</code>
|
||||
*/
|
||||
float getDefaultFloat();
|
||||
|
||||
/**
|
||||
* <code>optional double default_double = 8;</code>
|
||||
*/
|
||||
double getDefaultDouble();
|
||||
|
||||
/**
|
||||
* <code>optional bytes default_bytes = 9;</code>
|
||||
*/
|
||||
com.google.protobuf.ByteString getDefaultBytes();
|
||||
}
|
||||
/**
|
||||
* Protobuf type {@code com.google.protobuf.jruby.Sentinel}
|
||||
*/
|
||||
public static final class Sentinel extends
|
||||
com.google.protobuf.GeneratedMessage implements
|
||||
// @@protoc_insertion_point(message_implements:com.google.protobuf.jruby.Sentinel)
|
||||
SentinelOrBuilder {
|
||||
// Use Sentinel.newBuilder() to construct.
|
||||
private Sentinel(com.google.protobuf.GeneratedMessage.Builder builder) {
|
||||
super(builder);
|
||||
}
|
||||
private Sentinel() {
|
||||
defaultInt32_ = 0;
|
||||
defaultInt64_ = 0L;
|
||||
defaultUnit32_ = 0;
|
||||
defaultUint64_ = 0L;
|
||||
defaultString_ = "";
|
||||
defaultBool_ = false;
|
||||
defaultFloat_ = 0F;
|
||||
defaultDouble_ = 0D;
|
||||
defaultBytes_ = com.google.protobuf.ByteString.EMPTY;
|
||||
}
|
||||
|
||||
@java.lang.Override
|
||||
public final com.google.protobuf.UnknownFieldSet
|
||||
getUnknownFields() {
|
||||
return com.google.protobuf.UnknownFieldSet.getDefaultInstance();
|
||||
}
|
||||
public static final com.google.protobuf.Descriptors.Descriptor
|
||||
getDescriptor() {
|
||||
return com.google.protobuf.jruby.SentinelOuterClass.internal_static_com_google_protobuf_jruby_Sentinel_descriptor;
|
||||
}
|
||||
|
||||
protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
|
||||
internalGetFieldAccessorTable() {
|
||||
return com.google.protobuf.jruby.SentinelOuterClass.internal_static_com_google_protobuf_jruby_Sentinel_fieldAccessorTable
|
||||
.ensureFieldAccessorsInitialized(
|
||||
com.google.protobuf.jruby.SentinelOuterClass.Sentinel.class, com.google.protobuf.jruby.SentinelOuterClass.Sentinel.Builder.class);
|
||||
}
|
||||
|
||||
public static final com.google.protobuf.Parser<Sentinel> PARSER =
|
||||
new com.google.protobuf.AbstractParser<Sentinel>() {
|
||||
public Sentinel parsePartialFrom(
|
||||
com.google.protobuf.CodedInputStream input,
|
||||
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
|
||||
throws com.google.protobuf.InvalidProtocolBufferException {
|
||||
Builder builder = newBuilder();
|
||||
try {
|
||||
builder.mergeFrom(input, extensionRegistry);
|
||||
} catch (com.google.protobuf.InvalidProtocolBufferException e) {
|
||||
throw e.setUnfinishedMessage(builder.buildPartial());
|
||||
} catch (java.io.IOException e) {
|
||||
throw new com.google.protobuf.InvalidProtocolBufferException(
|
||||
e.getMessage()).setUnfinishedMessage(builder.buildPartial());
|
||||
}
|
||||
return builder.buildPartial();
|
||||
}
|
||||
};
|
||||
|
||||
@java.lang.Override
|
||||
public com.google.protobuf.Parser<Sentinel> getParserForType() {
|
||||
return PARSER;
|
||||
}
|
||||
|
||||
public static final int DEFAULT_INT32_FIELD_NUMBER = 1;
|
||||
private int defaultInt32_;
|
||||
/**
|
||||
* <code>optional int32 default_int32 = 1;</code>
|
||||
*/
|
||||
public int getDefaultInt32() {
|
||||
return defaultInt32_;
|
||||
}
|
||||
|
||||
public static final int DEFAULT_INT64_FIELD_NUMBER = 2;
|
||||
private long defaultInt64_;
|
||||
/**
|
||||
* <code>optional int64 default_int64 = 2;</code>
|
||||
*/
|
||||
public long getDefaultInt64() {
|
||||
return defaultInt64_;
|
||||
}
|
||||
|
||||
public static final int DEFAULT_UNIT32_FIELD_NUMBER = 3;
|
||||
private int defaultUnit32_;
|
||||
/**
|
||||
* <code>optional uint32 default_unit32 = 3;</code>
|
||||
*/
|
||||
public int getDefaultUnit32() {
|
||||
return defaultUnit32_;
|
||||
}
|
||||
|
||||
public static final int DEFAULT_UINT64_FIELD_NUMBER = 4;
|
||||
private long defaultUint64_;
|
||||
/**
|
||||
* <code>optional uint64 default_uint64 = 4;</code>
|
||||
*/
|
||||
public long getDefaultUint64() {
|
||||
return defaultUint64_;
|
||||
}
|
||||
|
||||
public static final int DEFAULT_STRING_FIELD_NUMBER = 5;
|
||||
private java.lang.Object defaultString_;
|
||||
/**
|
||||
* <code>optional string default_string = 5;</code>
|
||||
*/
|
||||
public java.lang.String getDefaultString() {
|
||||
java.lang.Object ref = defaultString_;
|
||||
if (ref instanceof java.lang.String) {
|
||||
return (java.lang.String) ref;
|
||||
} else {
|
||||
com.google.protobuf.ByteString bs =
|
||||
(com.google.protobuf.ByteString) ref;
|
||||
java.lang.String s = bs.toStringUtf8();
|
||||
if (bs.isValidUtf8()) {
|
||||
defaultString_ = s;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* <code>optional string default_string = 5;</code>
|
||||
*/
|
||||
public com.google.protobuf.ByteString
|
||||
getDefaultStringBytes() {
|
||||
java.lang.Object ref = defaultString_;
|
||||
if (ref instanceof java.lang.String) {
|
||||
com.google.protobuf.ByteString b =
|
||||
com.google.protobuf.ByteString.copyFromUtf8(
|
||||
(java.lang.String) ref);
|
||||
defaultString_ = b;
|
||||
return b;
|
||||
} else {
|
||||
return (com.google.protobuf.ByteString) ref;
|
||||
}
|
||||
}
|
||||
|
||||
public static final int DEFAULT_BOOL_FIELD_NUMBER = 6;
|
||||
private boolean defaultBool_;
|
||||
/**
|
||||
* <code>optional bool default_bool = 6;</code>
|
||||
*/
|
||||
public boolean getDefaultBool() {
|
||||
return defaultBool_;
|
||||
}
|
||||
|
||||
public static final int DEFAULT_FLOAT_FIELD_NUMBER = 7;
|
||||
private float defaultFloat_;
|
||||
/**
|
||||
* <code>optional float default_float = 7;</code>
|
||||
*/
|
||||
public float getDefaultFloat() {
|
||||
return defaultFloat_;
|
||||
}
|
||||
|
||||
public static final int DEFAULT_DOUBLE_FIELD_NUMBER = 8;
|
||||
private double defaultDouble_;
|
||||
/**
|
||||
* <code>optional double default_double = 8;</code>
|
||||
*/
|
||||
public double getDefaultDouble() {
|
||||
return defaultDouble_;
|
||||
}
|
||||
|
||||
public static final int DEFAULT_BYTES_FIELD_NUMBER = 9;
|
||||
private com.google.protobuf.ByteString defaultBytes_;
|
||||
/**
|
||||
* <code>optional bytes default_bytes = 9;</code>
|
||||
*/
|
||||
public com.google.protobuf.ByteString getDefaultBytes() {
|
||||
return defaultBytes_;
|
||||
}
|
||||
|
||||
public static com.google.protobuf.jruby.SentinelOuterClass.Sentinel parseFrom(
|
||||
com.google.protobuf.ByteString data)
|
||||
throws com.google.protobuf.InvalidProtocolBufferException {
|
||||
return PARSER.parseFrom(data);
|
||||
}
|
||||
public static com.google.protobuf.jruby.SentinelOuterClass.Sentinel parseFrom(
|
||||
com.google.protobuf.ByteString data,
|
||||
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
|
||||
throws com.google.protobuf.InvalidProtocolBufferException {
|
||||
return PARSER.parseFrom(data, extensionRegistry);
|
||||
}
|
||||
public static com.google.protobuf.jruby.SentinelOuterClass.Sentinel parseFrom(byte[] data)
|
||||
throws com.google.protobuf.InvalidProtocolBufferException {
|
||||
return PARSER.parseFrom(data);
|
||||
}
|
||||
public static com.google.protobuf.jruby.SentinelOuterClass.Sentinel parseFrom(
|
||||
byte[] data,
|
||||
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
|
||||
throws com.google.protobuf.InvalidProtocolBufferException {
|
||||
return PARSER.parseFrom(data, extensionRegistry);
|
||||
}
|
||||
public static com.google.protobuf.jruby.SentinelOuterClass.Sentinel parseFrom(java.io.InputStream input)
|
||||
throws java.io.IOException {
|
||||
return PARSER.parseFrom(input);
|
||||
}
|
||||
public static com.google.protobuf.jruby.SentinelOuterClass.Sentinel parseFrom(
|
||||
java.io.InputStream input,
|
||||
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
|
||||
throws java.io.IOException {
|
||||
return PARSER.parseFrom(input, extensionRegistry);
|
||||
}
|
||||
public static com.google.protobuf.jruby.SentinelOuterClass.Sentinel parseDelimitedFrom(java.io.InputStream input)
|
||||
throws java.io.IOException {
|
||||
return PARSER.parseDelimitedFrom(input);
|
||||
}
|
||||
public static com.google.protobuf.jruby.SentinelOuterClass.Sentinel parseDelimitedFrom(
|
||||
java.io.InputStream input,
|
||||
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
|
||||
throws java.io.IOException {
|
||||
return PARSER.parseDelimitedFrom(input, extensionRegistry);
|
||||
}
|
||||
public static com.google.protobuf.jruby.SentinelOuterClass.Sentinel parseFrom(
|
||||
com.google.protobuf.CodedInputStream input)
|
||||
throws java.io.IOException {
|
||||
return PARSER.parseFrom(input);
|
||||
}
|
||||
public static com.google.protobuf.jruby.SentinelOuterClass.Sentinel parseFrom(
|
||||
com.google.protobuf.CodedInputStream input,
|
||||
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
|
||||
throws java.io.IOException {
|
||||
return PARSER.parseFrom(input, extensionRegistry);
|
||||
}
|
||||
|
||||
public static Builder newBuilder() { return new Builder(); }
|
||||
public Builder newBuilderForType() { return newBuilder(); }
|
||||
public static Builder newBuilder(com.google.protobuf.jruby.SentinelOuterClass.Sentinel prototype) {
|
||||
return newBuilder().mergeFrom(prototype);
|
||||
}
|
||||
public Builder toBuilder() { return newBuilder(this); }
|
||||
|
||||
@java.lang.Override
|
||||
protected Builder newBuilderForType(
|
||||
com.google.protobuf.GeneratedMessage.BuilderParent parent) {
|
||||
Builder builder = new Builder(parent);
|
||||
return builder;
|
||||
}
|
||||
/**
|
||||
* Protobuf type {@code com.google.protobuf.jruby.Sentinel}
|
||||
*/
|
||||
public static final class Builder extends
|
||||
com.google.protobuf.GeneratedMessage.Builder<Builder> implements
|
||||
// @@protoc_insertion_point(builder_implements:com.google.protobuf.jruby.Sentinel)
|
||||
com.google.protobuf.jruby.SentinelOuterClass.SentinelOrBuilder {
|
||||
public static final com.google.protobuf.Descriptors.Descriptor
|
||||
getDescriptor() {
|
||||
return com.google.protobuf.jruby.SentinelOuterClass.internal_static_com_google_protobuf_jruby_Sentinel_descriptor;
|
||||
}
|
||||
|
||||
protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
|
||||
internalGetFieldAccessorTable() {
|
||||
return com.google.protobuf.jruby.SentinelOuterClass.internal_static_com_google_protobuf_jruby_Sentinel_fieldAccessorTable
|
||||
.ensureFieldAccessorsInitialized(
|
||||
com.google.protobuf.jruby.SentinelOuterClass.Sentinel.class, com.google.protobuf.jruby.SentinelOuterClass.Sentinel.Builder.class);
|
||||
}
|
||||
|
||||
// Construct using com.google.protobuf.jruby.SentinelOuterClass.Sentinel.newBuilder()
|
||||
private Builder() {
|
||||
maybeForceBuilderInitialization();
|
||||
}
|
||||
|
||||
private Builder(
|
||||
com.google.protobuf.GeneratedMessage.BuilderParent parent) {
|
||||
super(parent);
|
||||
maybeForceBuilderInitialization();
|
||||
}
|
||||
private void maybeForceBuilderInitialization() {
|
||||
if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {
|
||||
}
|
||||
}
|
||||
public Builder clear() {
|
||||
super.clear();
|
||||
defaultInt32_ = 0;
|
||||
|
||||
defaultInt64_ = 0L;
|
||||
|
||||
defaultUnit32_ = 0;
|
||||
|
||||
defaultUint64_ = 0L;
|
||||
|
||||
defaultString_ = "";
|
||||
|
||||
defaultBool_ = false;
|
||||
|
||||
defaultFloat_ = 0F;
|
||||
|
||||
defaultDouble_ = 0D;
|
||||
|
||||
defaultBytes_ = com.google.protobuf.ByteString.EMPTY;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public com.google.protobuf.Descriptors.Descriptor
|
||||
getDescriptorForType() {
|
||||
return com.google.protobuf.jruby.SentinelOuterClass.internal_static_com_google_protobuf_jruby_Sentinel_descriptor;
|
||||
}
|
||||
|
||||
public com.google.protobuf.jruby.SentinelOuterClass.Sentinel getDefaultInstanceForType() {
|
||||
return com.google.protobuf.jruby.SentinelOuterClass.Sentinel.getDefaultInstance();
|
||||
}
|
||||
|
||||
public com.google.protobuf.jruby.SentinelOuterClass.Sentinel build() {
|
||||
com.google.protobuf.jruby.SentinelOuterClass.Sentinel result = buildPartial();
|
||||
if (!result.isInitialized()) {
|
||||
throw newUninitializedMessageException(result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public com.google.protobuf.jruby.SentinelOuterClass.Sentinel buildPartial() {
|
||||
com.google.protobuf.jruby.SentinelOuterClass.Sentinel result = new com.google.protobuf.jruby.SentinelOuterClass.Sentinel(this);
|
||||
result.defaultInt32_ = defaultInt32_;
|
||||
result.defaultInt64_ = defaultInt64_;
|
||||
result.defaultUnit32_ = defaultUnit32_;
|
||||
result.defaultUint64_ = defaultUint64_;
|
||||
result.defaultString_ = defaultString_;
|
||||
result.defaultBool_ = defaultBool_;
|
||||
result.defaultFloat_ = defaultFloat_;
|
||||
result.defaultDouble_ = defaultDouble_;
|
||||
result.defaultBytes_ = defaultBytes_;
|
||||
onBuilt();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
private int defaultInt32_ ;
|
||||
/**
|
||||
* <code>optional int32 default_int32 = 1;</code>
|
||||
*/
|
||||
public int getDefaultInt32() {
|
||||
return defaultInt32_;
|
||||
}
|
||||
/**
|
||||
* <code>optional int32 default_int32 = 1;</code>
|
||||
*/
|
||||
public Builder setDefaultInt32(int value) {
|
||||
|
||||
defaultInt32_ = value;
|
||||
onChanged();
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* <code>optional int32 default_int32 = 1;</code>
|
||||
*/
|
||||
public Builder clearDefaultInt32() {
|
||||
|
||||
defaultInt32_ = 0;
|
||||
onChanged();
|
||||
return this;
|
||||
}
|
||||
|
||||
private long defaultInt64_ ;
|
||||
/**
|
||||
* <code>optional int64 default_int64 = 2;</code>
|
||||
*/
|
||||
public long getDefaultInt64() {
|
||||
return defaultInt64_;
|
||||
}
|
||||
/**
|
||||
* <code>optional int64 default_int64 = 2;</code>
|
||||
*/
|
||||
public Builder setDefaultInt64(long value) {
|
||||
|
||||
defaultInt64_ = value;
|
||||
onChanged();
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* <code>optional int64 default_int64 = 2;</code>
|
||||
*/
|
||||
public Builder clearDefaultInt64() {
|
||||
|
||||
defaultInt64_ = 0L;
|
||||
onChanged();
|
||||
return this;
|
||||
}
|
||||
|
||||
private int defaultUnit32_ ;
|
||||
/**
|
||||
* <code>optional uint32 default_unit32 = 3;</code>
|
||||
*/
|
||||
public int getDefaultUnit32() {
|
||||
return defaultUnit32_;
|
||||
}
|
||||
/**
|
||||
* <code>optional uint32 default_unit32 = 3;</code>
|
||||
*/
|
||||
public Builder setDefaultUnit32(int value) {
|
||||
|
||||
defaultUnit32_ = value;
|
||||
onChanged();
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* <code>optional uint32 default_unit32 = 3;</code>
|
||||
*/
|
||||
public Builder clearDefaultUnit32() {
|
||||
|
||||
defaultUnit32_ = 0;
|
||||
onChanged();
|
||||
return this;
|
||||
}
|
||||
|
||||
private long defaultUint64_ ;
|
||||
/**
|
||||
* <code>optional uint64 default_uint64 = 4;</code>
|
||||
*/
|
||||
public long getDefaultUint64() {
|
||||
return defaultUint64_;
|
||||
}
|
||||
/**
|
||||
* <code>optional uint64 default_uint64 = 4;</code>
|
||||
*/
|
||||
public Builder setDefaultUint64(long value) {
|
||||
|
||||
defaultUint64_ = value;
|
||||
onChanged();
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* <code>optional uint64 default_uint64 = 4;</code>
|
||||
*/
|
||||
public Builder clearDefaultUint64() {
|
||||
|
||||
defaultUint64_ = 0L;
|
||||
onChanged();
|
||||
return this;
|
||||
}
|
||||
|
||||
private java.lang.Object defaultString_ = "";
|
||||
/**
|
||||
* <code>optional string default_string = 5;</code>
|
||||
*/
|
||||
public java.lang.String getDefaultString() {
|
||||
java.lang.Object ref = defaultString_;
|
||||
if (!(ref instanceof java.lang.String)) {
|
||||
com.google.protobuf.ByteString bs =
|
||||
(com.google.protobuf.ByteString) ref;
|
||||
java.lang.String s = bs.toStringUtf8();
|
||||
if (bs.isValidUtf8()) {
|
||||
defaultString_ = s;
|
||||
}
|
||||
return s;
|
||||
} else {
|
||||
return (java.lang.String) ref;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* <code>optional string default_string = 5;</code>
|
||||
*/
|
||||
public com.google.protobuf.ByteString
|
||||
getDefaultStringBytes() {
|
||||
java.lang.Object ref = defaultString_;
|
||||
if (ref instanceof String) {
|
||||
com.google.protobuf.ByteString b =
|
||||
com.google.protobuf.ByteString.copyFromUtf8(
|
||||
(java.lang.String) ref);
|
||||
defaultString_ = b;
|
||||
return b;
|
||||
} else {
|
||||
return (com.google.protobuf.ByteString) ref;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* <code>optional string default_string = 5;</code>
|
||||
*/
|
||||
public Builder setDefaultString(
|
||||
java.lang.String value) {
|
||||
if (value == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
|
||||
defaultString_ = value;
|
||||
onChanged();
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* <code>optional string default_string = 5;</code>
|
||||
*/
|
||||
public Builder clearDefaultString() {
|
||||
|
||||
defaultString_ = getDefaultInstance().getDefaultString();
|
||||
onChanged();
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* <code>optional string default_string = 5;</code>
|
||||
*/
|
||||
public Builder setDefaultStringBytes(
|
||||
com.google.protobuf.ByteString value) {
|
||||
if (value == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
|
||||
defaultString_ = value;
|
||||
onChanged();
|
||||
return this;
|
||||
}
|
||||
|
||||
private boolean defaultBool_ ;
|
||||
/**
|
||||
* <code>optional bool default_bool = 6;</code>
|
||||
*/
|
||||
public boolean getDefaultBool() {
|
||||
return defaultBool_;
|
||||
}
|
||||
/**
|
||||
* <code>optional bool default_bool = 6;</code>
|
||||
*/
|
||||
public Builder setDefaultBool(boolean value) {
|
||||
|
||||
defaultBool_ = value;
|
||||
onChanged();
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* <code>optional bool default_bool = 6;</code>
|
||||
*/
|
||||
public Builder clearDefaultBool() {
|
||||
|
||||
defaultBool_ = false;
|
||||
onChanged();
|
||||
return this;
|
||||
}
|
||||
|
||||
private float defaultFloat_ ;
|
||||
/**
|
||||
* <code>optional float default_float = 7;</code>
|
||||
*/
|
||||
public float getDefaultFloat() {
|
||||
return defaultFloat_;
|
||||
}
|
||||
/**
|
||||
* <code>optional float default_float = 7;</code>
|
||||
*/
|
||||
public Builder setDefaultFloat(float value) {
|
||||
|
||||
defaultFloat_ = value;
|
||||
onChanged();
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* <code>optional float default_float = 7;</code>
|
||||
*/
|
||||
public Builder clearDefaultFloat() {
|
||||
|
||||
defaultFloat_ = 0F;
|
||||
onChanged();
|
||||
return this;
|
||||
}
|
||||
|
||||
private double defaultDouble_ ;
|
||||
/**
|
||||
* <code>optional double default_double = 8;</code>
|
||||
*/
|
||||
public double getDefaultDouble() {
|
||||
return defaultDouble_;
|
||||
}
|
||||
/**
|
||||
* <code>optional double default_double = 8;</code>
|
||||
*/
|
||||
public Builder setDefaultDouble(double value) {
|
||||
|
||||
defaultDouble_ = value;
|
||||
onChanged();
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* <code>optional double default_double = 8;</code>
|
||||
*/
|
||||
public Builder clearDefaultDouble() {
|
||||
|
||||
defaultDouble_ = 0D;
|
||||
onChanged();
|
||||
return this;
|
||||
}
|
||||
|
||||
private com.google.protobuf.ByteString defaultBytes_ = com.google.protobuf.ByteString.EMPTY;
|
||||
/**
|
||||
* <code>optional bytes default_bytes = 9;</code>
|
||||
*/
|
||||
public com.google.protobuf.ByteString getDefaultBytes() {
|
||||
return defaultBytes_;
|
||||
}
|
||||
/**
|
||||
* <code>optional bytes default_bytes = 9;</code>
|
||||
*/
|
||||
public Builder setDefaultBytes(com.google.protobuf.ByteString value) {
|
||||
if (value == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
|
||||
defaultBytes_ = value;
|
||||
onChanged();
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* <code>optional bytes default_bytes = 9;</code>
|
||||
*/
|
||||
public Builder clearDefaultBytes() {
|
||||
|
||||
defaultBytes_ = getDefaultInstance().getDefaultBytes();
|
||||
onChanged();
|
||||
return this;
|
||||
}
|
||||
public final Builder setUnknownFields(
|
||||
final com.google.protobuf.UnknownFieldSet unknownFields) {
|
||||
return this;
|
||||
}
|
||||
|
||||
public final Builder mergeUnknownFields(
|
||||
final com.google.protobuf.UnknownFieldSet unknownFields) {
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
// @@protoc_insertion_point(builder_scope:com.google.protobuf.jruby.Sentinel)
|
||||
}
|
||||
|
||||
// @@protoc_insertion_point(class_scope:com.google.protobuf.jruby.Sentinel)
|
||||
private static final com.google.protobuf.jruby.SentinelOuterClass.Sentinel defaultInstance;static {
|
||||
defaultInstance = new com.google.protobuf.jruby.SentinelOuterClass.Sentinel();
|
||||
}
|
||||
|
||||
public static com.google.protobuf.jruby.SentinelOuterClass.Sentinel getDefaultInstance() {
|
||||
return defaultInstance;
|
||||
}
|
||||
|
||||
public com.google.protobuf.jruby.SentinelOuterClass.Sentinel getDefaultInstanceForType() {
|
||||
return defaultInstance;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static final com.google.protobuf.Descriptors.Descriptor
|
||||
internal_static_com_google_protobuf_jruby_Sentinel_descriptor;
|
||||
private static
|
||||
com.google.protobuf.GeneratedMessage.FieldAccessorTable
|
||||
internal_static_com_google_protobuf_jruby_Sentinel_fieldAccessorTable;
|
||||
|
||||
public static com.google.protobuf.Descriptors.FileDescriptor
|
||||
getDescriptor() {
|
||||
return descriptor;
|
||||
}
|
||||
private static com.google.protobuf.Descriptors.FileDescriptor
|
||||
descriptor;
|
||||
static {
|
||||
java.lang.String[] descriptorData = {
|
||||
"\n\016sentinel.proto\022\031com.google.protobuf.jr" +
|
||||
"uby\"\334\001\n\010Sentinel\022\025\n\rdefault_int32\030\001 \001(\005\022" +
|
||||
"\025\n\rdefault_int64\030\002 \001(\003\022\026\n\016default_unit32" +
|
||||
"\030\003 \001(\r\022\026\n\016default_uint64\030\004 \001(\004\022\026\n\016defaul" +
|
||||
"t_string\030\005 \001(\t\022\024\n\014default_bool\030\006 \001(\010\022\025\n\r" +
|
||||
"default_float\030\007 \001(\002\022\026\n\016default_double\030\010 " +
|
||||
"\001(\001\022\025\n\rdefault_bytes\030\t \001(\014B\002H\002b\006proto3"
|
||||
};
|
||||
com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
|
||||
new com.google.protobuf.Descriptors.FileDescriptor. InternalDescriptorAssigner() {
|
||||
public com.google.protobuf.ExtensionRegistry assignDescriptors(
|
||||
com.google.protobuf.Descriptors.FileDescriptor root) {
|
||||
descriptor = root;
|
||||
return null;
|
||||
}
|
||||
};
|
||||
com.google.protobuf.Descriptors.FileDescriptor
|
||||
.internalBuildGeneratedFileFrom(descriptorData,
|
||||
new com.google.protobuf.Descriptors.FileDescriptor[] {
|
||||
}, assigner);
|
||||
internal_static_com_google_protobuf_jruby_Sentinel_descriptor =
|
||||
getDescriptor().getMessageTypes().get(0);
|
||||
internal_static_com_google_protobuf_jruby_Sentinel_fieldAccessorTable = new
|
||||
com.google.protobuf.GeneratedMessage.FieldAccessorTable(
|
||||
internal_static_com_google_protobuf_jruby_Sentinel_descriptor,
|
||||
new java.lang.String[] { "DefaultInt32", "DefaultInt64", "DefaultUnit32", "DefaultUint64", "DefaultString", "DefaultBool", "DefaultFloat", "DefaultDouble", "DefaultBytes", });
|
||||
}
|
||||
|
||||
// @@protoc_insertion_point(outer_class_scope)
|
||||
}
|
345
deps/protobuf/ruby/src/main/java/com/google/protobuf/jruby/Utils.java
vendored
Normal file
345
deps/protobuf/ruby/src/main/java/com/google/protobuf/jruby/Utils.java
vendored
Normal file
@ -0,0 +1,345 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.google.protobuf.jruby;
|
||||
|
||||
import com.google.protobuf.ByteString;
|
||||
import com.google.protobuf.DescriptorProtos.FieldDescriptorProto;
|
||||
import com.google.protobuf.Descriptors.FieldDescriptor;
|
||||
import org.jcodings.specific.ASCIIEncoding;
|
||||
import org.jruby.*;
|
||||
import org.jruby.exceptions.RaiseException;
|
||||
import org.jruby.ext.bigdecimal.RubyBigDecimal;
|
||||
import org.jruby.runtime.Block;
|
||||
import org.jruby.runtime.Helpers;
|
||||
import org.jruby.runtime.ThreadContext;
|
||||
import org.jruby.runtime.builtin.IRubyObject;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
public class Utils {
|
||||
public static FieldDescriptor.Type rubyToFieldType(IRubyObject typeClass) {
|
||||
return FieldDescriptor.Type.valueOf(typeClass.asJavaString().toUpperCase());
|
||||
}
|
||||
|
||||
public static IRubyObject fieldTypeToRuby(ThreadContext context, FieldDescriptor.Type type) {
|
||||
return fieldTypeToRuby(context, type.name());
|
||||
}
|
||||
|
||||
public static IRubyObject fieldTypeToRuby(ThreadContext context, FieldDescriptorProto.Type type) {
|
||||
return fieldTypeToRuby(context, type.name());
|
||||
}
|
||||
|
||||
private static IRubyObject fieldTypeToRuby(ThreadContext context, String typeName) {
|
||||
|
||||
return context.runtime.newSymbol(typeName.replace("TYPE_", "").toLowerCase());
|
||||
}
|
||||
|
||||
public static IRubyObject checkType(ThreadContext context, FieldDescriptor.Type fieldType,
|
||||
String fieldName, IRubyObject value, RubyModule typeClass) {
|
||||
Ruby runtime = context.runtime;
|
||||
|
||||
switch(fieldType) {
|
||||
case SFIXED32:
|
||||
case SFIXED64:
|
||||
case FIXED64:
|
||||
case SINT64:
|
||||
case SINT32:
|
||||
case FIXED32:
|
||||
case INT32:
|
||||
case INT64:
|
||||
case UINT32:
|
||||
case UINT64:
|
||||
if (!isRubyNum(value))
|
||||
throw createExpectedTypeError(context, "number", "integral", fieldName, value);
|
||||
|
||||
if (value instanceof RubyFloat) {
|
||||
double doubleVal = RubyNumeric.num2dbl(value);
|
||||
if (Math.floor(doubleVal) != doubleVal) {
|
||||
throw runtime.newRangeError("Non-integral floating point value assigned to integer field '" + fieldName + "' (given " + value.getMetaClass() + ").");
|
||||
}
|
||||
}
|
||||
if (fieldType == FieldDescriptor.Type.UINT32 || fieldType == FieldDescriptor.Type.UINT64 ||
|
||||
fieldType == FieldDescriptor.Type.FIXED32 || fieldType == FieldDescriptor.Type.FIXED64) {
|
||||
if (((RubyNumeric) value).isNegative()) {
|
||||
throw runtime.newRangeError("Assigning negative value to unsigned integer field '" + fieldName + "' (given " + value.getMetaClass() + ").");
|
||||
}
|
||||
}
|
||||
|
||||
switch(fieldType) {
|
||||
case INT32:
|
||||
RubyNumeric.num2int(value);
|
||||
break;
|
||||
case UINT32:
|
||||
case FIXED32:
|
||||
num2uint(value);
|
||||
break;
|
||||
case UINT64:
|
||||
case FIXED64:
|
||||
num2ulong(context.runtime, value);
|
||||
break;
|
||||
default:
|
||||
RubyNumeric.num2long(value);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case FLOAT:
|
||||
if (!isRubyNum(value))
|
||||
throw createExpectedTypeError(context, "number", "float", fieldName, value);
|
||||
break;
|
||||
case DOUBLE:
|
||||
if (!isRubyNum(value))
|
||||
throw createExpectedTypeError(context, "number", "double", fieldName, value);
|
||||
break;
|
||||
case BOOL:
|
||||
if (!(value instanceof RubyBoolean))
|
||||
throw createInvalidTypeError(context, "boolean", fieldName, value);
|
||||
break;
|
||||
case BYTES:
|
||||
value = validateAndEncodeString(context, "bytes", fieldName, value, "Encoding::ASCII_8BIT");
|
||||
break;
|
||||
case STRING:
|
||||
value = validateAndEncodeString(context, "string", fieldName, symToString(value), "Encoding::UTF_8");
|
||||
break;
|
||||
case MESSAGE:
|
||||
if (value.getMetaClass() != typeClass) {
|
||||
// See if we can convert the value before flagging it as invalid
|
||||
String className = typeClass.getName();
|
||||
|
||||
if (className.equals("Google::Protobuf::Timestamp") && value instanceof RubyTime) {
|
||||
RubyTime rt = (RubyTime) value;
|
||||
RubyHash timestampArgs =
|
||||
Helpers.constructHash(runtime,
|
||||
runtime.newString("nanos"), rt.nsec(), false,
|
||||
runtime.newString("seconds"), rt.to_i(), false);
|
||||
return ((RubyClass) typeClass).newInstance(context, timestampArgs, Block.NULL_BLOCK);
|
||||
|
||||
} else if (className.equals("Google::Protobuf::Duration") && value instanceof RubyNumeric) {
|
||||
IRubyObject seconds;
|
||||
if (value instanceof RubyFloat) {
|
||||
seconds = ((RubyFloat) value).truncate(context);
|
||||
} else if (value instanceof RubyRational) {
|
||||
seconds = ((RubyRational) value).to_i(context);
|
||||
} else if (value instanceof RubyBigDecimal) {
|
||||
seconds = ((RubyBigDecimal) value).to_int(context);
|
||||
} else {
|
||||
seconds = ((RubyInteger) value).to_i();
|
||||
}
|
||||
|
||||
IRubyObject nanos = ((RubyNumeric) value).remainder(context, RubyFixnum.one(runtime));
|
||||
if (nanos instanceof RubyFloat) {
|
||||
nanos = ((RubyFloat) nanos).op_mul(context, 1000000000);
|
||||
} else if (nanos instanceof RubyRational) {
|
||||
nanos = ((RubyRational) nanos).op_mul(context, runtime.newFixnum(1000000000));
|
||||
} else if (nanos instanceof RubyBigDecimal) {
|
||||
nanos = ((RubyBigDecimal) nanos).op_mul(context, runtime.newFixnum(1000000000));
|
||||
} else {
|
||||
nanos = ((RubyInteger) nanos).op_mul(context, 1000000000);
|
||||
}
|
||||
|
||||
RubyHash durationArgs =
|
||||
Helpers.constructHash(runtime,
|
||||
runtime.newString("nanos"), ((RubyNumeric) nanos).round(context), false,
|
||||
runtime.newString("seconds"), seconds, false);
|
||||
return ((RubyClass) typeClass).newInstance(context, durationArgs, Block.NULL_BLOCK);
|
||||
}
|
||||
|
||||
// Not able to convert so flag as invalid
|
||||
throw createTypeError(context, "Invalid type " + value.getMetaClass() + " to assign to submessage field '" + fieldName + "'.");
|
||||
}
|
||||
|
||||
break;
|
||||
case ENUM:
|
||||
boolean isValid = ((RubyEnumDescriptor) typeClass.getInstanceVariable(DESCRIPTOR_INSTANCE_VAR)).isValidValue(context, value);
|
||||
if (!isValid) {
|
||||
throw runtime.newRangeError("Unknown symbol value for enum field '" + fieldName + "'.");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
public static IRubyObject wrapPrimaryValue(ThreadContext context, FieldDescriptor.Type fieldType, Object value) {
|
||||
return wrapPrimaryValue(context, fieldType, value, false);
|
||||
}
|
||||
|
||||
public static IRubyObject wrapPrimaryValue(ThreadContext context, FieldDescriptor.Type fieldType, Object value, boolean encodeBytes) {
|
||||
Ruby runtime = context.runtime;
|
||||
switch (fieldType) {
|
||||
case INT32:
|
||||
case SFIXED32:
|
||||
case SINT32:
|
||||
return runtime.newFixnum((Integer) value);
|
||||
case SFIXED64:
|
||||
case SINT64:
|
||||
case INT64:
|
||||
return runtime.newFixnum((Long) value);
|
||||
case FIXED32:
|
||||
case UINT32:
|
||||
return runtime.newFixnum(((Integer) value) & (-1l >>> 32));
|
||||
case FIXED64:
|
||||
case UINT64:
|
||||
long ret = (Long) value;
|
||||
return ret >= 0 ? runtime.newFixnum(ret) :
|
||||
RubyBignum.newBignum(runtime, UINT64_COMPLEMENTARY.add(new BigInteger(ret + "")));
|
||||
case FLOAT:
|
||||
return runtime.newFloat((Float) value);
|
||||
case DOUBLE:
|
||||
return runtime.newFloat((Double) value);
|
||||
case BOOL:
|
||||
return (Boolean) value ? runtime.getTrue() : runtime.getFalse();
|
||||
case BYTES: {
|
||||
IRubyObject wrapped = encodeBytes ?
|
||||
RubyString.newString(runtime, ((ByteString) value).toStringUtf8(), ASCIIEncoding.INSTANCE) :
|
||||
RubyString.newString(runtime, ((ByteString) value).toByteArray());
|
||||
wrapped.setFrozen(true);
|
||||
return wrapped;
|
||||
}
|
||||
case STRING: {
|
||||
IRubyObject wrapped = runtime.newString(value.toString());
|
||||
wrapped.setFrozen(true);
|
||||
return wrapped;
|
||||
}
|
||||
default:
|
||||
return runtime.getNil();
|
||||
}
|
||||
}
|
||||
|
||||
public static int num2uint(IRubyObject value) {
|
||||
long longVal = RubyNumeric.num2long(value);
|
||||
if (longVal > UINT_MAX)
|
||||
throw value.getRuntime().newRangeError("Integer " + longVal + " too big to convert to 'unsigned int'");
|
||||
long num = longVal;
|
||||
if (num > Integer.MAX_VALUE || num < Integer.MIN_VALUE)
|
||||
// encode to UINT32
|
||||
num = (-longVal ^ (-1l >>> 32) ) + 1;
|
||||
RubyNumeric.checkInt(value, num);
|
||||
return (int) num;
|
||||
}
|
||||
|
||||
public static long num2ulong(Ruby runtime, IRubyObject value) {
|
||||
if (value instanceof RubyFloat) {
|
||||
RubyBignum bignum = RubyBignum.newBignum(runtime, ((RubyFloat) value).getDoubleValue());
|
||||
return RubyBignum.big2ulong(bignum);
|
||||
} else if (value instanceof RubyBignum) {
|
||||
return RubyBignum.big2ulong((RubyBignum) value);
|
||||
} else {
|
||||
return RubyNumeric.num2long(value);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper to make it easier to support symbols being passed instead of strings
|
||||
*/
|
||||
public static IRubyObject symToString(IRubyObject sym) {
|
||||
if (sym instanceof RubySymbol) {
|
||||
return ((RubySymbol) sym).id2name();
|
||||
}
|
||||
return sym;
|
||||
}
|
||||
|
||||
public static void checkNameAvailability(ThreadContext context, String name) {
|
||||
if (context.runtime.getObject().getConstantAt(name) != null)
|
||||
throw context.runtime.newNameError(name + " is already defined", name);
|
||||
}
|
||||
|
||||
public static boolean isMapEntry(FieldDescriptor fieldDescriptor) {
|
||||
return fieldDescriptor.getType() == FieldDescriptor.Type.MESSAGE &&
|
||||
fieldDescriptor.isRepeated() &&
|
||||
fieldDescriptor.getMessageType().getOptions().getMapEntry();
|
||||
}
|
||||
|
||||
public static RaiseException createTypeError(ThreadContext context, String message) {
|
||||
if (cTypeError == null) {
|
||||
cTypeError = (RubyClass) context.runtime.getClassFromPath("Google::Protobuf::TypeError");
|
||||
}
|
||||
return RaiseException.from(context.runtime, cTypeError, message);
|
||||
}
|
||||
|
||||
public static RaiseException createExpectedTypeError(ThreadContext context, String type, String fieldType, String fieldName, IRubyObject value) {
|
||||
return createTypeError(context, String.format(EXPECTED_TYPE_ERROR_FORMAT, type, fieldType, fieldName, value.getMetaClass()));
|
||||
}
|
||||
|
||||
public static RaiseException createInvalidTypeError(ThreadContext context, String fieldType, String fieldName, IRubyObject value) {
|
||||
return createTypeError(context, String.format(INVALID_TYPE_ERROR_FORMAT, fieldType, fieldName, value.getMetaClass()));
|
||||
}
|
||||
|
||||
protected static boolean isRubyNum(Object value) {
|
||||
return value instanceof RubyFixnum || value instanceof RubyFloat || value instanceof RubyBignum;
|
||||
}
|
||||
|
||||
protected static void validateTypeClass(ThreadContext context, FieldDescriptor.Type type, IRubyObject value) {
|
||||
Ruby runtime = context.runtime;
|
||||
if (!(value instanceof RubyModule)) {
|
||||
throw runtime.newArgumentError("TypeClass has incorrect type");
|
||||
}
|
||||
RubyModule klass = (RubyModule) value;
|
||||
IRubyObject descriptor = klass.getInstanceVariable(DESCRIPTOR_INSTANCE_VAR);
|
||||
if (descriptor.isNil()) {
|
||||
throw runtime.newArgumentError("Type class has no descriptor. Please pass a " +
|
||||
"class or enum as returned by the DescriptorPool.");
|
||||
}
|
||||
if (type == FieldDescriptor.Type.MESSAGE) {
|
||||
if (! (descriptor instanceof RubyDescriptor)) {
|
||||
throw runtime.newArgumentError("Descriptor has an incorrect type");
|
||||
}
|
||||
} else if (type == FieldDescriptor.Type.ENUM) {
|
||||
if (! (descriptor instanceof RubyEnumDescriptor)) {
|
||||
throw runtime.newArgumentError("Descriptor has an incorrect type");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static IRubyObject validateAndEncodeString(ThreadContext context, String fieldType, String fieldName, IRubyObject value, String encoding) {
|
||||
if (!(value instanceof RubyString))
|
||||
throw createInvalidTypeError(context, fieldType, fieldName, value);
|
||||
|
||||
value = ((RubyString) value).encode(context, context.runtime.evalScriptlet(encoding));
|
||||
value.setFrozen(true);
|
||||
return value;
|
||||
}
|
||||
|
||||
public static final String DESCRIPTOR_INSTANCE_VAR = "@descriptor";
|
||||
|
||||
public static final String EQUAL_SIGN = "=";
|
||||
|
||||
private static final BigInteger UINT64_COMPLEMENTARY = new BigInteger("18446744073709551616"); //Math.pow(2, 64)
|
||||
|
||||
private static final String EXPECTED_TYPE_ERROR_FORMAT = "Expected %s type for %s field '%s' (given %s).";
|
||||
private static final String INVALID_TYPE_ERROR_FORMAT = "Invalid argument for %s field '%s' (given %s).";
|
||||
|
||||
private static final long UINT_MAX = 0xffffffffl;
|
||||
|
||||
private static RubyClass cTypeError;
|
||||
}
|
62
deps/protobuf/ruby/src/main/java/google/ProtobufJavaService.java
vendored
Normal file
62
deps/protobuf/ruby/src/main/java/google/ProtobufJavaService.java
vendored
Normal file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package google;
|
||||
|
||||
import com.google.protobuf.jruby.*;
|
||||
import org.jruby.Ruby;
|
||||
import org.jruby.runtime.load.BasicLibraryService;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class ProtobufJavaService implements BasicLibraryService {
|
||||
@Override
|
||||
public boolean basicLoad(Ruby ruby) throws IOException {
|
||||
ruby.defineModule("Google");
|
||||
|
||||
/*
|
||||
* The order these happen in is important because we
|
||||
* save a static reference to some classes and they
|
||||
* need to exist before we try to save a reference to them
|
||||
*/
|
||||
RubyProtobuf.createProtobuf(ruby);
|
||||
RubyFileDescriptor.createRubyFileDescriptor(ruby);
|
||||
RubyEnumDescriptor.createRubyEnumDescriptor(ruby);
|
||||
RubyRepeatedField.createRubyRepeatedField(ruby);
|
||||
RubyFieldDescriptor.createRubyFieldDescriptor(ruby);
|
||||
RubyMap.createRubyMap(ruby);
|
||||
RubyOneofDescriptor.createRubyOneofDescriptor(ruby);
|
||||
RubyDescriptor.createRubyDescriptor(ruby);
|
||||
RubyDescriptorPool.createRubyDescriptorPool(ruby);
|
||||
return true;
|
||||
}
|
||||
}
|
15
deps/protobuf/ruby/src/main/sentinel.proto
vendored
Normal file
15
deps/protobuf/ruby/src/main/sentinel.proto
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
syntax = "proto3";
|
||||
package com.google.protobuf.jruby;
|
||||
option optimize_for = CODE_SIZE;
|
||||
|
||||
message Sentinel {
|
||||
int32 default_int32 = 1;
|
||||
int64 default_int64 = 2;
|
||||
uint32 default_unit32 = 3;
|
||||
uint64 default_uint64 = 4;
|
||||
string default_string = 5;
|
||||
bool default_bool = 6;
|
||||
float default_float = 7;
|
||||
double default_double = 8;
|
||||
bytes default_bytes = 9;
|
||||
}
|
739
deps/protobuf/ruby/tests/basic.rb
vendored
Normal file
739
deps/protobuf/ruby/tests/basic.rb
vendored
Normal file
@ -0,0 +1,739 @@
|
||||
#!/usr/bin/ruby
|
||||
|
||||
# basic_test_pb.rb is in the same directory as this test.
|
||||
$LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__)))
|
||||
|
||||
require 'basic_test_pb'
|
||||
require 'common_tests'
|
||||
require 'google/protobuf'
|
||||
require 'json'
|
||||
require 'test/unit'
|
||||
|
||||
# ------------- generated code --------------
|
||||
|
||||
module BasicTest
|
||||
pool = Google::Protobuf::DescriptorPool.new
|
||||
pool.build do
|
||||
add_message "BadFieldNames" do
|
||||
optional :dup, :int32, 1
|
||||
optional :class, :int32, 2
|
||||
end
|
||||
end
|
||||
|
||||
BadFieldNames = pool.lookup("BadFieldNames").msgclass
|
||||
|
||||
# ------------ test cases ---------------
|
||||
|
||||
class MessageContainerTest < Test::Unit::TestCase
|
||||
# Required by CommonTests module to resolve proto3 proto classes used in tests.
|
||||
def proto_module
|
||||
::BasicTest
|
||||
end
|
||||
include CommonTests
|
||||
|
||||
def test_issue_8311_crash
|
||||
Google::Protobuf::DescriptorPool.generated_pool.build do
|
||||
add_file("inner.proto", :syntax => :proto3) do
|
||||
add_message "Inner" do
|
||||
# Removing either of these fixes the segfault.
|
||||
optional :foo, :string, 1
|
||||
optional :bar, :string, 2
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Google::Protobuf::DescriptorPool.generated_pool.build do
|
||||
add_file("outer.proto", :syntax => :proto3) do
|
||||
add_message "Outer" do
|
||||
repeated :inners, :message, 1, "Inner"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
outer = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("Outer").msgclass
|
||||
|
||||
outer.new(
|
||||
inners: []
|
||||
)['inners'].to_s
|
||||
|
||||
assert_raise Google::Protobuf::TypeError do
|
||||
outer.new(
|
||||
inners: [nil]
|
||||
).to_s
|
||||
end
|
||||
end
|
||||
|
||||
def test_issue_8559_crash
|
||||
msg = TestMessage.new
|
||||
msg.repeated_int32 = ::Google::Protobuf::RepeatedField.new(:int32, [1, 2, 3])
|
||||
|
||||
# https://github.com/jruby/jruby/issues/6818 was fixed in JRuby 9.3.0.0
|
||||
if cruby_or_jruby_9_3_or_higher?
|
||||
GC.start(full_mark: true, immediate_sweep: true)
|
||||
end
|
||||
TestMessage.encode(msg)
|
||||
end
|
||||
|
||||
def test_issue_9440
|
||||
msg = HelloRequest.new
|
||||
msg.id = 8
|
||||
assert_equal 8, msg.id
|
||||
msg.version = '1'
|
||||
assert_equal 8, msg.id
|
||||
end
|
||||
|
||||
def test_issue_9507
|
||||
pool = Google::Protobuf::DescriptorPool.new
|
||||
pool.build do
|
||||
add_message "NpeMessage" do
|
||||
optional :type, :enum, 1, "TestEnum"
|
||||
optional :other, :string, 2
|
||||
end
|
||||
add_enum "TestEnum" do
|
||||
value :Something, 0
|
||||
end
|
||||
end
|
||||
|
||||
msgclass = pool.lookup("NpeMessage").msgclass
|
||||
|
||||
m = msgclass.new(
|
||||
other: "foo" # must be set, but can be blank
|
||||
)
|
||||
|
||||
begin
|
||||
encoded = msgclass.encode(m)
|
||||
rescue java.lang.NullPointerException
|
||||
flunk "NPE rescued"
|
||||
end
|
||||
decoded = msgclass.decode(encoded)
|
||||
decoded.inspect
|
||||
decoded.to_proto
|
||||
end
|
||||
|
||||
def test_has_field
|
||||
m = TestSingularFields.new
|
||||
assert !m.has_singular_msg?
|
||||
m.singular_msg = TestMessage2.new
|
||||
assert m.has_singular_msg?
|
||||
assert TestSingularFields.descriptor.lookup('singular_msg').has?(m)
|
||||
|
||||
m = OneofMessage.new
|
||||
assert !m.has_my_oneof?
|
||||
m.a = "foo"
|
||||
assert m.has_my_oneof?
|
||||
assert_raise NoMethodError do
|
||||
m.has_a?
|
||||
end
|
||||
assert_true OneofMessage.descriptor.lookup('a').has?(m)
|
||||
|
||||
m = TestSingularFields.new
|
||||
assert_raise NoMethodError do
|
||||
m.has_singular_int32?
|
||||
end
|
||||
assert_raise ArgumentError do
|
||||
TestSingularFields.descriptor.lookup('singular_int32').has?(m)
|
||||
end
|
||||
|
||||
assert_raise NoMethodError do
|
||||
m.has_singular_string?
|
||||
end
|
||||
assert_raise ArgumentError do
|
||||
TestSingularFields.descriptor.lookup('singular_string').has?(m)
|
||||
end
|
||||
|
||||
assert_raise NoMethodError do
|
||||
m.has_singular_bool?
|
||||
end
|
||||
assert_raise ArgumentError do
|
||||
TestSingularFields.descriptor.lookup('singular_bool').has?(m)
|
||||
end
|
||||
|
||||
m = TestMessage.new
|
||||
assert_raise NoMethodError do
|
||||
m.has_repeated_msg?
|
||||
end
|
||||
assert_raise ArgumentError do
|
||||
TestMessage.descriptor.lookup('repeated_msg').has?(m)
|
||||
end
|
||||
end
|
||||
|
||||
def test_no_presence
|
||||
m = TestSingularFields.new
|
||||
|
||||
# Explicitly setting to zero does not cause anything to be serialized.
|
||||
m.singular_int32 = 0
|
||||
assert_equal "", TestSingularFields.encode(m)
|
||||
|
||||
# Explicitly setting to a non-zero value *does* cause serialization.
|
||||
m.singular_int32 = 1
|
||||
assert_not_equal "", TestSingularFields.encode(m)
|
||||
|
||||
m.singular_int32 = 0
|
||||
assert_equal "", TestSingularFields.encode(m)
|
||||
end
|
||||
|
||||
def test_set_clear_defaults
|
||||
m = TestSingularFields.new
|
||||
|
||||
m.singular_int32 = -42
|
||||
assert_equal( -42, m.singular_int32 )
|
||||
m.clear_singular_int32
|
||||
assert_equal 0, m.singular_int32
|
||||
|
||||
m.singular_int32 = 50
|
||||
assert_equal 50, m.singular_int32
|
||||
TestSingularFields.descriptor.lookup('singular_int32').clear(m)
|
||||
assert_equal 0, m.singular_int32
|
||||
|
||||
m.singular_string = "foo bar"
|
||||
assert_equal "foo bar", m.singular_string
|
||||
m.clear_singular_string
|
||||
assert_equal "", m.singular_string
|
||||
|
||||
m.singular_string = "foo"
|
||||
assert_equal "foo", m.singular_string
|
||||
TestSingularFields.descriptor.lookup('singular_string').clear(m)
|
||||
assert_equal "", m.singular_string
|
||||
|
||||
m.singular_msg = TestMessage2.new(:foo => 42)
|
||||
assert_equal TestMessage2.new(:foo => 42), m.singular_msg
|
||||
assert m.has_singular_msg?
|
||||
m.clear_singular_msg
|
||||
assert_equal nil, m.singular_msg
|
||||
assert !m.has_singular_msg?
|
||||
|
||||
m.singular_msg = TestMessage2.new(:foo => 42)
|
||||
assert_equal TestMessage2.new(:foo => 42), m.singular_msg
|
||||
TestSingularFields.descriptor.lookup('singular_msg').clear(m)
|
||||
assert_equal nil, m.singular_msg
|
||||
end
|
||||
|
||||
def test_import_proto2
|
||||
m = TestMessage.new
|
||||
assert !m.has_optional_proto2_submessage?
|
||||
m.optional_proto2_submessage = ::FooBar::Proto2::TestImportedMessage.new
|
||||
assert m.has_optional_proto2_submessage?
|
||||
assert TestMessage.descriptor.lookup('optional_proto2_submessage').has?(m)
|
||||
|
||||
m.clear_optional_proto2_submessage
|
||||
assert !m.has_optional_proto2_submessage?
|
||||
end
|
||||
|
||||
def test_clear_repeated_fields
|
||||
m = TestMessage.new
|
||||
|
||||
m.repeated_int32.push(1)
|
||||
assert_equal [1], m.repeated_int32
|
||||
m.clear_repeated_int32
|
||||
assert_equal [], m.repeated_int32
|
||||
|
||||
m.repeated_int32.push(1)
|
||||
assert_equal [1], m.repeated_int32
|
||||
TestMessage.descriptor.lookup('repeated_int32').clear(m)
|
||||
assert_equal [], m.repeated_int32
|
||||
|
||||
m = OneofMessage.new
|
||||
m.a = "foo"
|
||||
assert_equal "foo", m.a
|
||||
assert m.has_my_oneof?
|
||||
assert_equal :a, m.my_oneof
|
||||
m.clear_a
|
||||
assert !m.has_my_oneof?
|
||||
|
||||
m.a = "foobar"
|
||||
assert m.has_my_oneof?
|
||||
m.clear_my_oneof
|
||||
assert !m.has_my_oneof?
|
||||
|
||||
m.a = "bar"
|
||||
assert_equal "bar", m.a
|
||||
assert m.has_my_oneof?
|
||||
OneofMessage.descriptor.lookup('a').clear(m)
|
||||
assert !m.has_my_oneof?
|
||||
end
|
||||
|
||||
def test_initialization_map_errors
|
||||
e = assert_raise ArgumentError do
|
||||
TestMessage.new(:hello => "world")
|
||||
end
|
||||
assert_match(/hello/, e.message)
|
||||
|
||||
e = assert_raise ArgumentError do
|
||||
MapMessage.new(:map_string_int32 => "hello")
|
||||
end
|
||||
assert_equal e.message, "Expected Hash object as initializer value for map field 'map_string_int32' (given String)."
|
||||
|
||||
e = assert_raise ArgumentError do
|
||||
TestMessage.new(:repeated_uint32 => "hello")
|
||||
end
|
||||
assert_equal e.message, "Expected array as initializer value for repeated field 'repeated_uint32' (given String)."
|
||||
end
|
||||
|
||||
def test_map_field
|
||||
m = MapMessage.new
|
||||
assert m.map_string_int32 == {}
|
||||
assert m.map_string_msg == {}
|
||||
|
||||
m = MapMessage.new(
|
||||
:map_string_int32 => {"a" => 1, "b" => 2},
|
||||
:map_string_msg => {"a" => TestMessage2.new(:foo => 1),
|
||||
"b" => TestMessage2.new(:foo => 2)},
|
||||
:map_string_enum => {"a" => :A, "b" => :B})
|
||||
assert m.map_string_int32.keys.sort == ["a", "b"]
|
||||
assert m.map_string_int32["a"] == 1
|
||||
assert m.map_string_msg["b"].foo == 2
|
||||
assert m.map_string_enum["a"] == :A
|
||||
|
||||
m.map_string_int32["c"] = 3
|
||||
assert m.map_string_int32["c"] == 3
|
||||
m.map_string_msg["c"] = TestMessage2.new(:foo => 3)
|
||||
assert m.map_string_msg["c"] == TestMessage2.new(:foo => 3)
|
||||
m.map_string_msg.delete("b")
|
||||
m.map_string_msg.delete("c")
|
||||
assert m.map_string_msg == { "a" => TestMessage2.new(:foo => 1) }
|
||||
|
||||
assert_raise Google::Protobuf::TypeError do
|
||||
m.map_string_msg["e"] = TestMessage.new # wrong value type
|
||||
end
|
||||
# ensure nothing was added by the above
|
||||
assert m.map_string_msg == { "a" => TestMessage2.new(:foo => 1) }
|
||||
|
||||
m.map_string_int32 = Google::Protobuf::Map.new(:string, :int32)
|
||||
assert_raise Google::Protobuf::TypeError do
|
||||
m.map_string_int32 = Google::Protobuf::Map.new(:string, :int64)
|
||||
end
|
||||
assert_raise Google::Protobuf::TypeError do
|
||||
m.map_string_int32 = {}
|
||||
end
|
||||
|
||||
assert_raise Google::Protobuf::TypeError do
|
||||
m = MapMessage.new(:map_string_int32 => { 1 => "I am not a number" })
|
||||
end
|
||||
end
|
||||
|
||||
def test_map_field_with_symbol
|
||||
m = MapMessage.new
|
||||
assert m.map_string_int32 == {}
|
||||
assert m.map_string_msg == {}
|
||||
|
||||
m = MapMessage.new(
|
||||
:map_string_int32 => {a: 1, "b" => 2},
|
||||
:map_string_msg => {a: TestMessage2.new(:foo => 1),
|
||||
b: TestMessage2.new(:foo => 10)})
|
||||
assert_equal 1, m.map_string_int32[:a]
|
||||
assert_equal 2, m.map_string_int32[:b]
|
||||
assert_equal 10, m.map_string_msg[:b].foo
|
||||
end
|
||||
|
||||
def test_map_inspect
|
||||
m = MapMessage.new(
|
||||
:map_string_int32 => {"a" => 1, "b" => 2},
|
||||
:map_string_msg => {"a" => TestMessage2.new(:foo => 1),
|
||||
"b" => TestMessage2.new(:foo => 2)},
|
||||
:map_string_enum => {"a" => :A, "b" => :B})
|
||||
|
||||
# JRuby doesn't keep consistent ordering so check for either version
|
||||
expected_a = "<BasicTest::MapMessage: map_string_int32: {\"b\"=>2, \"a\"=>1}, map_string_msg: {\"b\"=><BasicTest::TestMessage2: foo: 2>, \"a\"=><BasicTest::TestMessage2: foo: 1>}, map_string_enum: {\"b\"=>:B, \"a\"=>:A}>"
|
||||
expected_b = "<BasicTest::MapMessage: map_string_int32: {\"a\"=>1, \"b\"=>2}, map_string_msg: {\"a\"=><BasicTest::TestMessage2: foo: 1>, \"b\"=><BasicTest::TestMessage2: foo: 2>}, map_string_enum: {\"a\"=>:A, \"b\"=>:B}>"
|
||||
inspect_result = m.inspect
|
||||
assert expected_a == inspect_result || expected_b == inspect_result, "Incorrect inspect result: #{inspect_result}"
|
||||
end
|
||||
|
||||
def test_map_corruption
|
||||
# This pattern led to a crash in a previous version of upb/protobuf.
|
||||
m = MapMessage.new(map_string_int32: { "aaa" => 1 })
|
||||
m.map_string_int32['podid'] = 2
|
||||
m.map_string_int32['aaa'] = 3
|
||||
end
|
||||
|
||||
def test_map_wrappers
|
||||
run_asserts = ->(m) {
|
||||
assert_equal 2.0, m.map_double[0].value
|
||||
assert_equal 4.0, m.map_float[0].value
|
||||
assert_equal 3, m.map_int32[0].value
|
||||
assert_equal 4, m.map_int64[0].value
|
||||
assert_equal 5, m.map_uint32[0].value
|
||||
assert_equal 6, m.map_uint64[0].value
|
||||
assert_equal true, m.map_bool[0].value
|
||||
assert_equal 'str', m.map_string[0].value
|
||||
assert_equal 'fun', m.map_bytes[0].value
|
||||
}
|
||||
|
||||
m = proto_module::Wrapper.new(
|
||||
map_double: {0 => Google::Protobuf::DoubleValue.new(value: 2.0)},
|
||||
map_float: {0 => Google::Protobuf::FloatValue.new(value: 4.0)},
|
||||
map_int32: {0 => Google::Protobuf::Int32Value.new(value: 3)},
|
||||
map_int64: {0 => Google::Protobuf::Int64Value.new(value: 4)},
|
||||
map_uint32: {0 => Google::Protobuf::UInt32Value.new(value: 5)},
|
||||
map_uint64: {0 => Google::Protobuf::UInt64Value.new(value: 6)},
|
||||
map_bool: {0 => Google::Protobuf::BoolValue.new(value: true)},
|
||||
map_string: {0 => Google::Protobuf::StringValue.new(value: 'str')},
|
||||
map_bytes: {0 => Google::Protobuf::BytesValue.new(value: 'fun')},
|
||||
)
|
||||
|
||||
run_asserts.call(m)
|
||||
serialized = proto_module::Wrapper::encode(m)
|
||||
m2 = proto_module::Wrapper::decode(serialized)
|
||||
run_asserts.call(m2)
|
||||
|
||||
# Test the case where we are serializing directly from the parsed form
|
||||
# (before anything lazy is materialized).
|
||||
m3 = proto_module::Wrapper::decode(serialized)
|
||||
serialized2 = proto_module::Wrapper::encode(m3)
|
||||
m4 = proto_module::Wrapper::decode(serialized2)
|
||||
run_asserts.call(m4)
|
||||
|
||||
# Test that the lazy form compares equal to the expanded form.
|
||||
m5 = proto_module::Wrapper::decode(serialized2)
|
||||
assert_equal m5, m
|
||||
end
|
||||
|
||||
def test_map_wrappers_with_default_values
|
||||
run_asserts = ->(m) {
|
||||
assert_equal 0.0, m.map_double[0].value
|
||||
assert_equal 0.0, m.map_float[0].value
|
||||
assert_equal 0, m.map_int32[0].value
|
||||
assert_equal 0, m.map_int64[0].value
|
||||
assert_equal 0, m.map_uint32[0].value
|
||||
assert_equal 0, m.map_uint64[0].value
|
||||
assert_equal false, m.map_bool[0].value
|
||||
assert_equal '', m.map_string[0].value
|
||||
assert_equal '', m.map_bytes[0].value
|
||||
}
|
||||
|
||||
m = proto_module::Wrapper.new(
|
||||
map_double: {0 => Google::Protobuf::DoubleValue.new(value: 0.0)},
|
||||
map_float: {0 => Google::Protobuf::FloatValue.new(value: 0.0)},
|
||||
map_int32: {0 => Google::Protobuf::Int32Value.new(value: 0)},
|
||||
map_int64: {0 => Google::Protobuf::Int64Value.new(value: 0)},
|
||||
map_uint32: {0 => Google::Protobuf::UInt32Value.new(value: 0)},
|
||||
map_uint64: {0 => Google::Protobuf::UInt64Value.new(value: 0)},
|
||||
map_bool: {0 => Google::Protobuf::BoolValue.new(value: false)},
|
||||
map_string: {0 => Google::Protobuf::StringValue.new(value: '')},
|
||||
map_bytes: {0 => Google::Protobuf::BytesValue.new(value: '')},
|
||||
)
|
||||
|
||||
run_asserts.call(m)
|
||||
serialized = proto_module::Wrapper::encode(m)
|
||||
m2 = proto_module::Wrapper::decode(serialized)
|
||||
run_asserts.call(m2)
|
||||
|
||||
# Test the case where we are serializing directly from the parsed form
|
||||
# (before anything lazy is materialized).
|
||||
m3 = proto_module::Wrapper::decode(serialized)
|
||||
serialized2 = proto_module::Wrapper::encode(m3)
|
||||
m4 = proto_module::Wrapper::decode(serialized2)
|
||||
run_asserts.call(m4)
|
||||
|
||||
# Test that the lazy form compares equal to the expanded form.
|
||||
m5 = proto_module::Wrapper::decode(serialized2)
|
||||
assert_equal m5, m
|
||||
end
|
||||
|
||||
def test_map_wrappers_with_no_value
|
||||
run_asserts = ->(m) {
|
||||
assert_equal 0.0, m.map_double[0].value
|
||||
assert_equal 0.0, m.map_float[0].value
|
||||
assert_equal 0, m.map_int32[0].value
|
||||
assert_equal 0, m.map_int64[0].value
|
||||
assert_equal 0, m.map_uint32[0].value
|
||||
assert_equal 0, m.map_uint64[0].value
|
||||
assert_equal false, m.map_bool[0].value
|
||||
assert_equal '', m.map_string[0].value
|
||||
assert_equal '', m.map_bytes[0].value
|
||||
}
|
||||
|
||||
m = proto_module::Wrapper.new(
|
||||
map_double: {0 => Google::Protobuf::DoubleValue.new()},
|
||||
map_float: {0 => Google::Protobuf::FloatValue.new()},
|
||||
map_int32: {0 => Google::Protobuf::Int32Value.new()},
|
||||
map_int64: {0 => Google::Protobuf::Int64Value.new()},
|
||||
map_uint32: {0 => Google::Protobuf::UInt32Value.new()},
|
||||
map_uint64: {0 => Google::Protobuf::UInt64Value.new()},
|
||||
map_bool: {0 => Google::Protobuf::BoolValue.new()},
|
||||
map_string: {0 => Google::Protobuf::StringValue.new()},
|
||||
map_bytes: {0 => Google::Protobuf::BytesValue.new()},
|
||||
)
|
||||
run_asserts.call(m)
|
||||
|
||||
serialized = proto_module::Wrapper::encode(m)
|
||||
m2 = proto_module::Wrapper::decode(serialized)
|
||||
run_asserts.call(m2)
|
||||
|
||||
# Test the case where we are serializing directly from the parsed form
|
||||
# (before anything lazy is materialized).
|
||||
m3 = proto_module::Wrapper::decode(serialized)
|
||||
serialized2 = proto_module::Wrapper::encode(m3)
|
||||
m4 = proto_module::Wrapper::decode(serialized2)
|
||||
run_asserts.call(m4)
|
||||
end
|
||||
|
||||
def test_concurrent_decoding
|
||||
o = Outer.new
|
||||
o.items[0] = Inner.new
|
||||
raw = Outer.encode(o)
|
||||
|
||||
thds = 2.times.map do
|
||||
Thread.new do
|
||||
100000.times do
|
||||
assert_equal o, Outer.decode(raw)
|
||||
end
|
||||
end
|
||||
end
|
||||
thds.map(&:join)
|
||||
end
|
||||
|
||||
def test_map_encode_decode
|
||||
m = MapMessage.new(
|
||||
:map_string_int32 => {"a" => 1, "b" => 2},
|
||||
:map_string_msg => {"a" => TestMessage2.new(:foo => 1),
|
||||
"b" => TestMessage2.new(:foo => 2)},
|
||||
:map_string_enum => {"a" => :A, "b" => :B})
|
||||
m2 = MapMessage.decode(MapMessage.encode(m))
|
||||
assert m == m2
|
||||
|
||||
m3 = MapMessageWireEquiv.decode(MapMessage.encode(m))
|
||||
assert m3.map_string_int32.length == 2
|
||||
|
||||
kv = {}
|
||||
m3.map_string_int32.map { |msg| kv[msg.key] = msg.value }
|
||||
assert kv == {"a" => 1, "b" => 2}
|
||||
|
||||
kv = {}
|
||||
m3.map_string_msg.map { |msg| kv[msg.key] = msg.value }
|
||||
assert kv == {"a" => TestMessage2.new(:foo => 1),
|
||||
"b" => TestMessage2.new(:foo => 2)}
|
||||
end
|
||||
|
||||
def test_protobuf_decode_json_ignore_unknown_fields
|
||||
m = TestMessage.decode_json({
|
||||
optional_string: "foo",
|
||||
not_in_message: "some_value"
|
||||
}.to_json, { ignore_unknown_fields: true })
|
||||
|
||||
assert_equal m.optional_string, "foo"
|
||||
e = assert_raise Google::Protobuf::ParseError do
|
||||
TestMessage.decode_json({ not_in_message: "some_value" }.to_json)
|
||||
end
|
||||
assert_match(/No such field: not_in_message/, e.message)
|
||||
end
|
||||
|
||||
#def test_json_quoted_string
|
||||
# m = TestMessage.decode_json(%q(
|
||||
# "optionalInt64": "1",,
|
||||
# }))
|
||||
# puts(m)
|
||||
# assert_equal 1, m.optional_int32
|
||||
#end
|
||||
|
||||
def test_to_h
|
||||
m = TestMessage.new(:optional_bool => true, :optional_double => -10.100001, :optional_string => 'foo', :repeated_string => ['bar1', 'bar2'], :repeated_msg => [TestMessage2.new(:foo => 100)])
|
||||
expected_result = {
|
||||
:optional_bool=>true,
|
||||
:optional_bytes=>"",
|
||||
:optional_double=>-10.100001,
|
||||
:optional_enum=>:Default,
|
||||
:optional_float=>0.0,
|
||||
:optional_int32=>0,
|
||||
:optional_int64=>0,
|
||||
:optional_msg=>nil,
|
||||
:optional_msg2=>nil,
|
||||
:optional_proto2_submessage=>nil,
|
||||
:optional_string=>"foo",
|
||||
:optional_uint32=>0,
|
||||
:optional_uint64=>0,
|
||||
:repeated_bool=>[],
|
||||
:repeated_bytes=>[],
|
||||
:repeated_double=>[],
|
||||
:repeated_enum=>[],
|
||||
:repeated_float=>[],
|
||||
:repeated_int32=>[],
|
||||
:repeated_int64=>[],
|
||||
:repeated_msg=>[{:foo => 100}],
|
||||
:repeated_string=>["bar1", "bar2"],
|
||||
:repeated_uint32=>[],
|
||||
:repeated_uint64=>[]
|
||||
}
|
||||
assert_equal expected_result, m.to_h
|
||||
|
||||
m = MapMessage.new(
|
||||
:map_string_int32 => {"a" => 1, "b" => 2},
|
||||
:map_string_msg => {"a" => TestMessage2.new(:foo => 1),
|
||||
"b" => TestMessage2.new(:foo => 2)},
|
||||
:map_string_enum => {"a" => :A, "b" => :B})
|
||||
expected_result = {
|
||||
:map_string_int32 => {"a" => 1, "b" => 2},
|
||||
:map_string_msg => {"a" => {:foo => 1}, "b" => {:foo => 2}},
|
||||
:map_string_enum => {"a" => :A, "b" => :B}
|
||||
}
|
||||
assert_equal expected_result, m.to_h
|
||||
end
|
||||
|
||||
|
||||
def test_json_maps
|
||||
m = MapMessage.new(:map_string_int32 => {"a" => 1})
|
||||
expected = {mapStringInt32: {a: 1}, mapStringMsg: {}, mapStringEnum: {}}
|
||||
expected_preserve = {map_string_int32: {a: 1}, map_string_msg: {}, map_string_enum: {}}
|
||||
assert_equal JSON.parse(MapMessage.encode_json(m, :emit_defaults=>true), :symbolize_names => true), expected
|
||||
|
||||
json = MapMessage.encode_json(m, :preserve_proto_fieldnames => true, :emit_defaults=>true)
|
||||
assert_equal JSON.parse(json, :symbolize_names => true), expected_preserve
|
||||
|
||||
m2 = MapMessage.decode_json(MapMessage.encode_json(m))
|
||||
assert_equal m, m2
|
||||
end
|
||||
|
||||
def test_json_maps_emit_defaults_submsg
|
||||
m = MapMessage.new(:map_string_msg => {"a" => TestMessage2.new(foo: 0)})
|
||||
expected = {mapStringInt32: {}, mapStringMsg: {a: {foo: 0}}, mapStringEnum: {}}
|
||||
|
||||
actual = MapMessage.encode_json(m, :emit_defaults => true)
|
||||
|
||||
assert_equal JSON.parse(actual, :symbolize_names => true), expected
|
||||
end
|
||||
|
||||
def test_json_emit_defaults_submsg
|
||||
m = TestSingularFields.new(singular_msg: proto_module::TestMessage2.new)
|
||||
|
||||
expected = {
|
||||
singularInt32: 0,
|
||||
singularInt64: "0",
|
||||
singularUint32: 0,
|
||||
singularUint64: "0",
|
||||
singularBool: false,
|
||||
singularFloat: 0,
|
||||
singularDouble: 0,
|
||||
singularString: "",
|
||||
singularBytes: "",
|
||||
singularMsg: {},
|
||||
singularEnum: "Default",
|
||||
}
|
||||
|
||||
actual = proto_module::TestMessage.encode_json(m, :emit_defaults => true)
|
||||
|
||||
assert_equal expected, JSON.parse(actual, :symbolize_names => true)
|
||||
end
|
||||
|
||||
def test_respond_to
|
||||
msg = MapMessage.new
|
||||
assert msg.respond_to?(:map_string_int32)
|
||||
assert !msg.respond_to?(:bacon)
|
||||
end
|
||||
|
||||
def test_file_descriptor
|
||||
file_descriptor = TestMessage.descriptor.file_descriptor
|
||||
assert nil != file_descriptor
|
||||
assert_equal "tests/basic_test.proto", file_descriptor.name
|
||||
assert_equal :proto3, file_descriptor.syntax
|
||||
|
||||
file_descriptor = TestEnum.descriptor.file_descriptor
|
||||
assert nil != file_descriptor
|
||||
assert_equal "tests/basic_test.proto", file_descriptor.name
|
||||
assert_equal :proto3, file_descriptor.syntax
|
||||
end
|
||||
|
||||
# Ruby 2.5 changed to raise FrozenError instead of RuntimeError
|
||||
FrozenErrorType = Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.5') ? RuntimeError : FrozenError
|
||||
|
||||
def test_map_freeze
|
||||
m = proto_module::MapMessage.new
|
||||
m.map_string_int32['a'] = 5
|
||||
m.map_string_msg['b'] = proto_module::TestMessage2.new
|
||||
|
||||
m.map_string_int32.freeze
|
||||
m.map_string_msg.freeze
|
||||
|
||||
assert m.map_string_int32.frozen?
|
||||
assert m.map_string_msg.frozen?
|
||||
|
||||
assert_raise(FrozenErrorType) { m.map_string_int32['foo'] = 1 }
|
||||
assert_raise(FrozenErrorType) { m.map_string_msg['bar'] = proto_module::TestMessage2.new }
|
||||
assert_raise(FrozenErrorType) { m.map_string_int32.delete('a') }
|
||||
assert_raise(FrozenErrorType) { m.map_string_int32.clear }
|
||||
end
|
||||
|
||||
def test_map_length
|
||||
m = proto_module::MapMessage.new
|
||||
assert_equal 0, m.map_string_int32.length
|
||||
assert_equal 0, m.map_string_msg.length
|
||||
assert_equal 0, m.map_string_int32.size
|
||||
assert_equal 0, m.map_string_msg.size
|
||||
|
||||
m.map_string_int32['a'] = 1
|
||||
m.map_string_int32['b'] = 2
|
||||
m.map_string_msg['a'] = proto_module::TestMessage2.new
|
||||
assert_equal 2, m.map_string_int32.length
|
||||
assert_equal 1, m.map_string_msg.length
|
||||
assert_equal 2, m.map_string_int32.size
|
||||
assert_equal 1, m.map_string_msg.size
|
||||
end
|
||||
|
||||
def test_string_with_singleton_class_enabled
|
||||
str = 'foobar'
|
||||
# NOTE: Accessing a singleton class of an object changes its low level class representation
|
||||
# as far as the C API's CLASS_OF() method concerned, exposing the issue
|
||||
str.singleton_class
|
||||
m = proto_module::TestMessage.new(
|
||||
optional_string: str,
|
||||
optional_bytes: str
|
||||
)
|
||||
|
||||
assert_equal str, m.optional_string
|
||||
assert_equal str, m.optional_bytes
|
||||
end
|
||||
|
||||
def test_utf8
|
||||
m = proto_module::TestMessage.new(
|
||||
optional_string: "µpb",
|
||||
)
|
||||
m2 = proto_module::TestMessage.decode(proto_module::TestMessage.encode(m))
|
||||
assert_equal m2, m
|
||||
end
|
||||
|
||||
def test_map_fields_respond_to? # regression test for issue 9202
|
||||
msg = proto_module::MapMessage.new
|
||||
assert msg.respond_to?(:map_string_int32=)
|
||||
msg.map_string_int32 = Google::Protobuf::Map.new(:string, :int32)
|
||||
assert msg.respond_to?(:map_string_int32)
|
||||
assert_equal( Google::Protobuf::Map.new(:string, :int32), msg.map_string_int32 )
|
||||
assert msg.respond_to?(:clear_map_string_int32)
|
||||
msg.clear_map_string_int32
|
||||
|
||||
assert !msg.respond_to?(:has_map_string_int32?)
|
||||
assert_raise NoMethodError do
|
||||
msg.has_map_string_int32?
|
||||
end
|
||||
assert !msg.respond_to?(:map_string_int32_as_value)
|
||||
assert_raise NoMethodError do
|
||||
msg.map_string_int32_as_value
|
||||
end
|
||||
assert !msg.respond_to?(:map_string_int32_as_value=)
|
||||
assert_raise NoMethodError do
|
||||
msg.map_string_int32_as_value = :boom
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def test_oneof_fields_respond_to? # regression test for issue 9202
|
||||
msg = proto_module::OneofMessage.new
|
||||
# `has_` prefix + "?" suffix actions should only work for oneofs fields.
|
||||
assert msg.has_my_oneof?
|
||||
assert msg.respond_to? :has_my_oneof?
|
||||
assert !msg.respond_to?( :has_a? )
|
||||
assert_raise NoMethodError do
|
||||
msg.has_a?
|
||||
end
|
||||
assert !msg.respond_to?( :has_b? )
|
||||
assert_raise NoMethodError do
|
||||
msg.has_b?
|
||||
end
|
||||
assert !msg.respond_to?( :has_c? )
|
||||
assert_raise NoMethodError do
|
||||
msg.has_c?
|
||||
end
|
||||
assert !msg.respond_to?( :has_d? )
|
||||
assert_raise NoMethodError do
|
||||
msg.has_d?
|
||||
end
|
||||
end
|
||||
end
|
274
deps/protobuf/ruby/tests/basic_proto2.rb
vendored
Normal file
274
deps/protobuf/ruby/tests/basic_proto2.rb
vendored
Normal file
@ -0,0 +1,274 @@
|
||||
#!/usr/bin/ruby
|
||||
|
||||
# basic_test_pb.rb is in the same directory as this test.
|
||||
$LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__)))
|
||||
|
||||
require 'basic_test_proto2_pb'
|
||||
require 'common_tests'
|
||||
require 'google/protobuf'
|
||||
require 'json'
|
||||
require 'test/unit'
|
||||
|
||||
# ------------- generated code --------------
|
||||
|
||||
module BasicTestProto2
|
||||
pool = Google::Protobuf::DescriptorPool.new
|
||||
pool.build do
|
||||
add_file "test_proto2.proto", syntax: :proto2 do
|
||||
add_message "BadFieldNames" do
|
||||
optional :dup, :int32, 1
|
||||
optional :class, :int32, 2
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
BadFieldNames = pool.lookup("BadFieldNames").msgclass
|
||||
|
||||
# ------------ test cases ---------------
|
||||
|
||||
class MessageContainerTest < Test::Unit::TestCase
|
||||
# Required by CommonTests module to resolve proto2 proto classes used in tests.
|
||||
def proto_module
|
||||
::BasicTestProto2
|
||||
end
|
||||
include CommonTests
|
||||
|
||||
def test_has_field
|
||||
m = TestMessage.new
|
||||
assert !m.has_optional_int32?
|
||||
assert !TestMessage.descriptor.lookup('optional_int32').has?(m)
|
||||
assert !m.has_optional_int64?
|
||||
assert !TestMessage.descriptor.lookup('optional_int64').has?(m)
|
||||
assert !m.has_optional_uint32?
|
||||
assert !TestMessage.descriptor.lookup('optional_uint32').has?(m)
|
||||
assert !m.has_optional_uint64?
|
||||
assert !TestMessage.descriptor.lookup('optional_uint64').has?(m)
|
||||
assert !m.has_optional_bool?
|
||||
assert !TestMessage.descriptor.lookup('optional_bool').has?(m)
|
||||
assert !m.has_optional_float?
|
||||
assert !TestMessage.descriptor.lookup('optional_float').has?(m)
|
||||
assert !m.has_optional_double?
|
||||
assert !TestMessage.descriptor.lookup('optional_double').has?(m)
|
||||
assert !m.has_optional_string?
|
||||
assert !TestMessage.descriptor.lookup('optional_string').has?(m)
|
||||
assert !m.has_optional_bytes?
|
||||
assert !TestMessage.descriptor.lookup('optional_bytes').has?(m)
|
||||
assert !m.has_optional_enum?
|
||||
assert !TestMessage.descriptor.lookup('optional_enum').has?(m)
|
||||
|
||||
m = TestMessage.new(:optional_int32 => nil)
|
||||
assert !m.has_optional_int32?
|
||||
|
||||
assert_raise NoMethodError do
|
||||
m.has_repeated_msg?
|
||||
end
|
||||
assert_raise ArgumentError do
|
||||
TestMessage.descriptor.lookup('repeated_msg').has?(m)
|
||||
end
|
||||
|
||||
m.optional_msg = TestMessage2.new
|
||||
assert m.has_optional_msg?
|
||||
assert TestMessage.descriptor.lookup('optional_msg').has?(m)
|
||||
|
||||
m = OneofMessage.new
|
||||
assert !m.has_my_oneof?
|
||||
m.a = "foo"
|
||||
assert m.has_my_oneof?
|
||||
assert_equal :a, m.my_oneof
|
||||
assert m.has_a?
|
||||
assert OneofMessage.descriptor.lookup('a').has?(m)
|
||||
assert_equal "foo", m.a
|
||||
assert !m.has_b?
|
||||
assert !OneofMessage.descriptor.lookup('b').has?(m)
|
||||
assert !m.has_c?
|
||||
assert !OneofMessage.descriptor.lookup('c').has?(m)
|
||||
assert !m.has_d?
|
||||
assert !OneofMessage.descriptor.lookup('d').has?(m)
|
||||
|
||||
m = OneofMessage.new
|
||||
m.b = 100
|
||||
assert m.has_b?
|
||||
assert_equal 100, m.b
|
||||
assert m.has_my_oneof?
|
||||
assert !m.has_a?
|
||||
assert !m.has_c?
|
||||
assert !m.has_d?
|
||||
|
||||
m = OneofMessage.new
|
||||
m.c = TestMessage2.new
|
||||
assert m.has_c?
|
||||
assert_equal TestMessage2.new, m.c
|
||||
assert m.has_my_oneof?
|
||||
assert !m.has_a?
|
||||
assert !m.has_b?
|
||||
assert !m.has_d?
|
||||
|
||||
m = OneofMessage.new
|
||||
m.d = :A
|
||||
assert m.has_d?
|
||||
assert_equal :A, m.d
|
||||
assert m.has_my_oneof?
|
||||
assert !m.has_a?
|
||||
assert !m.has_b?
|
||||
assert !m.has_c?
|
||||
end
|
||||
|
||||
def test_defined_defaults
|
||||
m = TestMessageDefaults.new
|
||||
assert_equal 1, m.optional_int32
|
||||
assert_equal 2, m.optional_int64
|
||||
assert_equal 3, m.optional_uint32
|
||||
assert_equal 4, m.optional_uint64
|
||||
assert_equal true, m.optional_bool
|
||||
assert_equal 6.0, m.optional_float
|
||||
assert_equal 7.0, m.optional_double
|
||||
assert_equal "Default Str", m.optional_string
|
||||
assert_equal "\xCF\xA5s\xBD\xBA\xE6fubar".force_encoding("ASCII-8BIT"), m.optional_bytes
|
||||
assert_equal :B2, m.optional_enum
|
||||
|
||||
assert !m.has_optional_int32?
|
||||
assert !m.has_optional_int64?
|
||||
assert !m.has_optional_uint32?
|
||||
assert !m.has_optional_uint64?
|
||||
assert !m.has_optional_bool?
|
||||
assert !m.has_optional_float?
|
||||
assert !m.has_optional_double?
|
||||
assert !m.has_optional_string?
|
||||
assert !m.has_optional_bytes?
|
||||
assert !m.has_optional_enum?
|
||||
end
|
||||
|
||||
def test_set_clear_defaults
|
||||
m = TestMessageDefaults.new
|
||||
|
||||
m.optional_int32 = -42
|
||||
assert_equal( -42, m.optional_int32 )
|
||||
assert m.has_optional_int32?
|
||||
m.clear_optional_int32
|
||||
assert_equal 1, m.optional_int32
|
||||
assert !m.has_optional_int32?
|
||||
|
||||
m.optional_string = "foo bar"
|
||||
assert_equal "foo bar", m.optional_string
|
||||
assert m.has_optional_string?
|
||||
m.clear_optional_string
|
||||
assert_equal "Default Str", m.optional_string
|
||||
assert !m.has_optional_string?
|
||||
|
||||
m.optional_msg = TestMessage2.new(:foo => 42)
|
||||
assert_equal TestMessage2.new(:foo => 42), m.optional_msg
|
||||
assert m.has_optional_msg?
|
||||
|
||||
m.clear_optional_msg
|
||||
assert_equal nil, m.optional_msg
|
||||
assert !m.has_optional_msg?
|
||||
|
||||
m.optional_msg = TestMessage2.new(:foo => 42)
|
||||
assert_equal TestMessage2.new(:foo => 42), m.optional_msg
|
||||
assert TestMessageDefaults.descriptor.lookup('optional_msg').has?(m)
|
||||
|
||||
TestMessageDefaults.descriptor.lookup('optional_msg').clear(m)
|
||||
assert_equal nil, m.optional_msg
|
||||
assert !TestMessageDefaults.descriptor.lookup('optional_msg').has?(m)
|
||||
|
||||
m = TestMessage.new
|
||||
m.repeated_int32.push(1)
|
||||
assert_equal [1], m.repeated_int32
|
||||
m.clear_repeated_int32
|
||||
assert_equal [], m.repeated_int32
|
||||
|
||||
m = OneofMessage.new
|
||||
m.a = "foo"
|
||||
assert_equal "foo", m.a
|
||||
assert m.has_a?
|
||||
m.clear_a
|
||||
assert !m.has_a?
|
||||
|
||||
m = OneofMessage.new
|
||||
m.a = "foobar"
|
||||
assert m.has_my_oneof?
|
||||
m.clear_my_oneof
|
||||
assert !m.has_my_oneof?
|
||||
|
||||
m = OneofMessage.new
|
||||
m.a = "bar"
|
||||
assert_equal "bar", m.a
|
||||
assert m.has_my_oneof?
|
||||
OneofMessage.descriptor.lookup('a').clear(m)
|
||||
assert !m.has_my_oneof?
|
||||
end
|
||||
|
||||
def test_assign_nil
|
||||
m = TestMessageDefaults.new
|
||||
m.optional_msg = TestMessage2.new(:foo => 42)
|
||||
|
||||
assert_equal TestMessage2.new(:foo => 42), m.optional_msg
|
||||
assert m.has_optional_msg?
|
||||
m.optional_msg = nil
|
||||
assert_equal nil, m.optional_msg
|
||||
assert !m.has_optional_msg?
|
||||
end
|
||||
|
||||
def test_initialization_map_errors
|
||||
e = assert_raise ArgumentError do
|
||||
TestMessage.new(:hello => "world")
|
||||
end
|
||||
assert_match(/hello/, e.message)
|
||||
|
||||
e = assert_raise ArgumentError do
|
||||
TestMessage.new(:repeated_uint32 => "hello")
|
||||
end
|
||||
assert_equal e.message, "Expected array as initializer value for repeated field 'repeated_uint32' (given String)."
|
||||
end
|
||||
|
||||
|
||||
def test_to_h
|
||||
m = TestMessage.new(:optional_bool => true, :optional_double => -10.100001, :optional_string => 'foo', :repeated_string => ['bar1', 'bar2'])
|
||||
expected_result = {
|
||||
:optional_bool=>true,
|
||||
:optional_double=>-10.100001,
|
||||
:optional_string=>"foo",
|
||||
:repeated_string=>["bar1", "bar2"],
|
||||
}
|
||||
assert_equal expected_result, m.to_h
|
||||
|
||||
m = OneofMessage.new(:a => "foo")
|
||||
expected_result = {:a => "foo"}
|
||||
assert_equal expected_result, m.to_h
|
||||
end
|
||||
|
||||
def test_respond_to
|
||||
# This test fails with JRuby 1.7.23, likely because of an old JRuby bug.
|
||||
return if RUBY_PLATFORM == "java"
|
||||
msg = TestMessage.new
|
||||
assert !msg.respond_to?(:bacon)
|
||||
end
|
||||
|
||||
def test_file_descriptor
|
||||
file_descriptor = TestMessage.descriptor.file_descriptor
|
||||
assert nil != file_descriptor
|
||||
assert_equal "tests/basic_test_proto2.proto", file_descriptor.name
|
||||
assert_equal :proto2, file_descriptor.syntax
|
||||
|
||||
file_descriptor = TestEnum.descriptor.file_descriptor
|
||||
assert nil != file_descriptor
|
||||
assert_equal "tests/basic_test_proto2.proto", file_descriptor.name
|
||||
assert_equal :proto2, file_descriptor.syntax
|
||||
end
|
||||
|
||||
def test_oneof_fields_respond_to? # regression test for issue 9202
|
||||
msg = proto_module::OneofMessage.new(a: "foo")
|
||||
# `has_` prefix + "?" suffix actions should only work for oneofs fields.
|
||||
assert msg.respond_to? :has_my_oneof?
|
||||
assert msg.has_my_oneof?
|
||||
assert msg.respond_to? :has_a?
|
||||
assert msg.has_a?
|
||||
assert msg.respond_to? :has_b?
|
||||
assert !msg.has_b?
|
||||
assert msg.respond_to? :has_c?
|
||||
assert !msg.has_c?
|
||||
assert msg.respond_to? :has_d?
|
||||
assert !msg.has_d?
|
||||
end
|
||||
end
|
||||
end
|
252
deps/protobuf/ruby/tests/basic_test.proto
vendored
Normal file
252
deps/protobuf/ruby/tests/basic_test.proto
vendored
Normal file
@ -0,0 +1,252 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package basic_test;
|
||||
|
||||
import "google/protobuf/wrappers.proto";
|
||||
import "google/protobuf/timestamp.proto";
|
||||
import "google/protobuf/duration.proto";
|
||||
import "google/protobuf/struct.proto";
|
||||
import "test_import_proto2.proto";
|
||||
|
||||
message Foo {
|
||||
Bar bar = 1;
|
||||
repeated Baz baz = 2;
|
||||
}
|
||||
|
||||
message Bar {
|
||||
string msg = 1;
|
||||
}
|
||||
|
||||
message Baz {
|
||||
string msg = 1;
|
||||
}
|
||||
|
||||
message TestMessage {
|
||||
optional int32 optional_int32 = 1;
|
||||
optional int64 optional_int64 = 2;
|
||||
optional uint32 optional_uint32 = 3;
|
||||
optional uint64 optional_uint64 = 4;
|
||||
optional bool optional_bool = 5;
|
||||
optional float optional_float = 6;
|
||||
optional double optional_double = 7;
|
||||
optional string optional_string = 8;
|
||||
optional bytes optional_bytes = 9;
|
||||
optional TestMessage2 optional_msg = 10;
|
||||
optional TestEnum optional_enum = 11;
|
||||
optional foo_bar.proto2.TestImportedMessage optional_proto2_submessage = 24;
|
||||
|
||||
repeated int32 repeated_int32 = 12;
|
||||
repeated int64 repeated_int64 = 13;
|
||||
repeated uint32 repeated_uint32 = 14;
|
||||
repeated uint64 repeated_uint64 = 15;
|
||||
repeated bool repeated_bool = 16;
|
||||
repeated float repeated_float = 17;
|
||||
repeated double repeated_double = 18;
|
||||
repeated string repeated_string = 19;
|
||||
repeated bytes repeated_bytes = 20;
|
||||
repeated TestMessage2 repeated_msg = 21;
|
||||
repeated TestEnum repeated_enum = 22;
|
||||
|
||||
optional TestSingularFields optional_msg2 = 23;
|
||||
}
|
||||
|
||||
message TestSingularFields {
|
||||
int32 singular_int32 = 1;
|
||||
int64 singular_int64 = 2;
|
||||
uint32 singular_uint32 = 3;
|
||||
uint64 singular_uint64 = 4;
|
||||
bool singular_bool = 5;
|
||||
float singular_float = 6;
|
||||
double singular_double = 7;
|
||||
string singular_string = 8;
|
||||
bytes singular_bytes = 9;
|
||||
TestMessage2 singular_msg = 10;
|
||||
TestEnum singular_enum = 11;
|
||||
}
|
||||
|
||||
message TestMessage2 {
|
||||
optional int32 foo = 1;
|
||||
}
|
||||
|
||||
enum TestEnum {
|
||||
Default = 0;
|
||||
A = 1;
|
||||
B = 2;
|
||||
C = 3;
|
||||
}
|
||||
|
||||
message TestEmbeddedMessageParent {
|
||||
TestEmbeddedMessageChild child_msg = 1;
|
||||
int32 number = 2;
|
||||
|
||||
repeated TestEmbeddedMessageChild repeated_msg = 3;
|
||||
repeated int32 repeated_number = 4;
|
||||
}
|
||||
|
||||
message TestEmbeddedMessageChild {
|
||||
TestMessage sub_child = 1;
|
||||
}
|
||||
|
||||
message Recursive1 {
|
||||
Recursive2 foo = 1;
|
||||
}
|
||||
|
||||
message Recursive2 {
|
||||
Recursive1 foo = 1;
|
||||
}
|
||||
|
||||
message MapMessage {
|
||||
map<string, int32> map_string_int32 = 1;
|
||||
map<string, TestMessage2> map_string_msg = 2;
|
||||
map<string, TestEnum> map_string_enum = 3;
|
||||
}
|
||||
|
||||
message MapMessageWireEquiv {
|
||||
repeated MapMessageWireEquiv_entry1 map_string_int32 = 1;
|
||||
repeated MapMessageWireEquiv_entry2 map_string_msg = 2;
|
||||
}
|
||||
|
||||
message MapMessageWireEquiv_entry1 {
|
||||
string key = 1;
|
||||
int32 value = 2;
|
||||
}
|
||||
|
||||
message MapMessageWireEquiv_entry2 {
|
||||
string key = 1;
|
||||
TestMessage2 value = 2;
|
||||
}
|
||||
|
||||
message OneofMessage {
|
||||
oneof my_oneof {
|
||||
string a = 1;
|
||||
int32 b = 2;
|
||||
TestMessage2 c = 3;
|
||||
TestEnum d = 4;
|
||||
}
|
||||
}
|
||||
|
||||
message Outer {
|
||||
map<int32, Inner> items = 1;
|
||||
}
|
||||
|
||||
message Inner {
|
||||
}
|
||||
|
||||
message Wrapper {
|
||||
google.protobuf.DoubleValue double = 1;
|
||||
google.protobuf.FloatValue float = 2;
|
||||
google.protobuf.Int32Value int32 = 3;
|
||||
google.protobuf.Int64Value int64 = 4;
|
||||
google.protobuf.UInt32Value uint32 = 5;
|
||||
google.protobuf.UInt64Value uint64 = 6;
|
||||
google.protobuf.BoolValue bool = 7;
|
||||
google.protobuf.StringValue string = 8;
|
||||
google.protobuf.BytesValue bytes = 9;
|
||||
string real_string = 100;
|
||||
oneof a_oneof {
|
||||
string string_in_oneof = 10;
|
||||
}
|
||||
|
||||
// Repeated wrappers don't make sense, but we still need to make sure they
|
||||
// work and don't crash.
|
||||
repeated google.protobuf.DoubleValue repeated_double = 11;
|
||||
repeated google.protobuf.FloatValue repeated_float = 12;
|
||||
repeated google.protobuf.Int32Value repeated_int32 = 13;
|
||||
repeated google.protobuf.Int64Value repeated_int64 = 14;
|
||||
repeated google.protobuf.UInt32Value repeated_uint32 = 15;
|
||||
repeated google.protobuf.UInt64Value repeated_uint64 = 16;
|
||||
repeated google.protobuf.BoolValue repeated_bool = 17;
|
||||
repeated google.protobuf.StringValue repeated_string = 18;
|
||||
repeated google.protobuf.BytesValue repeated_bytes = 19;
|
||||
|
||||
// Wrappers as map keys don't make sense, but we still need to make sure they
|
||||
// work and don't crash.
|
||||
map<int32, google.protobuf.DoubleValue> map_double = 21;
|
||||
map<int32, google.protobuf.FloatValue> map_float = 22;
|
||||
map<int32, google.protobuf.Int32Value> map_int32 = 23;
|
||||
map<int32, google.protobuf.Int64Value> map_int64 = 24;
|
||||
map<int32, google.protobuf.UInt32Value> map_uint32 = 25;
|
||||
map<int32, google.protobuf.UInt64Value> map_uint64 = 26;
|
||||
map<int32, google.protobuf.BoolValue> map_bool = 27;
|
||||
map<int32, google.protobuf.StringValue> map_string = 28;
|
||||
map<int32, google.protobuf.BytesValue> map_bytes = 29;
|
||||
|
||||
// Wrappers in oneofs don't make sense, but we still need to make sure they
|
||||
// work and don't crash.
|
||||
oneof wrapper_oneof {
|
||||
google.protobuf.DoubleValue oneof_double = 31;
|
||||
google.protobuf.FloatValue oneof_float = 32;
|
||||
google.protobuf.Int32Value oneof_int32 = 33;
|
||||
google.protobuf.Int64Value oneof_int64 = 34;
|
||||
google.protobuf.UInt32Value oneof_uint32 = 35;
|
||||
google.protobuf.UInt64Value oneof_uint64 = 36;
|
||||
google.protobuf.BoolValue oneof_bool = 37;
|
||||
google.protobuf.StringValue oneof_string = 38;
|
||||
google.protobuf.BytesValue oneof_bytes = 39;
|
||||
string oneof_plain_string = 101;
|
||||
}
|
||||
}
|
||||
|
||||
message TimeMessage {
|
||||
google.protobuf.Timestamp timestamp = 1;
|
||||
google.protobuf.Duration duration = 2;
|
||||
}
|
||||
|
||||
message Enumer {
|
||||
TestEnum optional_enum = 1;
|
||||
repeated TestEnum repeated_enum = 2;
|
||||
string a_const = 3;
|
||||
oneof a_oneof {
|
||||
string str = 10;
|
||||
TestEnum const = 11;
|
||||
}
|
||||
}
|
||||
|
||||
message MyRepeatedStruct {
|
||||
repeated MyStruct structs = 1;
|
||||
}
|
||||
|
||||
message MyStruct {
|
||||
string string = 1;
|
||||
google.protobuf.Struct struct = 2;
|
||||
}
|
||||
|
||||
message WithJsonName {
|
||||
optional int32 foo_bar = 1 [json_name="jsonFooBar"];
|
||||
repeated WithJsonName baz = 2 [json_name="jsonBaz"];
|
||||
}
|
||||
|
||||
message HelloRequest {
|
||||
optional uint32 id = 1;
|
||||
optional uint32 random_name_a0 = 2;
|
||||
optional uint32 random_name_a1 = 3;
|
||||
optional uint32 random_name_a2 = 4;
|
||||
optional uint32 random_name_a3 = 5;
|
||||
optional uint32 random_name_a4 = 6;
|
||||
optional uint32 random_name_a5 = 7;
|
||||
optional uint32 random_name_a6 = 8;
|
||||
optional uint32 random_name_a7 = 9;
|
||||
optional uint32 random_name_a8 = 10;
|
||||
optional uint32 random_name_a9 = 11;
|
||||
optional uint32 random_name_b0 = 12;
|
||||
optional uint32 random_name_b1 = 13;
|
||||
optional uint32 random_name_b2 = 14;
|
||||
optional uint32 random_name_b3 = 15;
|
||||
optional uint32 random_name_b4 = 16;
|
||||
optional uint32 random_name_b5 = 17;
|
||||
optional uint32 random_name_b6 = 18;
|
||||
optional uint32 random_name_b7 = 19;
|
||||
optional uint32 random_name_b8 = 20;
|
||||
optional uint32 random_name_b9 = 21;
|
||||
optional uint32 random_name_c0 = 22;
|
||||
optional uint32 random_name_c1 = 23;
|
||||
optional uint32 random_name_c2 = 24;
|
||||
optional uint32 random_name_c3 = 25;
|
||||
optional uint32 random_name_c4 = 26;
|
||||
optional uint32 random_name_c5 = 27;
|
||||
optional uint32 random_name_c6 = 28;
|
||||
optional uint32 random_name_c7 = 29;
|
||||
optional uint32 random_name_c8 = 30;
|
||||
optional uint32 random_name_c9 = 31;
|
||||
optional string version = 32;
|
||||
}
|
189
deps/protobuf/ruby/tests/basic_test_proto2.proto
vendored
Normal file
189
deps/protobuf/ruby/tests/basic_test_proto2.proto
vendored
Normal file
@ -0,0 +1,189 @@
|
||||
syntax = "proto2";
|
||||
|
||||
package basic_test_proto2;
|
||||
|
||||
import "google/protobuf/wrappers.proto";
|
||||
import "google/protobuf/timestamp.proto";
|
||||
import "google/protobuf/duration.proto";
|
||||
import "google/protobuf/struct.proto";
|
||||
|
||||
message Foo {
|
||||
optional Bar bar = 1;
|
||||
repeated Baz baz = 2;
|
||||
}
|
||||
|
||||
message Bar {
|
||||
optional string msg = 1;
|
||||
}
|
||||
|
||||
message Baz {
|
||||
optional string msg = 1;
|
||||
}
|
||||
|
||||
message TestMessage {
|
||||
optional int32 optional_int32 = 1;
|
||||
optional int64 optional_int64 = 2;
|
||||
optional uint32 optional_uint32 = 3;
|
||||
optional uint64 optional_uint64 = 4;
|
||||
optional bool optional_bool = 5;
|
||||
optional float optional_float = 6;
|
||||
optional double optional_double = 7;
|
||||
optional string optional_string = 8;
|
||||
optional bytes optional_bytes = 9;
|
||||
optional TestMessage2 optional_msg = 10;
|
||||
optional TestEnum optional_enum = 11;
|
||||
|
||||
repeated int32 repeated_int32 = 12;
|
||||
repeated int64 repeated_int64 = 13;
|
||||
repeated uint32 repeated_uint32 = 14;
|
||||
repeated uint64 repeated_uint64 = 15;
|
||||
repeated bool repeated_bool = 16;
|
||||
repeated float repeated_float = 17;
|
||||
repeated double repeated_double = 18;
|
||||
repeated string repeated_string = 19;
|
||||
repeated bytes repeated_bytes = 20;
|
||||
repeated TestMessage2 repeated_msg = 21;
|
||||
repeated TestEnum repeated_enum = 22;
|
||||
}
|
||||
|
||||
message TestMessage2 {
|
||||
optional int32 foo = 1;
|
||||
}
|
||||
|
||||
message TestMessageDefaults {
|
||||
optional int32 optional_int32 = 1 [default = 1];
|
||||
optional int64 optional_int64 = 2 [default = 2];
|
||||
optional uint32 optional_uint32 = 3 [default = 3];
|
||||
optional uint64 optional_uint64 = 4 [default = 4];
|
||||
optional bool optional_bool = 5 [default = true];
|
||||
optional float optional_float = 6 [default = 6];
|
||||
optional double optional_double = 7 [default = 7];
|
||||
optional string optional_string = 8 [default = "Default Str"];
|
||||
optional bytes optional_bytes = 9 [default = "\xCF\xA5s\xBD\xBA\xE6fubar"];
|
||||
optional TestMessage2 optional_msg = 10;
|
||||
optional TestNonZeroEnum optional_enum = 11 [default = B2];
|
||||
}
|
||||
|
||||
enum TestEnum {
|
||||
Default = 0;
|
||||
A = 1;
|
||||
B = 2;
|
||||
C = 3;
|
||||
}
|
||||
|
||||
enum TestNonZeroEnum {
|
||||
A2 = 1;
|
||||
B2 = 2;
|
||||
C2 = 3;
|
||||
}
|
||||
|
||||
message TestEmbeddedMessageParent {
|
||||
optional TestEmbeddedMessageChild child_msg = 1;
|
||||
optional int32 number = 2;
|
||||
|
||||
repeated TestEmbeddedMessageChild repeated_msg = 3;
|
||||
repeated int32 repeated_number = 4;
|
||||
}
|
||||
|
||||
message TestEmbeddedMessageChild {
|
||||
optional TestMessage sub_child = 1;
|
||||
}
|
||||
|
||||
message Recursive1 {
|
||||
optional Recursive2 foo = 1;
|
||||
}
|
||||
|
||||
message Recursive2 {
|
||||
optional Recursive1 foo = 1;
|
||||
}
|
||||
|
||||
message MapMessageWireEquiv {
|
||||
repeated MapMessageWireEquiv_entry1 map_string_int32 = 1;
|
||||
repeated MapMessageWireEquiv_entry2 map_string_msg = 2;
|
||||
}
|
||||
|
||||
message MapMessageWireEquiv_entry1 {
|
||||
optional string key = 1;
|
||||
optional int32 value = 2;
|
||||
}
|
||||
|
||||
message MapMessageWireEquiv_entry2 {
|
||||
optional string key = 1;
|
||||
optional TestMessage2 value = 2;
|
||||
}
|
||||
|
||||
message OneofMessage {
|
||||
oneof my_oneof {
|
||||
string a = 1;
|
||||
int32 b = 2;
|
||||
TestMessage2 c = 3;
|
||||
TestEnum d = 4;
|
||||
}
|
||||
}
|
||||
|
||||
message Wrapper {
|
||||
optional google.protobuf.DoubleValue double = 1;
|
||||
optional google.protobuf.FloatValue float = 2;
|
||||
optional google.protobuf.Int32Value int32 = 3;
|
||||
optional google.protobuf.Int64Value int64 = 4;
|
||||
optional google.protobuf.UInt32Value uint32 = 5;
|
||||
optional google.protobuf.UInt64Value uint64 = 6;
|
||||
optional google.protobuf.BoolValue bool = 7;
|
||||
optional google.protobuf.StringValue string = 8;
|
||||
optional google.protobuf.BytesValue bytes = 9;
|
||||
optional string real_string = 100;
|
||||
oneof a_oneof {
|
||||
string string_in_oneof = 10;
|
||||
}
|
||||
|
||||
// Repeated wrappers don't really make sense, but we still need to make sure
|
||||
// they work and don't crash.
|
||||
repeated google.protobuf.DoubleValue repeated_double = 11;
|
||||
repeated google.protobuf.FloatValue repeated_float = 12;
|
||||
repeated google.protobuf.Int32Value repeated_int32 = 13;
|
||||
repeated google.protobuf.Int64Value repeated_int64 = 14;
|
||||
repeated google.protobuf.UInt32Value repeated_uint32 = 15;
|
||||
repeated google.protobuf.UInt64Value repeated_uint64 = 16;
|
||||
repeated google.protobuf.BoolValue repeated_bool = 17;
|
||||
repeated google.protobuf.StringValue repeated_string = 18;
|
||||
repeated google.protobuf.BytesValue repeated_bytes = 19;
|
||||
|
||||
// Wrappers in oneofs don't make sense, but we still need to make sure they
|
||||
// work and don't crash.
|
||||
oneof wrapper_oneof {
|
||||
google.protobuf.DoubleValue oneof_double = 31;
|
||||
google.protobuf.FloatValue oneof_float = 32;
|
||||
google.protobuf.Int32Value oneof_int32 = 33;
|
||||
google.protobuf.Int64Value oneof_int64 = 34;
|
||||
google.protobuf.UInt32Value oneof_uint32 = 35;
|
||||
google.protobuf.UInt64Value oneof_uint64 = 36;
|
||||
google.protobuf.BoolValue oneof_bool = 37;
|
||||
google.protobuf.StringValue oneof_string = 38;
|
||||
google.protobuf.BytesValue oneof_bytes = 39;
|
||||
string oneof_plain_string = 101;
|
||||
}
|
||||
}
|
||||
|
||||
message TimeMessage {
|
||||
optional google.protobuf.Timestamp timestamp = 1;
|
||||
optional google.protobuf.Duration duration = 2;
|
||||
}
|
||||
|
||||
message Enumer {
|
||||
optional TestEnum optional_enum = 11;
|
||||
repeated TestEnum repeated_enum = 22;
|
||||
optional string a_const = 3;
|
||||
oneof a_oneof {
|
||||
string str = 100;
|
||||
TestEnum const = 101;
|
||||
}
|
||||
}
|
||||
|
||||
message MyRepeatedStruct {
|
||||
repeated MyStruct structs = 1;
|
||||
}
|
||||
|
||||
message MyStruct {
|
||||
optional string string = 1;
|
||||
optional google.protobuf.Struct struct = 2;
|
||||
}
|
1983
deps/protobuf/ruby/tests/common_tests.rb
vendored
Normal file
1983
deps/protobuf/ruby/tests/common_tests.rb
vendored
Normal file
File diff suppressed because it is too large
Load Diff
155
deps/protobuf/ruby/tests/encode_decode_test.rb
vendored
Normal file
155
deps/protobuf/ruby/tests/encode_decode_test.rb
vendored
Normal file
@ -0,0 +1,155 @@
|
||||
#!/usr/bin/ruby
|
||||
|
||||
# generated_code.rb is in the same directory as this test.
|
||||
$LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__)))
|
||||
|
||||
require 'generated_code_pb'
|
||||
require 'google/protobuf/well_known_types'
|
||||
require 'test/unit'
|
||||
|
||||
def hex2bin(s)
|
||||
s.scan(/../).map { |x| x.hex.chr }.join
|
||||
end
|
||||
|
||||
class EncodeDecodeTest < Test::Unit::TestCase
|
||||
def test_discard_unknown
|
||||
# Test discard unknown in message.
|
||||
unknown_msg = A::B::C::TestUnknown.new(:unknown_field => 1)
|
||||
from = A::B::C::TestUnknown.encode(unknown_msg)
|
||||
m = A::B::C::TestMessage.decode(from)
|
||||
Google::Protobuf.discard_unknown(m)
|
||||
to = A::B::C::TestMessage.encode(m)
|
||||
assert_equal '', to
|
||||
|
||||
# Test discard unknown for singular message field.
|
||||
unknown_msg = A::B::C::TestUnknown.new(
|
||||
:optional_unknown =>
|
||||
A::B::C::TestUnknown.new(:unknown_field => 1))
|
||||
from = A::B::C::TestUnknown.encode(unknown_msg)
|
||||
m = A::B::C::TestMessage.decode(from)
|
||||
Google::Protobuf.discard_unknown(m)
|
||||
to = A::B::C::TestMessage.encode(m.optional_msg)
|
||||
assert_equal '', to
|
||||
|
||||
# Test discard unknown for repeated message field.
|
||||
unknown_msg = A::B::C::TestUnknown.new(
|
||||
:repeated_unknown =>
|
||||
[A::B::C::TestUnknown.new(:unknown_field => 1)])
|
||||
from = A::B::C::TestUnknown.encode(unknown_msg)
|
||||
m = A::B::C::TestMessage.decode(from)
|
||||
Google::Protobuf.discard_unknown(m)
|
||||
to = A::B::C::TestMessage.encode(m.repeated_msg[0])
|
||||
assert_equal '', to
|
||||
|
||||
# Test discard unknown for map value message field.
|
||||
unknown_msg = A::B::C::TestUnknown.new(
|
||||
:map_unknown =>
|
||||
{"" => A::B::C::TestUnknown.new(:unknown_field => 1)})
|
||||
from = A::B::C::TestUnknown.encode(unknown_msg)
|
||||
m = A::B::C::TestMessage.decode(from)
|
||||
Google::Protobuf.discard_unknown(m)
|
||||
to = A::B::C::TestMessage.encode(m.map_string_msg[''])
|
||||
assert_equal '', to
|
||||
|
||||
# Test discard unknown for oneof message field.
|
||||
unknown_msg = A::B::C::TestUnknown.new(
|
||||
:oneof_unknown =>
|
||||
A::B::C::TestUnknown.new(:unknown_field => 1))
|
||||
from = A::B::C::TestUnknown.encode(unknown_msg)
|
||||
m = A::B::C::TestMessage.decode(from)
|
||||
Google::Protobuf.discard_unknown(m)
|
||||
to = A::B::C::TestMessage.encode(m.oneof_msg)
|
||||
assert_equal '', to
|
||||
end
|
||||
|
||||
def test_encode_json
|
||||
msg = A::B::C::TestMessage.new({ optional_int32: 22 })
|
||||
json = msg.to_json
|
||||
|
||||
to = A::B::C::TestMessage.decode_json(json)
|
||||
assert_equal to.optional_int32, 22
|
||||
|
||||
msg = A::B::C::TestMessage.new({ optional_int32: 22 })
|
||||
json = msg.to_json({ preserve_proto_fieldnames: true })
|
||||
|
||||
assert_match 'optional_int32', json
|
||||
|
||||
to = A::B::C::TestMessage.decode_json(json)
|
||||
assert_equal 22, to.optional_int32
|
||||
|
||||
msg = A::B::C::TestMessage.new({ optional_int32: 22 })
|
||||
json = A::B::C::TestMessage.encode_json(
|
||||
msg,
|
||||
{ preserve_proto_fieldnames: true, emit_defaults: true }
|
||||
)
|
||||
|
||||
assert_match 'optional_int32', json
|
||||
end
|
||||
|
||||
def test_encode_wrong_msg
|
||||
assert_raise ::ArgumentError do
|
||||
m = A::B::C::TestMessage.new(
|
||||
:optional_int32 => 1,
|
||||
)
|
||||
Google::Protobuf::Any.encode(m)
|
||||
end
|
||||
end
|
||||
|
||||
def test_json_name
|
||||
msg = A::B::C::TestJsonName.new(:value => 42)
|
||||
json = msg.to_json
|
||||
assert_match json, "{\"CustomJsonName\":42}"
|
||||
end
|
||||
|
||||
def test_decode_depth_limit
|
||||
msg = A::B::C::TestMessage.new(
|
||||
optional_msg: A::B::C::TestMessage.new(
|
||||
optional_msg: A::B::C::TestMessage.new(
|
||||
optional_msg: A::B::C::TestMessage.new(
|
||||
optional_msg: A::B::C::TestMessage.new(
|
||||
optional_msg: A::B::C::TestMessage.new(
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
msg_encoded = A::B::C::TestMessage.encode(msg)
|
||||
msg_out = A::B::C::TestMessage.decode(msg_encoded)
|
||||
assert_match msg.to_json, msg_out.to_json
|
||||
|
||||
assert_raise Google::Protobuf::ParseError do
|
||||
A::B::C::TestMessage.decode(msg_encoded, { recursion_limit: 4 })
|
||||
end
|
||||
|
||||
msg_out = A::B::C::TestMessage.decode(msg_encoded, { recursion_limit: 5 })
|
||||
assert_match msg.to_json, msg_out.to_json
|
||||
end
|
||||
|
||||
def test_encode_depth_limit
|
||||
msg = A::B::C::TestMessage.new(
|
||||
optional_msg: A::B::C::TestMessage.new(
|
||||
optional_msg: A::B::C::TestMessage.new(
|
||||
optional_msg: A::B::C::TestMessage.new(
|
||||
optional_msg: A::B::C::TestMessage.new(
|
||||
optional_msg: A::B::C::TestMessage.new(
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
msg_encoded = A::B::C::TestMessage.encode(msg)
|
||||
msg_out = A::B::C::TestMessage.decode(msg_encoded)
|
||||
assert_match msg.to_json, msg_out.to_json
|
||||
|
||||
assert_raise RuntimeError do
|
||||
A::B::C::TestMessage.encode(msg, { recursion_limit: 5 })
|
||||
end
|
||||
|
||||
msg_encoded = A::B::C::TestMessage.encode(msg, { recursion_limit: 6 })
|
||||
msg_out = A::B::C::TestMessage.decode(msg_encoded)
|
||||
assert_match msg.to_json, msg_out.to_json
|
||||
end
|
||||
|
||||
end
|
109
deps/protobuf/ruby/tests/gc_test.rb
vendored
Normal file
109
deps/protobuf/ruby/tests/gc_test.rb
vendored
Normal file
@ -0,0 +1,109 @@
|
||||
#!/usr/bin/ruby
|
||||
#
|
||||
# generated_code.rb is in the same directory as this test.
|
||||
$LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__)))
|
||||
|
||||
old_gc = GC.stress
|
||||
# Ruby 2.7.0 - 2.7.1 has a GC bug in its parser, so turn off stress for now
|
||||
# See https://bugs.ruby-lang.org/issues/16807
|
||||
GC.stress = 0x01 | 0x04 unless RUBY_VERSION.match?(/^2\.7\./)
|
||||
require 'generated_code_pb'
|
||||
require 'generated_code_proto2_pb'
|
||||
GC.stress = old_gc
|
||||
|
||||
require 'test/unit'
|
||||
|
||||
class GCTest < Test::Unit::TestCase
|
||||
def get_msg_proto3
|
||||
A::B::C::TestMessage.new(
|
||||
:optional_int32 => 1,
|
||||
:optional_int64 => 1,
|
||||
:optional_uint32 => 1,
|
||||
:optional_uint64 => 1,
|
||||
:optional_bool => true,
|
||||
:optional_double => 1.0,
|
||||
:optional_float => 1.0,
|
||||
:optional_string => "a",
|
||||
:optional_bytes => "b",
|
||||
:optional_enum => A::B::C::TestEnum::A,
|
||||
:optional_msg => A::B::C::TestMessage.new(),
|
||||
:repeated_int32 => [1],
|
||||
:repeated_int64 => [1],
|
||||
:repeated_uint32 => [1],
|
||||
:repeated_uint64 => [1],
|
||||
:repeated_bool => [true],
|
||||
:repeated_double => [1.0],
|
||||
:repeated_float => [1.0],
|
||||
:repeated_string => ["a"],
|
||||
:repeated_bytes => ["b"],
|
||||
:repeated_enum => [A::B::C::TestEnum::A],
|
||||
:repeated_msg => [A::B::C::TestMessage.new()],
|
||||
:map_int32_string => {1 => "a"},
|
||||
:map_int64_string => {1 => "a"},
|
||||
:map_uint32_string => {1 => "a"},
|
||||
:map_uint64_string => {1 => "a"},
|
||||
:map_bool_string => {true => "a"},
|
||||
:map_string_string => {"a" => "a"},
|
||||
:map_string_msg => {"a" => A::B::C::TestMessage.new()},
|
||||
:map_string_int32 => {"a" => 1},
|
||||
:map_string_bool => {"a" => true},
|
||||
)
|
||||
end
|
||||
|
||||
def get_msg_proto2
|
||||
A::B::Proto2::TestMessage.new(
|
||||
:optional_int32 => 1,
|
||||
:optional_int64 => 1,
|
||||
:optional_uint32 => 1,
|
||||
:optional_uint64 => 1,
|
||||
:optional_bool => true,
|
||||
:optional_double => 1.0,
|
||||
:optional_float => 1.0,
|
||||
:optional_string => "a",
|
||||
:optional_bytes => "b",
|
||||
:optional_enum => A::B::Proto2::TestEnum::A,
|
||||
:optional_msg => A::B::Proto2::TestMessage.new(),
|
||||
:repeated_int32 => [1],
|
||||
:repeated_int64 => [1],
|
||||
:repeated_uint32 => [1],
|
||||
:repeated_uint64 => [1],
|
||||
:repeated_bool => [true],
|
||||
:repeated_double => [1.0],
|
||||
:repeated_float => [1.0],
|
||||
:repeated_string => ["a"],
|
||||
:repeated_bytes => ["b"],
|
||||
:repeated_enum => [A::B::Proto2::TestEnum::A],
|
||||
:repeated_msg => [A::B::Proto2::TestMessage.new()],
|
||||
:required_int32 => 1,
|
||||
:required_int64 => 1,
|
||||
:required_uint32 => 1,
|
||||
:required_uint64 => 1,
|
||||
:required_bool => true,
|
||||
:required_double => 1.0,
|
||||
:required_float => 1.0,
|
||||
:required_string => "a",
|
||||
:required_bytes => "b",
|
||||
:required_enum => A::B::Proto2::TestEnum::A,
|
||||
:required_msg => A::B::Proto2::TestMessage.new(),
|
||||
)
|
||||
end
|
||||
|
||||
def test_generated_msg
|
||||
old_gc = GC.stress
|
||||
GC.stress = 0x01 | 0x04
|
||||
from = get_msg_proto3
|
||||
data = A::B::C::TestMessage.encode(from)
|
||||
to = A::B::C::TestMessage.decode(data)
|
||||
# This doesn't work for proto2 on JRuby because there is a nested required message.
|
||||
# A::B::Proto2::TestMessage has :required_msg which is of type:
|
||||
# A::B::Proto2::TestMessage so there is no way to generate a valid
|
||||
# message that doesn't exceed the depth limit
|
||||
if !defined? JRUBY_VERSION
|
||||
from = get_msg_proto2
|
||||
data = A::B::Proto2::TestMessage.encode(from)
|
||||
to = A::B::Proto2::TestMessage.decode(data)
|
||||
end
|
||||
GC.stress = old_gc
|
||||
puts "passed"
|
||||
end
|
||||
end
|
89
deps/protobuf/ruby/tests/generated_code.proto
vendored
Normal file
89
deps/protobuf/ruby/tests/generated_code.proto
vendored
Normal file
@ -0,0 +1,89 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package a.b.c;
|
||||
|
||||
message TestMessage {
|
||||
int32 optional_int32 = 1;
|
||||
int64 optional_int64 = 2;
|
||||
uint32 optional_uint32 = 3;
|
||||
uint64 optional_uint64 = 4;
|
||||
bool optional_bool = 5;
|
||||
double optional_double = 6;
|
||||
float optional_float = 7;
|
||||
string optional_string = 8;
|
||||
bytes optional_bytes = 9;
|
||||
TestEnum optional_enum = 10;
|
||||
TestMessage optional_msg = 11;
|
||||
|
||||
repeated int32 repeated_int32 = 21;
|
||||
repeated int64 repeated_int64 = 22;
|
||||
repeated uint32 repeated_uint32 = 23;
|
||||
repeated uint64 repeated_uint64 = 24;
|
||||
repeated bool repeated_bool = 25;
|
||||
repeated double repeated_double = 26;
|
||||
repeated float repeated_float = 27;
|
||||
repeated string repeated_string = 28;
|
||||
repeated bytes repeated_bytes = 29;
|
||||
repeated TestEnum repeated_enum = 30;
|
||||
repeated TestMessage repeated_msg = 31;
|
||||
|
||||
oneof my_oneof {
|
||||
int32 oneof_int32 = 41;
|
||||
int64 oneof_int64 = 42;
|
||||
uint32 oneof_uint32 = 43;
|
||||
uint64 oneof_uint64 = 44;
|
||||
bool oneof_bool = 45;
|
||||
double oneof_double = 46;
|
||||
float oneof_float = 47;
|
||||
string oneof_string = 48;
|
||||
bytes oneof_bytes = 49;
|
||||
TestEnum oneof_enum = 50;
|
||||
TestMessage oneof_msg = 51;
|
||||
}
|
||||
|
||||
map<int32, string> map_int32_string = 61;
|
||||
map<int64, string> map_int64_string = 62;
|
||||
map<uint32, string> map_uint32_string = 63;
|
||||
map<uint64, string> map_uint64_string = 64;
|
||||
map<bool, string> map_bool_string = 65;
|
||||
map<string, string> map_string_string = 66;
|
||||
map<string, TestMessage> map_string_msg = 67;
|
||||
map<string, TestEnum> map_string_enum = 68;
|
||||
map<string, int32> map_string_int32 = 69;
|
||||
map<string, bool> map_string_bool = 70;
|
||||
|
||||
message NestedMessage {
|
||||
int32 foo = 1;
|
||||
}
|
||||
|
||||
NestedMessage nested_message = 80;
|
||||
|
||||
// Reserved for non-existing field test.
|
||||
// int32 non_exist = 89;
|
||||
}
|
||||
|
||||
enum TestEnum {
|
||||
Default = 0;
|
||||
A = 1;
|
||||
B = 2;
|
||||
C = 3;
|
||||
}
|
||||
|
||||
message testLowercaseNested {
|
||||
message lowercase{}
|
||||
}
|
||||
|
||||
|
||||
message TestUnknown {
|
||||
TestUnknown optional_unknown = 11;
|
||||
repeated TestUnknown repeated_unknown = 31;
|
||||
oneof my_oneof {
|
||||
TestUnknown oneof_unknown = 51;
|
||||
}
|
||||
map<string, TestUnknown> map_unknown = 67;
|
||||
int32 unknown_field = 89;
|
||||
}
|
||||
|
||||
message TestJsonName {
|
||||
int32 value = 1 [json_name = "CustomJsonName"];
|
||||
}
|
80
deps/protobuf/ruby/tests/generated_code_proto2.proto
vendored
Normal file
80
deps/protobuf/ruby/tests/generated_code_proto2.proto
vendored
Normal file
@ -0,0 +1,80 @@
|
||||
syntax = "proto2";
|
||||
|
||||
package a.b.proto2;
|
||||
|
||||
message TestMessage {
|
||||
optional int32 optional_int32 = 1;
|
||||
optional int64 optional_int64 = 2;
|
||||
optional uint32 optional_uint32 = 3;
|
||||
optional uint64 optional_uint64 = 4;
|
||||
optional bool optional_bool = 5;
|
||||
optional double optional_double = 6;
|
||||
optional float optional_float = 7;
|
||||
optional string optional_string = 8;
|
||||
optional bytes optional_bytes = 9;
|
||||
optional TestEnum optional_enum = 10;
|
||||
optional TestMessage optional_msg = 11;
|
||||
|
||||
repeated int32 repeated_int32 = 21;
|
||||
repeated int64 repeated_int64 = 22;
|
||||
repeated uint32 repeated_uint32 = 23;
|
||||
repeated uint64 repeated_uint64 = 24;
|
||||
repeated bool repeated_bool = 25;
|
||||
repeated double repeated_double = 26;
|
||||
repeated float repeated_float = 27;
|
||||
repeated string repeated_string = 28;
|
||||
repeated bytes repeated_bytes = 29;
|
||||
repeated TestEnum repeated_enum = 30;
|
||||
repeated TestMessage repeated_msg = 31;
|
||||
|
||||
required int32 required_int32 = 41;
|
||||
required int64 required_int64 = 42;
|
||||
required uint32 required_uint32 = 43;
|
||||
required uint64 required_uint64 = 44;
|
||||
required bool required_bool = 45;
|
||||
required double required_double = 46;
|
||||
required float required_float = 47;
|
||||
required string required_string = 48;
|
||||
required bytes required_bytes = 49;
|
||||
required TestEnum required_enum = 50;
|
||||
required TestMessage required_msg = 51;
|
||||
|
||||
oneof my_oneof {
|
||||
int32 oneof_int32 = 61;
|
||||
int64 oneof_int64 = 62;
|
||||
uint32 oneof_uint32 = 63;
|
||||
uint64 oneof_uint64 = 64;
|
||||
bool oneof_bool = 65;
|
||||
double oneof_double = 66;
|
||||
float oneof_float = 67;
|
||||
string oneof_string = 68;
|
||||
bytes oneof_bytes = 69;
|
||||
TestEnum oneof_enum = 70;
|
||||
TestMessage oneof_msg = 71;
|
||||
}
|
||||
|
||||
message NestedMessage {
|
||||
optional int32 foo = 1;
|
||||
}
|
||||
|
||||
optional NestedMessage nested_message = 80;
|
||||
|
||||
// Reserved for non-existing field test.
|
||||
// int32 non_exist = 89;
|
||||
}
|
||||
|
||||
enum TestEnum {
|
||||
Default = 0;
|
||||
A = 1;
|
||||
B = 2;
|
||||
C = 3;
|
||||
}
|
||||
|
||||
message TestUnknown {
|
||||
optional TestUnknown optional_unknown = 11;
|
||||
repeated TestUnknown repeated_unknown = 31;
|
||||
oneof my_oneof {
|
||||
TestUnknown oneof_unknown = 51;
|
||||
}
|
||||
optional int32 unknown_field = 89;
|
||||
}
|
21
deps/protobuf/ruby/tests/generated_code_proto2_test.rb
vendored
Normal file
21
deps/protobuf/ruby/tests/generated_code_proto2_test.rb
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
#!/usr/bin/ruby
|
||||
|
||||
# generated_code.rb is in the same directory as this test.
|
||||
$LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__)))
|
||||
|
||||
require 'generated_code_proto2_pb'
|
||||
require 'test_import_proto2_pb'
|
||||
require 'test_ruby_package_proto2_pb'
|
||||
require 'test/unit'
|
||||
|
||||
class GeneratedCodeProto2Test < Test::Unit::TestCase
|
||||
def test_generated_msg
|
||||
# just test that we can instantiate the message. The purpose of this test
|
||||
# is to ensure that the output of the code generator is valid Ruby and
|
||||
# successfully creates message definitions and classes, not to test every
|
||||
# aspect of the extension (basic.rb is for that).
|
||||
A::B::Proto2::TestMessage.new
|
||||
FooBar::Proto2::TestImportedMessage.new
|
||||
A::B::Proto2::TestRubyPackageMessage.new
|
||||
end
|
||||
end
|
23
deps/protobuf/ruby/tests/generated_code_test.rb
vendored
Normal file
23
deps/protobuf/ruby/tests/generated_code_test.rb
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
#!/usr/bin/ruby
|
||||
|
||||
# generated_code.rb is in the same directory as this test.
|
||||
$LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__)))
|
||||
|
||||
require 'generated_code_pb'
|
||||
require 'test_import_pb'
|
||||
require 'test_ruby_package_pb'
|
||||
require 'test/unit'
|
||||
|
||||
class GeneratedCodeTest < Test::Unit::TestCase
|
||||
def test_generated_msg
|
||||
# just test that we can instantiate the message. The purpose of this test
|
||||
# is to ensure that the output of the code generator is valid Ruby and
|
||||
# successfully creates message definitions and classes, not to test every
|
||||
# aspect of the extension (basic.rb is for that).
|
||||
A::B::C::TestMessage.new
|
||||
A::B::C::TestMessage::NestedMessage.new
|
||||
A::B::C::TestLowercaseNested::Lowercase.new
|
||||
FooBar::TestImportedMessage.new
|
||||
A::B::TestRubyPackageMessage.new
|
||||
end
|
||||
end
|
19
deps/protobuf/ruby/tests/multi_level_nesting_test.proto
vendored
Normal file
19
deps/protobuf/ruby/tests/multi_level_nesting_test.proto
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
syntax = "proto3";
|
||||
|
||||
message Function {
|
||||
string name = 1;
|
||||
repeated Function.Parameter parameters = 2;
|
||||
string return_type = 3;
|
||||
|
||||
message Parameter {
|
||||
string name = 1;
|
||||
Function.Parameter.Value value = 2;
|
||||
|
||||
message Value {
|
||||
oneof type {
|
||||
string string = 1;
|
||||
int64 integer = 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
20
deps/protobuf/ruby/tests/multi_level_nesting_test.rb
vendored
Normal file
20
deps/protobuf/ruby/tests/multi_level_nesting_test.rb
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
#!/usr/bin/ruby
|
||||
|
||||
# multi_level_nesting_test_pb.rb is in the same directory as this test.
|
||||
$LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__)))
|
||||
|
||||
require 'test/unit'
|
||||
require 'multi_level_nesting_test_pb'
|
||||
|
||||
#
|
||||
# Provide tests for having messages nested 3 levels deep
|
||||
#
|
||||
class MultiLevelNestingTest < Test::Unit::TestCase
|
||||
|
||||
def test_levels_exist
|
||||
assert ::Google::Protobuf::DescriptorPool.generated_pool.lookup("Function").msgclass
|
||||
assert ::Google::Protobuf::DescriptorPool.generated_pool.lookup("Function.Parameter").msgclass
|
||||
assert ::Google::Protobuf::DescriptorPool.generated_pool.lookup("Function.Parameter.Value").msgclass
|
||||
end
|
||||
|
||||
end
|
653
deps/protobuf/ruby/tests/repeated_field_test.rb
vendored
Normal file
653
deps/protobuf/ruby/tests/repeated_field_test.rb
vendored
Normal file
@ -0,0 +1,653 @@
|
||||
#!/usr/bin/ruby
|
||||
|
||||
require 'google/protobuf'
|
||||
require 'test/unit'
|
||||
|
||||
class RepeatedFieldTest < Test::Unit::TestCase
|
||||
|
||||
def test_acts_like_enumerator
|
||||
m = TestMessage.new
|
||||
(Enumerable.instance_methods - TestMessage.new.repeated_string.methods).each do |method_name|
|
||||
assert m.repeated_string.respond_to?(method_name) == true, "does not respond to #{method_name}"
|
||||
end
|
||||
end
|
||||
|
||||
def test_acts_like_an_array
|
||||
m = TestMessage.new
|
||||
arr_methods = ([].methods - TestMessage.new.repeated_string.methods)
|
||||
# jRuby additions to the Array class that we can ignore
|
||||
arr_methods -= [ :indices, :iter_for_each, :iter_for_each_index,
|
||||
:iter_for_each_with_index, :dimensions, :copy_data, :copy_data_simple,
|
||||
:nitems, :iter_for_reverse_each, :indexes, :append, :prepend]
|
||||
arr_methods -= [:union, :difference, :filter!]
|
||||
arr_methods -= [:intersection, :deconstruct] # ruby 2.7 methods we can ignore
|
||||
arr_methods -= [:intersect?] # ruby 3.1 methods we can ignore
|
||||
arr_methods.each do |method_name|
|
||||
assert m.repeated_string.respond_to?(method_name) == true, "does not respond to #{method_name}"
|
||||
end
|
||||
end
|
||||
|
||||
def test_first
|
||||
m = TestMessage.new
|
||||
repeated_field_names(TestMessage).each do |field_name|
|
||||
assert_nil m.send(field_name).first
|
||||
assert_equal [], m.send(field_name).first(0)
|
||||
assert_equal [], m.send(field_name).first(1)
|
||||
end
|
||||
|
||||
fill_test_msg(m)
|
||||
assert_equal -10, m.repeated_int32.first
|
||||
assert_equal -1_000_000, m.repeated_int64.first
|
||||
assert_equal 10, m.repeated_uint32.first
|
||||
assert_equal 1_000_000, m.repeated_uint64.first
|
||||
assert_equal true, m.repeated_bool.first
|
||||
assert_equal -1.01, m.repeated_float.first.round(2)
|
||||
assert_equal -1.0000000000001, m.repeated_double.first
|
||||
assert_equal 'foo', m.repeated_string.first
|
||||
assert_equal "bar".encode!('ASCII-8BIT'), m.repeated_bytes.first
|
||||
assert_equal TestMessage2.new(:foo => 1), m.repeated_msg.first
|
||||
assert_equal :A, m.repeated_enum.first
|
||||
|
||||
assert_equal [], m.repeated_int32.first(0)
|
||||
assert_equal [-10], m.repeated_int32.first(1)
|
||||
assert_equal [-10, -11], m.repeated_int32.first(2)
|
||||
assert_equal [-10, -11], m.repeated_int32.first(3)
|
||||
end
|
||||
|
||||
|
||||
def test_last
|
||||
m = TestMessage.new
|
||||
repeated_field_names(TestMessage).each do |field_name|
|
||||
assert_nil m.send(field_name).first
|
||||
end
|
||||
fill_test_msg(m)
|
||||
assert_equal -11, m.repeated_int32.last
|
||||
assert_equal -1_000_001, m.repeated_int64.last
|
||||
assert_equal 11, m.repeated_uint32.last
|
||||
assert_equal 1_000_001, m.repeated_uint64.last
|
||||
assert_equal false, m.repeated_bool.last
|
||||
assert_equal -1.02, m.repeated_float.last.round(2)
|
||||
assert_equal -1.0000000000002, m.repeated_double.last
|
||||
assert_equal 'bar', m.repeated_string.last
|
||||
assert_equal "foo".encode!('ASCII-8BIT'), m.repeated_bytes.last
|
||||
assert_equal TestMessage2.new(:foo => 2), m.repeated_msg.last
|
||||
assert_equal :B, m.repeated_enum.last
|
||||
end
|
||||
|
||||
|
||||
def test_pop
|
||||
m = TestMessage.new
|
||||
repeated_field_names(TestMessage).each do |field_name|
|
||||
assert_nil m.send(field_name).pop
|
||||
end
|
||||
fill_test_msg(m)
|
||||
|
||||
assert_equal -11, m.repeated_int32.pop
|
||||
assert_equal -10, m.repeated_int32.pop
|
||||
assert_equal -1_000_001, m.repeated_int64.pop
|
||||
assert_equal -1_000_000, m.repeated_int64.pop
|
||||
assert_equal 11, m.repeated_uint32.pop
|
||||
assert_equal 10, m.repeated_uint32.pop
|
||||
assert_equal 1_000_001, m.repeated_uint64.pop
|
||||
assert_equal 1_000_000, m.repeated_uint64.pop
|
||||
assert_equal false, m.repeated_bool.pop
|
||||
assert_equal true, m.repeated_bool.pop
|
||||
assert_equal -1.02, m.repeated_float.pop.round(2)
|
||||
assert_equal -1.01, m.repeated_float.pop.round(2)
|
||||
assert_equal -1.0000000000002, m.repeated_double.pop
|
||||
assert_equal -1.0000000000001, m.repeated_double.pop
|
||||
assert_equal 'bar', m.repeated_string.pop
|
||||
assert_equal 'foo', m.repeated_string.pop
|
||||
assert_equal "foo".encode!('ASCII-8BIT'), m.repeated_bytes.pop
|
||||
assert_equal "bar".encode!('ASCII-8BIT'), m.repeated_bytes.pop
|
||||
assert_equal TestMessage2.new(:foo => 2), m.repeated_msg.pop
|
||||
assert_equal TestMessage2.new(:foo => 1), m.repeated_msg.pop
|
||||
assert_equal :B, m.repeated_enum.pop
|
||||
assert_equal :A, m.repeated_enum.pop
|
||||
repeated_field_names(TestMessage).each do |field_name|
|
||||
assert_nil m.send(field_name).pop
|
||||
end
|
||||
|
||||
fill_test_msg(m)
|
||||
assert_equal ['bar', 'foo'], m.repeated_string.pop(2)
|
||||
assert_nil m.repeated_string.pop
|
||||
end
|
||||
|
||||
|
||||
def test_each
|
||||
m = TestMessage.new
|
||||
5.times{|i| m.repeated_string << 'string' }
|
||||
count = 0
|
||||
m.repeated_string.each do |val|
|
||||
assert_equal 'string', val
|
||||
count += 1
|
||||
end
|
||||
assert_equal 5, count
|
||||
result = m.repeated_string.each{|val| val + '_junk'}
|
||||
assert_equal ['string'] * 5, result
|
||||
end
|
||||
|
||||
|
||||
def test_empty?
|
||||
m = TestMessage.new
|
||||
assert_equal true, m.repeated_string.empty?
|
||||
m.repeated_string << 'foo'
|
||||
assert_equal false, m.repeated_string.empty?
|
||||
m.repeated_string << 'bar'
|
||||
assert_equal false, m.repeated_string.empty?
|
||||
end
|
||||
|
||||
def test_reassign
|
||||
m = TestMessage.new
|
||||
m.repeated_msg = Google::Protobuf::RepeatedField.new(:message, TestMessage2, [TestMessage2.new(:foo => 1)])
|
||||
assert_equal m.repeated_msg.first, TestMessage2.new(:foo => 1)
|
||||
end
|
||||
|
||||
def test_array_accessor
|
||||
m = TestMessage.new
|
||||
reference_arr = %w(foo bar baz)
|
||||
m.repeated_string += reference_arr.clone
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr[1]
|
||||
end
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr[-2]
|
||||
end
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr[20]
|
||||
end
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr[1, 2]
|
||||
end
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr[0..2]
|
||||
end
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr[-1, 1]
|
||||
end
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr[10, 12]
|
||||
end
|
||||
end
|
||||
|
||||
def test_array_settor
|
||||
m = TestMessage.new
|
||||
reference_arr = %w(foo bar baz)
|
||||
m.repeated_string += reference_arr.clone
|
||||
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr[1] = 'junk'
|
||||
end
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr[-2] = 'snappy'
|
||||
end
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr[3] = ''
|
||||
end
|
||||
# slight deviation; we are strongly typed, and nil is not allowed
|
||||
# for string types;
|
||||
m.repeated_string[5] = 'spacious'
|
||||
assert_equal ["foo", "snappy", "baz", "", "", "spacious"], m.repeated_string
|
||||
|
||||
#make sure it sests the default types for other fields besides strings
|
||||
%w(repeated_int32 repeated_int64 repeated_uint32 repeated_uint64).each do |field_name|
|
||||
m.send(field_name)[3] = 10
|
||||
assert_equal [0,0,0,10], m.send(field_name)
|
||||
end
|
||||
m.repeated_float[3] = 10.1
|
||||
#wonky mri float handling
|
||||
assert_equal [0,0,0], m.repeated_float.to_a[0..2]
|
||||
assert_equal 10.1, m.repeated_float[3].round(1)
|
||||
m.repeated_double[3] = 10.1
|
||||
assert_equal [0,0,0,10.1], m.repeated_double
|
||||
m.repeated_bool[3] = true
|
||||
assert_equal [false, false, false, true], m.repeated_bool
|
||||
m.repeated_bytes[3] = "bar".encode!('ASCII-8BIT')
|
||||
assert_equal ['', '', '', "bar".encode!('ASCII-8BIT')], m.repeated_bytes
|
||||
m.repeated_msg[3] = TestMessage2.new(:foo => 1)
|
||||
assert_equal [nil, nil, nil, TestMessage2.new(:foo => 1)], m.repeated_msg
|
||||
m.repeated_enum[3] = :A
|
||||
assert_equal [:Default, :Default, :Default, :A], m.repeated_enum
|
||||
|
||||
# check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
# arr[20] = 'spacious'
|
||||
# end
|
||||
# TODO: accessor doesn't allow other ruby-like methods
|
||||
# check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
# arr[1, 2] = 'fizz'
|
||||
# end
|
||||
# check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
# arr[0..2] = 'buzz'
|
||||
# end
|
||||
end
|
||||
|
||||
def test_push
|
||||
m = TestMessage.new
|
||||
reference_arr = %w[foo bar baz]
|
||||
m.repeated_string += reference_arr.clone
|
||||
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr.push('fizz')
|
||||
end
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr << 'fizz'
|
||||
end
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr.push('fizz', 'buzz')
|
||||
end
|
||||
end
|
||||
|
||||
def test_clear
|
||||
m = TestMessage.new
|
||||
reference_arr = %w(foo bar baz)
|
||||
m.repeated_string += reference_arr.clone
|
||||
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr.clear
|
||||
end
|
||||
end
|
||||
|
||||
def test_concat
|
||||
m = TestMessage.new
|
||||
reference_arr = %w(foo bar baz)
|
||||
m.repeated_string += reference_arr.clone
|
||||
m.repeated_string.concat(['fizz', 'buzz'])
|
||||
assert_equal %w(foo bar baz fizz buzz), m.repeated_string
|
||||
#TODO: concat should return the orig array
|
||||
# check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
# arr.concat(['fizz', 'buzz'])
|
||||
# end
|
||||
end
|
||||
|
||||
def test_equal
|
||||
m = TestMessage.new
|
||||
reference_arr = %w(foo bar baz)
|
||||
m.repeated_string += reference_arr.clone
|
||||
assert_equal reference_arr, m.repeated_string
|
||||
reference_arr << 'fizz'
|
||||
assert_not_equal reference_arr, m.repeated_string
|
||||
m.repeated_string << 'fizz'
|
||||
assert_equal reference_arr, m.repeated_string
|
||||
end
|
||||
|
||||
def test_hash
|
||||
# just a sanity check
|
||||
m = TestMessage.new
|
||||
reference_arr = %w(foo bar baz)
|
||||
m.repeated_string += reference_arr.clone
|
||||
assert m.repeated_string.hash.is_a?(Integer)
|
||||
hash = m.repeated_string.hash
|
||||
assert_equal hash, m.repeated_string.hash
|
||||
m.repeated_string << 'j'
|
||||
assert_not_equal hash, m.repeated_string.hash
|
||||
end
|
||||
|
||||
def test_plus
|
||||
m = TestMessage.new
|
||||
reference_arr = %w(foo bar baz)
|
||||
m.repeated_string += reference_arr.clone
|
||||
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr + ['fizz', 'buzz']
|
||||
end
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr += ['fizz', 'buzz']
|
||||
end
|
||||
end
|
||||
|
||||
def test_replace
|
||||
m = TestMessage.new
|
||||
reference_arr = %w(foo bar baz)
|
||||
m.repeated_string += reference_arr.clone
|
||||
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr.replace(['fizz', 'buzz'])
|
||||
end
|
||||
end
|
||||
|
||||
def test_to_a
|
||||
m = TestMessage.new
|
||||
reference_arr = %w(foo bar baz)
|
||||
m.repeated_string += reference_arr.clone
|
||||
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr.to_a
|
||||
end
|
||||
end
|
||||
|
||||
def test_to_ary
|
||||
m = TestMessage.new
|
||||
reference_arr = %w(foo bar baz)
|
||||
m.repeated_string += reference_arr.clone
|
||||
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr.to_ary
|
||||
end
|
||||
end
|
||||
|
||||
# emulate Array behavior
|
||||
##########################
|
||||
|
||||
def test_collect!
|
||||
m = TestMessage.new
|
||||
reference_arr = %w(foo bar baz)
|
||||
m.repeated_string += reference_arr.clone
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr.collect!{|x| x + "!" }
|
||||
end
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr.collect!.with_index{|x, i| x[0...i] }
|
||||
end
|
||||
end
|
||||
|
||||
def test_delete
|
||||
m = TestMessage.new
|
||||
reference_arr = %w(foo bar baz)
|
||||
m.repeated_string += reference_arr.clone
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr.delete('bar')
|
||||
end
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr.delete('nope')
|
||||
end
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr.delete('nope'){'within'}
|
||||
end
|
||||
end
|
||||
|
||||
def test_delete_at
|
||||
m = TestMessage.new
|
||||
reference_arr = %w(foo bar baz)
|
||||
m.repeated_string += reference_arr.clone
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr.delete_at(2)
|
||||
end
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr.delete_at(10)
|
||||
end
|
||||
end
|
||||
|
||||
def test_delete_if
|
||||
m = TestMessage.new
|
||||
reference_arr = %w(foo bar baz)
|
||||
m.repeated_string += reference_arr.clone
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr.delete_if { |v| v == "bar" }
|
||||
end
|
||||
end
|
||||
|
||||
def test_fill
|
||||
m = TestMessage.new
|
||||
reference_arr = %w(foo bar baz)
|
||||
m.repeated_string += reference_arr.clone
|
||||
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr.fill("x")
|
||||
end
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr.fill("z", 2, 2)
|
||||
end
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr.fill("y", 0..1)
|
||||
end
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr.fill { |i| (i*i).to_s }
|
||||
end
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr.fill(-2) { |i| (i*i*i).to_s }
|
||||
end
|
||||
end
|
||||
|
||||
def test_flatten!
|
||||
m = TestMessage.new
|
||||
reference_arr = %w(foo bar baz)
|
||||
m.repeated_string += reference_arr.clone
|
||||
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr.flatten!
|
||||
end
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr.flatten!(1)
|
||||
end
|
||||
end
|
||||
|
||||
def test_insert
|
||||
m = TestMessage.new
|
||||
reference_arr = %w(foo bar baz)
|
||||
m.repeated_string += reference_arr.clone
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr.insert(2, 'fizz')
|
||||
end
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr.insert(3, 'fizz', 'buzz', 'bazz')
|
||||
end
|
||||
end
|
||||
|
||||
def test_inspect
|
||||
m = TestMessage.new
|
||||
assert_equal '[]', m.repeated_string.inspect
|
||||
m.repeated_string << 'foo'
|
||||
assert_equal m.repeated_string.to_a.inspect, m.repeated_string.inspect
|
||||
m.repeated_string << 'bar'
|
||||
assert_equal m.repeated_string.to_a.inspect, m.repeated_string.inspect
|
||||
end
|
||||
|
||||
def test_reverse!
|
||||
m = TestMessage.new
|
||||
reference_arr = %w(foo bar baz)
|
||||
m.repeated_string += reference_arr.clone
|
||||
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr.reverse!
|
||||
end
|
||||
end
|
||||
|
||||
def test_rotate!
|
||||
m = TestMessage.new
|
||||
reference_arr = %w(foo bar baz)
|
||||
m.repeated_string += reference_arr.clone
|
||||
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr.rotate!
|
||||
end
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr.rotate!(2)
|
||||
end
|
||||
end
|
||||
|
||||
def test_select!
|
||||
m = TestMessage.new
|
||||
reference_arr = %w(foo bar baz)
|
||||
m.repeated_string += reference_arr.clone
|
||||
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr.select! { |v| v =~ /[aeiou]/ }
|
||||
end
|
||||
end
|
||||
|
||||
def test_shift
|
||||
m = TestMessage.new
|
||||
reference_arr = %w(foo bar baz)
|
||||
m.repeated_string += reference_arr.clone
|
||||
|
||||
# should return an element
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr.shift
|
||||
end
|
||||
# should return an array
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr.shift(2)
|
||||
end
|
||||
# should return nil
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr.shift
|
||||
end
|
||||
end
|
||||
|
||||
def test_shuffle!
|
||||
m = TestMessage.new
|
||||
m.repeated_string += %w(foo bar baz)
|
||||
orig_repeated_string = m.repeated_string.clone
|
||||
result = m.repeated_string.shuffle!
|
||||
assert_equal m.repeated_string, result
|
||||
# NOTE: sometimes it doesn't change the order...
|
||||
# assert_not_equal m.repeated_string.to_a, orig_repeated_string.to_a
|
||||
end
|
||||
|
||||
def test_slice!
|
||||
m = TestMessage.new
|
||||
reference_arr = %w(foo bar baz bar fizz buzz)
|
||||
m.repeated_string += reference_arr.clone
|
||||
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr.slice!(2)
|
||||
end
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr.slice!(1,2)
|
||||
end
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr.slice!(0..1)
|
||||
end
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr.slice!(10)
|
||||
end
|
||||
end
|
||||
|
||||
def test_sort!
|
||||
m = TestMessage.new
|
||||
reference_arr = %w(foo bar baz)
|
||||
m.repeated_string += reference_arr.clone
|
||||
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr.sort!
|
||||
end
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr.sort! { |x,y| y <=> x }
|
||||
end
|
||||
end
|
||||
|
||||
def test_sort_by!
|
||||
m = TestMessage.new
|
||||
reference_arr = %w(foo bar baz)
|
||||
m.repeated_string += reference_arr.clone
|
||||
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr.sort_by!
|
||||
end
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr.sort_by!(&:hash)
|
||||
end
|
||||
end
|
||||
|
||||
def test_uniq!
|
||||
m = TestMessage.new
|
||||
reference_arr = %w(foo bar baz)
|
||||
m.repeated_string += reference_arr.clone
|
||||
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr.uniq!
|
||||
end
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr.uniq!{|s| s[0] }
|
||||
end
|
||||
end
|
||||
|
||||
def test_unshift
|
||||
m = TestMessage.new
|
||||
reference_arr = %w(foo bar baz)
|
||||
m.repeated_string += reference_arr.clone
|
||||
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr.unshift('1')
|
||||
end
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr.unshift('a', 'b')
|
||||
end
|
||||
check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
|
||||
arr.unshift('')
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
##### HELPER METHODS
|
||||
|
||||
def check_self_modifying_method(repeated_field, ref_array)
|
||||
expected_result = yield(ref_array)
|
||||
actual_result = yield(repeated_field)
|
||||
if expected_result.is_a?(Enumerator)
|
||||
assert_equal expected_result.to_a, actual_result.to_a
|
||||
else
|
||||
assert_equal expected_result, actual_result
|
||||
end
|
||||
assert_equal ref_array, repeated_field
|
||||
end
|
||||
|
||||
|
||||
def repeated_field_names(klass)
|
||||
klass.descriptor.find_all{|f| f.label == :repeated}.map(&:name)
|
||||
end
|
||||
|
||||
|
||||
def fill_test_msg(test_msg)
|
||||
test_msg.repeated_int32 += [-10, -11]
|
||||
test_msg.repeated_int64 += [-1_000_000, -1_000_001]
|
||||
test_msg.repeated_uint32 += [10, 11]
|
||||
test_msg.repeated_uint64 += [1_000_000, 1_000_001]
|
||||
test_msg.repeated_bool += [true, false]
|
||||
test_msg.repeated_float += [-1.01, -1.02]
|
||||
test_msg.repeated_double += [-1.0000000000001, -1.0000000000002]
|
||||
test_msg.repeated_string += %w(foo bar)
|
||||
test_msg.repeated_bytes += ["bar".encode!('ASCII-8BIT'), "foo".encode!('ASCII-8BIT')]
|
||||
test_msg.repeated_msg << TestMessage2.new(:foo => 1)
|
||||
test_msg.repeated_msg << TestMessage2.new(:foo => 2)
|
||||
test_msg.repeated_enum << :A
|
||||
test_msg.repeated_enum << :B
|
||||
end
|
||||
|
||||
|
||||
pool = Google::Protobuf::DescriptorPool.new
|
||||
pool.build do
|
||||
|
||||
add_message "TestMessage" do
|
||||
optional :optional_int32, :int32, 1
|
||||
optional :optional_int64, :int64, 2
|
||||
optional :optional_uint32, :uint32, 3
|
||||
optional :optional_uint64, :uint64, 4
|
||||
optional :optional_bool, :bool, 5
|
||||
optional :optional_float, :float, 6
|
||||
optional :optional_double, :double, 7
|
||||
optional :optional_string, :string, 8
|
||||
optional :optional_bytes, :bytes, 9
|
||||
optional :optional_msg, :message, 10, "TestMessage2"
|
||||
optional :optional_enum, :enum, 11, "TestEnum"
|
||||
|
||||
repeated :repeated_int32, :int32, 12
|
||||
repeated :repeated_int64, :int64, 13
|
||||
repeated :repeated_uint32, :uint32, 14
|
||||
repeated :repeated_uint64, :uint64, 15
|
||||
repeated :repeated_bool, :bool, 16
|
||||
repeated :repeated_float, :float, 17
|
||||
repeated :repeated_double, :double, 18
|
||||
repeated :repeated_string, :string, 19
|
||||
repeated :repeated_bytes, :bytes, 20
|
||||
repeated :repeated_msg, :message, 21, "TestMessage2"
|
||||
repeated :repeated_enum, :enum, 22, "TestEnum"
|
||||
end
|
||||
add_message "TestMessage2" do
|
||||
optional :foo, :int32, 1
|
||||
end
|
||||
|
||||
add_enum "TestEnum" do
|
||||
value :Default, 0
|
||||
value :A, 1
|
||||
value :B, 2
|
||||
value :C, 3
|
||||
end
|
||||
end
|
||||
|
||||
TestMessage = pool.lookup("TestMessage").msgclass
|
||||
TestMessage2 = pool.lookup("TestMessage2").msgclass
|
||||
TestEnum = pool.lookup("TestEnum").enummodule
|
||||
|
||||
|
||||
end
|
38
deps/protobuf/ruby/tests/stress.rb
vendored
Normal file
38
deps/protobuf/ruby/tests/stress.rb
vendored
Normal file
@ -0,0 +1,38 @@
|
||||
#!/usr/bin/ruby
|
||||
|
||||
require 'google/protobuf'
|
||||
require 'test/unit'
|
||||
|
||||
module StressTest
|
||||
pool = Google::Protobuf::DescriptorPool.new
|
||||
pool.build do
|
||||
add_message "TestMessage" do
|
||||
optional :a, :int32, 1
|
||||
repeated :b, :message, 2, "M"
|
||||
end
|
||||
add_message "M" do
|
||||
optional :foo, :string, 1
|
||||
end
|
||||
end
|
||||
|
||||
TestMessage = pool.lookup("TestMessage").msgclass
|
||||
M = pool.lookup("M").msgclass
|
||||
|
||||
class StressTest < Test::Unit::TestCase
|
||||
def get_msg
|
||||
TestMessage.new(:a => 1000,
|
||||
:b => [M.new(:foo => "hello"),
|
||||
M.new(:foo => "world")])
|
||||
end
|
||||
def test_stress
|
||||
m = get_msg
|
||||
data = TestMessage.encode(m)
|
||||
100_000.times do
|
||||
mnew = TestMessage.decode(data)
|
||||
mnew = mnew.dup
|
||||
assert_equal m.inspect, mnew.inspect
|
||||
assert TestMessage.encode(mnew) == data
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
5
deps/protobuf/ruby/tests/test_import.proto
vendored
Normal file
5
deps/protobuf/ruby/tests/test_import.proto
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package foo_bar;
|
||||
|
||||
message TestImportedMessage {}
|
5
deps/protobuf/ruby/tests/test_import_proto2.proto
vendored
Normal file
5
deps/protobuf/ruby/tests/test_import_proto2.proto
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
syntax = "proto2";
|
||||
|
||||
package foo_bar.proto2;
|
||||
|
||||
message TestImportedMessage {}
|
7
deps/protobuf/ruby/tests/test_ruby_package.proto
vendored
Normal file
7
deps/protobuf/ruby/tests/test_ruby_package.proto
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package foo_bar;
|
||||
|
||||
option ruby_package = "A::B";
|
||||
|
||||
message TestRubyPackageMessage {}
|
7
deps/protobuf/ruby/tests/test_ruby_package_proto2.proto
vendored
Normal file
7
deps/protobuf/ruby/tests/test_ruby_package_proto2.proto
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
syntax = "proto2";
|
||||
|
||||
package foo_bar_proto2;
|
||||
|
||||
option ruby_package = "A::B::Proto2";
|
||||
|
||||
message TestRubyPackageMessage {}
|
176
deps/protobuf/ruby/tests/type_errors.rb
vendored
Normal file
176
deps/protobuf/ruby/tests/type_errors.rb
vendored
Normal file
@ -0,0 +1,176 @@
|
||||
#!/usr/bin/ruby
|
||||
|
||||
# generated_code.rb is in the same directory as this test.
|
||||
$LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__)))
|
||||
|
||||
require 'test/unit'
|
||||
require 'google/protobuf/well_known_types'
|
||||
require 'generated_code_pb'
|
||||
|
||||
class TestTypeErrors < Test::Unit::TestCase
|
||||
# Ruby 2.4 unified Fixnum with Integer
|
||||
IntegerType = Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.4') ? Fixnum : Integer
|
||||
|
||||
def test_bad_string
|
||||
check_error Google::Protobuf::TypeError,
|
||||
"Invalid argument for string field 'optional_string' (given #{IntegerType.name})." do
|
||||
A::B::C::TestMessage.new(optional_string: 4)
|
||||
end
|
||||
check_error Google::Protobuf::TypeError,
|
||||
"Invalid argument for string field 'oneof_string' (given #{IntegerType.name})." do
|
||||
A::B::C::TestMessage.new(oneof_string: 4)
|
||||
end
|
||||
check_error ArgumentError,
|
||||
"Expected array as initializer value for repeated field 'repeated_string' (given String)." do
|
||||
A::B::C::TestMessage.new(repeated_string: '4')
|
||||
end
|
||||
end
|
||||
|
||||
def test_bad_float
|
||||
check_error Google::Protobuf::TypeError,
|
||||
"Expected number type for float field 'optional_float' (given TrueClass)." do
|
||||
A::B::C::TestMessage.new(optional_float: true)
|
||||
end
|
||||
check_error Google::Protobuf::TypeError,
|
||||
"Expected number type for float field 'oneof_float' (given TrueClass)." do
|
||||
A::B::C::TestMessage.new(oneof_float: true)
|
||||
end
|
||||
check_error ArgumentError,
|
||||
"Expected array as initializer value for repeated field 'repeated_float' (given String)." do
|
||||
A::B::C::TestMessage.new(repeated_float: 'true')
|
||||
end
|
||||
end
|
||||
|
||||
def test_bad_double
|
||||
check_error Google::Protobuf::TypeError,
|
||||
"Expected number type for double field 'optional_double' (given Symbol)." do
|
||||
A::B::C::TestMessage.new(optional_double: :double)
|
||||
end
|
||||
check_error Google::Protobuf::TypeError,
|
||||
"Expected number type for double field 'oneof_double' (given Symbol)." do
|
||||
A::B::C::TestMessage.new(oneof_double: :double)
|
||||
end
|
||||
check_error ArgumentError,
|
||||
"Expected array as initializer value for repeated field 'repeated_double' (given FalseClass)." do
|
||||
A::B::C::TestMessage.new(repeated_double: false)
|
||||
end
|
||||
end
|
||||
|
||||
def test_bad_bool
|
||||
check_error Google::Protobuf::TypeError,
|
||||
"Invalid argument for boolean field 'optional_bool' (given Float)." do
|
||||
A::B::C::TestMessage.new(optional_bool: 4.4)
|
||||
end
|
||||
check_error Google::Protobuf::TypeError,
|
||||
"Invalid argument for boolean field 'oneof_bool' (given Float)." do
|
||||
A::B::C::TestMessage.new(oneof_bool: 4.4)
|
||||
end
|
||||
check_error ArgumentError,
|
||||
"Expected array as initializer value for repeated field 'repeated_bool' (given String)." do
|
||||
A::B::C::TestMessage.new(repeated_bool: 'hi')
|
||||
end
|
||||
end
|
||||
|
||||
def test_bad_int
|
||||
check_error Google::Protobuf::TypeError,
|
||||
"Expected number type for integral field 'optional_int32' (given String)." do
|
||||
A::B::C::TestMessage.new(optional_int32: 'hi')
|
||||
end
|
||||
check_error RangeError,
|
||||
"Non-integral floating point value assigned to integer field 'optional_int64' (given Float)." do
|
||||
A::B::C::TestMessage.new(optional_int64: 2.4)
|
||||
end
|
||||
check_error Google::Protobuf::TypeError,
|
||||
"Expected number type for integral field 'optional_uint32' (given Symbol)." do
|
||||
A::B::C::TestMessage.new(optional_uint32: :thing)
|
||||
end
|
||||
check_error Google::Protobuf::TypeError,
|
||||
"Expected number type for integral field 'optional_uint64' (given FalseClass)." do
|
||||
A::B::C::TestMessage.new(optional_uint64: false)
|
||||
end
|
||||
check_error Google::Protobuf::TypeError,
|
||||
"Expected number type for integral field 'oneof_int32' (given Symbol)." do
|
||||
A::B::C::TestMessage.new(oneof_int32: :hi)
|
||||
end
|
||||
check_error RangeError,
|
||||
"Non-integral floating point value assigned to integer field 'oneof_int64' (given Float)." do
|
||||
A::B::C::TestMessage.new(oneof_int64: 2.4)
|
||||
end
|
||||
check_error Google::Protobuf::TypeError,
|
||||
"Expected number type for integral field 'oneof_uint32' (given String)." do
|
||||
A::B::C::TestMessage.new(oneof_uint32: 'x')
|
||||
end
|
||||
check_error RangeError,
|
||||
"Non-integral floating point value assigned to integer field 'oneof_uint64' (given Float)." do
|
||||
A::B::C::TestMessage.new(oneof_uint64: 1.1)
|
||||
end
|
||||
check_error ArgumentError,
|
||||
"Expected array as initializer value for repeated field 'repeated_int32' (given Symbol)." do
|
||||
A::B::C::TestMessage.new(repeated_int32: :hi)
|
||||
end
|
||||
check_error ArgumentError,
|
||||
"Expected array as initializer value for repeated field 'repeated_int64' (given Float)." do
|
||||
A::B::C::TestMessage.new(repeated_int64: 2.4)
|
||||
end
|
||||
check_error ArgumentError,
|
||||
"Expected array as initializer value for repeated field 'repeated_uint32' (given String)." do
|
||||
A::B::C::TestMessage.new(repeated_uint32: 'x')
|
||||
end
|
||||
check_error ArgumentError,
|
||||
"Expected array as initializer value for repeated field 'repeated_uint64' (given Float)." do
|
||||
A::B::C::TestMessage.new(repeated_uint64: 1.1)
|
||||
end
|
||||
end
|
||||
|
||||
def test_bad_enum
|
||||
check_error RangeError,
|
||||
"Unknown symbol value for enum field 'optional_enum'." do
|
||||
A::B::C::TestMessage.new(optional_enum: 'enum')
|
||||
end
|
||||
check_error RangeError,
|
||||
"Unknown symbol value for enum field 'oneof_enum'." do
|
||||
A::B::C::TestMessage.new(oneof_enum: '')
|
||||
end
|
||||
check_error ArgumentError,
|
||||
"Expected array as initializer value for repeated field 'repeated_enum' (given String)." do
|
||||
A::B::C::TestMessage.new(repeated_enum: '')
|
||||
end
|
||||
end
|
||||
|
||||
def test_bad_bytes
|
||||
check_error Google::Protobuf::TypeError,
|
||||
"Invalid argument for bytes field 'optional_bytes' (given Float)." do
|
||||
A::B::C::TestMessage.new(optional_bytes: 22.22)
|
||||
end
|
||||
check_error Google::Protobuf::TypeError,
|
||||
"Invalid argument for bytes field 'oneof_bytes' (given Symbol)." do
|
||||
A::B::C::TestMessage.new(oneof_bytes: :T22)
|
||||
end
|
||||
check_error ArgumentError,
|
||||
"Expected array as initializer value for repeated field 'repeated_bytes' (given Symbol)." do
|
||||
A::B::C::TestMessage.new(repeated_bytes: :T22)
|
||||
end
|
||||
end
|
||||
|
||||
def test_bad_msg
|
||||
check_error Google::Protobuf::TypeError,
|
||||
"Invalid type #{IntegerType.name} to assign to submessage field 'optional_msg'." do
|
||||
A::B::C::TestMessage.new(optional_msg: 2)
|
||||
end
|
||||
check_error Google::Protobuf::TypeError,
|
||||
"Invalid type String to assign to submessage field 'oneof_msg'." do
|
||||
A::B::C::TestMessage.new(oneof_msg: '2')
|
||||
end
|
||||
check_error ArgumentError,
|
||||
"Expected array as initializer value for repeated field 'repeated_msg' (given String)." do
|
||||
A::B::C::TestMessage.new(repeated_msg: '2')
|
||||
end
|
||||
end
|
||||
|
||||
def check_error(type, message)
|
||||
err = assert_raises type do
|
||||
yield
|
||||
end
|
||||
assert_equal message, err.message
|
||||
end
|
||||
end
|
247
deps/protobuf/ruby/tests/well_known_types_test.rb
vendored
Normal file
247
deps/protobuf/ruby/tests/well_known_types_test.rb
vendored
Normal file
@ -0,0 +1,247 @@
|
||||
#!/usr/bin/ruby
|
||||
|
||||
require 'test/unit'
|
||||
require 'google/protobuf/well_known_types'
|
||||
|
||||
class TestWellKnownTypes < Test::Unit::TestCase
|
||||
def test_timestamp
|
||||
ts = Google::Protobuf::Timestamp.new
|
||||
|
||||
assert_equal Time.at(0), ts.to_time
|
||||
|
||||
ts.seconds = 12345
|
||||
assert_equal Time.at(12345), ts.to_time
|
||||
assert_equal 12345, ts.to_i
|
||||
|
||||
# millisecond accuracy
|
||||
time = Time.at(123456, 654321)
|
||||
resp = ts.from_time(time)
|
||||
assert_equal 123456, ts.seconds
|
||||
assert_equal 654321000, ts.nanos
|
||||
assert_equal time, ts.to_time
|
||||
assert_equal resp, ts
|
||||
|
||||
# nanosecond accuracy
|
||||
time = Time.at(123456, Rational(654321321, 1000))
|
||||
resp = ts.from_time(time)
|
||||
assert_equal 123456, ts.seconds
|
||||
assert_equal 654321321, ts.nanos
|
||||
assert_equal time, ts.to_time
|
||||
assert_equal resp, ts
|
||||
|
||||
# Class based initialisation using from_time
|
||||
time = Time.at(123456, Rational(654321321, 1000))
|
||||
ts = Google::Protobuf::Timestamp.from_time(time)
|
||||
assert_equal 123456, ts.seconds
|
||||
assert_equal 654321321, ts.nanos
|
||||
assert_equal time, ts.to_time
|
||||
|
||||
# Instance method returns the same value as class method
|
||||
assert_equal Google::Protobuf::Timestamp.new.from_time(time),
|
||||
Google::Protobuf::Timestamp.from_time(time)
|
||||
end
|
||||
|
||||
def test_duration
|
||||
duration = Google::Protobuf::Duration.new(seconds: 123, nanos: 456)
|
||||
assert_equal 123.000000456, duration.to_f
|
||||
end
|
||||
|
||||
def test_struct
|
||||
struct = Google::Protobuf::Struct.new
|
||||
|
||||
substruct = {
|
||||
"subkey" => 999,
|
||||
"subkey2" => false
|
||||
}
|
||||
|
||||
sublist = ["abc", 123, {"deepkey" => "deepval"}]
|
||||
|
||||
struct["number"] = 12345
|
||||
struct["boolean-true"] = true
|
||||
struct["boolean-false"] = false
|
||||
struct["null"] = nil
|
||||
struct["string"] = "abcdef"
|
||||
struct["substruct"] = substruct
|
||||
struct["sublist"] = sublist
|
||||
|
||||
assert_equal 12345, struct["number"]
|
||||
assert_equal true, struct["boolean-true"]
|
||||
assert_equal false, struct["boolean-false"]
|
||||
assert_equal nil, struct["null"]
|
||||
assert_equal "abcdef", struct["string"]
|
||||
assert_equal(Google::Protobuf::Struct.from_hash(substruct),
|
||||
struct["substruct"])
|
||||
assert_equal(Google::Protobuf::ListValue.from_a(sublist),
|
||||
struct["sublist"])
|
||||
|
||||
assert_equal true, struct.has_key?("null")
|
||||
assert_equal false, struct.has_key?("missing_key")
|
||||
|
||||
should_equal = {
|
||||
"number" => 12345,
|
||||
"boolean-true" => true,
|
||||
"boolean-false" => false,
|
||||
"null" => nil,
|
||||
"string" => "abcdef",
|
||||
"substruct" => {
|
||||
"subkey" => 999,
|
||||
"subkey2" => false
|
||||
},
|
||||
"sublist" => ["abc", 123, {"deepkey" => "deepval"}]
|
||||
}
|
||||
|
||||
list = struct["sublist"]
|
||||
list.is_a?(Google::Protobuf::ListValue)
|
||||
assert_equal "abc", list[0]
|
||||
assert_equal 123, list[1]
|
||||
assert_equal({"deepkey" => "deepval"}, list[2].to_h)
|
||||
|
||||
# to_h returns a fully-flattened Ruby structure (Hash and Array).
|
||||
assert_equal(should_equal, struct.to_h)
|
||||
|
||||
# Test that we can safely access a missing key
|
||||
assert_equal(nil, struct["missing_key"])
|
||||
|
||||
# Test that we can assign Struct and ListValue directly.
|
||||
struct["substruct"] = Google::Protobuf::Struct.from_hash(substruct)
|
||||
struct["sublist"] = Google::Protobuf::ListValue.from_a(sublist)
|
||||
|
||||
assert_equal(should_equal, struct.to_h)
|
||||
|
||||
struct["sublist"] << nil
|
||||
should_equal["sublist"] << nil
|
||||
|
||||
assert_equal(should_equal, struct.to_h)
|
||||
assert_equal(should_equal["sublist"].length, struct["sublist"].length)
|
||||
|
||||
assert_raise Google::Protobuf::UnexpectedStructType do
|
||||
struct[123] = 5
|
||||
end
|
||||
|
||||
assert_raise Google::Protobuf::UnexpectedStructType do
|
||||
struct[5] = Time.new
|
||||
end
|
||||
|
||||
assert_raise Google::Protobuf::UnexpectedStructType do
|
||||
struct[5] = [Time.new]
|
||||
end
|
||||
|
||||
assert_raise Google::Protobuf::UnexpectedStructType do
|
||||
struct[5] = {123 => 456}
|
||||
end
|
||||
|
||||
assert_raise Google::Protobuf::UnexpectedStructType do
|
||||
struct = Google::Protobuf::Struct.new
|
||||
struct.fields["foo"] = Google::Protobuf::Value.new
|
||||
# Tries to return a Ruby value for a Value class whose type
|
||||
# hasn't been filled in.
|
||||
struct["foo"]
|
||||
end
|
||||
end
|
||||
|
||||
def test_any
|
||||
ts = Google::Protobuf::Timestamp.new(seconds: 12345, nanos: 6789)
|
||||
|
||||
any = Google::Protobuf::Any.new
|
||||
any.pack(ts)
|
||||
|
||||
assert any.is(Google::Protobuf::Timestamp)
|
||||
assert_equal ts, any.unpack(Google::Protobuf::Timestamp)
|
||||
|
||||
any = Google::Protobuf::Any.pack(ts)
|
||||
|
||||
assert any.is(Google::Protobuf::Timestamp)
|
||||
assert_equal ts, any.unpack(Google::Protobuf::Timestamp)
|
||||
end
|
||||
|
||||
def test_struct_init
|
||||
s = Google::Protobuf::Struct.new(fields: {'a' => Google::Protobuf::Value.new({number_value: 4.4})})
|
||||
assert_equal 4.4, s['a']
|
||||
|
||||
s = Google::Protobuf::Struct.new(fields: {'a' => {number_value: 2.2}})
|
||||
assert_equal 2.2, s['a']
|
||||
|
||||
s = Google::Protobuf::Struct.new(fields: {a: {number_value: 1.1}})
|
||||
assert_equal 1.1, s[:a]
|
||||
end
|
||||
|
||||
def test_struct_nested_init
|
||||
s = Google::Protobuf::Struct.new(
|
||||
fields: {
|
||||
'a' => {string_value: 'A'},
|
||||
'b' => {struct_value: {
|
||||
fields: {
|
||||
'x' => {list_value: {values: [{number_value: 1.0}, {string_value: "ok"}]}},
|
||||
'y' => {bool_value: true}}}
|
||||
},
|
||||
'c' => {struct_value: {}}
|
||||
}
|
||||
)
|
||||
assert_equal 'A', s['a']
|
||||
assert_equal 'A', s[:a]
|
||||
expected_b_x = [Google::Protobuf::Value.new(number_value: 1.0), Google::Protobuf::Value.new(string_value: "ok")]
|
||||
assert_equal expected_b_x, s['b']['x'].values
|
||||
assert_equal expected_b_x, s[:b][:x].values
|
||||
assert_equal expected_b_x, s['b'][:x].values
|
||||
assert_equal expected_b_x, s[:b]['x'].values
|
||||
assert_equal true, s['b']['y']
|
||||
assert_equal true, s[:b][:y]
|
||||
assert_equal true, s[:b]['y']
|
||||
assert_equal true, s['b'][:y]
|
||||
assert_equal Google::Protobuf::Struct.new, s['c']
|
||||
assert_equal Google::Protobuf::Struct.new, s[:c]
|
||||
|
||||
s = Google::Protobuf::Struct.new(
|
||||
fields: {
|
||||
a: {string_value: 'Eh'},
|
||||
b: {struct_value: {
|
||||
fields: {
|
||||
y: {bool_value: false}}}
|
||||
}
|
||||
}
|
||||
)
|
||||
assert_equal 'Eh', s['a']
|
||||
assert_equal 'Eh', s[:a]
|
||||
assert_equal false, s['b']['y']
|
||||
assert_equal false, s[:b][:y]
|
||||
assert_equal false, s['b'][:y]
|
||||
assert_equal false, s[:b]['y']
|
||||
end
|
||||
|
||||
def test_b8325
|
||||
value_field = Google::Protobuf::ListValue.descriptor.lookup("values")
|
||||
proto = Google::Protobuf::ListValue.new(
|
||||
values: [Google::Protobuf::Value.new(string_value: "Hello")]
|
||||
)
|
||||
assert_equal '[<Google::Protobuf::Value: string_value: "Hello">]', value_field.get(proto).inspect
|
||||
end
|
||||
|
||||
def test_from_ruby
|
||||
pb = Google::Protobuf::Value.from_ruby(nil)
|
||||
assert_equal pb.null_value, :NULL_VALUE
|
||||
|
||||
pb = Google::Protobuf::Value.from_ruby(1.23)
|
||||
assert_equal pb.number_value, 1.23
|
||||
|
||||
pb = Google::Protobuf::Value.from_ruby('1.23')
|
||||
assert_equal pb.string_value, '1.23'
|
||||
|
||||
pb = Google::Protobuf::Value.from_ruby(true)
|
||||
assert_equal pb.bool_value, true
|
||||
|
||||
pb = Google::Protobuf::Value.from_ruby(false)
|
||||
assert_equal pb.bool_value, false
|
||||
|
||||
pb = Google::Protobuf::Value.from_ruby(Google::Protobuf::Struct.from_hash({ 'a' => 1, 'b' => '2', 'c' => [1, 2, 3], 'd' => nil, 'e' => true }))
|
||||
assert_equal pb.struct_value, Google::Protobuf::Struct.from_hash({ 'a' => 1, 'b' => '2', 'c' => [1, 2, 3], 'd' => nil, 'e' => true })
|
||||
|
||||
pb = Google::Protobuf::Value.from_ruby({ 'a' => 1, 'b' => '2', 'c' => [1, 2, 3], 'd' => nil, 'e' => true })
|
||||
assert_equal pb.struct_value, Google::Protobuf::Struct.from_hash({ 'a' => 1, 'b' => '2', 'c' => [1, 2, 3], 'd' => nil, 'e' => true })
|
||||
|
||||
pb = Google::Protobuf::Value.from_ruby(Google::Protobuf::ListValue.from_a([1, 2, 3]))
|
||||
assert_equal pb.list_value, Google::Protobuf::ListValue.from_a([1, 2, 3])
|
||||
|
||||
pb = Google::Protobuf::Value.from_ruby([1, 2, 3])
|
||||
assert_equal pb.list_value, Google::Protobuf::ListValue.from_a([1, 2, 3])
|
||||
end
|
||||
end
|
36
deps/protobuf/ruby/travis-test.sh
vendored
Normal file
36
deps/protobuf/ruby/travis-test.sh
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Exit on any error.
|
||||
set -ex
|
||||
|
||||
test_version() {
|
||||
version=$1
|
||||
|
||||
RUBY_CONFORMANCE=test_ruby
|
||||
|
||||
if [[ $version == jruby-9* ]] ; then
|
||||
bash --login -c \
|
||||
"rvm install $version && rvm use $version && rvm get head && \
|
||||
which ruby && \
|
||||
git clean -f && \
|
||||
gem install --no-document bundler -v 2.3.26 && \ # Pin to bundler with ruby 2.5 support
|
||||
bundle && \
|
||||
rake test && \
|
||||
rake gc_test && \
|
||||
cd ../conformance && make test_jruby && \
|
||||
cd ../ruby/compatibility_tests/v3.0.0 && ./test.sh"
|
||||
else
|
||||
bash --login -c \
|
||||
"rvm install $version && rvm use $version && \
|
||||
which ruby && \
|
||||
git clean -f && \
|
||||
gem install --no-document bundler -v 1.17.3 && bundle && \
|
||||
rake test && \
|
||||
rake gc_test && \
|
||||
cd ../conformance && make ${RUBY_CONFORMANCE} && \
|
||||
cd ../ruby/compatibility_tests/v3.0.0 && \
|
||||
cp -R ../../lib lib && ./test.sh"
|
||||
fi
|
||||
}
|
||||
|
||||
test_version $1
|
Reference in New Issue
Block a user