google-protobuf-3.2.0/0000755000175000017500000000000013043000403013635 5ustar pravipravigoogle-protobuf-3.2.0/.gitignore0000644000175000017500000000012713042756211015643 0ustar pravipravi*.bundle tags .idea/ lib/google/protobuf_java.jar protobuf-jruby.iml target/ pkg/ tmp/ google-protobuf-3.2.0/README.md0000644000175000017500000001005713042756211015135 0ustar pravipraviThis 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 --------------------- When we release a version of Protocol Buffers, we will upload a Gem to [RubyGems](https://www.rubygems.org/). To use this pre-packaged gem, simply install it as you would any other gem: $ gem install [--prerelease] google-protobuf The `--pre` flag is necessary if we have not yet made a non-alpha/beta release of the Ruby extension; it allows `gem` to consider these "pre-release" alpha/beta versions. 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. google-protobuf-3.2.0/tests/0000755000175000017500000000000013043000403014777 5ustar pravipravigoogle-protobuf-3.2.0/tests/repeated_field_test.rb0000644000175000017500000004727213042756211021351 0ustar pravipravi#!/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] 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_compact! m = TestMessage.new m.repeated_msg << TestMessage2.new(:foo => 1) m.repeated_msg << nil m.repeated_msg << TestMessage2.new(:foo => 2) reference_arr = m.repeated_string.to_a check_self_modifying_method(m.repeated_string, reference_arr) do |arr| arr.compact! 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 google-protobuf-3.2.0/tests/basic.rb0000644000175000017500000011075713042777744016454 0ustar pravipravi#!/usr/bin/ruby require 'google/protobuf' require 'test/unit' # ------------- generated code -------------- module BasicTest pool = Google::Protobuf::DescriptorPool.new pool.build do add_message "Foo" do optional :bar, :message, 1, "Bar" repeated :baz, :message, 2, "Baz" end add_message "Bar" do optional :msg, :string, 1 end add_message "Baz" do optional :msg, :string, 1 end 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_message "Recursive1" do optional :foo, :message, 1, "Recursive2" end add_message "Recursive2" do optional :foo, :message, 1, "Recursive1" end add_enum "TestEnum" do value :Default, 0 value :A, 1 value :B, 2 value :C, 3 end add_message "BadFieldNames" do optional :dup, :int32, 1 optional :class, :int32, 2 optional :"a.b", :int32, 3 end add_message "MapMessage" do map :map_string_int32, :string, :int32, 1 map :map_string_msg, :string, :message, 2, "TestMessage2" end add_message "MapMessageWireEquiv" do repeated :map_string_int32, :message, 1, "MapMessageWireEquiv_entry1" repeated :map_string_msg, :message, 2, "MapMessageWireEquiv_entry2" end add_message "MapMessageWireEquiv_entry1" do optional :key, :string, 1 optional :value, :int32, 2 end add_message "MapMessageWireEquiv_entry2" do optional :key, :string, 1 optional :value, :message, 2, "TestMessage2" end add_message "OneofMessage" do oneof :my_oneof do optional :a, :string, 1 optional :b, :int32, 2 optional :c, :message, 3, "TestMessage2" optional :d, :enum, 4, "TestEnum" end end end Foo = pool.lookup("Foo").msgclass Bar = pool.lookup("Bar").msgclass Baz = pool.lookup("Baz").msgclass TestMessage = pool.lookup("TestMessage").msgclass TestMessage2 = pool.lookup("TestMessage2").msgclass Recursive1 = pool.lookup("Recursive1").msgclass Recursive2 = pool.lookup("Recursive2").msgclass TestEnum = pool.lookup("TestEnum").enummodule BadFieldNames = pool.lookup("BadFieldNames").msgclass MapMessage = pool.lookup("MapMessage").msgclass MapMessageWireEquiv = pool.lookup("MapMessageWireEquiv").msgclass MapMessageWireEquiv_entry1 = pool.lookup("MapMessageWireEquiv_entry1").msgclass MapMessageWireEquiv_entry2 = pool.lookup("MapMessageWireEquiv_entry2").msgclass OneofMessage = pool.lookup("OneofMessage").msgclass # ------------ test cases --------------- class MessageContainerTest < Test::Unit::TestCase def test_defaults m = TestMessage.new assert m.optional_int32 == 0 assert m.optional_int64 == 0 assert m.optional_uint32 == 0 assert m.optional_uint64 == 0 assert m.optional_bool == false assert m.optional_float == 0.0 assert m.optional_double == 0.0 assert m.optional_string == "" assert m.optional_bytes == "" assert m.optional_msg == nil assert m.optional_enum == :Default end def test_setters m = TestMessage.new m.optional_int32 = -42 assert m.optional_int32 == -42 m.optional_int64 = -0x1_0000_0000 assert m.optional_int64 == -0x1_0000_0000 m.optional_uint32 = 0x9000_0000 assert m.optional_uint32 == 0x9000_0000 m.optional_uint64 = 0x9000_0000_0000_0000 assert m.optional_uint64 == 0x9000_0000_0000_0000 m.optional_bool = true assert m.optional_bool == true m.optional_float = 0.5 assert m.optional_float == 0.5 m.optional_double = 0.5 m.optional_string = "hello" assert m.optional_string == "hello" m.optional_bytes = "world".encode!('ASCII-8BIT') assert m.optional_bytes == "world" m.optional_msg = TestMessage2.new(:foo => 42) assert m.optional_msg == TestMessage2.new(:foo => 42) m.optional_msg = nil assert m.optional_msg == nil end def test_ctor_args m = TestMessage.new(:optional_int32 => -42, :optional_msg => TestMessage2.new, :optional_enum => :C, :repeated_string => ["hello", "there", "world"]) assert m.optional_int32 == -42 assert m.optional_msg.class == TestMessage2 assert m.repeated_string.length == 3 assert m.optional_enum == :C assert m.repeated_string[0] == "hello" assert m.repeated_string[1] == "there" assert m.repeated_string[2] == "world" end def test_inspect m = TestMessage.new(:optional_int32 => -42, :optional_enum => :A, :optional_msg => TestMessage2.new, :repeated_string => ["hello", "there", "world"]) expected = ', optional_enum: :A, repeated_int32: [], repeated_int64: [], repeated_uint32: [], repeated_uint64: [], repeated_bool: [], repeated_float: [], repeated_double: [], repeated_string: ["hello", "there", "world"], repeated_bytes: [], repeated_msg: [], repeated_enum: []>' assert_equal expected, m.inspect end def test_hash m1 = TestMessage.new(:optional_int32 => 42) m2 = TestMessage.new(:optional_int32 => 102, repeated_string: ['please', 'work', 'ok?']) m3 = TestMessage.new(:optional_int32 => 102, repeated_string: ['please', 'work', 'ok?']) assert m1.hash != 0 assert m2.hash != 0 assert m3.hash != 0 # relying on the randomness here -- if hash function changes and we are # unlucky enough to get a collision, then change the values above. assert m1.hash != m2.hash assert_equal m2.hash, m3.hash end def test_unknown_field_errors e = assert_raise NoMethodError do TestMessage.new.hello end assert_match(/hello/, e.message) e = assert_raise NoMethodError do TestMessage.new.hello = "world" end assert_match(/hello/, e.message) 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'." 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'." end def test_type_errors m = TestMessage.new assert_raise TypeError do m.optional_int32 = "hello" end assert_raise TypeError do m.optional_string = 42 end assert_raise TypeError do m.optional_string = nil end assert_raise TypeError do m.optional_bool = 42 end assert_raise TypeError do m.optional_msg = TestMessage.new # expects TestMessage2 end assert_raise TypeError do m.repeated_int32 = [] # needs RepeatedField end assert_raise TypeError do m.repeated_int32.push "hello" end assert_raise TypeError do m.repeated_msg.push TestMessage.new end end def test_string_encoding m = TestMessage.new # Assigning a normal (ASCII or UTF8) string to a bytes field, or # ASCII-8BIT to a string field will convert to the proper encoding. m.optional_bytes = "Test string ASCII".encode!('ASCII') assert m.optional_bytes.frozen? assert_equal Encoding::ASCII_8BIT, m.optional_bytes.encoding assert_equal "Test string ASCII", m.optional_bytes assert_raise Encoding::UndefinedConversionError do m.optional_bytes = "Test string UTF-8 \u0100".encode!('UTF-8') end assert_raise Encoding::UndefinedConversionError do m.optional_string = ["FFFF"].pack('H*') end # "Ordinary" use case. m.optional_bytes = ["FFFF"].pack('H*') m.optional_string = "\u0100" # strings are immutable so we can't do this, but serialize should catch it. m.optional_string = "asdf".encode!('UTF-8') assert_raise RuntimeError do m.optional_string.encode!('ASCII-8BIT') end end def test_rptfield_int32 l = Google::Protobuf::RepeatedField.new(:int32) assert l.count == 0 l = Google::Protobuf::RepeatedField.new(:int32, [1, 2, 3]) assert l.count == 3 assert_equal [1, 2, 3], l assert_equal l, [1, 2, 3] l.push 4 assert l == [1, 2, 3, 4] dst_list = [] l.each { |val| dst_list.push val } assert dst_list == [1, 2, 3, 4] assert l.to_a == [1, 2, 3, 4] assert l[0] == 1 assert l[3] == 4 l[0] = 5 assert l == [5, 2, 3, 4] l2 = l.dup assert l == l2 assert l.object_id != l2.object_id l2.push 6 assert l.count == 4 assert l2.count == 5 assert l.inspect == '[5, 2, 3, 4]' l.concat([7, 8, 9]) assert l == [5, 2, 3, 4, 7, 8, 9] assert l.pop == 9 assert l == [5, 2, 3, 4, 7, 8] assert_raise TypeError do m = TestMessage.new l.push m end m = TestMessage.new m.repeated_int32 = l assert m.repeated_int32 == [5, 2, 3, 4, 7, 8] assert m.repeated_int32.object_id == l.object_id l.push 42 assert m.repeated_int32.pop == 42 l3 = l + l.dup assert l3.count == l.count * 2 l.count.times do |i| assert l3[i] == l[i] assert l3[l.count + i] == l[i] end l.clear assert l.count == 0 l += [1, 2, 3, 4] l.replace([5, 6, 7, 8]) assert l == [5, 6, 7, 8] l4 = Google::Protobuf::RepeatedField.new(:int32) l4[5] = 42 assert l4 == [0, 0, 0, 0, 0, 42] l4 << 100 assert l4 == [0, 0, 0, 0, 0, 42, 100] l4 << 101 << 102 assert l4 == [0, 0, 0, 0, 0, 42, 100, 101, 102] end def test_parent_rptfield #make sure we set the RepeatedField and can add to it m = TestMessage.new assert m.repeated_string == [] m.repeated_string << 'ok' m.repeated_string.push('ok2') assert m.repeated_string == ['ok', 'ok2'] m.repeated_string += ['ok3'] assert m.repeated_string == ['ok', 'ok2', 'ok3'] end def test_rptfield_msg l = Google::Protobuf::RepeatedField.new(:message, TestMessage) l.push TestMessage.new assert l.count == 1 assert_raise TypeError do l.push TestMessage2.new end assert_raise TypeError do l.push 42 end l2 = l.dup assert l2[0] == l[0] assert l2[0].object_id == l[0].object_id l2 = Google::Protobuf.deep_copy(l) assert l2[0] == l[0] assert l2[0].object_id != l[0].object_id l3 = l + l2 assert l3.count == 2 assert l3[0] == l[0] assert l3[1] == l2[0] l3[0].optional_int32 = 1000 assert l[0].optional_int32 == 1000 new_msg = TestMessage.new(:optional_int32 => 200) l4 = l + [new_msg] assert l4.count == 2 new_msg.optional_int32 = 1000 assert l4[1].optional_int32 == 1000 end def test_rptfield_enum l = Google::Protobuf::RepeatedField.new(:enum, TestEnum) l.push :A l.push :B l.push :C assert l.count == 3 assert_raise RangeError do l.push :D end assert l[0] == :A l.push 4 assert l[3] == 4 end def test_rptfield_initialize assert_raise ArgumentError do l = Google::Protobuf::RepeatedField.new end assert_raise ArgumentError do l = Google::Protobuf::RepeatedField.new(:message) end assert_raise ArgumentError do l = Google::Protobuf::RepeatedField.new([1, 2, 3]) end assert_raise ArgumentError do l = Google::Protobuf::RepeatedField.new(:message, [TestMessage2.new]) end end def test_rptfield_array_ducktyping l = Google::Protobuf::RepeatedField.new(:int32) length_methods = %w(count length size) length_methods.each do |lm| assert l.send(lm) == 0 end # out of bounds returns a nil assert l[0] == nil assert l[1] == nil assert l[-1] == nil l.push 4 length_methods.each do |lm| assert l.send(lm) == 1 end assert l[0] == 4 assert l[1] == nil assert l[-1] == 4 assert l[-2] == nil l.push 2 length_methods.each do |lm| assert l.send(lm) == 2 end assert l[0] == 4 assert l[1] == 2 assert l[2] == nil assert l[-1] == 2 assert l[-2] == 4 assert l[-3] == nil #adding out of scope will backfill with empty objects end def test_map_basic # allowed key types: # :int32, :int64, :uint32, :uint64, :bool, :string, :bytes. m = Google::Protobuf::Map.new(:string, :int32) m["asdf"] = 1 assert m["asdf"] == 1 m["jkl;"] = 42 assert m == { "jkl;" => 42, "asdf" => 1 } assert m.has_key?("asdf") assert !m.has_key?("qwerty") assert m.length == 2 m2 = m.dup assert_equal m, m2 assert m.hash != 0 assert_equal m.hash, m2.hash collected = {} m.each { |k,v| collected[v] = k } assert collected == { 42 => "jkl;", 1 => "asdf" } assert m.delete("asdf") == 1 assert !m.has_key?("asdf") assert m["asdf"] == nil assert !m.has_key?("asdf") # We only assert on inspect value when there is one map entry because the # order in which elements appear is unspecified (depends on the internal # hash function). We don't want a brittle test. assert m.inspect == "{\"jkl;\"=>42}" assert m.keys == ["jkl;"] assert m.values == [42] m.clear assert m.length == 0 assert m == {} assert_raise TypeError do m[1] = 1 end assert_raise RangeError do m["asdf"] = 0x1_0000_0000 end end def test_map_ctor m = Google::Protobuf::Map.new(:string, :int32, {"a" => 1, "b" => 2, "c" => 3}) assert m == {"a" => 1, "c" => 3, "b" => 2} end def test_map_keytypes m = Google::Protobuf::Map.new(:int32, :int32) m[1] = 42 m[-1] = 42 assert_raise RangeError do m[0x8000_0000] = 1 end assert_raise TypeError do m["asdf"] = 1 end m = Google::Protobuf::Map.new(:int64, :int32) m[0x1000_0000_0000_0000] = 1 assert_raise RangeError do m[0x1_0000_0000_0000_0000] = 1 end assert_raise TypeError do m["asdf"] = 1 end m = Google::Protobuf::Map.new(:uint32, :int32) m[0x8000_0000] = 1 assert_raise RangeError do m[0x1_0000_0000] = 1 end assert_raise RangeError do m[-1] = 1 end m = Google::Protobuf::Map.new(:uint64, :int32) m[0x8000_0000_0000_0000] = 1 assert_raise RangeError do m[0x1_0000_0000_0000_0000] = 1 end assert_raise RangeError do m[-1] = 1 end m = Google::Protobuf::Map.new(:bool, :int32) m[true] = 1 m[false] = 2 assert_raise TypeError do m[1] = 1 end assert_raise TypeError do m["asdf"] = 1 end m = Google::Protobuf::Map.new(:string, :int32) m["asdf"] = 1 assert_raise TypeError do m[1] = 1 end assert_raise Encoding::UndefinedConversionError do bytestring = ["FFFF"].pack("H*") m[bytestring] = 1 end m = Google::Protobuf::Map.new(:bytes, :int32) bytestring = ["FFFF"].pack("H*") m[bytestring] = 1 # Allowed -- we will automatically convert to ASCII-8BIT. m["asdf"] = 1 assert_raise TypeError do m[1] = 1 end end def test_map_msg_enum_valuetypes m = Google::Protobuf::Map.new(:string, :message, TestMessage) m["asdf"] = TestMessage.new assert_raise TypeError do m["jkl;"] = TestMessage2.new end m = Google::Protobuf::Map.new( :string, :message, TestMessage, { "a" => TestMessage.new(:optional_int32 => 42), "b" => TestMessage.new(:optional_int32 => 84) }) assert m.length == 2 assert m.values.map{|msg| msg.optional_int32}.sort == [42, 84] m = Google::Protobuf::Map.new(:string, :enum, TestEnum, { "x" => :A, "y" => :B, "z" => :C }) assert m.length == 3 assert m["z"] == :C m["z"] = 2 assert m["z"] == :B m["z"] = 4 assert m["z"] == 4 assert_raise RangeError do m["z"] = :Z end assert_raise TypeError do m["z"] = "z" end end def test_map_dup_deep_copy m = Google::Protobuf::Map.new( :string, :message, TestMessage, { "a" => TestMessage.new(:optional_int32 => 42), "b" => TestMessage.new(:optional_int32 => 84) }) m2 = m.dup assert m == m2 assert m.object_id != m2.object_id assert m["a"].object_id == m2["a"].object_id assert m["b"].object_id == m2["b"].object_id m2 = Google::Protobuf.deep_copy(m) assert m == m2 assert m.object_id != m2.object_id assert m["a"].object_id != m2["a"].object_id assert m["b"].object_id != m2["b"].object_id 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)}) assert m.map_string_int32.keys.sort == ["a", "b"] assert m.map_string_int32["a"] == 1 assert m.map_string_msg["b"].foo == 2 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 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 TypeError do m.map_string_int32 = Google::Protobuf::Map.new(:string, :int64) end assert_raise TypeError do m.map_string_int32 = {} end assert_raise TypeError do m = MapMessage.new(:map_string_int32 => { 1 => "I am not a number" }) end 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_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)}) 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_oneof_descriptors d = OneofMessage.descriptor o = d.lookup_oneof("my_oneof") assert o != nil assert o.class == Google::Protobuf::OneofDescriptor assert o.name == "my_oneof" oneof_count = 0 d.each_oneof{ |oneof| oneof_count += 1 assert oneof == o } assert oneof_count == 1 assert o.count == 4 field_names = o.map{|f| f.name}.sort assert field_names == ["a", "b", "c", "d"] end def test_oneof d = OneofMessage.new assert d.a == "" assert d.b == 0 assert d.c == nil assert d.d == :Default assert d.my_oneof == nil d.a = "hi" assert d.a == "hi" assert d.b == 0 assert d.c == nil assert d.d == :Default assert d.my_oneof == :a d.b = 42 assert d.a == "" assert d.b == 42 assert d.c == nil assert d.d == :Default assert d.my_oneof == :b d.c = TestMessage2.new(:foo => 100) assert d.a == "" assert d.b == 0 assert d.c.foo == 100 assert d.d == :Default assert d.my_oneof == :c d.d = :C assert d.a == "" assert d.b == 0 assert d.c == nil assert d.d == :C assert d.my_oneof == :d d2 = OneofMessage.decode(OneofMessage.encode(d)) assert d2 == d encoded_field_a = OneofMessage.encode(OneofMessage.new(:a => "string")) encoded_field_b = OneofMessage.encode(OneofMessage.new(:b => 1000)) encoded_field_c = OneofMessage.encode( OneofMessage.new(:c => TestMessage2.new(:foo => 1))) encoded_field_d = OneofMessage.encode(OneofMessage.new(:d => :B)) d3 = OneofMessage.decode( encoded_field_c + encoded_field_a + encoded_field_d) assert d3.a == "" assert d3.b == 0 assert d3.c == nil assert d3.d == :B d4 = OneofMessage.decode( encoded_field_c + encoded_field_a + encoded_field_d + encoded_field_c) assert d4.a == "" assert d4.b == 0 assert d4.c.foo == 1 assert d4.d == :Default d5 = OneofMessage.new(:a => "hello") assert d5.a == "hello" d5.a = nil assert d5.a == "" assert OneofMessage.encode(d5) == '' assert d5.my_oneof == nil end def test_enum_field m = TestMessage.new assert m.optional_enum == :Default m.optional_enum = :A assert m.optional_enum == :A assert_raise RangeError do m.optional_enum = :ASDF end m.optional_enum = 1 assert m.optional_enum == :A m.optional_enum = 100 assert m.optional_enum == 100 end def test_dup m = TestMessage.new m.optional_string = "hello" m.optional_int32 = 42 tm1 = TestMessage2.new(:foo => 100) tm2 = TestMessage2.new(:foo => 200) m.repeated_msg.push tm1 assert m.repeated_msg[-1] == tm1 m.repeated_msg.push tm2 assert m.repeated_msg[-1] == tm2 m2 = m.dup assert m == m2 m.optional_int32 += 1 assert m != m2 assert m.repeated_msg[0] == m2.repeated_msg[0] assert m.repeated_msg[0].object_id == m2.repeated_msg[0].object_id end def test_deep_copy m = TestMessage.new(:optional_int32 => 42, :repeated_msg => [TestMessage2.new(:foo => 100)]) m2 = Google::Protobuf.deep_copy(m) assert m == m2 assert m.repeated_msg == m2.repeated_msg assert m.repeated_msg.object_id != m2.repeated_msg.object_id assert m.repeated_msg[0].object_id != m2.repeated_msg[0].object_id end def test_eq m = TestMessage.new(:optional_int32 => 42, :repeated_int32 => [1, 2, 3]) m2 = TestMessage.new(:optional_int32 => 43, :repeated_int32 => [1, 2, 3]) assert m != m2 end def test_enum_lookup assert TestEnum::A == 1 assert TestEnum::B == 2 assert TestEnum::C == 3 assert TestEnum::lookup(1) == :A assert TestEnum::lookup(2) == :B assert TestEnum::lookup(3) == :C assert TestEnum::resolve(:A) == 1 assert TestEnum::resolve(:B) == 2 assert TestEnum::resolve(:C) == 3 end def test_parse_serialize m = TestMessage.new(:optional_int32 => 42, :optional_string => "hello world", :optional_enum => :B, :repeated_string => ["a", "b", "c"], :repeated_int32 => [42, 43, 44], :repeated_enum => [:A, :B, :C, 100], :repeated_msg => [TestMessage2.new(:foo => 1), TestMessage2.new(:foo => 2)]) data = TestMessage.encode m m2 = TestMessage.decode data assert m == m2 data = Google::Protobuf.encode m m2 = Google::Protobuf.decode(TestMessage, data) assert m == m2 end def test_encode_decode_helpers m = TestMessage.new(:optional_string => 'foo', :repeated_string => ['bar1', 'bar2']) assert_equal 'foo', m.optional_string assert_equal ['bar1', 'bar2'], m.repeated_string json = m.to_json m2 = TestMessage.decode_json(json) assert_equal 'foo', m2.optional_string assert_equal ['bar1', 'bar2'], m2.repeated_string if RUBY_PLATFORM != "java" assert m2.optional_string.frozen? assert m2.repeated_string[0].frozen? end proto = m.to_proto m2 = TestMessage.decode(proto) assert_equal 'foo', m2.optional_string assert_equal ['bar1', 'bar2'], m2.repeated_string end def test_protobuf_encode_decode_helpers m = TestMessage.new(:optional_string => 'foo', :repeated_string => ['bar1', 'bar2']) encoded_msg = Google::Protobuf.encode(m) assert_equal m.to_proto, encoded_msg decoded_msg = Google::Protobuf.decode(TestMessage, encoded_msg) assert_equal TestMessage.decode(m.to_proto), decoded_msg end def test_protobuf_encode_decode_json_helpers m = TestMessage.new(:optional_string => 'foo', :repeated_string => ['bar1', 'bar2']) encoded_msg = Google::Protobuf.encode_json(m) assert_equal m.to_json, encoded_msg decoded_msg = Google::Protobuf.decode_json(TestMessage, encoded_msg) assert_equal TestMessage.decode_json(m.to_json), decoded_msg 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_bytes=>"", :optional_double=>-10.100001, :optional_enum=>:Default, :optional_float=>0.0, :optional_int32=>0, :optional_int64=>0, :optional_msg=>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=>[], :repeated_string=>["bar1", "bar2"], :repeated_uint32=>[], :repeated_uint64=>[] } assert_equal expected_result, m.to_h end def test_def_errors s = Google::Protobuf::DescriptorPool.new assert_raise TypeError do s.build do # enum with no default (integer value 0) add_enum "MyEnum" do value :A, 1 end end end assert_raise TypeError do s.build do # message with required field (unsupported in proto3) add_message "MyMessage" do required :foo, :int32, 1 end end end end def test_corecursive # just be sure that we can instantiate types with corecursive field-type # references. m = Recursive1.new(:foo => Recursive2.new(:foo => Recursive1.new)) assert Recursive1.descriptor.lookup("foo").subtype == Recursive2.descriptor assert Recursive2.descriptor.lookup("foo").subtype == Recursive1.descriptor serialized = Recursive1.encode(m) m2 = Recursive1.decode(serialized) assert m == m2 end def test_serialize_cycle m = Recursive1.new(:foo => Recursive2.new) m.foo.foo = m assert_raise RuntimeError do serialized = Recursive1.encode(m) end end def test_bad_field_names m = BadFieldNames.new(:dup => 1, :class => 2) m2 = m.dup assert m == m2 assert m['dup'] == 1 assert m['class'] == 2 m['dup'] = 3 assert m['dup'] == 3 m['a.b'] = 4 assert m['a.b'] == 4 end def test_int_ranges m = TestMessage.new m.optional_int32 = 0 m.optional_int32 = -0x8000_0000 m.optional_int32 = +0x7fff_ffff m.optional_int32 = 1.0 m.optional_int32 = -1.0 m.optional_int32 = 2e9 assert_raise RangeError do m.optional_int32 = -0x8000_0001 end assert_raise RangeError do m.optional_int32 = +0x8000_0000 end assert_raise RangeError do m.optional_int32 = +0x1000_0000_0000_0000_0000_0000 # force Bignum end assert_raise RangeError do m.optional_int32 = 1e12 end assert_raise RangeError do m.optional_int32 = 1.5 end m.optional_uint32 = 0 m.optional_uint32 = +0xffff_ffff m.optional_uint32 = 1.0 m.optional_uint32 = 4e9 assert_raise RangeError do m.optional_uint32 = -1 end assert_raise RangeError do m.optional_uint32 = -1.5 end assert_raise RangeError do m.optional_uint32 = -1.5e12 end assert_raise RangeError do m.optional_uint32 = -0x1000_0000_0000_0000 end assert_raise RangeError do m.optional_uint32 = +0x1_0000_0000 end assert_raise RangeError do m.optional_uint32 = +0x1000_0000_0000_0000_0000_0000 # force Bignum end assert_raise RangeError do m.optional_uint32 = 1e12 end assert_raise RangeError do m.optional_uint32 = 1.5 end m.optional_int64 = 0 m.optional_int64 = -0x8000_0000_0000_0000 m.optional_int64 = +0x7fff_ffff_ffff_ffff m.optional_int64 = 1.0 m.optional_int64 = -1.0 m.optional_int64 = 8e18 m.optional_int64 = -8e18 assert_raise RangeError do m.optional_int64 = -0x8000_0000_0000_0001 end assert_raise RangeError do m.optional_int64 = +0x8000_0000_0000_0000 end assert_raise RangeError do m.optional_int64 = +0x1000_0000_0000_0000_0000_0000 # force Bignum end assert_raise RangeError do m.optional_int64 = 1e50 end assert_raise RangeError do m.optional_int64 = 1.5 end m.optional_uint64 = 0 m.optional_uint64 = +0xffff_ffff_ffff_ffff m.optional_uint64 = 1.0 m.optional_uint64 = 16e18 assert_raise RangeError do m.optional_uint64 = -1 end assert_raise RangeError do m.optional_uint64 = -1.5 end assert_raise RangeError do m.optional_uint64 = -1.5e12 end assert_raise RangeError do m.optional_uint64 = -0x1_0000_0000_0000_0000 end assert_raise RangeError do m.optional_uint64 = +0x1_0000_0000_0000_0000 end assert_raise RangeError do m.optional_uint64 = +0x1000_0000_0000_0000_0000_0000 # force Bignum end assert_raise RangeError do m.optional_uint64 = 1e50 end assert_raise RangeError do m.optional_uint64 = 1.5 end end def test_stress_test m = TestMessage.new m.optional_int32 = 42 m.optional_int64 = 0x100000000 m.optional_string = "hello world" 10.times do m.repeated_msg.push TestMessage2.new(:foo => 42) end 10.times do m.repeated_string.push "hello world" end data = TestMessage.encode(m) l = 0 10_000.times do m = TestMessage.decode(data) data_new = TestMessage.encode(m) assert data_new == data data = data_new end end def test_reflection m = TestMessage.new(:optional_int32 => 1234) msgdef = m.class.descriptor assert msgdef.class == Google::Protobuf::Descriptor assert msgdef.any? {|field| field.name == "optional_int32"} optional_int32 = msgdef.lookup "optional_int32" assert optional_int32.class == Google::Protobuf::FieldDescriptor assert optional_int32 != nil assert optional_int32.name == "optional_int32" assert optional_int32.type == :int32 optional_int32.set(m, 5678) assert m.optional_int32 == 5678 m.optional_int32 = 1000 assert optional_int32.get(m) == 1000 optional_msg = msgdef.lookup "optional_msg" assert optional_msg.subtype == TestMessage2.descriptor optional_msg.set(m, optional_msg.subtype.msgclass.new) assert msgdef.msgclass == TestMessage optional_enum = msgdef.lookup "optional_enum" assert optional_enum.subtype == TestEnum.descriptor assert optional_enum.subtype.class == Google::Protobuf::EnumDescriptor optional_enum.subtype.each do |k, v| # set with integer, check resolution to symbolic name optional_enum.set(m, v) assert optional_enum.get(m) == k end end def test_json # TODO: Fix JSON in JRuby version. return if RUBY_PLATFORM == "java" m = TestMessage.new(:optional_int32 => 1234, :optional_int64 => -0x1_0000_0000, :optional_uint32 => 0x8000_0000, :optional_uint64 => 0xffff_ffff_ffff_ffff, :optional_bool => true, :optional_float => 1.0, :optional_double => -1e100, :optional_string => "Test string", :optional_bytes => ["FFFFFFFF"].pack('H*'), :optional_msg => TestMessage2.new(:foo => 42), :repeated_int32 => [1, 2, 3, 4], :repeated_string => ["a", "b", "c"], :repeated_bool => [true, false, true, false], :repeated_msg => [TestMessage2.new(:foo => 1), TestMessage2.new(:foo => 2)]) json_text = TestMessage.encode_json(m) m2 = TestMessage.decode_json(json_text) assert m == m2 # Crash case from GitHub issue 283. bar = Bar.new(msg: "bar") baz1 = Baz.new(msg: "baz") baz2 = Baz.new(msg: "quux") Foo.encode_json(Foo.new) Foo.encode_json(Foo.new(bar: bar)) Foo.encode_json(Foo.new(bar: bar, baz: [baz1, baz2])) end def test_json_maps # TODO: Fix JSON in JRuby version. return if RUBY_PLATFORM == "java" m = MapMessage.new(:map_string_int32 => {"a" => 1}) expected = '{"mapStringInt32":{"a":1},"mapStringMsg":{}}' expected_preserve = '{"map_string_int32":{"a":1},"map_string_msg":{}}' assert MapMessage.encode_json(m) == expected json = MapMessage.encode_json(m, :preserve_proto_fieldnames => true) assert json == expected_preserve m2 = MapMessage.decode_json(MapMessage.encode_json(m)) assert m == m2 end def test_comparison_with_arbitrary_object assert MapMessage.new != nil 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 = MapMessage.new assert msg.respond_to?(:map_string_int32) assert !msg.respond_to?(:bacon) end end end google-protobuf-3.2.0/tests/test_import.proto0000644000175000017500000000010513042756211020447 0ustar pravipravisyntax = "proto3"; package foo_bar; message TestImportedMessage {} google-protobuf-3.2.0/tests/generated_code.proto0000644000175000017500000000333313042756211021034 0ustar pravipravisyntax = "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 map_int32_string = 61; map map_int64_string = 62; map map_uint32_string = 63; map map_uint64_string = 64; map map_bool_string = 65; map map_string_string = 66; map map_string_msg = 67; map map_string_enum = 68; map map_string_int32 = 69; map map_string_bool = 70; message NestedMessage { int32 foo = 1; } NestedMessage nested_message = 80; } enum TestEnum { Default = 0; A = 1; B = 2; C = 3; } google-protobuf-3.2.0/tests/generated_code_test.rb0000644000175000017500000000122113042756211021325 0ustar pravipravi#!/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 google-protobuf-3.2.0/tests/stress.rb0000644000175000017500000000161313042756211016666 0ustar pravipravi#!/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 google-protobuf-3.2.0/tests/well_known_types_test.rb0000644000175000017500000000660213042756211022010 0ustar pravipravi#!/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 ts.from_time(Time.at(123456, 654321)) assert_equal 123456, ts.seconds assert_equal 654321000, ts.nanos assert_equal Time.at(123456.654321), ts.to_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"]) 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 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 any = Google::Protobuf::Any.new ts = Google::Protobuf::Timestamp.new(seconds: 12345, nanos: 6789) any.pack(ts) assert any.is(Google::Protobuf::Timestamp) assert_equal ts, any.unpack(Google::Protobuf::Timestamp) end end google-protobuf-3.2.0/Rakefile0000644000175000017500000000545413042756211015330 0ustar pravipravirequire "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/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 ] # These are omitted for now because we don't support proto2. proto2_protos = %w[ google/protobuf/descriptor.proto google/protobuf/compiler/plugin.proto ] 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 "../src/protoc -I../src --ruby_out=lib #{input_file}" end end end if RUBY_PLATFORM == "java" if `which mvn` == '' raise ArgumentError, "maven needs to be installed" end task :clean do system("mvn --batch-mode clean") end task :compile do system("mvn --batch-mode package") end else Rake::ExtensionTask.new("protobuf_c", spec) do |ext| 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', 'universal-darwin' ] end task 'gem:windows' do require 'rake_compiler_dock' RakeCompilerDock.sh "bundle && IN_DOCKER=true rake cross native gem RUBY_CC_VERSION=2.3.0:2.2.2:2.1.5:2.0.0" end if RUBY_PLATFORM =~ /darwin/ task 'gem:native' do system "rake genproto" system "rake cross native gem RUBY_CC_VERSION=2.3.0:2.2.2:2.1.5:2.0.0" end else task 'gem:native' => [:genproto, 'gem:windows'] end end # Proto for tests. 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 "../src/protoc --ruby_out=. tests/generated_code.proto" end file "tests/test_import.rb" => "tests/test_import.proto" do |file_task| sh "../src/protoc --ruby_out=. tests/test_import.proto" 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) do |t| t.test_files = FileList["tests/*.rb"] end task :build => [:clean, :compile, :genproto] task :default => [:build] # vim:sw=2:et google-protobuf-3.2.0/travis-test.sh0000754000175000017500000000121013042756211016470 0ustar pravipravi#!/usr/bin/env bash # Exit on any error. set -e test_version() { version=$1 if [ "$version" == "jruby-1.7" ] ; then # No conformance tests yet -- JRuby is too broken to run them. bash --login -c \ "rvm install $version && rvm use $version && rvm get head && \ which ruby && \ git clean -f && \ gem install bundler && bundle && \ rake test" else bash --login -c \ "rvm install $version && rvm use $version && \ which ruby && \ git clean -f && \ gem install bundler && bundle && \ rake test && cd ../conformance && make test_ruby" fi } test_version $1 google-protobuf-3.2.0/pom.xml0000644000175000017500000000642613042756211015200 0ustar pravipravi 4.0.0 com.google google 1 com.google.protobuf.jruby protobuf-jruby 1.0-SNAPSHOT Protocol Buffer JRuby native extension Protocol Buffers are a way of encoding structured data in an efficient yet extensible format. 2014 https://developers.google.com/protocol-buffers/ New BSD license http://www.opensource.org/licenses/bsd-license.php repo https://github.com/google/protobuf scm:git:https://github.com/google/protobuf.git UTF-8 lib/google protobuf_java org.apache.maven.plugins maven-assembly-plugin ${jar.finalName} ${ruby.sources} false jar-with-dependencies make-assembly package single org.apache.maven.plugins maven-compiler-plugin 1.6 1.6 com.fasterxml.jackson.core jackson-core 2.4.3 org.jruby jruby-complete 1.7.13 provided com.google.protobuf protobuf-java 3.0.0 google-protobuf-3.2.0/lib/0000755000175000017500000000000013043000402014402 5ustar pravipravigoogle-protobuf-3.2.0/lib/google/0000755000175000017500000000000013043000403015657 5ustar pravipravigoogle-protobuf-3.2.0/lib/google/protobuf/0000755000175000017500000000000013043000403017517 5ustar pravipravigoogle-protobuf-3.2.0/lib/google/protobuf/repeated_field.rb0000644000175000017500000001471213042756211023023 0ustar pravipravi# 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 delete_if shift slice! unshift).each do |method_name| define_array_wrapper_method(method_name) end %w(collect! compact! 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 google-protobuf-3.2.0/lib/google/protobuf/message_exts.rb0000644000175000017500000000375013042756211022556 0ustar pravipravi# 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 self.class.encode_json(self) end def to_proto self.class.encode(self) end end end end google-protobuf-3.2.0/lib/google/protobuf/well_known_types.rb0000644000175000017500000001300013042756211023457 0ustar pravipravi#!/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 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 def to_time Time.at(self.to_f) end def from_time(time) self.seconds = time.to_i self.nanos = time.nsec end def to_i self.seconds end def to_f self.seconds + (self.nanos.to_f / 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 from_ruby(value) case value when NilClass self.null_value = 0 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 end end Struct.class_eval do def [](key) self.fields[key].to_ruby 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 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 google-protobuf-3.2.0/lib/google/protobuf.rb0000644000175000017500000000473713042756211020075 0ustar pravipravi# 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 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/repeated_field' module Google module Protobuf def self.encode(msg) msg.to_proto end def self.encode_json(msg) msg.to_json end def self.decode(klass, proto) klass.decode(proto) end def self.decode_json(klass, json) klass.decode_json(json) end end end google-protobuf-3.2.0/Gemfile0000644000175000017500000000004713042756211015147 0ustar pravipravisource 'https://rubygems.org' gemspec google-protobuf-3.2.0/google-protobuf.gemspec0000644000175000017500000000201213042777744020343 0ustar pravipraviGem::Specification.new do |s| s.name = "google-protobuf" s.version = "3.2.0" s.licenses = ["BSD"] 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.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", "~> 0.5.1" end s.test_files = ["tests/basic.rb", "tests/stress.rb", "tests/generated_code_test.rb"] s.add_development_dependency "rake-compiler", "~> 0.9.5" s.add_development_dependency "test-unit", "~> 3.0.9" s.add_development_dependency "rubygems-tasks", "~> 0.2.4" end google-protobuf-3.2.0/ext/0000755000175000017500000000000013043000402014434 5ustar pravipravigoogle-protobuf-3.2.0/ext/google/0000755000175000017500000000000013043000402015710 5ustar pravipravigoogle-protobuf-3.2.0/ext/google/protobuf_c/0000755000175000017500000000000013043000402020052 5ustar pravipravigoogle-protobuf-3.2.0/ext/google/protobuf_c/encode_decode.c0000644000175000017500000013047313042777744023023 0ustar pravipravi// 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" // This function is equivalent to rb_str_cat(), but unlike the real // rb_str_cat(), it doesn't leak memory in some versions of Ruby. // For more information, see: // https://bugs.ruby-lang.org/issues/11328 VALUE noleak_rb_str_cat(VALUE rb_str, const char *str, long len) { char *p; size_t oldlen = RSTRING_LEN(rb_str); rb_str_modify_expand(rb_str, len); p = RSTRING_PTR(rb_str); memcpy(p + oldlen, str, len); rb_str_set_len(rb_str, oldlen + len); return rb_str; } // ----------------------------------------------------------------------------- // Parsing. // ----------------------------------------------------------------------------- #define DEREF(msg, ofs, type) *(type*)(((uint8_t *)msg) + ofs) // Creates a handlerdata that simply contains the offset for this field. static const void* newhandlerdata(upb_handlers* h, uint32_t ofs) { size_t* hd_ofs = ALLOC(size_t); *hd_ofs = ofs; upb_handlers_addcleanup(h, hd_ofs, xfree); return hd_ofs; } typedef struct { size_t ofs; const upb_msgdef *md; } submsg_handlerdata_t; // Creates a handlerdata that contains offset and submessage type information. static const void *newsubmsghandlerdata(upb_handlers* h, uint32_t ofs, const upb_fielddef* f) { submsg_handlerdata_t *hd = ALLOC(submsg_handlerdata_t); hd->ofs = ofs; hd->md = upb_fielddef_msgsubdef(f); upb_handlers_addcleanup(h, hd, xfree); return hd; } typedef struct { size_t ofs; // union data slot size_t case_ofs; // oneof_case field uint32_t oneof_case_num; // oneof-case number to place in oneof_case field const upb_msgdef *md; // msgdef, for oneof submessage handler } oneof_handlerdata_t; static const void *newoneofhandlerdata(upb_handlers *h, uint32_t ofs, uint32_t case_ofs, const upb_fielddef *f) { oneof_handlerdata_t *hd = ALLOC(oneof_handlerdata_t); hd->ofs = ofs; hd->case_ofs = case_ofs; // We reuse the field tag number as a oneof union discriminant tag. Note that // we don't expose these numbers to the user, so the only requirement is that // we have some unique ID for each union case/possibility. The field tag // numbers are already present and are easy to use so there's no reason to // create a separate ID space. In addition, using the field tag number here // lets us easily look up the field in the oneof accessor. hd->oneof_case_num = upb_fielddef_number(f); if (upb_fielddef_type(f) == UPB_TYPE_MESSAGE) { hd->md = upb_fielddef_msgsubdef(f); } else { hd->md = NULL; } upb_handlers_addcleanup(h, hd, xfree); return hd; } // A handler that starts a repeated field. Gets the Repeated*Field instance for // this field (such an instance always exists even in an empty message). static void *startseq_handler(void* closure, const void* hd) { MessageHeader* msg = closure; const size_t *ofs = hd; return (void*)DEREF(msg, *ofs, VALUE); } // Handlers that append primitive values to a repeated field. #define DEFINE_APPEND_HANDLER(type, ctype) \ static bool append##type##_handler(void *closure, const void *hd, \ ctype val) { \ VALUE ary = (VALUE)closure; \ RepeatedField_push_native(ary, &val); \ return true; \ } DEFINE_APPEND_HANDLER(bool, bool) DEFINE_APPEND_HANDLER(int32, int32_t) DEFINE_APPEND_HANDLER(uint32, uint32_t) DEFINE_APPEND_HANDLER(float, float) DEFINE_APPEND_HANDLER(int64, int64_t) DEFINE_APPEND_HANDLER(uint64, uint64_t) DEFINE_APPEND_HANDLER(double, double) // Appends a string to a repeated field. static void* appendstr_handler(void *closure, const void *hd, size_t size_hint) { VALUE ary = (VALUE)closure; VALUE str = rb_str_new2(""); rb_enc_associate(str, kRubyStringUtf8Encoding); RepeatedField_push_native(ary, &str); return (void*)str; } // Appends a 'bytes' string to a repeated field. static void* appendbytes_handler(void *closure, const void *hd, size_t size_hint) { VALUE ary = (VALUE)closure; VALUE str = rb_str_new2(""); rb_enc_associate(str, kRubyString8bitEncoding); RepeatedField_push_native(ary, &str); return (void*)str; } // Sets a non-repeated string field in a message. static void* str_handler(void *closure, const void *hd, size_t size_hint) { MessageHeader* msg = closure; const size_t *ofs = hd; VALUE str = rb_str_new2(""); rb_enc_associate(str, kRubyStringUtf8Encoding); DEREF(msg, *ofs, VALUE) = str; return (void*)str; } // Sets a non-repeated 'bytes' field in a message. static void* bytes_handler(void *closure, const void *hd, size_t size_hint) { MessageHeader* msg = closure; const size_t *ofs = hd; VALUE str = rb_str_new2(""); rb_enc_associate(str, kRubyString8bitEncoding); DEREF(msg, *ofs, VALUE) = str; return (void*)str; } static size_t stringdata_handler(void* closure, const void* hd, const char* str, size_t len, const upb_bufhandle* handle) { VALUE rb_str = (VALUE)closure; noleak_rb_str_cat(rb_str, str, len); return len; } static bool stringdata_end_handler(void* closure, const void* hd) { MessageHeader* msg = closure; const size_t *ofs = hd; VALUE rb_str = DEREF(msg, *ofs, VALUE); rb_obj_freeze(rb_str); return true; } static bool appendstring_end_handler(void* closure, const void* hd) { VALUE ary = (VALUE)closure; int size = RepeatedField_size(ary); VALUE* last = RepeatedField_index_native(ary, size - 1); VALUE rb_str = *last; rb_obj_freeze(rb_str); return true; } // Appends a submessage to a repeated field (a regular Ruby array for now). static void *appendsubmsg_handler(void *closure, const void *hd) { VALUE ary = (VALUE)closure; const submsg_handlerdata_t *submsgdata = hd; VALUE subdesc = get_def_obj((void*)submsgdata->md); VALUE subklass = Descriptor_msgclass(subdesc); MessageHeader* submsg; VALUE submsg_rb = rb_class_new_instance(0, NULL, subklass); RepeatedField_push(ary, submsg_rb); TypedData_Get_Struct(submsg_rb, MessageHeader, &Message_type, submsg); return submsg; } // Sets a non-repeated submessage field in a message. static void *submsg_handler(void *closure, const void *hd) { MessageHeader* msg = closure; const submsg_handlerdata_t* submsgdata = hd; VALUE subdesc = get_def_obj((void*)submsgdata->md); VALUE subklass = Descriptor_msgclass(subdesc); VALUE submsg_rb; MessageHeader* submsg; if (DEREF(msg, submsgdata->ofs, VALUE) == Qnil) { DEREF(msg, submsgdata->ofs, VALUE) = rb_class_new_instance(0, NULL, subklass); } submsg_rb = DEREF(msg, submsgdata->ofs, VALUE); TypedData_Get_Struct(submsg_rb, MessageHeader, &Message_type, submsg); return submsg; } // Handler data for startmap/endmap handlers. typedef struct { size_t ofs; upb_fieldtype_t key_field_type; upb_fieldtype_t value_field_type; // We know that we can hold this reference because the handlerdata has the // same lifetime as the upb_handlers struct, and the upb_handlers struct holds // a reference to the upb_msgdef, which in turn has references to its subdefs. const upb_def* value_field_subdef; } map_handlerdata_t; // Temporary frame for map parsing: at the beginning of a map entry message, a // submsg handler allocates a frame to hold (i) a reference to the Map object // into which this message will be inserted and (ii) storage slots to // temporarily hold the key and value for this map entry until the end of the // submessage. When the submessage ends, another handler is called to insert the // value into the map. typedef struct { VALUE map; const map_handlerdata_t* handlerdata; char key_storage[NATIVE_SLOT_MAX_SIZE]; char value_storage[NATIVE_SLOT_MAX_SIZE]; } map_parse_frame_t; static void MapParseFrame_mark(void* _self) { map_parse_frame_t* frame = _self; // This shouldn't strictly be necessary since this should be rooted by the // message itself, but it can't hurt. rb_gc_mark(frame->map); native_slot_mark(frame->handlerdata->key_field_type, &frame->key_storage); native_slot_mark(frame->handlerdata->value_field_type, &frame->value_storage); } void MapParseFrame_free(void* self) { xfree(self); } rb_data_type_t MapParseFrame_type = { "MapParseFrame", { MapParseFrame_mark, MapParseFrame_free, NULL }, }; // Array of Ruby objects wrapping map_parse_frame_t. // We don't allow multiple concurrent decodes, so we assume that this global // variable is specific to the "current" decode. VALUE map_parse_frames; static map_parse_frame_t* map_push_frame(VALUE map, const map_handlerdata_t* handlerdata) { map_parse_frame_t* frame = ALLOC(map_parse_frame_t); frame->handlerdata = handlerdata; frame->map = map; native_slot_init(handlerdata->key_field_type, &frame->key_storage); native_slot_init(handlerdata->value_field_type, &frame->value_storage); rb_ary_push(map_parse_frames, TypedData_Wrap_Struct(rb_cObject, &MapParseFrame_type, frame)); return frame; } static void map_pop_frame() { rb_ary_pop(map_parse_frames); } // Handler to begin a map entry: allocates a temporary frame. This is the // 'startsubmsg' handler on the msgdef that contains the map field. static void *startmapentry_handler(void *closure, const void *hd) { MessageHeader* msg = closure; const map_handlerdata_t* mapdata = hd; VALUE map_rb = DEREF(msg, mapdata->ofs, VALUE); return map_push_frame(map_rb, mapdata); } // Handler to end a map entry: inserts the value defined during the message into // the map. This is the 'endmsg' handler on the map entry msgdef. static bool endmap_handler(void *closure, const void *hd, upb_status* s) { map_parse_frame_t* frame = closure; const map_handlerdata_t* mapdata = hd; VALUE key = native_slot_get( mapdata->key_field_type, Qnil, &frame->key_storage); VALUE value_field_typeclass = Qnil; VALUE value; if (mapdata->value_field_type == UPB_TYPE_MESSAGE || mapdata->value_field_type == UPB_TYPE_ENUM) { value_field_typeclass = get_def_obj(mapdata->value_field_subdef); } value = native_slot_get( mapdata->value_field_type, value_field_typeclass, &frame->value_storage); Map_index_set(frame->map, key, value); map_pop_frame(); return true; } // Allocates a new map_handlerdata_t given the map entry message definition. If // the offset of the field within the parent message is also given, that is // added to the handler data as well. Note that this is called *twice* per map // field: once in the parent message handler setup when setting the startsubmsg // handler and once in the map entry message handler setup when setting the // key/value and endmsg handlers. The reason is that there is no easy way to // pass the handlerdata down to the sub-message handler setup. static map_handlerdata_t* new_map_handlerdata( size_t ofs, const upb_msgdef* mapentry_def, Descriptor* desc) { const upb_fielddef* key_field; const upb_fielddef* value_field; map_handlerdata_t* hd = ALLOC(map_handlerdata_t); hd->ofs = ofs; key_field = upb_msgdef_itof(mapentry_def, MAP_KEY_FIELD); assert(key_field != NULL); hd->key_field_type = upb_fielddef_type(key_field); value_field = upb_msgdef_itof(mapentry_def, MAP_VALUE_FIELD); assert(value_field != NULL); hd->value_field_type = upb_fielddef_type(value_field); hd->value_field_subdef = upb_fielddef_subdef(value_field); return hd; } // Handlers that set primitive values in oneofs. #define DEFINE_ONEOF_HANDLER(type, ctype) \ static bool oneof##type##_handler(void *closure, const void *hd, \ ctype val) { \ const oneof_handlerdata_t *oneofdata = hd; \ DEREF(closure, oneofdata->case_ofs, uint32_t) = \ oneofdata->oneof_case_num; \ DEREF(closure, oneofdata->ofs, ctype) = val; \ return true; \ } DEFINE_ONEOF_HANDLER(bool, bool) DEFINE_ONEOF_HANDLER(int32, int32_t) DEFINE_ONEOF_HANDLER(uint32, uint32_t) DEFINE_ONEOF_HANDLER(float, float) DEFINE_ONEOF_HANDLER(int64, int64_t) DEFINE_ONEOF_HANDLER(uint64, uint64_t) DEFINE_ONEOF_HANDLER(double, double) #undef DEFINE_ONEOF_HANDLER // Handlers for strings in a oneof. static void *oneofstr_handler(void *closure, const void *hd, size_t size_hint) { MessageHeader* msg = closure; const oneof_handlerdata_t *oneofdata = hd; VALUE str = rb_str_new2(""); rb_enc_associate(str, kRubyStringUtf8Encoding); DEREF(msg, oneofdata->case_ofs, uint32_t) = oneofdata->oneof_case_num; DEREF(msg, oneofdata->ofs, VALUE) = str; return (void*)str; } static void *oneofbytes_handler(void *closure, const void *hd, size_t size_hint) { MessageHeader* msg = closure; const oneof_handlerdata_t *oneofdata = hd; VALUE str = rb_str_new2(""); rb_enc_associate(str, kRubyString8bitEncoding); DEREF(msg, oneofdata->case_ofs, uint32_t) = oneofdata->oneof_case_num; DEREF(msg, oneofdata->ofs, VALUE) = str; return (void*)str; } static bool oneofstring_end_handler(void* closure, const void* hd) { MessageHeader* msg = closure; const oneof_handlerdata_t *oneofdata = hd; rb_obj_freeze(DEREF(msg, oneofdata->ofs, VALUE)); return true; } // Handler for a submessage field in a oneof. static void *oneofsubmsg_handler(void *closure, const void *hd) { MessageHeader* msg = closure; const oneof_handlerdata_t *oneofdata = hd; uint32_t oldcase = DEREF(msg, oneofdata->case_ofs, uint32_t); VALUE subdesc = get_def_obj((void*)oneofdata->md); VALUE subklass = Descriptor_msgclass(subdesc); VALUE submsg_rb; MessageHeader* submsg; if (oldcase != oneofdata->oneof_case_num || DEREF(msg, oneofdata->ofs, VALUE) == Qnil) { DEREF(msg, oneofdata->ofs, VALUE) = rb_class_new_instance(0, NULL, subklass); } // Set the oneof case *after* allocating the new class instance -- otherwise, // if the Ruby GC is invoked as part of a call into the VM, it might invoke // our mark routines, and our mark routines might see the case value // indicating a VALUE is present and expect a valid VALUE. See comment in // layout_set() for more detail: basically, the change to the value and the // case must be atomic w.r.t. the Ruby VM. DEREF(msg, oneofdata->case_ofs, uint32_t) = oneofdata->oneof_case_num; submsg_rb = DEREF(msg, oneofdata->ofs, VALUE); TypedData_Get_Struct(submsg_rb, MessageHeader, &Message_type, submsg); return submsg; } // Set up handlers for a repeated field. static void add_handlers_for_repeated_field(upb_handlers *h, const upb_fielddef *f, size_t offset) { upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER; upb_handlerattr_sethandlerdata(&attr, newhandlerdata(h, offset)); upb_handlers_setstartseq(h, f, startseq_handler, &attr); upb_handlerattr_uninit(&attr); switch (upb_fielddef_type(f)) { #define SET_HANDLER(utype, ltype) \ case utype: \ upb_handlers_set##ltype(h, f, append##ltype##_handler, NULL); \ break; SET_HANDLER(UPB_TYPE_BOOL, bool); SET_HANDLER(UPB_TYPE_INT32, int32); SET_HANDLER(UPB_TYPE_UINT32, uint32); SET_HANDLER(UPB_TYPE_ENUM, int32); SET_HANDLER(UPB_TYPE_FLOAT, float); SET_HANDLER(UPB_TYPE_INT64, int64); SET_HANDLER(UPB_TYPE_UINT64, uint64); SET_HANDLER(UPB_TYPE_DOUBLE, double); #undef SET_HANDLER case UPB_TYPE_STRING: case UPB_TYPE_BYTES: { bool is_bytes = upb_fielddef_type(f) == UPB_TYPE_BYTES; upb_handlers_setstartstr(h, f, is_bytes ? appendbytes_handler : appendstr_handler, NULL); upb_handlers_setstring(h, f, stringdata_handler, NULL); upb_handlers_setendstr(h, f, appendstring_end_handler, NULL); break; } case UPB_TYPE_MESSAGE: { upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER; upb_handlerattr_sethandlerdata(&attr, newsubmsghandlerdata(h, 0, f)); upb_handlers_setstartsubmsg(h, f, appendsubmsg_handler, &attr); upb_handlerattr_uninit(&attr); break; } } } // Set up handlers for a singular field. static void add_handlers_for_singular_field(upb_handlers *h, const upb_fielddef *f, size_t offset) { switch (upb_fielddef_type(f)) { case UPB_TYPE_BOOL: case UPB_TYPE_INT32: case UPB_TYPE_UINT32: case UPB_TYPE_ENUM: case UPB_TYPE_FLOAT: case UPB_TYPE_INT64: case UPB_TYPE_UINT64: case UPB_TYPE_DOUBLE: upb_msg_setscalarhandler(h, f, offset, -1); break; case UPB_TYPE_STRING: case UPB_TYPE_BYTES: { bool is_bytes = upb_fielddef_type(f) == UPB_TYPE_BYTES; upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER; upb_handlerattr_sethandlerdata(&attr, newhandlerdata(h, offset)); upb_handlers_setstartstr(h, f, is_bytes ? bytes_handler : str_handler, &attr); upb_handlers_setstring(h, f, stringdata_handler, &attr); upb_handlers_setendstr(h, f, stringdata_end_handler, &attr); upb_handlerattr_uninit(&attr); break; } case UPB_TYPE_MESSAGE: { upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER; upb_handlerattr_sethandlerdata(&attr, newsubmsghandlerdata(h, offset, f)); upb_handlers_setstartsubmsg(h, f, submsg_handler, &attr); upb_handlerattr_uninit(&attr); break; } } } // Adds handlers to a map field. static void add_handlers_for_mapfield(upb_handlers* h, const upb_fielddef* fielddef, size_t offset, Descriptor* desc) { const upb_msgdef* map_msgdef = upb_fielddef_msgsubdef(fielddef); map_handlerdata_t* hd = new_map_handlerdata(offset, map_msgdef, desc); upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER; upb_handlers_addcleanup(h, hd, xfree); upb_handlerattr_sethandlerdata(&attr, hd); upb_handlers_setstartsubmsg(h, fielddef, startmapentry_handler, &attr); upb_handlerattr_uninit(&attr); } // Adds handlers to a map-entry msgdef. static void add_handlers_for_mapentry(const upb_msgdef* msgdef, upb_handlers* h, Descriptor* desc) { const upb_fielddef* key_field = map_entry_key(msgdef); const upb_fielddef* value_field = map_entry_value(msgdef); map_handlerdata_t* hd = new_map_handlerdata(0, msgdef, desc); upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER; upb_handlers_addcleanup(h, hd, xfree); upb_handlerattr_sethandlerdata(&attr, hd); upb_handlers_setendmsg(h, endmap_handler, &attr); add_handlers_for_singular_field( h, key_field, offsetof(map_parse_frame_t, key_storage)); add_handlers_for_singular_field( h, value_field, offsetof(map_parse_frame_t, value_storage)); } // Set up handlers for a oneof field. static void add_handlers_for_oneof_field(upb_handlers *h, const upb_fielddef *f, size_t offset, size_t oneof_case_offset) { upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER; upb_handlerattr_sethandlerdata( &attr, newoneofhandlerdata(h, offset, oneof_case_offset, f)); switch (upb_fielddef_type(f)) { #define SET_HANDLER(utype, ltype) \ case utype: \ upb_handlers_set##ltype(h, f, oneof##ltype##_handler, &attr); \ break; SET_HANDLER(UPB_TYPE_BOOL, bool); SET_HANDLER(UPB_TYPE_INT32, int32); SET_HANDLER(UPB_TYPE_UINT32, uint32); SET_HANDLER(UPB_TYPE_ENUM, int32); SET_HANDLER(UPB_TYPE_FLOAT, float); SET_HANDLER(UPB_TYPE_INT64, int64); SET_HANDLER(UPB_TYPE_UINT64, uint64); SET_HANDLER(UPB_TYPE_DOUBLE, double); #undef SET_HANDLER case UPB_TYPE_STRING: case UPB_TYPE_BYTES: { bool is_bytes = upb_fielddef_type(f) == UPB_TYPE_BYTES; upb_handlers_setstartstr(h, f, is_bytes ? oneofbytes_handler : oneofstr_handler, &attr); upb_handlers_setstring(h, f, stringdata_handler, NULL); upb_handlers_setendstr(h, f, oneofstring_end_handler, &attr); break; } case UPB_TYPE_MESSAGE: { upb_handlers_setstartsubmsg(h, f, oneofsubmsg_handler, &attr); break; } } upb_handlerattr_uninit(&attr); } static void add_handlers_for_message(const void *closure, upb_handlers *h) { const upb_msgdef* msgdef = upb_handlers_msgdef(h); Descriptor* desc = ruby_to_Descriptor(get_def_obj((void*)msgdef)); upb_msg_field_iter i; // If this is a mapentry message type, set up a special set of handlers and // bail out of the normal (user-defined) message type handling. if (upb_msgdef_mapentry(msgdef)) { add_handlers_for_mapentry(msgdef, h, desc); return; } // Ensure layout exists. We may be invoked to create handlers for a given // message if we are included as a submsg of another message type before our // class is actually built, so to work around this, we just create the layout // (and handlers, in the class-building function) on-demand. if (desc->layout == NULL) { desc->layout = create_layout(desc->msgdef); } for (upb_msg_field_begin(&i, desc->msgdef); !upb_msg_field_done(&i); upb_msg_field_next(&i)) { const upb_fielddef *f = upb_msg_iter_field(&i); size_t offset = desc->layout->fields[upb_fielddef_index(f)].offset + sizeof(MessageHeader); if (upb_fielddef_containingoneof(f)) { size_t oneof_case_offset = desc->layout->fields[upb_fielddef_index(f)].case_offset + sizeof(MessageHeader); add_handlers_for_oneof_field(h, f, offset, oneof_case_offset); } else if (is_map_field(f)) { add_handlers_for_mapfield(h, f, offset, desc); } else if (upb_fielddef_isseq(f)) { add_handlers_for_repeated_field(h, f, offset); } else { add_handlers_for_singular_field(h, f, offset); } } } // Creates upb handlers for populating a message. static const upb_handlers *new_fill_handlers(Descriptor* desc, const void* owner) { // TODO(cfallin, haberman): once upb gets a caching/memoization layer for // handlers, reuse subdef handlers so that e.g. if we already parse // B-with-field-of-type-C, we don't have to rebuild the whole hierarchy to // parse A-with-field-of-type-B-with-field-of-type-C. return upb_handlers_newfrozen(desc->msgdef, owner, add_handlers_for_message, NULL); } // Constructs the handlers for filling a message's data into an in-memory // object. const upb_handlers* get_fill_handlers(Descriptor* desc) { if (!desc->fill_handlers) { desc->fill_handlers = new_fill_handlers(desc, &desc->fill_handlers); } return desc->fill_handlers; } // Constructs the upb decoder method for parsing messages of this type. // This is called from the message class creation code. const upb_pbdecodermethod *new_fillmsg_decodermethod(Descriptor* desc, const void* owner) { const upb_handlers* handlers = get_fill_handlers(desc); upb_pbdecodermethodopts opts; upb_pbdecodermethodopts_init(&opts, handlers); return upb_pbdecodermethod_new(&opts, owner); } static const upb_pbdecodermethod *msgdef_decodermethod(Descriptor* desc) { if (desc->fill_method == NULL) { desc->fill_method = new_fillmsg_decodermethod( desc, &desc->fill_method); } return desc->fill_method; } static const upb_json_parsermethod *msgdef_jsonparsermethod(Descriptor* desc) { if (desc->json_fill_method == NULL) { desc->json_fill_method = upb_json_parsermethod_new(desc->msgdef, &desc->json_fill_method); } return desc->json_fill_method; } // Stack-allocated context during an encode/decode operation. Contains the upb // environment and its stack-based allocator, an initial buffer for allocations // to avoid malloc() when possible, and a template for Ruby exception messages // if any error occurs. #define STACK_ENV_STACKBYTES 4096 typedef struct { upb_env env; const char* ruby_error_template; char allocbuf[STACK_ENV_STACKBYTES]; } stackenv; static void stackenv_init(stackenv* se, const char* errmsg); static void stackenv_uninit(stackenv* se); // Callback invoked by upb if any error occurs during parsing or serialization. static bool env_error_func(void* ud, const upb_status* status) { stackenv* se = ud; // Free the env -- rb_raise will longjmp up the stack past the encode/decode // function so it would not otherwise have been freed. stackenv_uninit(se); // TODO(haberman): have a way to verify that this is actually a parse error, // instead of just throwing "parse error" unconditionally. rb_raise(cParseError, se->ruby_error_template, upb_status_errmsg(status)); // Never reached: rb_raise() always longjmp()s up the stack, past all of our // code, back to Ruby. return false; } static void stackenv_init(stackenv* se, const char* errmsg) { se->ruby_error_template = errmsg; upb_env_init2(&se->env, se->allocbuf, sizeof(se->allocbuf), NULL); upb_env_seterrorfunc(&se->env, env_error_func, se); } static void stackenv_uninit(stackenv* se) { upb_env_uninit(&se->env); } /* * call-seq: * MessageClass.decode(data) => message * * Decodes the given data (as a string containing bytes in protocol buffers wire * format) under the interpretration given by this message class's definition * and returns a message object with the corresponding field values. */ VALUE Message_decode(VALUE klass, VALUE data) { VALUE descriptor = rb_ivar_get(klass, descriptor_instancevar_interned); Descriptor* desc = ruby_to_Descriptor(descriptor); VALUE msgklass = Descriptor_msgclass(descriptor); VALUE msg_rb; MessageHeader* msg; if (TYPE(data) != T_STRING) { rb_raise(rb_eArgError, "Expected string for binary protobuf data."); } msg_rb = rb_class_new_instance(0, NULL, msgklass); TypedData_Get_Struct(msg_rb, MessageHeader, &Message_type, msg); // We generally expect this to be clear already, but clear it in case parsing // previously got interrupted somehow. rb_ary_clear(map_parse_frames); { const upb_pbdecodermethod* method = msgdef_decodermethod(desc); const upb_handlers* h = upb_pbdecodermethod_desthandlers(method); stackenv se; upb_sink sink; upb_pbdecoder* decoder; stackenv_init(&se, "Error occurred during parsing: %s"); upb_sink_reset(&sink, h, msg); decoder = upb_pbdecoder_create(&se.env, method, &sink); upb_bufsrc_putbuf(RSTRING_PTR(data), RSTRING_LEN(data), upb_pbdecoder_input(decoder)); stackenv_uninit(&se); } return msg_rb; } /* * call-seq: * MessageClass.decode_json(data) => message * * Decodes the given data (as a string containing bytes in protocol buffers wire * format) under the interpretration given by this message class's definition * and returns a message object with the corresponding field values. */ VALUE Message_decode_json(VALUE klass, VALUE data) { VALUE descriptor = rb_ivar_get(klass, descriptor_instancevar_interned); Descriptor* desc = ruby_to_Descriptor(descriptor); VALUE msgklass = Descriptor_msgclass(descriptor); VALUE msg_rb; MessageHeader* msg; if (TYPE(data) != T_STRING) { rb_raise(rb_eArgError, "Expected string for JSON data."); } // TODO(cfallin): Check and respect string encoding. If not UTF-8, we need to // convert, because string handlers pass data directly to message string // fields. msg_rb = rb_class_new_instance(0, NULL, msgklass); TypedData_Get_Struct(msg_rb, MessageHeader, &Message_type, msg); // We generally expect this to be clear already, but clear it in case parsing // previously got interrupted somehow. rb_ary_clear(map_parse_frames); { const upb_json_parsermethod* method = msgdef_jsonparsermethod(desc); stackenv se; upb_sink sink; upb_json_parser* parser; stackenv_init(&se, "Error occurred during parsing: %s"); upb_sink_reset(&sink, get_fill_handlers(desc), msg); parser = upb_json_parser_create(&se.env, method, &sink); upb_bufsrc_putbuf(RSTRING_PTR(data), RSTRING_LEN(data), upb_json_parser_input(parser)); stackenv_uninit(&se); } return msg_rb; } // ----------------------------------------------------------------------------- // Serializing. // ----------------------------------------------------------------------------- // // The code below also comes from upb's prototype Ruby binding, developed by // haberman@. /* stringsink *****************************************************************/ // This should probably be factored into a common upb component. typedef struct { upb_byteshandler handler; upb_bytessink sink; char *ptr; size_t len, size; } stringsink; static void *stringsink_start(void *_sink, const void *hd, size_t size_hint) { stringsink *sink = _sink; sink->len = 0; return sink; } static size_t stringsink_string(void *_sink, const void *hd, const char *ptr, size_t len, const upb_bufhandle *handle) { stringsink *sink = _sink; size_t new_size = sink->size; UPB_UNUSED(hd); UPB_UNUSED(handle); while (sink->len + len > new_size) { new_size *= 2; } if (new_size != sink->size) { sink->ptr = realloc(sink->ptr, new_size); sink->size = new_size; } memcpy(sink->ptr + sink->len, ptr, len); sink->len += len; return len; } void stringsink_init(stringsink *sink) { upb_byteshandler_init(&sink->handler); upb_byteshandler_setstartstr(&sink->handler, stringsink_start, NULL); upb_byteshandler_setstring(&sink->handler, stringsink_string, NULL); upb_bytessink_reset(&sink->sink, &sink->handler, sink); sink->size = 32; sink->ptr = malloc(sink->size); sink->len = 0; } void stringsink_uninit(stringsink *sink) { free(sink->ptr); } /* msgvisitor *****************************************************************/ // TODO: If/when we support proto2 semantics in addition to the current proto3 // semantics, which means that we have true field presence, we will want to // modify msgvisitor so that it emits all present fields rather than all // non-default-value fields. // // Likewise, when implementing JSON serialization, we may need to have a // 'verbose' mode that outputs all fields and a 'concise' mode that outputs only // those with non-default values. static void putmsg(VALUE msg, const Descriptor* desc, upb_sink *sink, int depth); static upb_selector_t getsel(const upb_fielddef *f, upb_handlertype_t type) { upb_selector_t ret; bool ok = upb_handlers_getselector(f, type, &ret); UPB_ASSERT(ok); return ret; } static void putstr(VALUE str, const upb_fielddef *f, upb_sink *sink) { upb_sink subsink; if (str == Qnil) return; assert(BUILTIN_TYPE(str) == RUBY_T_STRING); // We should be guaranteed that the string has the correct encoding because // we ensured this at assignment time and then froze the string. if (upb_fielddef_type(f) == UPB_TYPE_STRING) { assert(rb_enc_from_index(ENCODING_GET(str)) == kRubyStringUtf8Encoding); } else { assert(rb_enc_from_index(ENCODING_GET(str)) == kRubyString8bitEncoding); } upb_sink_startstr(sink, getsel(f, UPB_HANDLER_STARTSTR), RSTRING_LEN(str), &subsink); upb_sink_putstring(&subsink, getsel(f, UPB_HANDLER_STRING), RSTRING_PTR(str), RSTRING_LEN(str), NULL); upb_sink_endstr(sink, getsel(f, UPB_HANDLER_ENDSTR)); } static void putsubmsg(VALUE submsg, const upb_fielddef *f, upb_sink *sink, int depth) { upb_sink subsink; VALUE descriptor; Descriptor* subdesc; if (submsg == Qnil) return; descriptor = rb_ivar_get(submsg, descriptor_instancevar_interned); subdesc = ruby_to_Descriptor(descriptor); upb_sink_startsubmsg(sink, getsel(f, UPB_HANDLER_STARTSUBMSG), &subsink); putmsg(submsg, subdesc, &subsink, depth + 1); upb_sink_endsubmsg(sink, getsel(f, UPB_HANDLER_ENDSUBMSG)); } static void putary(VALUE ary, const upb_fielddef *f, upb_sink *sink, int depth) { upb_sink subsink; upb_fieldtype_t type = upb_fielddef_type(f); upb_selector_t sel = 0; int size; if (ary == Qnil) return; upb_sink_startseq(sink, getsel(f, UPB_HANDLER_STARTSEQ), &subsink); if (upb_fielddef_isprimitive(f)) { sel = getsel(f, upb_handlers_getprimitivehandlertype(f)); } size = NUM2INT(RepeatedField_length(ary)); for (int i = 0; i < size; i++) { void* memory = RepeatedField_index_native(ary, i); switch (type) { #define T(upbtypeconst, upbtype, ctype) \ case upbtypeconst: \ upb_sink_put##upbtype(&subsink, sel, *((ctype *)memory)); \ break; T(UPB_TYPE_FLOAT, float, float) T(UPB_TYPE_DOUBLE, double, double) T(UPB_TYPE_BOOL, bool, int8_t) case UPB_TYPE_ENUM: T(UPB_TYPE_INT32, int32, int32_t) T(UPB_TYPE_UINT32, uint32, uint32_t) T(UPB_TYPE_INT64, int64, int64_t) T(UPB_TYPE_UINT64, uint64, uint64_t) case UPB_TYPE_STRING: case UPB_TYPE_BYTES: putstr(*((VALUE *)memory), f, &subsink); break; case UPB_TYPE_MESSAGE: putsubmsg(*((VALUE *)memory), f, &subsink, depth); break; #undef T } } upb_sink_endseq(sink, getsel(f, UPB_HANDLER_ENDSEQ)); } static void put_ruby_value(VALUE value, const upb_fielddef *f, VALUE type_class, int depth, upb_sink *sink) { upb_selector_t sel = 0; if (upb_fielddef_isprimitive(f)) { sel = getsel(f, upb_handlers_getprimitivehandlertype(f)); } switch (upb_fielddef_type(f)) { case UPB_TYPE_INT32: upb_sink_putint32(sink, sel, NUM2INT(value)); break; case UPB_TYPE_INT64: upb_sink_putint64(sink, sel, NUM2LL(value)); break; case UPB_TYPE_UINT32: upb_sink_putuint32(sink, sel, NUM2UINT(value)); break; case UPB_TYPE_UINT64: upb_sink_putuint64(sink, sel, NUM2ULL(value)); break; case UPB_TYPE_FLOAT: upb_sink_putfloat(sink, sel, NUM2DBL(value)); break; case UPB_TYPE_DOUBLE: upb_sink_putdouble(sink, sel, NUM2DBL(value)); break; case UPB_TYPE_ENUM: { if (TYPE(value) == T_SYMBOL) { value = rb_funcall(type_class, rb_intern("resolve"), 1, value); } upb_sink_putint32(sink, sel, NUM2INT(value)); break; } case UPB_TYPE_BOOL: upb_sink_putbool(sink, sel, value == Qtrue); break; case UPB_TYPE_STRING: case UPB_TYPE_BYTES: putstr(value, f, sink); break; case UPB_TYPE_MESSAGE: putsubmsg(value, f, sink, depth); } } static void putmap(VALUE map, const upb_fielddef *f, upb_sink *sink, int depth) { Map* self; upb_sink subsink; const upb_fielddef* key_field; const upb_fielddef* value_field; Map_iter it; if (map == Qnil) return; self = ruby_to_Map(map); upb_sink_startseq(sink, getsel(f, UPB_HANDLER_STARTSEQ), &subsink); assert(upb_fielddef_type(f) == UPB_TYPE_MESSAGE); key_field = map_field_key(f); value_field = map_field_value(f); for (Map_begin(map, &it); !Map_done(&it); Map_next(&it)) { VALUE key = Map_iter_key(&it); VALUE value = Map_iter_value(&it); upb_status status; upb_sink entry_sink; upb_sink_startsubmsg(&subsink, getsel(f, UPB_HANDLER_STARTSUBMSG), &entry_sink); upb_sink_startmsg(&entry_sink); put_ruby_value(key, key_field, Qnil, depth + 1, &entry_sink); put_ruby_value(value, value_field, self->value_type_class, depth + 1, &entry_sink); upb_sink_endmsg(&entry_sink, &status); upb_sink_endsubmsg(&subsink, getsel(f, UPB_HANDLER_ENDSUBMSG)); } upb_sink_endseq(sink, getsel(f, UPB_HANDLER_ENDSEQ)); } static void putmsg(VALUE msg_rb, const Descriptor* desc, upb_sink *sink, int depth) { MessageHeader* msg; upb_msg_field_iter i; upb_status status; upb_sink_startmsg(sink); // Protect against cycles (possible because users may freely reassign message // and repeated fields) by imposing a maximum recursion depth. if (depth > ENCODE_MAX_NESTING) { rb_raise(rb_eRuntimeError, "Maximum recursion depth exceeded during encoding."); } TypedData_Get_Struct(msg_rb, MessageHeader, &Message_type, msg); for (upb_msg_field_begin(&i, desc->msgdef); !upb_msg_field_done(&i); upb_msg_field_next(&i)) { upb_fielddef *f = upb_msg_iter_field(&i); bool is_matching_oneof = false; uint32_t offset = desc->layout->fields[upb_fielddef_index(f)].offset + sizeof(MessageHeader); if (upb_fielddef_containingoneof(f)) { uint32_t oneof_case_offset = desc->layout->fields[upb_fielddef_index(f)].case_offset + sizeof(MessageHeader); // For a oneof, check that this field is actually present -- skip all the // below if not. if (DEREF(msg, oneof_case_offset, uint32_t) != upb_fielddef_number(f)) { continue; } // Otherwise, fall through to the appropriate singular-field handler // below. is_matching_oneof = true; } if (is_map_field(f)) { VALUE map = DEREF(msg, offset, VALUE); if (map != Qnil) { putmap(map, f, sink, depth); } } else if (upb_fielddef_isseq(f)) { VALUE ary = DEREF(msg, offset, VALUE); if (ary != Qnil) { putary(ary, f, sink, depth); } } else if (upb_fielddef_isstring(f)) { VALUE str = DEREF(msg, offset, VALUE); if (is_matching_oneof || RSTRING_LEN(str) > 0) { putstr(str, f, sink); } } else if (upb_fielddef_issubmsg(f)) { putsubmsg(DEREF(msg, offset, VALUE), f, sink, depth); } else { upb_selector_t sel = getsel(f, upb_handlers_getprimitivehandlertype(f)); #define T(upbtypeconst, upbtype, ctype, default_value) \ case upbtypeconst: { \ ctype value = DEREF(msg, offset, ctype); \ if (is_matching_oneof || value != default_value) { \ upb_sink_put##upbtype(sink, sel, value); \ } \ } \ break; switch (upb_fielddef_type(f)) { T(UPB_TYPE_FLOAT, float, float, 0.0) T(UPB_TYPE_DOUBLE, double, double, 0.0) T(UPB_TYPE_BOOL, bool, uint8_t, 0) case UPB_TYPE_ENUM: T(UPB_TYPE_INT32, int32, int32_t, 0) T(UPB_TYPE_UINT32, uint32, uint32_t, 0) T(UPB_TYPE_INT64, int64, int64_t, 0) T(UPB_TYPE_UINT64, uint64, uint64_t, 0) case UPB_TYPE_STRING: case UPB_TYPE_BYTES: case UPB_TYPE_MESSAGE: rb_raise(rb_eRuntimeError, "Internal error."); } #undef T } } upb_sink_endmsg(sink, &status); } static const upb_handlers* msgdef_pb_serialize_handlers(Descriptor* desc) { if (desc->pb_serialize_handlers == NULL) { desc->pb_serialize_handlers = upb_pb_encoder_newhandlers(desc->msgdef, &desc->pb_serialize_handlers); } return desc->pb_serialize_handlers; } static const upb_handlers* msgdef_json_serialize_handlers( Descriptor* desc, bool preserve_proto_fieldnames) { if (preserve_proto_fieldnames) { if (desc->json_serialize_handlers == NULL) { desc->json_serialize_handlers = upb_json_printer_newhandlers( desc->msgdef, true, &desc->json_serialize_handlers); } return desc->json_serialize_handlers; } else { if (desc->json_serialize_handlers_preserve == NULL) { desc->json_serialize_handlers_preserve = upb_json_printer_newhandlers( desc->msgdef, false, &desc->json_serialize_handlers_preserve); } return desc->json_serialize_handlers_preserve; } } /* * call-seq: * MessageClass.encode(msg) => bytes * * Encodes the given message object to its serialized form in protocol buffers * wire format. */ VALUE Message_encode(VALUE klass, VALUE msg_rb) { VALUE descriptor = rb_ivar_get(klass, descriptor_instancevar_interned); Descriptor* desc = ruby_to_Descriptor(descriptor); stringsink sink; stringsink_init(&sink); { const upb_handlers* serialize_handlers = msgdef_pb_serialize_handlers(desc); stackenv se; upb_pb_encoder* encoder; VALUE ret; stackenv_init(&se, "Error occurred during encoding: %s"); encoder = upb_pb_encoder_create(&se.env, serialize_handlers, &sink.sink); putmsg(msg_rb, desc, upb_pb_encoder_input(encoder), 0); ret = rb_str_new(sink.ptr, sink.len); stackenv_uninit(&se); stringsink_uninit(&sink); return ret; } } /* * call-seq: * MessageClass.encode_json(msg) => json_string * * Encodes the given message object into its serialized JSON representation. */ VALUE Message_encode_json(int argc, VALUE* argv, VALUE klass) { VALUE descriptor = rb_ivar_get(klass, descriptor_instancevar_interned); Descriptor* desc = ruby_to_Descriptor(descriptor); VALUE msg_rb; VALUE preserve_proto_fieldnames = Qfalse; stringsink sink; if (argc < 1 || argc > 2) { rb_raise(rb_eArgError, "Expected 1 or 2 arguments."); } msg_rb = argv[0]; if (argc == 2) { VALUE hash_args = argv[1]; if (TYPE(hash_args) != T_HASH) { rb_raise(rb_eArgError, "Expected hash arguments."); } preserve_proto_fieldnames = rb_hash_lookup2( hash_args, ID2SYM(rb_intern("preserve_proto_fieldnames")), Qfalse); } stringsink_init(&sink); { const upb_handlers* serialize_handlers = msgdef_json_serialize_handlers(desc, RTEST(preserve_proto_fieldnames)); upb_json_printer* printer; stackenv se; VALUE ret; stackenv_init(&se, "Error occurred during encoding: %s"); printer = upb_json_printer_create(&se.env, serialize_handlers, &sink.sink); putmsg(msg_rb, desc, upb_json_printer_input(printer), 0); ret = rb_enc_str_new(sink.ptr, sink.len, rb_utf8_encoding()); stackenv_uninit(&se); stringsink_uninit(&sink); return ret; } } google-protobuf-3.2.0/ext/google/protobuf_c/repeated_field.c0000644000175000017500000005225413042756211023201 0ustar pravipravi// 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" // ----------------------------------------------------------------------------- // Repeated field container type. // ----------------------------------------------------------------------------- const rb_data_type_t RepeatedField_type = { "Google::Protobuf::RepeatedField", { RepeatedField_mark, RepeatedField_free, NULL }, }; VALUE cRepeatedField; RepeatedField* ruby_to_RepeatedField(VALUE _self) { RepeatedField* self; TypedData_Get_Struct(_self, RepeatedField, &RepeatedField_type, self); return self; } void* RepeatedField_memoryat(RepeatedField* self, int index, int element_size) { return ((uint8_t *)self->elements) + index * element_size; } static int index_position(VALUE _index, RepeatedField* repeated_field) { int index = NUM2INT(_index); if (index < 0 && repeated_field->size > 0) { index = repeated_field->size + index; } return index; } VALUE RepeatedField_subarray(VALUE _self, long beg, long len) { RepeatedField* self = ruby_to_RepeatedField(_self); int element_size = native_slot_size(self->field_type); upb_fieldtype_t field_type = self->field_type; VALUE field_type_class = self->field_type_class; size_t off = beg * element_size; VALUE ary = rb_ary_new2(len); for (int i = beg; i < beg + len; i++, off += element_size) { void* mem = ((uint8_t *)self->elements) + off; VALUE elem = native_slot_get(field_type, field_type_class, mem); 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. */ VALUE RepeatedField_each(VALUE _self) { RepeatedField* self = ruby_to_RepeatedField(_self); upb_fieldtype_t field_type = self->field_type; VALUE field_type_class = self->field_type_class; int element_size = native_slot_size(field_type); size_t off = 0; for (int i = 0; i < self->size; i++, off += element_size) { void* memory = (void *) (((uint8_t *)self->elements) + off); VALUE val = native_slot_get(field_type, field_type_class, memory); rb_yield(val); } return _self; } /* * call-seq: * RepeatedField.[](index) => value * * Accesses the element at the given index. Returns nil on out-of-bounds */ VALUE RepeatedField_index(int argc, VALUE* argv, VALUE _self) { RepeatedField* self = ruby_to_RepeatedField(_self); int element_size = native_slot_size(self->field_type); upb_fieldtype_t field_type = self->field_type; VALUE field_type_class = self->field_type_class; VALUE arg = argv[0]; long beg, len; if (argc == 1){ if (FIXNUM_P(arg)) { /* standard case */ void* memory; int index = index_position(argv[0], self); if (index < 0 || index >= self->size) { return Qnil; } memory = RepeatedField_memoryat(self, index, element_size); return native_slot_get(field_type, field_type_class, memory); }else{ /* check if idx is Range */ switch (rb_range_beg_len(arg, &beg, &len, self->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 += self->size; } if (beg >= self->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. */ VALUE RepeatedField_index_set(VALUE _self, VALUE _index, VALUE val) { RepeatedField* self = ruby_to_RepeatedField(_self); upb_fieldtype_t field_type = self->field_type; VALUE field_type_class = self->field_type_class; int element_size = native_slot_size(field_type); void* memory; int index = index_position(_index, self); if (index < 0 || index >= (INT_MAX - 1)) { return Qnil; } if (index >= self->size) { upb_fieldtype_t field_type = self->field_type; int element_size = native_slot_size(field_type); RepeatedField_reserve(self, index + 1); for (int i = self->size; i <= index; i++) { void* elem = RepeatedField_memoryat(self, i, element_size); native_slot_init(field_type, elem); } self->size = index + 1; } memory = RepeatedField_memoryat(self, index, element_size); native_slot_set(field_type, field_type_class, memory, val); return Qnil; } static int kInitialSize = 8; void RepeatedField_reserve(RepeatedField* self, int new_size) { void* old_elems = self->elements; int elem_size = native_slot_size(self->field_type); if (new_size <= self->capacity) { return; } if (self->capacity == 0) { self->capacity = kInitialSize; } while (self->capacity < new_size) { self->capacity *= 2; } self->elements = ALLOC_N(uint8_t, elem_size * self->capacity); if (old_elems != NULL) { memcpy(self->elements, old_elems, self->size * elem_size); xfree(old_elems); } } /* * call-seq: * RepeatedField.push(value) * * Adds a new element to the repeated field. */ VALUE RepeatedField_push(VALUE _self, VALUE val) { RepeatedField* self = ruby_to_RepeatedField(_self); upb_fieldtype_t field_type = self->field_type; int element_size = native_slot_size(field_type); void* memory; RepeatedField_reserve(self, self->size + 1); memory = (void *) (((uint8_t *)self->elements) + self->size * element_size); native_slot_set(field_type, self->field_type_class, memory, val); // native_slot_set may raise an error; bump size only after set. self->size++; return _self; } // Used by parsing handlers. void RepeatedField_push_native(VALUE _self, void* data) { RepeatedField* self = ruby_to_RepeatedField(_self); upb_fieldtype_t field_type = self->field_type; int element_size = native_slot_size(field_type); void* memory; RepeatedField_reserve(self, self->size + 1); memory = (void *) (((uint8_t *)self->elements) + self->size * element_size); memcpy(memory, data, element_size); self->size++; } void* RepeatedField_index_native(VALUE _self, int index) { RepeatedField* self = ruby_to_RepeatedField(_self); upb_fieldtype_t field_type = self->field_type; int element_size = native_slot_size(field_type); return RepeatedField_memoryat(self, index, element_size); } int RepeatedField_size(VALUE _self) { RepeatedField* self = ruby_to_RepeatedField(_self); return self->size; } /* * Private ruby method, used by RepeatedField.pop */ VALUE RepeatedField_pop_one(VALUE _self) { RepeatedField* self = ruby_to_RepeatedField(_self); upb_fieldtype_t field_type = self->field_type; VALUE field_type_class = self->field_type_class; int element_size = native_slot_size(field_type); int index; void* memory; VALUE ret; if (self->size == 0) { return Qnil; } index = self->size - 1; memory = RepeatedField_memoryat(self, index, element_size); ret = native_slot_get(field_type, field_type_class, memory); self->size--; return ret; } /* * call-seq: * RepeatedField.replace(list) * * Replaces the contents of the repeated field with the given list of elements. */ VALUE RepeatedField_replace(VALUE _self, VALUE list) { RepeatedField* self = ruby_to_RepeatedField(_self); Check_Type(list, T_ARRAY); self->size = 0; for (int 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. */ VALUE RepeatedField_clear(VALUE _self) { RepeatedField* self = ruby_to_RepeatedField(_self); self->size = 0; return _self; } /* * call-seq: * RepeatedField.length * * Returns the length of this repeated field. */ VALUE RepeatedField_length(VALUE _self) { RepeatedField* self = ruby_to_RepeatedField(_self); return INT2NUM(self->size); } static VALUE RepeatedField_new_this_type(VALUE _self) { RepeatedField* self = ruby_to_RepeatedField(_self); VALUE new_rptfield = Qnil; VALUE element_type = fieldtype_to_ruby(self->field_type); if (self->field_type_class != Qnil) { new_rptfield = rb_funcall(CLASS_OF(_self), rb_intern("new"), 2, element_type, self->field_type_class); } else { new_rptfield = rb_funcall(CLASS_OF(_self), rb_intern("new"), 1, element_type); } return new_rptfield; } /* * 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. */ 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_fieldtype_t field_type = self->field_type; size_t elem_size = native_slot_size(field_type); size_t off = 0; RepeatedField_reserve(new_rptfield_self, self->size); for (int i = 0; i < self->size; i++, off += elem_size) { void* to_mem = (uint8_t *)new_rptfield_self->elements + off; void* from_mem = (uint8_t *)self->elements + off; native_slot_dup(field_type, to_mem, from_mem); new_rptfield_self->size++; } return new_rptfield; } // Internal only: used by Google::Protobuf.deep_copy. VALUE RepeatedField_deep_copy(VALUE _self) { RepeatedField* self = ruby_to_RepeatedField(_self); VALUE new_rptfield = RepeatedField_new_this_type(_self); RepeatedField* new_rptfield_self = ruby_to_RepeatedField(new_rptfield); upb_fieldtype_t field_type = self->field_type; size_t elem_size = native_slot_size(field_type); size_t off = 0; RepeatedField_reserve(new_rptfield_self, self->size); for (int i = 0; i < self->size; i++, off += elem_size) { void* to_mem = (uint8_t *)new_rptfield_self->elements + off; void* from_mem = (uint8_t *)self->elements + off; native_slot_deep_copy(field_type, to_mem, from_mem); new_rptfield_self->size++; } 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); upb_fieldtype_t field_type = self->field_type; size_t elem_size = native_slot_size(field_type); size_t off = 0; VALUE ary = rb_ary_new2(self->size); for (int i = 0; i < self->size; i++, off += elem_size) { void* mem = ((uint8_t *)self->elements) + off; VALUE elem = native_slot_get(field_type, self->field_type_class, mem); rb_ary_push(ary, elem); } 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); if (self->field_type != other->field_type || self->field_type_class != other->field_type_class || self->size != other->size) { return Qfalse; } { upb_fieldtype_t field_type = self->field_type; size_t elem_size = native_slot_size(field_type); size_t off = 0; for (int i = 0; i < self->size; i++, off += elem_size) { void* self_mem = ((uint8_t *)self->elements) + off; void* other_mem = ((uint8_t *)other->elements) + off; if (!native_slot_eq(field_type, self_mem, other_mem)) { return Qfalse; } } return Qtrue; } } /* * 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); st_index_t h = rb_hash_start(0); VALUE hash_sym = rb_intern("hash"); upb_fieldtype_t field_type = self->field_type; VALUE field_type_class = self->field_type_class; size_t elem_size = native_slot_size(field_type); size_t off = 0; for (int i = 0; i < self->size; i++, off += elem_size) { void* mem = ((uint8_t *)self->elements) + off; VALUE elem = native_slot_get(field_type, field_type_class, mem); h = rb_hash_uint(h, NUM2LONG(rb_funcall(elem, hash_sym, 0))); } h = rb_hash_end(h); return INT2FIX(h); } /* * 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) { for (int 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); if (self->field_type != list_rptfield->field_type || self->field_type_class != list_rptfield->field_type_class) { rb_raise(rb_eArgError, "Attempt to append RepeatedField with different element type."); } for (int i = 0; i < list_rptfield->size; i++) { void* mem = RepeatedField_index_native(list, i); RepeatedField_push_native(dupped, mem); } } 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) { Check_Type(list, T_ARRAY); for (int i = 0; i < RARRAY_LEN(list); i++) { RepeatedField_push(_self, rb_ary_entry(list, i)); } return _self; } void validate_type_class(upb_fieldtype_t type, VALUE klass) { if (rb_ivar_get(klass, descriptor_instancevar_interned) == Qnil) { rb_raise(rb_eArgError, "Type class has no descriptor. Please pass a " "class or enum as returned by the DescriptorPool."); } if (type == UPB_TYPE_MESSAGE) { VALUE desc = rb_ivar_get(klass, descriptor_instancevar_interned); if (!RB_TYPE_P(desc, T_DATA) || !RTYPEDDATA_P(desc) || RTYPEDDATA_TYPE(desc) != &_Descriptor_type) { rb_raise(rb_eArgError, "Descriptor has an incorrect type."); } if (rb_get_alloc_func(klass) != &Message_alloc) { rb_raise(rb_eArgError, "Message class was not returned by the DescriptorPool."); } } else if (type == UPB_TYPE_ENUM) { VALUE enumdesc = rb_ivar_get(klass, descriptor_instancevar_interned); if (!RB_TYPE_P(enumdesc, T_DATA) || !RTYPEDDATA_P(enumdesc) || RTYPEDDATA_TYPE(enumdesc) != &_EnumDescriptor_type) { rb_raise(rb_eArgError, "Descriptor has an incorrect type."); } } } void RepeatedField_init_args(int argc, VALUE* argv, VALUE _self) { RepeatedField* self = ruby_to_RepeatedField(_self); VALUE ary = Qnil; if (argc < 1) { rb_raise(rb_eArgError, "Expected at least 1 argument."); } self->field_type = ruby_to_fieldtype(argv[0]); if (self->field_type == UPB_TYPE_MESSAGE || self->field_type == UPB_TYPE_ENUM) { if (argc < 2) { rb_raise(rb_eArgError, "Expected at least 2 arguments for message/enum."); } self->field_type_class = argv[1]; if (argc > 2) { ary = argv[2]; } validate_type_class(self->field_type, self->field_type_class); } else { if (argc > 2) { rb_raise(rb_eArgError, "Too many arguments: expected 1 or 2."); } if (argc > 1) { ary = argv[1]; } } 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)); } } } // Mark, free, alloc, init and class setup functions. void RepeatedField_mark(void* _self) { RepeatedField* self = (RepeatedField*)_self; upb_fieldtype_t field_type = self->field_type; int element_size = native_slot_size(field_type); rb_gc_mark(self->field_type_class); for (int i = 0; i < self->size; i++) { void* memory = (((uint8_t *)self->elements) + i * element_size); native_slot_mark(self->field_type, memory); } } void RepeatedField_free(void* _self) { RepeatedField* self = (RepeatedField*)_self; xfree(self->elements); xfree(self); } /* * call-seq: * RepeatedField.new(type, type_class = nil, initial_elems = []) * * Creates a new repeated field. The provided type must be a Ruby symbol, and * can take on the same values as those accepted by FieldDescriptor#type=. If * the type is :message or :enum, type_class must be non-nil, and must be the * Ruby class or module returned by Descriptor#msgclass or * EnumDescriptor#enummodule, respectively. An initial list of elements may also * be provided. */ VALUE RepeatedField_alloc(VALUE klass) { RepeatedField* self = ALLOC(RepeatedField); self->elements = NULL; self->size = 0; self->capacity = 0; self->field_type = -1; self->field_type_class = Qnil; return TypedData_Wrap_Struct(klass, &RepeatedField_type, self); } VALUE RepeatedField_init(int argc, VALUE* argv, VALUE self) { RepeatedField_init_args(argc, argv, self); return Qnil; } void RepeatedField_register(VALUE module) { VALUE klass = rb_define_class_under( module, "RepeatedField", rb_cObject); rb_define_alloc_func(klass, RepeatedField_alloc); cRepeatedField = klass; rb_gc_register_address(&cRepeatedField); 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, 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, "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); } google-protobuf-3.2.0/ext/google/protobuf_c/map.c0000644000175000017500000006121113042756211021013 0ustar pravipravi// 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" // ----------------------------------------------------------------------------- // Basic map operations on top of upb's strtable. // // Note that we roll our own `Map` container here because, as for // `RepeatedField`, we want a strongly-typed container. This is so that any user // errors due to incorrect map key or value types are raised as close as // possible to the error site, rather than at some deferred point (e.g., // serialization). // // We build our `Map` on top of upb_strtable so that we're able to take // advantage of the native_slot storage abstraction, as RepeatedField does. // (This is not quite a perfect mapping -- see the key conversions below -- but // gives us full support and error-checking for all value types for free.) // ----------------------------------------------------------------------------- // Map values are stored using the native_slot abstraction (as with repeated // field values), but keys are a bit special. Since we use a strtable, we need // to store keys as sequences of bytes such that equality of those bytes maps // one-to-one to equality of keys. We store strings directly (i.e., they map to // their own bytes) and integers as native integers (using the native_slot // abstraction). // Note that there is another tradeoff here in keeping string keys as native // strings rather than Ruby strings: traversing the Map requires conversion to // Ruby string values on every traversal, potentially creating more garbage. We // should consider ways to cache a Ruby version of the key if this becomes an // issue later. // Forms a key to use with the underlying strtable from a Ruby key value. |buf| // must point to TABLE_KEY_BUF_LENGTH bytes of temporary space, used to // construct a key byte sequence if needed. |out_key| and |out_length| provide // the resulting key data/length. #define TABLE_KEY_BUF_LENGTH 8 // sizeof(uint64_t) static VALUE table_key(Map* self, VALUE key, char* buf, const char** out_key, size_t* out_length) { switch (self->key_type) { case UPB_TYPE_BYTES: case UPB_TYPE_STRING: // Strings: use string content directly. Check_Type(key, T_STRING); key = native_slot_encode_and_freeze_string(self->key_type, key); *out_key = RSTRING_PTR(key); *out_length = RSTRING_LEN(key); break; case UPB_TYPE_BOOL: case UPB_TYPE_INT32: case UPB_TYPE_INT64: case UPB_TYPE_UINT32: case UPB_TYPE_UINT64: native_slot_set(self->key_type, Qnil, buf, key); *out_key = buf; *out_length = native_slot_size(self->key_type); break; default: // Map constructor should not allow a Map with another key type to be // constructed. assert(false); break; } return key; } static VALUE table_key_to_ruby(Map* self, const char* buf, size_t length) { switch (self->key_type) { case UPB_TYPE_BYTES: case UPB_TYPE_STRING: { VALUE ret = rb_str_new(buf, length); rb_enc_associate(ret, (self->key_type == UPB_TYPE_BYTES) ? kRubyString8bitEncoding : kRubyStringUtf8Encoding); return ret; } case UPB_TYPE_BOOL: case UPB_TYPE_INT32: case UPB_TYPE_INT64: case UPB_TYPE_UINT32: case UPB_TYPE_UINT64: return native_slot_get(self->key_type, Qnil, buf); default: assert(false); return Qnil; } } static void* value_memory(upb_value* v) { return (void*)(&v->val); } // ----------------------------------------------------------------------------- // Map container type. // ----------------------------------------------------------------------------- const rb_data_type_t Map_type = { "Google::Protobuf::Map", { Map_mark, Map_free, NULL }, }; VALUE cMap; Map* ruby_to_Map(VALUE _self) { Map* self; TypedData_Get_Struct(_self, Map, &Map_type, self); return self; } void Map_mark(void* _self) { Map* self = _self; rb_gc_mark(self->value_type_class); if (self->value_type == UPB_TYPE_STRING || self->value_type == UPB_TYPE_BYTES || self->value_type == UPB_TYPE_MESSAGE) { upb_strtable_iter it; for (upb_strtable_begin(&it, &self->table); !upb_strtable_done(&it); upb_strtable_next(&it)) { upb_value v = upb_strtable_iter_value(&it); void* mem = value_memory(&v); native_slot_mark(self->value_type, mem); } } } void Map_free(void* _self) { Map* self = _self; upb_strtable_uninit(&self->table); xfree(self); } VALUE Map_alloc(VALUE klass) { Map* self = ALLOC(Map); memset(self, 0, sizeof(Map)); self->value_type_class = Qnil; return TypedData_Wrap_Struct(klass, &Map_type, self); } static bool needs_typeclass(upb_fieldtype_t type) { switch (type) { case UPB_TYPE_MESSAGE: case UPB_TYPE_ENUM: return true; default: return false; } } /* * 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. */ VALUE Map_init(int argc, VALUE* argv, VALUE _self) { Map* self = ruby_to_Map(_self); int init_value_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 = ruby_to_fieldtype(argv[1]); // Check that the key type is an allowed type. switch (self->key_type) { case UPB_TYPE_INT32: case UPB_TYPE_INT64: case UPB_TYPE_UINT32: case UPB_TYPE_UINT64: case UPB_TYPE_BOOL: case UPB_TYPE_STRING: case UPB_TYPE_BYTES: // These are OK. break; default: rb_raise(rb_eArgError, "Invalid key type for map."); } init_value_arg = 2; if (needs_typeclass(self->value_type) && argc > 2) { self->value_type_class = argv[2]; validate_type_class(self->value_type, self->value_type_class); init_value_arg = 3; } // Table value type is always UINT64: this ensures enough space to store the // native_slot value. if (!upb_strtable_init(&self->table, UPB_CTYPE_UINT64)) { rb_raise(rb_eRuntimeError, "Could not allocate table."); } if (argc > init_value_arg) { Map_merge_into_self(_self, argv[init_value_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. */ VALUE Map_each(VALUE _self) { Map* self = ruby_to_Map(_self); upb_strtable_iter it; for (upb_strtable_begin(&it, &self->table); !upb_strtable_done(&it); upb_strtable_next(&it)) { VALUE key = table_key_to_ruby( self, upb_strtable_iter_key(&it), upb_strtable_iter_keylength(&it)); upb_value v = upb_strtable_iter_value(&it); void* mem = value_memory(&v); VALUE value = native_slot_get(self->value_type, self->value_type_class, mem); rb_yield_values(2, key, value); } return Qnil; } /* * call-seq: * Map.keys => [list_of_keys] * * Returns the list of keys contained in the map, in unspecified order. */ VALUE Map_keys(VALUE _self) { Map* self = ruby_to_Map(_self); VALUE ret = rb_ary_new(); upb_strtable_iter it; for (upb_strtable_begin(&it, &self->table); !upb_strtable_done(&it); upb_strtable_next(&it)) { VALUE key = table_key_to_ruby( self, upb_strtable_iter_key(&it), upb_strtable_iter_keylength(&it)); rb_ary_push(ret, key); } return ret; } /* * call-seq: * Map.values => [list_of_values] * * Returns the list of values contained in the map, in unspecified order. */ VALUE Map_values(VALUE _self) { Map* self = ruby_to_Map(_self); VALUE ret = rb_ary_new(); upb_strtable_iter it; for (upb_strtable_begin(&it, &self->table); !upb_strtable_done(&it); upb_strtable_next(&it)) { upb_value v = upb_strtable_iter_value(&it); void* mem = value_memory(&v); VALUE value = native_slot_get(self->value_type, self->value_type_class, mem); rb_ary_push(ret, value); } 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. */ VALUE Map_index(VALUE _self, VALUE key) { Map* self = ruby_to_Map(_self); char keybuf[TABLE_KEY_BUF_LENGTH]; const char* keyval = NULL; size_t length = 0; upb_value v; key = table_key(self, key, keybuf, &keyval, &length); if (upb_strtable_lookup2(&self->table, keyval, length, &v)) { void* mem = value_memory(&v); return native_slot_get(self->value_type, self->value_type_class, mem); } 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. */ VALUE Map_index_set(VALUE _self, VALUE key, VALUE value) { Map* self = ruby_to_Map(_self); char keybuf[TABLE_KEY_BUF_LENGTH]; const char* keyval = NULL; size_t length = 0; upb_value v; void* mem; key = table_key(self, key, keybuf, &keyval, &length); mem = value_memory(&v); native_slot_set(self->value_type, self->value_type_class, mem, value); // Replace any existing value by issuing a 'remove' operation first. upb_strtable_remove2(&self->table, keyval, length, NULL); if (!upb_strtable_insert2(&self->table, keyval, length, v)) { rb_raise(rb_eRuntimeError, "Could not insert into table"); } // Ruby hashmap's :[]= method also returns the inserted value. return value; } /* * 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. */ VALUE Map_has_key(VALUE _self, VALUE key) { Map* self = ruby_to_Map(_self); char keybuf[TABLE_KEY_BUF_LENGTH]; const char* keyval = NULL; size_t length = 0; key = table_key(self, key, keybuf, &keyval, &length); if (upb_strtable_lookup2(&self->table, keyval, length, NULL)) { 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. */ VALUE Map_delete(VALUE _self, VALUE key) { Map* self = ruby_to_Map(_self); char keybuf[TABLE_KEY_BUF_LENGTH]; const char* keyval = NULL; size_t length = 0; upb_value v; key = table_key(self, key, keybuf, &keyval, &length); if (upb_strtable_remove2(&self->table, keyval, length, &v)) { void* mem = value_memory(&v); return native_slot_get(self->value_type, self->value_type_class, mem); } else { return Qnil; } } /* * call-seq: * Map.clear * * Removes all entries from the map. */ VALUE Map_clear(VALUE _self) { Map* self = ruby_to_Map(_self); // Uninit and reinit the table -- this is faster than iterating and doing a // delete-lookup on each key. upb_strtable_uninit(&self->table); if (!upb_strtable_init(&self->table, UPB_CTYPE_INT64)) { rb_raise(rb_eRuntimeError, "Unable to re-initialize table"); } return Qnil; } /* * call-seq: * Map.length * * Returns the number of entries (key-value pairs) in the map. */ VALUE Map_length(VALUE _self) { Map* self = ruby_to_Map(_self); return ULL2NUM(upb_strtable_count(&self->table)); } static VALUE Map_new_this_type(VALUE _self) { Map* self = ruby_to_Map(_self); VALUE new_map = Qnil; VALUE key_type = fieldtype_to_ruby(self->key_type); VALUE value_type = fieldtype_to_ruby(self->value_type); if (self->value_type_class != Qnil) { new_map = rb_funcall(CLASS_OF(_self), rb_intern("new"), 3, key_type, value_type, self->value_type_class); } else { new_map = rb_funcall(CLASS_OF(_self), rb_intern("new"), 2, key_type, value_type); } return new_map; } /* * 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. */ VALUE Map_dup(VALUE _self) { Map* self = ruby_to_Map(_self); VALUE new_map = Map_new_this_type(_self); Map* new_self = ruby_to_Map(new_map); upb_strtable_iter it; for (upb_strtable_begin(&it, &self->table); !upb_strtable_done(&it); upb_strtable_next(&it)) { upb_value v = upb_strtable_iter_value(&it); void* mem = value_memory(&v); upb_value dup; void* dup_mem = value_memory(&dup); native_slot_dup(self->value_type, dup_mem, mem); if (!upb_strtable_insert2(&new_self->table, upb_strtable_iter_key(&it), upb_strtable_iter_keylength(&it), dup)) { rb_raise(rb_eRuntimeError, "Error inserting value into new table"); } } return new_map; } // Used by Google::Protobuf.deep_copy but not exposed directly. VALUE Map_deep_copy(VALUE _self) { Map* self = ruby_to_Map(_self); VALUE new_map = Map_new_this_type(_self); Map* new_self = ruby_to_Map(new_map); upb_strtable_iter it; for (upb_strtable_begin(&it, &self->table); !upb_strtable_done(&it); upb_strtable_next(&it)) { upb_value v = upb_strtable_iter_value(&it); void* mem = value_memory(&v); upb_value dup; void* dup_mem = value_memory(&dup); native_slot_deep_copy(self->value_type, dup_mem, mem); if (!upb_strtable_insert2(&new_self->table, upb_strtable_iter_key(&it), upb_strtable_iter_keylength(&it), dup)) { rb_raise(rb_eRuntimeError, "Error inserting value into new table"); } } return new_map; } /* * 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; upb_strtable_iter it; // Allow comparisons to Ruby hashmaps by converting to a temporary Map // instance. Slow, but workable. if (TYPE(_other) == T_HASH) { VALUE other_map = Map_new_this_type(_self); 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 != other->value_type || self->value_type_class != other->value_type_class) { return Qfalse; } if (upb_strtable_count(&self->table) != upb_strtable_count(&other->table)) { return Qfalse; } // For each member of self, check that an equal member exists at the same key // in other. for (upb_strtable_begin(&it, &self->table); !upb_strtable_done(&it); upb_strtable_next(&it)) { upb_value v = upb_strtable_iter_value(&it); void* mem = value_memory(&v); upb_value other_v; void* other_mem = value_memory(&other_v); if (!upb_strtable_lookup2(&other->table, upb_strtable_iter_key(&it), upb_strtable_iter_keylength(&it), &other_v)) { // Not present in other map. return Qfalse; } if (!native_slot_eq(self->value_type, mem, other_mem)) { // Present, but value not equal. return Qfalse; } } return Qtrue; } /* * 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); st_index_t h = rb_hash_start(0); VALUE hash_sym = rb_intern("hash"); upb_strtable_iter it; for (upb_strtable_begin(&it, &self->table); !upb_strtable_done(&it); upb_strtable_next(&it)) { VALUE key = table_key_to_ruby( self, upb_strtable_iter_key(&it), upb_strtable_iter_keylength(&it)); upb_value v = upb_strtable_iter_value(&it); void* mem = value_memory(&v); VALUE value = native_slot_get(self->value_type, self->value_type_class, mem); h = rb_hash_uint(h, NUM2LONG(rb_funcall(key, hash_sym, 0))); h = rb_hash_uint(h, NUM2LONG(rb_funcall(value, hash_sym, 0))); } return INT2FIX(h); } /* * 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); VALUE str = rb_str_new2("{"); bool first = true; VALUE inspect_sym = rb_intern("inspect"); upb_strtable_iter it; for (upb_strtable_begin(&it, &self->table); !upb_strtable_done(&it); upb_strtable_next(&it)) { VALUE key = table_key_to_ruby( self, upb_strtable_iter_key(&it), upb_strtable_iter_keylength(&it)); upb_value v = upb_strtable_iter_value(&it); void* mem = value_memory(&v); VALUE value = native_slot_get(self->value_type, self->value_type_class, mem); if (!first) { str = rb_str_cat2(str, ", "); } else { first = false; } str = rb_str_append(str, rb_funcall(key, inspect_sym, 0)); str = rb_str_cat2(str, "=>"); str = rb_str_append(str, rb_funcall(value, inspect_sym, 0)); } str = rb_str_cat2(str, "}"); return str; } /* * 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. */ VALUE Map_merge(VALUE _self, VALUE hashmap) { VALUE dupped = Map_dup(_self); return Map_merge_into_self(dupped, hashmap); } static int merge_into_self_callback(VALUE key, VALUE value, VALUE self) { Map_index_set(self, key, value); return ST_CONTINUE; } // Used only internally -- shared by #merge and #initialize. VALUE Map_merge_into_self(VALUE _self, VALUE hashmap) { if (TYPE(hashmap) == T_HASH) { rb_hash_foreach(hashmap, merge_into_self_callback, _self); } else if (RB_TYPE_P(hashmap, T_DATA) && RTYPEDDATA_P(hashmap) && RTYPEDDATA_TYPE(hashmap) == &Map_type) { Map* self = ruby_to_Map(_self); Map* other = ruby_to_Map(hashmap); upb_strtable_iter it; if (self->key_type != other->key_type || self->value_type != other->value_type || self->value_type_class != other->value_type_class) { rb_raise(rb_eArgError, "Attempt to merge Map with mismatching types"); } for (upb_strtable_begin(&it, &other->table); !upb_strtable_done(&it); upb_strtable_next(&it)) { // Replace any existing value by issuing a 'remove' operation first. upb_value v; upb_value oldv; upb_strtable_remove2(&self->table, upb_strtable_iter_key(&it), upb_strtable_iter_keylength(&it), &oldv); v = upb_strtable_iter_value(&it); upb_strtable_insert2(&self->table, upb_strtable_iter_key(&it), upb_strtable_iter_keylength(&it), v); } } else { rb_raise(rb_eArgError, "Unknown type merging into Map"); } return _self; } // Internal method: map iterator initialization (used for serialization). void Map_begin(VALUE _self, Map_iter* iter) { Map* self = ruby_to_Map(_self); iter->self = self; upb_strtable_begin(&iter->it, &self->table); } void Map_next(Map_iter* iter) { upb_strtable_next(&iter->it); } bool Map_done(Map_iter* iter) { return upb_strtable_done(&iter->it); } VALUE Map_iter_key(Map_iter* iter) { return table_key_to_ruby( iter->self, upb_strtable_iter_key(&iter->it), upb_strtable_iter_keylength(&iter->it)); } VALUE Map_iter_value(Map_iter* iter) { upb_value v = upb_strtable_iter_value(&iter->it); void* mem = value_memory(&v); return native_slot_get(iter->self->value_type, iter->self->value_type_class, mem); } void Map_register(VALUE module) { VALUE klass = rb_define_class_under(module, "Map", rb_cObject); rb_define_alloc_func(klass, Map_alloc); cMap = klass; rb_gc_register_address(&cMap); 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, "dup", Map_dup, 0); rb_define_method(klass, "==", Map_eq, 1); rb_define_method(klass, "hash", Map_hash, 0); rb_define_method(klass, "inspect", Map_inspect, 0); rb_define_method(klass, "merge", Map_merge, 1); rb_include_module(klass, rb_mEnumerable); } google-protobuf-3.2.0/ext/google/protobuf_c/storage.c0000644000175000017500000007356013042756211021714 0ustar pravipravi// 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 #include // ----------------------------------------------------------------------------- // Ruby <-> native slot management. // ----------------------------------------------------------------------------- #define DEREF(memory, type) *(type*)(memory) size_t native_slot_size(upb_fieldtype_t type) { switch (type) { case UPB_TYPE_FLOAT: return 4; case UPB_TYPE_DOUBLE: return 8; case UPB_TYPE_BOOL: return 1; case UPB_TYPE_STRING: return sizeof(VALUE); case UPB_TYPE_BYTES: return sizeof(VALUE); case UPB_TYPE_MESSAGE: return sizeof(VALUE); case UPB_TYPE_ENUM: return 4; case UPB_TYPE_INT32: return 4; case UPB_TYPE_INT64: return 8; case UPB_TYPE_UINT32: return 4; case UPB_TYPE_UINT64: return 8; default: return 0; } } static VALUE value_from_default(const upb_fielddef *field) { switch (upb_fielddef_type(field)) { case UPB_TYPE_FLOAT: return DBL2NUM(upb_fielddef_defaultfloat(field)); case UPB_TYPE_DOUBLE: return DBL2NUM(upb_fielddef_defaultdouble(field)); case UPB_TYPE_BOOL: return upb_fielddef_defaultbool(field) ? Qtrue : Qfalse; case UPB_TYPE_MESSAGE: return Qnil; case UPB_TYPE_ENUM: { const upb_enumdef *enumdef = upb_fielddef_enumsubdef(field); int32_t num = upb_fielddef_defaultint32(field); const char *label = upb_enumdef_iton(enumdef, num); if (label) { return ID2SYM(rb_intern(label)); } else { return INT2NUM(num); } } case UPB_TYPE_INT32: return INT2NUM(upb_fielddef_defaultint32(field)); case UPB_TYPE_INT64: return LL2NUM(upb_fielddef_defaultint64(field));; case UPB_TYPE_UINT32: return UINT2NUM(upb_fielddef_defaultuint32(field)); case UPB_TYPE_UINT64: return ULL2NUM(upb_fielddef_defaultuint64(field)); case UPB_TYPE_STRING: case UPB_TYPE_BYTES: { size_t size; const char *str = upb_fielddef_defaultstr(field, &size); return rb_str_new(str, size); } default: return Qnil; } } static bool is_ruby_num(VALUE value) { return (TYPE(value) == T_FLOAT || TYPE(value) == T_FIXNUM || TYPE(value) == T_BIGNUM); } void native_slot_check_int_range_precision(upb_fieldtype_t type, VALUE val) { if (!is_ruby_num(val)) { rb_raise(rb_eTypeError, "Expected number type for integral field."); } // 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."); } } if (type == UPB_TYPE_UINT32 || type == UPB_TYPE_UINT64) { if (NUM2DBL(val) < 0) { rb_raise(rb_eRangeError, "Assigning negative value to unsigned integer field."); } } } VALUE native_slot_encode_and_freeze_string(upb_fieldtype_t type, VALUE value) { rb_encoding* desired_encoding = (type == UPB_TYPE_STRING) ? kRubyStringUtf8Encoding : kRubyString8bitEncoding; VALUE desired_encoding_value = rb_enc_from_encoding(desired_encoding); // Note: this will not duplicate underlying string data unless necessary. value = rb_str_encode(value, desired_encoding_value, 0, Qnil); if (type == UPB_TYPE_STRING && rb_enc_str_coderange(value) == ENC_CODERANGE_BROKEN) { rb_raise(rb_eEncodingError, "String is invalid UTF-8"); } // Ensure the data remains valid. Since we called #encode a moment ago, // this does not freeze the string the user assigned. rb_obj_freeze(value); return value; } void native_slot_set(upb_fieldtype_t type, VALUE type_class, void* memory, VALUE value) { native_slot_set_value_and_case(type, type_class, memory, value, NULL, 0); } void native_slot_set_value_and_case(upb_fieldtype_t type, VALUE type_class, void* memory, VALUE value, uint32_t* case_memory, uint32_t case_number) { // Note that in order to atomically change the value in memory and the case // value (w.r.t. Ruby VM calls), we must set the value at |memory| only after // all Ruby VM calls are complete. The case is then set at the bottom of this // function. switch (type) { case UPB_TYPE_FLOAT: if (!is_ruby_num(value)) { rb_raise(rb_eTypeError, "Expected number type for float field."); } DEREF(memory, float) = NUM2DBL(value); break; case UPB_TYPE_DOUBLE: if (!is_ruby_num(value)) { rb_raise(rb_eTypeError, "Expected number type for double field."); } DEREF(memory, double) = NUM2DBL(value); break; case UPB_TYPE_BOOL: { int8_t val = -1; if (value == Qtrue) { val = 1; } else if (value == Qfalse) { val = 0; } else { rb_raise(rb_eTypeError, "Invalid argument for boolean field."); } DEREF(memory, int8_t) = val; break; } case UPB_TYPE_STRING: case UPB_TYPE_BYTES: { if (CLASS_OF(value) != rb_cString) { rb_raise(rb_eTypeError, "Invalid argument for string field."); } DEREF(memory, VALUE) = native_slot_encode_and_freeze_string(type, value); break; } case UPB_TYPE_MESSAGE: { if (CLASS_OF(value) == CLASS_OF(Qnil)) { value = Qnil; } else if (CLASS_OF(value) != type_class) { rb_raise(rb_eTypeError, "Invalid type %s to assign to submessage field.", rb_class2name(CLASS_OF(value))); } DEREF(memory, VALUE) = value; break; } case UPB_TYPE_ENUM: { int32_t int_val = 0; if (!is_ruby_num(value) && TYPE(value) != T_SYMBOL) { rb_raise(rb_eTypeError, "Expected number or symbol type for enum field."); } if (TYPE(value) == T_SYMBOL) { // Ensure that the given symbol exists in the enum module. VALUE lookup = rb_funcall(type_class, rb_intern("resolve"), 1, value); if (lookup == Qnil) { rb_raise(rb_eRangeError, "Unknown symbol value for enum field."); } else { int_val = NUM2INT(lookup); } } else { native_slot_check_int_range_precision(UPB_TYPE_INT32, value); int_val = NUM2INT(value); } DEREF(memory, int32_t) = int_val; break; } case UPB_TYPE_INT32: case UPB_TYPE_INT64: case UPB_TYPE_UINT32: case UPB_TYPE_UINT64: native_slot_check_int_range_precision(type, value); switch (type) { case UPB_TYPE_INT32: DEREF(memory, int32_t) = NUM2INT(value); break; case UPB_TYPE_INT64: DEREF(memory, int64_t) = NUM2LL(value); break; case UPB_TYPE_UINT32: DEREF(memory, uint32_t) = NUM2UINT(value); break; case UPB_TYPE_UINT64: DEREF(memory, uint64_t) = NUM2ULL(value); break; default: break; } break; default: break; } if (case_memory != NULL) { *case_memory = case_number; } } VALUE native_slot_get(upb_fieldtype_t type, VALUE type_class, const void* memory) { switch (type) { case UPB_TYPE_FLOAT: return DBL2NUM(DEREF(memory, float)); case UPB_TYPE_DOUBLE: return DBL2NUM(DEREF(memory, double)); case UPB_TYPE_BOOL: return DEREF(memory, int8_t) ? Qtrue : Qfalse; case UPB_TYPE_STRING: case UPB_TYPE_BYTES: case UPB_TYPE_MESSAGE: return DEREF(memory, VALUE); case UPB_TYPE_ENUM: { int32_t val = DEREF(memory, int32_t); VALUE symbol = enum_lookup(type_class, INT2NUM(val)); if (symbol == Qnil) { return INT2NUM(val); } else { return symbol; } } case UPB_TYPE_INT32: return INT2NUM(DEREF(memory, int32_t)); case UPB_TYPE_INT64: return LL2NUM(DEREF(memory, int64_t)); case UPB_TYPE_UINT32: return UINT2NUM(DEREF(memory, uint32_t)); case UPB_TYPE_UINT64: return ULL2NUM(DEREF(memory, uint64_t)); default: return Qnil; } } void native_slot_init(upb_fieldtype_t type, void* memory) { switch (type) { case UPB_TYPE_FLOAT: DEREF(memory, float) = 0.0; break; case UPB_TYPE_DOUBLE: DEREF(memory, double) = 0.0; break; case UPB_TYPE_BOOL: DEREF(memory, int8_t) = 0; break; case UPB_TYPE_STRING: case UPB_TYPE_BYTES: DEREF(memory, VALUE) = rb_str_new2(""); rb_enc_associate(DEREF(memory, VALUE), (type == UPB_TYPE_BYTES) ? kRubyString8bitEncoding : kRubyStringUtf8Encoding); break; case UPB_TYPE_MESSAGE: DEREF(memory, VALUE) = Qnil; break; case UPB_TYPE_ENUM: case UPB_TYPE_INT32: DEREF(memory, int32_t) = 0; break; case UPB_TYPE_INT64: DEREF(memory, int64_t) = 0; break; case UPB_TYPE_UINT32: DEREF(memory, uint32_t) = 0; break; case UPB_TYPE_UINT64: DEREF(memory, uint64_t) = 0; break; default: break; } } void native_slot_mark(upb_fieldtype_t type, void* memory) { switch (type) { case UPB_TYPE_STRING: case UPB_TYPE_BYTES: case UPB_TYPE_MESSAGE: rb_gc_mark(DEREF(memory, VALUE)); break; default: break; } } void native_slot_dup(upb_fieldtype_t type, void* to, void* from) { memcpy(to, from, native_slot_size(type)); } void native_slot_deep_copy(upb_fieldtype_t type, void* to, void* from) { switch (type) { case UPB_TYPE_STRING: case UPB_TYPE_BYTES: { VALUE from_val = DEREF(from, VALUE); DEREF(to, VALUE) = (from_val != Qnil) ? rb_funcall(from_val, rb_intern("dup"), 0) : Qnil; break; } case UPB_TYPE_MESSAGE: { VALUE from_val = DEREF(from, VALUE); DEREF(to, VALUE) = (from_val != Qnil) ? Message_deep_copy(from_val) : Qnil; break; } default: memcpy(to, from, native_slot_size(type)); } } bool native_slot_eq(upb_fieldtype_t type, void* mem1, void* mem2) { switch (type) { case UPB_TYPE_STRING: case UPB_TYPE_BYTES: case UPB_TYPE_MESSAGE: { VALUE val1 = DEREF(mem1, VALUE); VALUE val2 = DEREF(mem2, VALUE); VALUE ret = rb_funcall(val1, rb_intern("=="), 1, val2); return ret == Qtrue; } default: return !memcmp(mem1, mem2, native_slot_size(type)); } } // ----------------------------------------------------------------------------- // Map field utilities. // ----------------------------------------------------------------------------- const upb_msgdef* tryget_map_entry_msgdef(const upb_fielddef* field) { const upb_msgdef* subdef; if (upb_fielddef_label(field) != UPB_LABEL_REPEATED || upb_fielddef_type(field) != UPB_TYPE_MESSAGE) { return NULL; } subdef = upb_fielddef_msgsubdef(field); return upb_msgdef_mapentry(subdef) ? subdef : NULL; } const upb_msgdef *map_entry_msgdef(const upb_fielddef* field) { const upb_msgdef* subdef = tryget_map_entry_msgdef(field); assert(subdef); return subdef; } bool is_map_field(const upb_fielddef *field) { return tryget_map_entry_msgdef(field) != NULL; } const upb_fielddef* map_field_key(const upb_fielddef* field) { const upb_msgdef* subdef = map_entry_msgdef(field); return map_entry_key(subdef); } const upb_fielddef* map_field_value(const upb_fielddef* field) { const upb_msgdef* subdef = map_entry_msgdef(field); return map_entry_value(subdef); } const upb_fielddef* map_entry_key(const upb_msgdef* msgdef) { const upb_fielddef* key_field = upb_msgdef_itof(msgdef, MAP_KEY_FIELD); assert(key_field != NULL); return key_field; } const upb_fielddef* map_entry_value(const upb_msgdef* msgdef) { const upb_fielddef* value_field = upb_msgdef_itof(msgdef, MAP_VALUE_FIELD); assert(value_field != NULL); return value_field; } // ----------------------------------------------------------------------------- // Memory layout management. // ----------------------------------------------------------------------------- static size_t align_up_to(size_t offset, size_t granularity) { // Granularity must be a power of two. return (offset + granularity - 1) & ~(granularity - 1); } MessageLayout* create_layout(const upb_msgdef* msgdef) { MessageLayout* layout = ALLOC(MessageLayout); int nfields = upb_msgdef_numfields(msgdef); upb_msg_field_iter it; upb_msg_oneof_iter oit; size_t off = 0; layout->fields = ALLOC_N(MessageField, nfields); for (upb_msg_field_begin(&it, msgdef); !upb_msg_field_done(&it); upb_msg_field_next(&it)) { const upb_fielddef* field = upb_msg_iter_field(&it); size_t field_size; if (upb_fielddef_containingoneof(field)) { // Oneofs are handled separately below. continue; } // Allocate |field_size| bytes for this field in the layout. field_size = 0; if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) { field_size = sizeof(VALUE); } else { field_size = native_slot_size(upb_fielddef_type(field)); } // Align current offset up to |size| granularity. off = align_up_to(off, field_size); layout->fields[upb_fielddef_index(field)].offset = off; layout->fields[upb_fielddef_index(field)].case_offset = MESSAGE_FIELD_NO_CASE; off += field_size; } // Handle oneofs now -- we iterate over oneofs specifically and allocate only // one slot per oneof. // // We assign all value slots first, then pack the 'case' fields at the end, // since in the common case (modern 64-bit platform) these are 8 bytes and 4 // bytes respectively and we want to avoid alignment overhead. // // Note that we reserve 4 bytes (a uint32) per 'case' slot because the value // space for oneof cases is conceptually as wide as field tag numbers. In // practice, it's unlikely that a oneof would have more than e.g. 256 or 64K // members (8 or 16 bits respectively), so conceivably we could assign // consecutive case numbers and then pick a smaller oneof case slot size, but // the complexity to implement this indirection is probably not worthwhile. for (upb_msg_oneof_begin(&oit, msgdef); !upb_msg_oneof_done(&oit); upb_msg_oneof_next(&oit)) { const upb_oneofdef* oneof = upb_msg_iter_oneof(&oit); upb_oneof_iter fit; // Always allocate NATIVE_SLOT_MAX_SIZE bytes, but share the slot between // all fields. size_t field_size = NATIVE_SLOT_MAX_SIZE; // Align the offset. off = align_up_to(off, field_size); // Assign all fields in the oneof this same offset. for (upb_oneof_begin(&fit, oneof); !upb_oneof_done(&fit); upb_oneof_next(&fit)) { const upb_fielddef* field = upb_oneof_iter_field(&fit); layout->fields[upb_fielddef_index(field)].offset = off; } off += field_size; } // Now the case fields. for (upb_msg_oneof_begin(&oit, msgdef); !upb_msg_oneof_done(&oit); upb_msg_oneof_next(&oit)) { const upb_oneofdef* oneof = upb_msg_iter_oneof(&oit); upb_oneof_iter fit; size_t field_size = sizeof(uint32_t); // Align the offset. off = (off + field_size - 1) & ~(field_size - 1); // Assign all fields in the oneof this same offset. for (upb_oneof_begin(&fit, oneof); !upb_oneof_done(&fit); upb_oneof_next(&fit)) { const upb_fielddef* field = upb_oneof_iter_field(&fit); layout->fields[upb_fielddef_index(field)].case_offset = off; } off += field_size; } layout->size = off; layout->msgdef = msgdef; upb_msgdef_ref(layout->msgdef, &layout->msgdef); return layout; } void free_layout(MessageLayout* layout) { xfree(layout->fields); upb_msgdef_unref(layout->msgdef, &layout->msgdef); xfree(layout); } VALUE field_type_class(const upb_fielddef* field) { VALUE type_class = Qnil; if (upb_fielddef_type(field) == UPB_TYPE_MESSAGE) { VALUE submsgdesc = get_def_obj(upb_fielddef_subdef(field)); type_class = Descriptor_msgclass(submsgdesc); } else if (upb_fielddef_type(field) == UPB_TYPE_ENUM) { VALUE subenumdesc = get_def_obj(upb_fielddef_subdef(field)); type_class = EnumDescriptor_enummodule(subenumdesc); } return type_class; } static void* slot_memory(MessageLayout* layout, const void* storage, const upb_fielddef* field) { return ((uint8_t *)storage) + layout->fields[upb_fielddef_index(field)].offset; } static uint32_t* slot_oneof_case(MessageLayout* layout, const void* storage, const upb_fielddef* field) { return (uint32_t *)(((uint8_t *)storage) + layout->fields[upb_fielddef_index(field)].case_offset); } VALUE layout_get(MessageLayout* layout, const void* storage, const upb_fielddef* field) { void* memory = slot_memory(layout, storage, field); uint32_t* oneof_case = slot_oneof_case(layout, storage, field); if (upb_fielddef_containingoneof(field)) { if (*oneof_case != upb_fielddef_number(field)) { return value_from_default(field); } return native_slot_get(upb_fielddef_type(field), field_type_class(field), memory); } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) { return *((VALUE *)memory); } else { return native_slot_get(upb_fielddef_type(field), field_type_class(field), memory); } } static void check_repeated_field_type(VALUE val, const upb_fielddef* field) { RepeatedField* self; assert(upb_fielddef_label(field) == UPB_LABEL_REPEATED); if (!RB_TYPE_P(val, T_DATA) || !RTYPEDDATA_P(val) || RTYPEDDATA_TYPE(val) != &RepeatedField_type) { rb_raise(rb_eTypeError, "Expected repeated field array"); } self = ruby_to_RepeatedField(val); if (self->field_type != upb_fielddef_type(field)) { rb_raise(rb_eTypeError, "Repeated field array has wrong element type"); } if (self->field_type == UPB_TYPE_MESSAGE || self->field_type == UPB_TYPE_ENUM) { if (self->field_type_class != get_def_obj(upb_fielddef_subdef(field))) { rb_raise(rb_eTypeError, "Repeated field array has wrong message/enum class"); } } } static void check_map_field_type(VALUE val, const upb_fielddef* field) { const upb_fielddef* key_field = map_field_key(field); const upb_fielddef* value_field = map_field_value(field); Map* self; if (!RB_TYPE_P(val, T_DATA) || !RTYPEDDATA_P(val) || RTYPEDDATA_TYPE(val) != &Map_type) { rb_raise(rb_eTypeError, "Expected Map instance"); } self = ruby_to_Map(val); if (self->key_type != upb_fielddef_type(key_field)) { rb_raise(rb_eTypeError, "Map key type does not match field's key type"); } if (self->value_type != upb_fielddef_type(value_field)) { rb_raise(rb_eTypeError, "Map value type does not match field's value type"); } if (upb_fielddef_type(value_field) == UPB_TYPE_MESSAGE || upb_fielddef_type(value_field) == UPB_TYPE_ENUM) { if (self->value_type_class != get_def_obj(upb_fielddef_subdef(value_field))) { rb_raise(rb_eTypeError, "Map value type has wrong message/enum class"); } } } void layout_set(MessageLayout* layout, void* storage, const upb_fielddef* field, VALUE val) { void* memory = slot_memory(layout, storage, field); uint32_t* oneof_case = slot_oneof_case(layout, storage, field); if (upb_fielddef_containingoneof(field)) { if (val == Qnil) { // Assigning nil to a oneof field clears the oneof completely. *oneof_case = ONEOF_CASE_NONE; memset(memory, 0, NATIVE_SLOT_MAX_SIZE); } else { // The transition between field types for a single oneof (union) slot is // somewhat complex because we need to ensure that a GC triggered at any // point by a call into the Ruby VM sees a valid state for this field and // does not either go off into the weeds (following what it thinks is a // VALUE but is actually a different field type) or miss an object (seeing // what it thinks is a primitive field but is actually a VALUE for the new // field type). // // In order for the transition to be safe, the oneof case slot must be in // sync with the value slot whenever the Ruby VM has been called. Thus, we // use native_slot_set_value_and_case(), which ensures that both the value // and case number are altered atomically (w.r.t. the Ruby VM). native_slot_set_value_and_case( upb_fielddef_type(field), field_type_class(field), memory, val, oneof_case, upb_fielddef_number(field)); } } else if (is_map_field(field)) { check_map_field_type(val, field); DEREF(memory, VALUE) = val; } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) { check_repeated_field_type(val, field); DEREF(memory, VALUE) = val; } else { native_slot_set(upb_fielddef_type(field), field_type_class(field), memory, val); } } void layout_init(MessageLayout* layout, void* storage) { upb_msg_field_iter it; for (upb_msg_field_begin(&it, layout->msgdef); !upb_msg_field_done(&it); upb_msg_field_next(&it)) { const upb_fielddef* field = upb_msg_iter_field(&it); void* memory = slot_memory(layout, storage, field); uint32_t* oneof_case = slot_oneof_case(layout, storage, field); if (upb_fielddef_containingoneof(field)) { memset(memory, 0, NATIVE_SLOT_MAX_SIZE); *oneof_case = ONEOF_CASE_NONE; } else if (is_map_field(field)) { VALUE map = Qnil; const upb_fielddef* key_field = map_field_key(field); const upb_fielddef* value_field = map_field_value(field); VALUE type_class = field_type_class(value_field); if (type_class != Qnil) { VALUE args[3] = { fieldtype_to_ruby(upb_fielddef_type(key_field)), fieldtype_to_ruby(upb_fielddef_type(value_field)), type_class, }; map = rb_class_new_instance(3, args, cMap); } else { VALUE args[2] = { fieldtype_to_ruby(upb_fielddef_type(key_field)), fieldtype_to_ruby(upb_fielddef_type(value_field)), }; map = rb_class_new_instance(2, args, cMap); } DEREF(memory, VALUE) = map; } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) { VALUE ary = Qnil; VALUE type_class = field_type_class(field); if (type_class != Qnil) { VALUE args[2] = { fieldtype_to_ruby(upb_fielddef_type(field)), type_class, }; ary = rb_class_new_instance(2, args, cRepeatedField); } else { VALUE args[1] = { fieldtype_to_ruby(upb_fielddef_type(field)) }; ary = rb_class_new_instance(1, args, cRepeatedField); } DEREF(memory, VALUE) = ary; } else { native_slot_init(upb_fielddef_type(field), memory); } } } void layout_mark(MessageLayout* layout, void* storage) { upb_msg_field_iter it; for (upb_msg_field_begin(&it, layout->msgdef); !upb_msg_field_done(&it); upb_msg_field_next(&it)) { const upb_fielddef* field = upb_msg_iter_field(&it); void* memory = slot_memory(layout, storage, field); uint32_t* oneof_case = slot_oneof_case(layout, storage, field); if (upb_fielddef_containingoneof(field)) { if (*oneof_case == upb_fielddef_number(field)) { native_slot_mark(upb_fielddef_type(field), memory); } } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) { rb_gc_mark(DEREF(memory, VALUE)); } else { native_slot_mark(upb_fielddef_type(field), memory); } } } void layout_dup(MessageLayout* layout, void* to, void* from) { upb_msg_field_iter it; for (upb_msg_field_begin(&it, layout->msgdef); !upb_msg_field_done(&it); upb_msg_field_next(&it)) { const upb_fielddef* field = upb_msg_iter_field(&it); void* to_memory = slot_memory(layout, to, field); uint32_t* to_oneof_case = slot_oneof_case(layout, to, field); void* from_memory = slot_memory(layout, from, field); uint32_t* from_oneof_case = slot_oneof_case(layout, from, field); if (upb_fielddef_containingoneof(field)) { if (*from_oneof_case == upb_fielddef_number(field)) { *to_oneof_case = *from_oneof_case; native_slot_dup(upb_fielddef_type(field), to_memory, from_memory); } } else if (is_map_field(field)) { DEREF(to_memory, VALUE) = Map_dup(DEREF(from_memory, VALUE)); } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) { DEREF(to_memory, VALUE) = RepeatedField_dup(DEREF(from_memory, VALUE)); } else { native_slot_dup(upb_fielddef_type(field), to_memory, from_memory); } } } void layout_deep_copy(MessageLayout* layout, void* to, void* from) { upb_msg_field_iter it; for (upb_msg_field_begin(&it, layout->msgdef); !upb_msg_field_done(&it); upb_msg_field_next(&it)) { const upb_fielddef* field = upb_msg_iter_field(&it); void* to_memory = slot_memory(layout, to, field); uint32_t* to_oneof_case = slot_oneof_case(layout, to, field); void* from_memory = slot_memory(layout, from, field); uint32_t* from_oneof_case = slot_oneof_case(layout, from, field); if (upb_fielddef_containingoneof(field)) { if (*from_oneof_case == upb_fielddef_number(field)) { *to_oneof_case = *from_oneof_case; native_slot_deep_copy(upb_fielddef_type(field), to_memory, from_memory); } } else if (is_map_field(field)) { DEREF(to_memory, VALUE) = Map_deep_copy(DEREF(from_memory, VALUE)); } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) { DEREF(to_memory, VALUE) = RepeatedField_deep_copy(DEREF(from_memory, VALUE)); } else { native_slot_deep_copy(upb_fielddef_type(field), to_memory, from_memory); } } } VALUE layout_eq(MessageLayout* layout, void* msg1, void* msg2) { upb_msg_field_iter it; for (upb_msg_field_begin(&it, layout->msgdef); !upb_msg_field_done(&it); upb_msg_field_next(&it)) { const upb_fielddef* field = upb_msg_iter_field(&it); void* msg1_memory = slot_memory(layout, msg1, field); uint32_t* msg1_oneof_case = slot_oneof_case(layout, msg1, field); void* msg2_memory = slot_memory(layout, msg2, field); uint32_t* msg2_oneof_case = slot_oneof_case(layout, msg2, field); if (upb_fielddef_containingoneof(field)) { if (*msg1_oneof_case != *msg2_oneof_case || (*msg1_oneof_case == upb_fielddef_number(field) && !native_slot_eq(upb_fielddef_type(field), msg1_memory, msg2_memory))) { return Qfalse; } } else if (is_map_field(field)) { if (!Map_eq(DEREF(msg1_memory, VALUE), DEREF(msg2_memory, VALUE))) { return Qfalse; } } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) { if (!RepeatedField_eq(DEREF(msg1_memory, VALUE), DEREF(msg2_memory, VALUE))) { return Qfalse; } } else { if (!native_slot_eq(upb_fielddef_type(field), msg1_memory, msg2_memory)) { return Qfalse; } } } return Qtrue; } VALUE layout_hash(MessageLayout* layout, void* storage) { upb_msg_field_iter it; st_index_t h = rb_hash_start(0); VALUE hash_sym = rb_intern("hash"); for (upb_msg_field_begin(&it, layout->msgdef); !upb_msg_field_done(&it); upb_msg_field_next(&it)) { const upb_fielddef* field = upb_msg_iter_field(&it); VALUE field_val = layout_get(layout, storage, field); h = rb_hash_uint(h, NUM2LONG(rb_funcall(field_val, hash_sym, 0))); } h = rb_hash_end(h); return INT2FIX(h); } VALUE layout_inspect(MessageLayout* layout, void* storage) { VALUE str = rb_str_new2(""); upb_msg_field_iter it; bool first = true; for (upb_msg_field_begin(&it, layout->msgdef); !upb_msg_field_done(&it); upb_msg_field_next(&it)) { const upb_fielddef* field = upb_msg_iter_field(&it); VALUE field_val = layout_get(layout, storage, field); if (!first) { str = rb_str_cat2(str, ", "); } else { first = false; } str = rb_str_cat2(str, upb_fielddef_name(field)); str = rb_str_cat2(str, ": "); str = rb_str_append(str, rb_funcall(field_val, rb_intern("inspect"), 0)); } return str; } google-protobuf-3.2.0/ext/google/protobuf_c/upb.h0000644000175000017500000122624713042777744021064 0ustar pravipravi// Amalgamated source file /* ** Defs are upb's internal representation of the constructs that can appear ** in a .proto file: ** ** - upb::MessageDef (upb_msgdef): describes a "message" construct. ** - upb::FieldDef (upb_fielddef): describes a message field. ** - upb::FileDef (upb_filedef): describes a .proto file and its defs. ** - upb::EnumDef (upb_enumdef): describes an enum. ** - upb::OneofDef (upb_oneofdef): describes a oneof. ** - upb::Def (upb_def): base class of all the others. ** ** TODO: definitions of services. ** ** Like upb_refcounted objects, defs are mutable only until frozen, and are ** only thread-safe once frozen. ** ** This is a mixed C/C++ interface that offers a full API to both languages. ** See the top-level README for more information. */ #ifndef UPB_DEF_H_ #define UPB_DEF_H_ /* ** upb::RefCounted (upb_refcounted) ** ** A refcounting scheme that supports circular refs. It accomplishes this by ** partitioning the set of objects into groups such that no cycle spans groups; ** we can then reference-count the group as a whole and ignore refs within the ** group. When objects are mutable, these groups are computed very ** conservatively; we group any objects that have ever had a link between them. ** When objects are frozen, we compute strongly-connected components which ** allows us to be precise and only group objects that are actually cyclic. ** ** This is a mixed C/C++ interface that offers a full API to both languages. ** See the top-level README for more information. */ #ifndef UPB_REFCOUNTED_H_ #define UPB_REFCOUNTED_H_ /* ** upb_table ** ** This header is INTERNAL-ONLY! Its interfaces are not public or stable! ** This file defines very fast int->upb_value (inttable) and string->upb_value ** (strtable) hash tables. ** ** The table uses chained scatter with Brent's variation (inspired by the Lua ** implementation of hash tables). The hash function for strings is Austin ** Appleby's "MurmurHash." ** ** The inttable uses uintptr_t as its key, which guarantees it can be used to ** store pointers or integers of at least 32 bits (upb isn't really useful on ** systems where sizeof(void*) < 4). ** ** The table must be homogenous (all values of the same type). In debug ** mode, we check this on insert and lookup. */ #ifndef UPB_TABLE_H_ #define UPB_TABLE_H_ #include #include /* ** This file contains shared definitions that are widely used across upb. ** ** This is a mixed C/C++ interface that offers a full API to both languages. ** See the top-level README for more information. */ #ifndef UPB_H_ #define UPB_H_ #include #include #include #include #ifdef __cplusplus namespace upb { class Allocator; class Arena; class Environment; class ErrorSpace; class Status; template class InlinedArena; template class InlinedEnvironment; } #endif /* UPB_INLINE: inline if possible, emit standalone code if required. */ #ifdef __cplusplus #define UPB_INLINE inline #elif defined (__GNUC__) #define UPB_INLINE static __inline__ #else #define UPB_INLINE static #endif /* Define UPB_BIG_ENDIAN manually if you're on big endian and your compiler * doesn't provide these preprocessor symbols. */ #if defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) #define UPB_BIG_ENDIAN #endif /* Macros for function attributes on compilers that support them. */ #ifdef __GNUC__ #define UPB_FORCEINLINE __inline__ __attribute__((always_inline)) #define UPB_NOINLINE __attribute__((noinline)) #define UPB_NORETURN __attribute__((__noreturn__)) #else /* !defined(__GNUC__) */ #define UPB_FORCEINLINE #define UPB_NOINLINE #define UPB_NORETURN #endif #if __STDC_VERSION__ >= 199901L || __cplusplus >= 201103L /* C99/C++11 versions. */ #include #define _upb_snprintf snprintf #define _upb_vsnprintf vsnprintf #define _upb_va_copy(a, b) va_copy(a, b) #elif defined __GNUC__ /* A few hacky workarounds for functions not in C89. * For internal use only! * TODO(haberman): fix these by including our own implementations, or finding * another workaround. */ #define _upb_snprintf __builtin_snprintf #define _upb_vsnprintf __builtin_vsnprintf #define _upb_va_copy(a, b) __va_copy(a, b) #else #error Need implementations of [v]snprintf and va_copy #endif #if ((defined(__cplusplus) && __cplusplus >= 201103L) || \ defined(__GXX_EXPERIMENTAL_CXX0X__)) && !defined(UPB_NO_CXX11) #define UPB_CXX11 #endif /* UPB_DISALLOW_COPY_AND_ASSIGN() * UPB_DISALLOW_POD_OPS() * * Declare these in the "private" section of a C++ class to forbid copy/assign * or all POD ops (construct, destruct, copy, assign) on that class. */ #ifdef UPB_CXX11 #include #define UPB_DISALLOW_COPY_AND_ASSIGN(class_name) \ class_name(const class_name&) = delete; \ void operator=(const class_name&) = delete; #define UPB_DISALLOW_POD_OPS(class_name, full_class_name) \ class_name() = delete; \ ~class_name() = delete; \ UPB_DISALLOW_COPY_AND_ASSIGN(class_name) #define UPB_ASSERT_STDLAYOUT(type) \ static_assert(std::is_standard_layout::value, \ #type " must be standard layout"); #define UPB_FINAL final #else /* !defined(UPB_CXX11) */ #define UPB_DISALLOW_COPY_AND_ASSIGN(class_name) \ class_name(const class_name&); \ void operator=(const class_name&); #define UPB_DISALLOW_POD_OPS(class_name, full_class_name) \ class_name(); \ ~class_name(); \ UPB_DISALLOW_COPY_AND_ASSIGN(class_name) #define UPB_ASSERT_STDLAYOUT(type) #define UPB_FINAL #endif /* UPB_DECLARE_TYPE() * UPB_DECLARE_DERIVED_TYPE() * UPB_DECLARE_DERIVED_TYPE2() * * Macros for declaring C and C++ types both, including inheritance. * The inheritance doesn't use real C++ inheritance, to stay compatible with C. * * These macros also provide upcasts: * - in C: types-specific functions (ie. upb_foo_upcast(foo)) * - in C++: upb::upcast(foo) along with implicit conversions * * Downcasts are not provided, but upb/def.h defines downcasts for upb::Def. */ #define UPB_C_UPCASTS(ty, base) \ UPB_INLINE base *ty ## _upcast_mutable(ty *p) { return (base*)p; } \ UPB_INLINE const base *ty ## _upcast(const ty *p) { return (const base*)p; } #define UPB_C_UPCASTS2(ty, base, base2) \ UPB_C_UPCASTS(ty, base) \ UPB_INLINE base2 *ty ## _upcast2_mutable(ty *p) { return (base2*)p; } \ UPB_INLINE const base2 *ty ## _upcast2(const ty *p) { return (const base2*)p; } #ifdef __cplusplus #define UPB_BEGIN_EXTERN_C extern "C" { #define UPB_END_EXTERN_C } #define UPB_PRIVATE_FOR_CPP private: #define UPB_DECLARE_TYPE(cppname, cname) typedef cppname cname; #define UPB_DECLARE_DERIVED_TYPE(cppname, cppbase, cname, cbase) \ UPB_DECLARE_TYPE(cppname, cname) \ UPB_C_UPCASTS(cname, cbase) \ namespace upb { \ template <> \ class Pointer : public PointerBase { \ public: \ explicit Pointer(cppname* ptr) \ : PointerBase(ptr) {} \ }; \ template <> \ class Pointer \ : public PointerBase { \ public: \ explicit Pointer(const cppname* ptr) \ : PointerBase(ptr) {} \ }; \ } #define UPB_DECLARE_DERIVED_TYPE2(cppname, cppbase, cppbase2, cname, cbase, \ cbase2) \ UPB_DECLARE_TYPE(cppname, cname) \ UPB_C_UPCASTS2(cname, cbase, cbase2) \ namespace upb { \ template <> \ class Pointer : public PointerBase2 { \ public: \ explicit Pointer(cppname* ptr) \ : PointerBase2(ptr) {} \ }; \ template <> \ class Pointer \ : public PointerBase2 { \ public: \ explicit Pointer(const cppname* ptr) \ : PointerBase2(ptr) {} \ }; \ } #else /* !defined(__cplusplus) */ #define UPB_BEGIN_EXTERN_C #define UPB_END_EXTERN_C #define UPB_PRIVATE_FOR_CPP #define UPB_DECLARE_TYPE(cppname, cname) \ struct cname; \ typedef struct cname cname; #define UPB_DECLARE_DERIVED_TYPE(cppname, cppbase, cname, cbase) \ UPB_DECLARE_TYPE(cppname, cname) \ UPB_C_UPCASTS(cname, cbase) #define UPB_DECLARE_DERIVED_TYPE2(cppname, cppbase, cppbase2, \ cname, cbase, cbase2) \ UPB_DECLARE_TYPE(cppname, cname) \ UPB_C_UPCASTS2(cname, cbase, cbase2) #endif /* defined(__cplusplus) */ #define UPB_MAX(x, y) ((x) > (y) ? (x) : (y)) #define UPB_MIN(x, y) ((x) < (y) ? (x) : (y)) #define UPB_UNUSED(var) (void)var /* UPB_ASSERT(): in release mode, we use the expression without letting it be * evaluated. This prevents "unused variable" warnings. */ #ifdef NDEBUG #define UPB_ASSERT(expr) do {} while (false && (expr)) #else #define UPB_ASSERT(expr) assert(expr) #endif /* UPB_ASSERT_DEBUGVAR(): assert that uses functions or variables that only * exist in debug mode. This turns into regular assert. */ #define UPB_ASSERT_DEBUGVAR(expr) assert(expr) #ifdef __GNUC__ #define UPB_UNREACHABLE() do { assert(0); __builtin_unreachable(); } while(0) #else #define UPB_UNREACHABLE() do { assert(0); } while(0) #endif /* Generic function type. */ typedef void upb_func(); /* C++ Casts ******************************************************************/ #ifdef __cplusplus namespace upb { template class Pointer; /* Casts to a subclass. The caller must know that cast is correct; an * incorrect cast will throw an assertion failure in debug mode. * * Example: * upb::Def* def = GetDef(); * // Assert-fails if this was not actually a MessageDef. * upb::MessgeDef* md = upb::down_cast(def); * * Note that downcasts are only defined for some types (at the moment you can * only downcast from a upb::Def to a specific Def type). */ template To down_cast(From* f); /* Casts to a subclass. If the class does not actually match the given To type, * returns NULL. * * Example: * upb::Def* def = GetDef(); * // md will be NULL if this was not actually a MessageDef. * upb::MessgeDef* md = upb::down_cast(def); * * Note that dynamic casts are only defined for some types (at the moment you * can only downcast from a upb::Def to a specific Def type).. */ template To dyn_cast(From* f); /* Casts to any base class, or the type itself (ie. can be a no-op). * * Example: * upb::MessageDef* md = GetDef(); * // This will fail to compile if this wasn't actually a base class. * upb::Def* def = upb::upcast(md); */ template inline Pointer upcast(T *f) { return Pointer(f); } /* Attempt upcast to specific base class. * * Example: * upb::MessageDef* md = GetDef(); * upb::upcast_to(md)->MethodOnDef(); */ template inline T* upcast_to(F *f) { return static_cast(upcast(f)); } /* PointerBase: implementation detail of upb::upcast(). * It is implicitly convertable to pointers to the Base class(es). */ template class PointerBase { public: explicit PointerBase(T* ptr) : ptr_(ptr) {} operator T*() { return ptr_; } operator Base*() { return (Base*)ptr_; } private: T* ptr_; }; template class PointerBase2 : public PointerBase { public: explicit PointerBase2(T* ptr) : PointerBase(ptr) {} operator Base2*() { return Pointer(*this); } }; } #endif /* upb::ErrorSpace ************************************************************/ /* A upb::ErrorSpace represents some domain of possible error values. This lets * upb::Status attach specific error codes to operations, like POSIX/C errno, * Win32 error codes, etc. Clients who want to know the very specific error * code can check the error space and then know the type of the integer code. * * NOTE: upb::ErrorSpace is currently not used and should be considered * experimental. It is important primarily in cases where upb is performing * I/O, but upb doesn't currently have any components that do this. */ UPB_DECLARE_TYPE(upb::ErrorSpace, upb_errorspace) #ifdef __cplusplus class upb::ErrorSpace { #else struct upb_errorspace { #endif const char *name; }; /* upb::Status ****************************************************************/ /* upb::Status represents a success or failure status and error message. * It owns no resources and allocates no memory, so it should work * even in OOM situations. */ UPB_DECLARE_TYPE(upb::Status, upb_status) /* The maximum length of an error message before it will get truncated. */ #define UPB_STATUS_MAX_MESSAGE 128 UPB_BEGIN_EXTERN_C const char *upb_status_errmsg(const upb_status *status); bool upb_ok(const upb_status *status); upb_errorspace *upb_status_errspace(const upb_status *status); int upb_status_errcode(const upb_status *status); /* Any of the functions that write to a status object allow status to be NULL, * to support use cases where the function's caller does not care about the * status message. */ void upb_status_clear(upb_status *status); void upb_status_seterrmsg(upb_status *status, const char *msg); void upb_status_seterrf(upb_status *status, const char *fmt, ...); void upb_status_vseterrf(upb_status *status, const char *fmt, va_list args); void upb_status_copy(upb_status *to, const upb_status *from); UPB_END_EXTERN_C #ifdef __cplusplus class upb::Status { public: Status() { upb_status_clear(this); } /* Returns true if there is no error. */ bool ok() const { return upb_ok(this); } /* Optional error space and code, useful if the caller wants to * programmatically check the specific kind of error. */ ErrorSpace* error_space() { return upb_status_errspace(this); } int error_code() const { return upb_status_errcode(this); } /* The returned string is invalidated by any other call into the status. */ const char *error_message() const { return upb_status_errmsg(this); } /* The error message will be truncated if it is longer than * UPB_STATUS_MAX_MESSAGE-4. */ void SetErrorMessage(const char* msg) { upb_status_seterrmsg(this, msg); } void SetFormattedErrorMessage(const char* fmt, ...) { va_list args; va_start(args, fmt); upb_status_vseterrf(this, fmt, args); va_end(args); } /* Resets the status to a successful state with no message. */ void Clear() { upb_status_clear(this); } void CopyFrom(const Status& other) { upb_status_copy(this, &other); } private: UPB_DISALLOW_COPY_AND_ASSIGN(Status) #else struct upb_status { #endif bool ok_; /* Specific status code defined by some error space (optional). */ int code_; upb_errorspace *error_space_; /* TODO(haberman): add file/line of error? */ /* Error message; NULL-terminated. */ char msg[UPB_STATUS_MAX_MESSAGE]; }; #define UPB_STATUS_INIT {true, 0, NULL, {0}} /** Built-in error spaces. ****************************************************/ /* Errors raised by upb that we want to be able to detect programmatically. */ typedef enum { UPB_NOMEM /* Can't reuse ENOMEM because it is POSIX, not ISO C. */ } upb_errcode_t; extern upb_errorspace upb_upberr; void upb_upberr_setoom(upb_status *s); /* Since errno is defined by standard C, we define an error space for it in * core upb. Other error spaces should be defined in other, platform-specific * modules. */ extern upb_errorspace upb_errnoerr; /** upb::Allocator ************************************************************/ /* A upb::Allocator is a possibly-stateful allocator object. * * It could either be an arena allocator (which doesn't require individual * free() calls) or a regular malloc() (which does). The client must therefore * free memory unless it knows that the allocator is an arena allocator. */ UPB_DECLARE_TYPE(upb::Allocator, upb_alloc) /* A malloc()/free() function. * If "size" is 0 then the function acts like free(), otherwise it acts like * realloc(). Only "oldsize" bytes from a previous allocation are preserved. */ typedef void *upb_alloc_func(upb_alloc *alloc, void *ptr, size_t oldsize, size_t size); #ifdef __cplusplus class upb::Allocator UPB_FINAL { public: Allocator() {} private: UPB_DISALLOW_COPY_AND_ASSIGN(Allocator) public: #else struct upb_alloc { #endif /* __cplusplus */ upb_alloc_func *func; }; UPB_INLINE void *upb_malloc(upb_alloc *alloc, size_t size) { UPB_ASSERT(alloc); return alloc->func(alloc, NULL, 0, size); } UPB_INLINE void *upb_realloc(upb_alloc *alloc, void *ptr, size_t oldsize, size_t size) { UPB_ASSERT(alloc); return alloc->func(alloc, ptr, oldsize, size); } UPB_INLINE void upb_free(upb_alloc *alloc, void *ptr) { assert(alloc); alloc->func(alloc, ptr, 0, 0); } /* The global allocator used by upb. Uses the standard malloc()/free(). */ extern upb_alloc upb_alloc_global; /* Functions that hard-code the global malloc. * * We still get benefit because we can put custom logic into our global * allocator, like injecting out-of-memory faults in debug/testing builds. */ UPB_INLINE void *upb_gmalloc(size_t size) { return upb_malloc(&upb_alloc_global, size); } UPB_INLINE void *upb_grealloc(void *ptr, size_t oldsize, size_t size) { return upb_realloc(&upb_alloc_global, ptr, oldsize, size); } UPB_INLINE void upb_gfree(void *ptr) { upb_free(&upb_alloc_global, ptr); } /* upb::Arena *****************************************************************/ /* upb::Arena is a specific allocator implementation that uses arena allocation. * The user provides an allocator that will be used to allocate the underlying * arena blocks. Arenas by nature do not require the individual allocations * to be freed. However the Arena does allow users to register cleanup * functions that will run when the arena is destroyed. * * A upb::Arena is *not* thread-safe. * * You could write a thread-safe arena allocator that satisfies the * upb::Allocator interface, but it would not be as efficient for the * single-threaded case. */ UPB_DECLARE_TYPE(upb::Arena, upb_arena) typedef void upb_cleanup_func(void *ud); #define UPB_ARENA_BLOCK_OVERHEAD (sizeof(size_t)*4) UPB_BEGIN_EXTERN_C void upb_arena_init(upb_arena *a); void upb_arena_init2(upb_arena *a, void *mem, size_t n, upb_alloc *alloc); void upb_arena_uninit(upb_arena *a); bool upb_arena_addcleanup(upb_arena *a, upb_cleanup_func *func, void *ud); size_t upb_arena_bytesallocated(const upb_arena *a); void upb_arena_setnextblocksize(upb_arena *a, size_t size); void upb_arena_setmaxblocksize(upb_arena *a, size_t size); UPB_INLINE upb_alloc *upb_arena_alloc(upb_arena *a) { return (upb_alloc*)a; } UPB_END_EXTERN_C #ifdef __cplusplus class upb::Arena { public: /* A simple arena with no initial memory block and the default allocator. */ Arena() { upb_arena_init(this); } /* Constructs an arena with the given initial block which allocates blocks * with the given allocator. The given allocator must outlive the Arena. * * If you pass NULL for the allocator it will default to the global allocator * upb_alloc_global, and NULL/0 for the initial block will cause there to be * no initial block. */ Arena(void *mem, size_t len, Allocator* a) { upb_arena_init2(this, mem, len, a); } ~Arena() { upb_arena_uninit(this); } /* Sets the size of the next block the Arena will request (unless the * requested allocation is larger). Each block will double in size until the * max limit is reached. */ void SetNextBlockSize(size_t size) { upb_arena_setnextblocksize(this, size); } /* Sets the maximum block size. No blocks larger than this will be requested * from the underlying allocator unless individual arena allocations are * larger. */ void SetMaxBlockSize(size_t size) { upb_arena_setmaxblocksize(this, size); } /* Allows this arena to be used as a generic allocator. * * The arena does not need free() calls so when using Arena as an allocator * it is safe to skip them. However they are no-ops so there is no harm in * calling free() either. */ Allocator* allocator() { return upb_arena_alloc(this); } /* Add a cleanup function to run when the arena is destroyed. * Returns false on out-of-memory. */ bool AddCleanup(upb_cleanup_func* func, void* ud) { return upb_arena_addcleanup(this, func, ud); } /* Total number of bytes that have been allocated. It is undefined what * Realloc() does to this counter. */ size_t BytesAllocated() const { return upb_arena_bytesallocated(this); } private: UPB_DISALLOW_COPY_AND_ASSIGN(Arena) #else struct upb_arena { #endif /* __cplusplus */ /* We implement the allocator interface. * This must be the first member of upb_arena! */ upb_alloc alloc; /* Allocator to allocate arena blocks. We are responsible for freeing these * when we are destroyed. */ upb_alloc *block_alloc; size_t bytes_allocated; size_t next_block_size; size_t max_block_size; /* Linked list of blocks. Points to an arena_block, defined in env.c */ void *block_head; /* Cleanup entries. Pointer to a cleanup_ent, defined in env.c */ void *cleanup_head; /* For future expansion, since the size of this struct is exposed to users. */ void *future1; void *future2; }; /* upb::Environment ***********************************************************/ /* A upb::Environment provides a means for injecting malloc and an * error-reporting callback into encoders/decoders. This allows them to be * independent of nearly all assumptions about their actual environment. * * It is also a container for allocating the encoders/decoders themselves that * insulates clients from knowing their actual size. This provides ABI * compatibility even if the size of the objects change. And this allows the * structure definitions to be in the .c files instead of the .h files, making * the .h files smaller and more readable. * * We might want to consider renaming this to "Pipeline" if/when the concept of * a pipeline element becomes more formalized. */ UPB_DECLARE_TYPE(upb::Environment, upb_env) /* A function that receives an error report from an encoder or decoder. The * callback can return true to request that the error should be recovered, but * if the error is not recoverable this has no effect. */ typedef bool upb_error_func(void *ud, const upb_status *status); UPB_BEGIN_EXTERN_C void upb_env_init(upb_env *e); void upb_env_init2(upb_env *e, void *mem, size_t n, upb_alloc *alloc); void upb_env_uninit(upb_env *e); void upb_env_initonly(upb_env *e); upb_arena *upb_env_arena(upb_env *e); bool upb_env_ok(const upb_env *e); void upb_env_seterrorfunc(upb_env *e, upb_error_func *func, void *ud); /* Convenience wrappers around the methods of the contained arena. */ void upb_env_reporterrorsto(upb_env *e, upb_status *s); bool upb_env_reporterror(upb_env *e, const upb_status *s); void *upb_env_malloc(upb_env *e, size_t size); void *upb_env_realloc(upb_env *e, void *ptr, size_t oldsize, size_t size); void upb_env_free(upb_env *e, void *ptr); bool upb_env_addcleanup(upb_env *e, upb_cleanup_func *func, void *ud); size_t upb_env_bytesallocated(const upb_env *e); UPB_END_EXTERN_C #ifdef __cplusplus class upb::Environment { public: /* The given Arena must outlive this environment. */ Environment() { upb_env_initonly(this); } Environment(void *mem, size_t len, Allocator *a) : arena_(mem, len, a) { upb_env_initonly(this); } Arena* arena() { return upb_env_arena(this); } /* Set a custom error reporting function. */ void SetErrorFunction(upb_error_func* func, void* ud) { upb_env_seterrorfunc(this, func, ud); } /* Set the error reporting function to simply copy the status to the given * status and abort. */ void ReportErrorsTo(Status* status) { upb_env_reporterrorsto(this, status); } /* Returns true if all allocations and AddCleanup() calls have succeeded, * and no errors were reported with ReportError() (except ones that recovered * successfully). */ bool ok() const { return upb_env_ok(this); } /* Reports an error to this environment's callback, returning true if * the caller should try to recover. */ bool ReportError(const Status* status) { return upb_env_reporterror(this, status); } private: UPB_DISALLOW_COPY_AND_ASSIGN(Environment) #else struct upb_env { #endif /* __cplusplus */ upb_arena arena_; upb_error_func *error_func_; void *error_ud_; bool ok_; }; /* upb::InlinedArena **********************************************************/ /* upb::InlinedEnvironment ****************************************************/ /* upb::InlinedArena and upb::InlinedEnvironment seed their arenas with a * predefined amount of memory. No heap memory will be allocated until the * initial block is exceeded. * * These types only exist in C++ */ #ifdef __cplusplus template class upb::InlinedArena : public upb::Arena { public: InlinedArena() : Arena(initial_block_, N, NULL) {} explicit InlinedArena(Allocator* a) : Arena(initial_block_, N, a) {} private: UPB_DISALLOW_COPY_AND_ASSIGN(InlinedArena) char initial_block_[N + UPB_ARENA_BLOCK_OVERHEAD]; }; template class upb::InlinedEnvironment : public upb::Environment { public: InlinedEnvironment() : Environment(initial_block_, N, NULL) {} explicit InlinedEnvironment(Allocator *a) : Environment(initial_block_, N, a) {} private: UPB_DISALLOW_COPY_AND_ASSIGN(InlinedEnvironment) char initial_block_[N + UPB_ARENA_BLOCK_OVERHEAD]; }; #endif /* __cplusplus */ #endif /* UPB_H_ */ #ifdef __cplusplus extern "C" { #endif /* upb_value ******************************************************************/ /* A tagged union (stored untagged inside the table) so that we can check that * clients calling table accessors are correctly typed without having to have * an explosion of accessors. */ typedef enum { UPB_CTYPE_INT32 = 1, UPB_CTYPE_INT64 = 2, UPB_CTYPE_UINT32 = 3, UPB_CTYPE_UINT64 = 4, UPB_CTYPE_BOOL = 5, UPB_CTYPE_CSTR = 6, UPB_CTYPE_PTR = 7, UPB_CTYPE_CONSTPTR = 8, UPB_CTYPE_FPTR = 9, UPB_CTYPE_FLOAT = 10, UPB_CTYPE_DOUBLE = 11 } upb_ctype_t; typedef struct { uint64_t val; #ifndef NDEBUG /* In debug mode we carry the value type around also so we can check accesses * to be sure the right member is being read. */ upb_ctype_t ctype; #endif } upb_value; #ifdef NDEBUG #define SET_TYPE(dest, val) UPB_UNUSED(val) #else #define SET_TYPE(dest, val) dest = val #endif /* Like strdup(), which isn't always available since it's not ANSI C. */ char *upb_strdup(const char *s, upb_alloc *a); /* Variant that works with a length-delimited rather than NULL-delimited string, * as supported by strtable. */ char *upb_strdup2(const char *s, size_t len, upb_alloc *a); UPB_INLINE char *upb_gstrdup(const char *s) { return upb_strdup(s, &upb_alloc_global); } UPB_INLINE void _upb_value_setval(upb_value *v, uint64_t val, upb_ctype_t ctype) { v->val = val; SET_TYPE(v->ctype, ctype); } UPB_INLINE upb_value _upb_value_val(uint64_t val, upb_ctype_t ctype) { upb_value ret; _upb_value_setval(&ret, val, ctype); return ret; } /* For each value ctype, define the following set of functions: * * // Get/set an int32 from a upb_value. * int32_t upb_value_getint32(upb_value val); * void upb_value_setint32(upb_value *val, int32_t cval); * * // Construct a new upb_value from an int32. * upb_value upb_value_int32(int32_t val); */ #define FUNCS(name, membername, type_t, converter, proto_type) \ UPB_INLINE void upb_value_set ## name(upb_value *val, type_t cval) { \ val->val = (converter)cval; \ SET_TYPE(val->ctype, proto_type); \ } \ UPB_INLINE upb_value upb_value_ ## name(type_t val) { \ upb_value ret; \ upb_value_set ## name(&ret, val); \ return ret; \ } \ UPB_INLINE type_t upb_value_get ## name(upb_value val) { \ UPB_ASSERT_DEBUGVAR(val.ctype == proto_type); \ return (type_t)(converter)val.val; \ } FUNCS(int32, int32, int32_t, int32_t, UPB_CTYPE_INT32) FUNCS(int64, int64, int64_t, int64_t, UPB_CTYPE_INT64) FUNCS(uint32, uint32, uint32_t, uint32_t, UPB_CTYPE_UINT32) FUNCS(uint64, uint64, uint64_t, uint64_t, UPB_CTYPE_UINT64) FUNCS(bool, _bool, bool, bool, UPB_CTYPE_BOOL) FUNCS(cstr, cstr, char*, uintptr_t, UPB_CTYPE_CSTR) FUNCS(ptr, ptr, void*, uintptr_t, UPB_CTYPE_PTR) FUNCS(constptr, constptr, const void*, uintptr_t, UPB_CTYPE_CONSTPTR) FUNCS(fptr, fptr, upb_func*, uintptr_t, UPB_CTYPE_FPTR) #undef FUNCS UPB_INLINE void upb_value_setfloat(upb_value *val, float cval) { memcpy(&val->val, &cval, sizeof(cval)); SET_TYPE(val->ctype, UPB_CTYPE_FLOAT); } UPB_INLINE void upb_value_setdouble(upb_value *val, double cval) { memcpy(&val->val, &cval, sizeof(cval)); SET_TYPE(val->ctype, UPB_CTYPE_DOUBLE); } UPB_INLINE upb_value upb_value_float(float cval) { upb_value ret; upb_value_setfloat(&ret, cval); return ret; } UPB_INLINE upb_value upb_value_double(double cval) { upb_value ret; upb_value_setdouble(&ret, cval); return ret; } #undef SET_TYPE /* upb_tabkey *****************************************************************/ /* Either: * 1. an actual integer key, or * 2. a pointer to a string prefixed by its uint32_t length, owned by us. * * ...depending on whether this is a string table or an int table. We would * make this a union of those two types, but C89 doesn't support statically * initializing a non-first union member. */ typedef uintptr_t upb_tabkey; #define UPB_TABKEY_NUM(n) n #define UPB_TABKEY_NONE 0 /* The preprocessor isn't quite powerful enough to turn the compile-time string * length into a byte-wise string representation, so code generation needs to * help it along. * * "len1" is the low byte and len4 is the high byte. */ #ifdef UPB_BIG_ENDIAN #define UPB_TABKEY_STR(len1, len2, len3, len4, strval) \ (uintptr_t)(len4 len3 len2 len1 strval) #else #define UPB_TABKEY_STR(len1, len2, len3, len4, strval) \ (uintptr_t)(len1 len2 len3 len4 strval) #endif UPB_INLINE char *upb_tabstr(upb_tabkey key, uint32_t *len) { char* mem = (char*)key; if (len) memcpy(len, mem, sizeof(*len)); return mem + sizeof(*len); } /* upb_tabval *****************************************************************/ #ifdef __cplusplus /* Status initialization not supported. * * This separate definition is necessary because in C++, UINTPTR_MAX isn't * reliably available. */ typedef struct { uint64_t val; } upb_tabval; #else /* C -- supports static initialization, but to support static initialization of * both integers and points for both 32 and 64 bit targets, it takes a little * bit of doing. */ #if UINTPTR_MAX == 0xffffffffffffffffULL #define UPB_PTR_IS_64BITS #elif UINTPTR_MAX != 0xffffffff #error Could not determine how many bits pointers are. #endif typedef union { /* For static initialization. * * Unfortunately this ugliness is necessary -- it is the only way that we can, * with -std=c89 -pedantic, statically initialize this to either a pointer or * an integer on 32-bit platforms. */ struct { #ifdef UPB_PTR_IS_64BITS uintptr_t val; #else uintptr_t val1; uintptr_t val2; #endif } staticinit; /* The normal accessor that we use for everything at runtime. */ uint64_t val; } upb_tabval; #ifdef UPB_PTR_IS_64BITS #define UPB_TABVALUE_INT_INIT(v) {{v}} #define UPB_TABVALUE_EMPTY_INIT {{-1}} #else /* 32-bit pointers */ #ifdef UPB_BIG_ENDIAN #define UPB_TABVALUE_INT_INIT(v) {{0, v}} #define UPB_TABVALUE_EMPTY_INIT {{-1, -1}} #else #define UPB_TABVALUE_INT_INIT(v) {{v, 0}} #define UPB_TABVALUE_EMPTY_INIT {{-1, -1}} #endif #endif #define UPB_TABVALUE_PTR_INIT(v) UPB_TABVALUE_INT_INIT((uintptr_t)v) #undef UPB_PTR_IS_64BITS #endif /* __cplusplus */ /* upb_table ******************************************************************/ typedef struct _upb_tabent { upb_tabkey key; upb_tabval val; /* Internal chaining. This is const so we can create static initializers for * tables. We cast away const sometimes, but *only* when the containing * upb_table is known to be non-const. This requires a bit of care, but * the subtlety is confined to table.c. */ const struct _upb_tabent *next; } upb_tabent; typedef struct { size_t count; /* Number of entries in the hash part. */ size_t mask; /* Mask to turn hash value -> bucket. */ upb_ctype_t ctype; /* Type of all values. */ uint8_t size_lg2; /* Size of the hashtable part is 2^size_lg2 entries. */ /* Hash table entries. * Making this const isn't entirely accurate; what we really want is for it to * have the same const-ness as the table it's inside. But there's no way to * declare that in C. So we have to make it const so that we can statically * initialize const hash tables. Then we cast away const when we have to. */ const upb_tabent *entries; #ifndef NDEBUG /* This table's allocator. We make the user pass it in to every relevant * function and only use this to check it in debug mode. We do this solely * to keep upb_table as small as possible. This might seem slightly paranoid * but the plan is to use upb_table for all map fields and extension sets in * a forthcoming message representation, so there could be a lot of these. * If this turns out to be too annoying later, we can change it (since this * is an internal-only header file). */ upb_alloc *alloc; #endif } upb_table; #ifdef NDEBUG # define UPB_TABLE_INIT(count, mask, ctype, size_lg2, entries) \ {count, mask, ctype, size_lg2, entries} #else # ifdef UPB_DEBUG_REFS /* At the moment the only mutable tables we statically initialize are debug * ref tables. */ # define UPB_TABLE_INIT(count, mask, ctype, size_lg2, entries) \ {count, mask, ctype, size_lg2, entries, &upb_alloc_debugrefs} # else # define UPB_TABLE_INIT(count, mask, ctype, size_lg2, entries) \ {count, mask, ctype, size_lg2, entries, NULL} # endif #endif typedef struct { upb_table t; } upb_strtable; #define UPB_STRTABLE_INIT(count, mask, ctype, size_lg2, entries) \ {UPB_TABLE_INIT(count, mask, ctype, size_lg2, entries)} #define UPB_EMPTY_STRTABLE_INIT(ctype) \ UPB_STRTABLE_INIT(0, 0, ctype, 0, NULL) typedef struct { upb_table t; /* For entries that don't fit in the array part. */ const upb_tabval *array; /* Array part of the table. See const note above. */ size_t array_size; /* Array part size. */ size_t array_count; /* Array part number of elements. */ } upb_inttable; #define UPB_INTTABLE_INIT(count, mask, ctype, size_lg2, ent, a, asize, acount) \ {UPB_TABLE_INIT(count, mask, ctype, size_lg2, ent), a, asize, acount} #define UPB_EMPTY_INTTABLE_INIT(ctype) \ UPB_INTTABLE_INIT(0, 0, ctype, 0, NULL, NULL, 0, 0) #define UPB_ARRAY_EMPTYENT -1 UPB_INLINE size_t upb_table_size(const upb_table *t) { if (t->size_lg2 == 0) return 0; else return 1 << t->size_lg2; } /* Internal-only functions, in .h file only out of necessity. */ UPB_INLINE bool upb_tabent_isempty(const upb_tabent *e) { return e->key == 0; } /* Used by some of the unit tests for generic hashing functionality. */ uint32_t MurmurHash2(const void * key, size_t len, uint32_t seed); UPB_INLINE uintptr_t upb_intkey(uintptr_t key) { return key; } UPB_INLINE uint32_t upb_inthash(uintptr_t key) { return (uint32_t)key; } static const upb_tabent *upb_getentry(const upb_table *t, uint32_t hash) { return t->entries + (hash & t->mask); } UPB_INLINE bool upb_arrhas(upb_tabval key) { return key.val != (uint64_t)-1; } /* Initialize and uninitialize a table, respectively. If memory allocation * failed, false is returned that the table is uninitialized. */ bool upb_inttable_init2(upb_inttable *table, upb_ctype_t ctype, upb_alloc *a); bool upb_strtable_init2(upb_strtable *table, upb_ctype_t ctype, upb_alloc *a); void upb_inttable_uninit2(upb_inttable *table, upb_alloc *a); void upb_strtable_uninit2(upb_strtable *table, upb_alloc *a); UPB_INLINE bool upb_inttable_init(upb_inttable *table, upb_ctype_t ctype) { return upb_inttable_init2(table, ctype, &upb_alloc_global); } UPB_INLINE bool upb_strtable_init(upb_strtable *table, upb_ctype_t ctype) { return upb_strtable_init2(table, ctype, &upb_alloc_global); } UPB_INLINE void upb_inttable_uninit(upb_inttable *table) { upb_inttable_uninit2(table, &upb_alloc_global); } UPB_INLINE void upb_strtable_uninit(upb_strtable *table) { upb_strtable_uninit2(table, &upb_alloc_global); } /* Returns the number of values in the table. */ size_t upb_inttable_count(const upb_inttable *t); UPB_INLINE size_t upb_strtable_count(const upb_strtable *t) { return t->t.count; } void upb_inttable_packedsize(const upb_inttable *t, size_t *size); void upb_strtable_packedsize(const upb_strtable *t, size_t *size); upb_inttable *upb_inttable_pack(const upb_inttable *t, void *p, size_t *ofs, size_t size); upb_strtable *upb_strtable_pack(const upb_strtable *t, void *p, size_t *ofs, size_t size); /* Inserts the given key into the hashtable with the given value. The key must * not already exist in the hash table. For string tables, the key must be * NULL-terminated, and the table will make an internal copy of the key. * Inttables must not insert a value of UINTPTR_MAX. * * If a table resize was required but memory allocation failed, false is * returned and the table is unchanged. */ bool upb_inttable_insert2(upb_inttable *t, uintptr_t key, upb_value val, upb_alloc *a); bool upb_strtable_insert3(upb_strtable *t, const char *key, size_t len, upb_value val, upb_alloc *a); UPB_INLINE bool upb_inttable_insert(upb_inttable *t, uintptr_t key, upb_value val) { return upb_inttable_insert2(t, key, val, &upb_alloc_global); } UPB_INLINE bool upb_strtable_insert2(upb_strtable *t, const char *key, size_t len, upb_value val) { return upb_strtable_insert3(t, key, len, val, &upb_alloc_global); } /* For NULL-terminated strings. */ UPB_INLINE bool upb_strtable_insert(upb_strtable *t, const char *key, upb_value val) { return upb_strtable_insert2(t, key, strlen(key), val); } /* Looks up key in this table, returning "true" if the key was found. * If v is non-NULL, copies the value for this key into *v. */ bool upb_inttable_lookup(const upb_inttable *t, uintptr_t key, upb_value *v); bool upb_strtable_lookup2(const upb_strtable *t, const char *key, size_t len, upb_value *v); /* For NULL-terminated strings. */ UPB_INLINE bool upb_strtable_lookup(const upb_strtable *t, const char *key, upb_value *v) { return upb_strtable_lookup2(t, key, strlen(key), v); } /* Removes an item from the table. Returns true if the remove was successful, * and stores the removed item in *val if non-NULL. */ bool upb_inttable_remove(upb_inttable *t, uintptr_t key, upb_value *val); bool upb_strtable_remove3(upb_strtable *t, const char *key, size_t len, upb_value *val, upb_alloc *alloc); UPB_INLINE bool upb_strtable_remove2(upb_strtable *t, const char *key, size_t len, upb_value *val) { return upb_strtable_remove3(t, key, len, val, &upb_alloc_global); } /* For NULL-terminated strings. */ UPB_INLINE bool upb_strtable_remove(upb_strtable *t, const char *key, upb_value *v) { return upb_strtable_remove2(t, key, strlen(key), v); } /* Updates an existing entry in an inttable. If the entry does not exist, * returns false and does nothing. Unlike insert/remove, this does not * invalidate iterators. */ bool upb_inttable_replace(upb_inttable *t, uintptr_t key, upb_value val); /* Handy routines for treating an inttable like a stack. May not be mixed with * other insert/remove calls. */ bool upb_inttable_push2(upb_inttable *t, upb_value val, upb_alloc *a); upb_value upb_inttable_pop(upb_inttable *t); UPB_INLINE bool upb_inttable_push(upb_inttable *t, upb_value val) { return upb_inttable_push2(t, val, &upb_alloc_global); } /* Convenience routines for inttables with pointer keys. */ bool upb_inttable_insertptr2(upb_inttable *t, const void *key, upb_value val, upb_alloc *a); bool upb_inttable_removeptr(upb_inttable *t, const void *key, upb_value *val); bool upb_inttable_lookupptr( const upb_inttable *t, const void *key, upb_value *val); UPB_INLINE bool upb_inttable_insertptr(upb_inttable *t, const void *key, upb_value val) { return upb_inttable_insertptr2(t, key, val, &upb_alloc_global); } /* Optimizes the table for the current set of entries, for both memory use and * lookup time. Client should call this after all entries have been inserted; * inserting more entries is legal, but will likely require a table resize. */ void upb_inttable_compact2(upb_inttable *t, upb_alloc *a); UPB_INLINE void upb_inttable_compact(upb_inttable *t) { upb_inttable_compact2(t, &upb_alloc_global); } /* A special-case inlinable version of the lookup routine for 32-bit * integers. */ UPB_INLINE bool upb_inttable_lookup32(const upb_inttable *t, uint32_t key, upb_value *v) { *v = upb_value_int32(0); /* Silence compiler warnings. */ if (key < t->array_size) { upb_tabval arrval = t->array[key]; if (upb_arrhas(arrval)) { _upb_value_setval(v, arrval.val, t->t.ctype); return true; } else { return false; } } else { const upb_tabent *e; if (t->t.entries == NULL) return false; for (e = upb_getentry(&t->t, upb_inthash(key)); true; e = e->next) { if ((uint32_t)e->key == key) { _upb_value_setval(v, e->val.val, t->t.ctype); return true; } if (e->next == NULL) return false; } } } /* Exposed for testing only. */ bool upb_strtable_resize(upb_strtable *t, size_t size_lg2, upb_alloc *a); /* Iterators ******************************************************************/ /* Iterators for int and string tables. We are subject to some kind of unusual * design constraints: * * For high-level languages: * - we must be able to guarantee that we don't crash or corrupt memory even if * the program accesses an invalidated iterator. * * For C++11 range-based for: * - iterators must be copyable * - iterators must be comparable * - it must be possible to construct an "end" value. * * Iteration order is undefined. * * Modifying the table invalidates iterators. upb_{str,int}table_done() is * guaranteed to work even on an invalidated iterator, as long as the table it * is iterating over has not been freed. Calling next() or accessing data from * an invalidated iterator yields unspecified elements from the table, but it is * guaranteed not to crash and to return real table elements (except when done() * is true). */ /* upb_strtable_iter **********************************************************/ /* upb_strtable_iter i; * upb_strtable_begin(&i, t); * for(; !upb_strtable_done(&i); upb_strtable_next(&i)) { * const char *key = upb_strtable_iter_key(&i); * const upb_value val = upb_strtable_iter_value(&i); * // ... * } */ typedef struct { const upb_strtable *t; size_t index; } upb_strtable_iter; void upb_strtable_begin(upb_strtable_iter *i, const upb_strtable *t); void upb_strtable_next(upb_strtable_iter *i); bool upb_strtable_done(const upb_strtable_iter *i); const char *upb_strtable_iter_key(const upb_strtable_iter *i); size_t upb_strtable_iter_keylength(const upb_strtable_iter *i); upb_value upb_strtable_iter_value(const upb_strtable_iter *i); void upb_strtable_iter_setdone(upb_strtable_iter *i); bool upb_strtable_iter_isequal(const upb_strtable_iter *i1, const upb_strtable_iter *i2); /* upb_inttable_iter **********************************************************/ /* upb_inttable_iter i; * upb_inttable_begin(&i, t); * for(; !upb_inttable_done(&i); upb_inttable_next(&i)) { * uintptr_t key = upb_inttable_iter_key(&i); * upb_value val = upb_inttable_iter_value(&i); * // ... * } */ typedef struct { const upb_inttable *t; size_t index; bool array_part; } upb_inttable_iter; void upb_inttable_begin(upb_inttable_iter *i, const upb_inttable *t); void upb_inttable_next(upb_inttable_iter *i); bool upb_inttable_done(const upb_inttable_iter *i); uintptr_t upb_inttable_iter_key(const upb_inttable_iter *i); upb_value upb_inttable_iter_value(const upb_inttable_iter *i); void upb_inttable_iter_setdone(upb_inttable_iter *i); bool upb_inttable_iter_isequal(const upb_inttable_iter *i1, const upb_inttable_iter *i2); #ifdef __cplusplus } /* extern "C" */ #endif #endif /* UPB_TABLE_H_ */ /* Reference tracking will check ref()/unref() operations to make sure the * ref ownership is correct. Where possible it will also make tools like * Valgrind attribute ref leaks to the code that took the leaked ref, not * the code that originally created the object. * * Enabling this requires the application to define upb_lock()/upb_unlock() * functions that acquire/release a global mutex (or #define UPB_THREAD_UNSAFE). * For this reason we don't enable it by default, even in debug builds. */ /* #define UPB_DEBUG_REFS */ #ifdef __cplusplus namespace upb { class RefCounted; template class reffed_ptr; } #endif UPB_DECLARE_TYPE(upb::RefCounted, upb_refcounted) struct upb_refcounted_vtbl; #ifdef __cplusplus class upb::RefCounted { public: /* Returns true if the given object is frozen. */ bool IsFrozen() const; /* Increases the ref count, the new ref is owned by "owner" which must not * already own a ref (and should not itself be a refcounted object if the ref * could possibly be circular; see below). * Thread-safe iff "this" is frozen. */ void Ref(const void *owner) const; /* Release a ref that was acquired from upb_refcounted_ref() and collects any * objects it can. */ void Unref(const void *owner) const; /* Moves an existing ref from "from" to "to", without changing the overall * ref count. DonateRef(foo, NULL, owner) is the same as Ref(foo, owner), * but "to" may not be NULL. */ void DonateRef(const void *from, const void *to) const; /* Verifies that a ref to the given object is currently held by the given * owner. Only effective in UPB_DEBUG_REFS builds. */ void CheckRef(const void *owner) const; private: UPB_DISALLOW_POD_OPS(RefCounted, upb::RefCounted) #else struct upb_refcounted { #endif /* TODO(haberman): move the actual structure definition to structdefs.int.h. * The only reason they are here is because inline functions need to see the * definition of upb_handlers, which needs to see this definition. But we * can change the upb_handlers inline functions to deal in raw offsets * instead. */ /* A single reference count shared by all objects in the group. */ uint32_t *group; /* A singly-linked list of all objects in the group. */ upb_refcounted *next; /* Table of function pointers for this type. */ const struct upb_refcounted_vtbl *vtbl; /* Maintained only when mutable, this tracks the number of refs (but not * ref2's) to this object. *group should be the sum of all individual_count * in the group. */ uint32_t individual_count; bool is_frozen; #ifdef UPB_DEBUG_REFS upb_inttable *refs; /* Maps owner -> trackedref for incoming refs. */ upb_inttable *ref2s; /* Set of targets for outgoing ref2s. */ #endif }; #ifdef UPB_DEBUG_REFS extern upb_alloc upb_alloc_debugrefs; #define UPB_REFCOUNT_INIT(vtbl, refs, ref2s) \ {&static_refcount, NULL, vtbl, 0, true, refs, ref2s} #else #define UPB_REFCOUNT_INIT(vtbl, refs, ref2s) \ {&static_refcount, NULL, vtbl, 0, true} #endif UPB_BEGIN_EXTERN_C /* It is better to use tracked refs when possible, for the extra debugging * capability. But if this is not possible (because you don't have easy access * to a stable pointer value that is associated with the ref), you can pass * UPB_UNTRACKED_REF instead. */ extern const void *UPB_UNTRACKED_REF; /* Native C API. */ bool upb_refcounted_isfrozen(const upb_refcounted *r); void upb_refcounted_ref(const upb_refcounted *r, const void *owner); void upb_refcounted_unref(const upb_refcounted *r, const void *owner); void upb_refcounted_donateref( const upb_refcounted *r, const void *from, const void *to); void upb_refcounted_checkref(const upb_refcounted *r, const void *owner); #define UPB_REFCOUNTED_CMETHODS(type, upcastfunc) \ UPB_INLINE bool type ## _isfrozen(const type *v) { \ return upb_refcounted_isfrozen(upcastfunc(v)); \ } \ UPB_INLINE void type ## _ref(const type *v, const void *owner) { \ upb_refcounted_ref(upcastfunc(v), owner); \ } \ UPB_INLINE void type ## _unref(const type *v, const void *owner) { \ upb_refcounted_unref(upcastfunc(v), owner); \ } \ UPB_INLINE void type ## _donateref(const type *v, const void *from, const void *to) { \ upb_refcounted_donateref(upcastfunc(v), from, to); \ } \ UPB_INLINE void type ## _checkref(const type *v, const void *owner) { \ upb_refcounted_checkref(upcastfunc(v), owner); \ } #define UPB_REFCOUNTED_CPPMETHODS \ bool IsFrozen() const { \ return upb::upcast_to(this)->IsFrozen(); \ } \ void Ref(const void *owner) const { \ return upb::upcast_to(this)->Ref(owner); \ } \ void Unref(const void *owner) const { \ return upb::upcast_to(this)->Unref(owner); \ } \ void DonateRef(const void *from, const void *to) const { \ return upb::upcast_to(this)->DonateRef(from, to); \ } \ void CheckRef(const void *owner) const { \ return upb::upcast_to(this)->CheckRef(owner); \ } /* Internal-to-upb Interface **************************************************/ typedef void upb_refcounted_visit(const upb_refcounted *r, const upb_refcounted *subobj, void *closure); struct upb_refcounted_vtbl { /* Must visit all subobjects that are currently ref'd via upb_refcounted_ref2. * Must be longjmp()-safe. */ void (*visit)(const upb_refcounted *r, upb_refcounted_visit *visit, void *c); /* Must free the object and release all references to other objects. */ void (*free)(upb_refcounted *r); }; /* Initializes the refcounted with a single ref for the given owner. Returns * false if memory could not be allocated. */ bool upb_refcounted_init(upb_refcounted *r, const struct upb_refcounted_vtbl *vtbl, const void *owner); /* Adds a ref from one refcounted object to another ("from" must not already * own a ref). These refs may be circular; cycles will be collected correctly * (if conservatively). These refs do not need to be freed in from's free() * function. */ void upb_refcounted_ref2(const upb_refcounted *r, upb_refcounted *from); /* Removes a ref that was acquired from upb_refcounted_ref2(), and collects any * object it can. This is only necessary when "from" no longer points to "r", * and not from from's "free" function. */ void upb_refcounted_unref2(const upb_refcounted *r, upb_refcounted *from); #define upb_ref2(r, from) \ upb_refcounted_ref2((const upb_refcounted*)r, (upb_refcounted*)from) #define upb_unref2(r, from) \ upb_refcounted_unref2((const upb_refcounted*)r, (upb_refcounted*)from) /* Freezes all mutable object reachable by ref2() refs from the given roots. * This will split refcounting groups into precise SCC groups, so that * refcounting of frozen objects can be more aggressive. If memory allocation * fails, or if more than 2**31 mutable objects are reachable from "roots", or * if the maximum depth of the graph exceeds "maxdepth", false is returned and * the objects are unchanged. * * After this operation succeeds, the objects are frozen/const, and may not be * used through non-const pointers. In particular, they may not be passed as * the second parameter of upb_refcounted_{ref,unref}2(). On the upside, all * operations on frozen refcounteds are threadsafe, and objects will be freed * at the precise moment that they become unreachable. * * Caller must own refs on each object in the "roots" list. */ bool upb_refcounted_freeze(upb_refcounted *const*roots, int n, upb_status *s, int maxdepth); /* Shared by all compiled-in refcounted objects. */ extern uint32_t static_refcount; UPB_END_EXTERN_C #ifdef __cplusplus /* C++ Wrappers. */ namespace upb { inline bool RefCounted::IsFrozen() const { return upb_refcounted_isfrozen(this); } inline void RefCounted::Ref(const void *owner) const { upb_refcounted_ref(this, owner); } inline void RefCounted::Unref(const void *owner) const { upb_refcounted_unref(this, owner); } inline void RefCounted::DonateRef(const void *from, const void *to) const { upb_refcounted_donateref(this, from, to); } inline void RefCounted::CheckRef(const void *owner) const { upb_refcounted_checkref(this, owner); } } /* namespace upb */ #endif /* upb::reffed_ptr ************************************************************/ #ifdef __cplusplus #include /* For std::swap(). */ /* Provides RAII semantics for upb refcounted objects. Each reffed_ptr owns a * ref on whatever object it points to (if any). */ template class upb::reffed_ptr { public: reffed_ptr() : ptr_(NULL) {} /* If ref_donor is NULL, takes a new ref, otherwise adopts from ref_donor. */ template reffed_ptr(U* val, const void* ref_donor = NULL) : ptr_(upb::upcast(val)) { if (ref_donor) { UPB_ASSERT(ptr_); ptr_->DonateRef(ref_donor, this); } else if (ptr_) { ptr_->Ref(this); } } template reffed_ptr(const reffed_ptr& other) : ptr_(upb::upcast(other.get())) { if (ptr_) ptr_->Ref(this); } reffed_ptr(const reffed_ptr& other) : ptr_(upb::upcast(other.get())) { if (ptr_) ptr_->Ref(this); } ~reffed_ptr() { if (ptr_) ptr_->Unref(this); } template reffed_ptr& operator=(const reffed_ptr& other) { reset(other.get()); return *this; } reffed_ptr& operator=(const reffed_ptr& other) { reset(other.get()); return *this; } /* TODO(haberman): add C++11 move construction/assignment for greater * efficiency. */ void swap(reffed_ptr& other) { if (ptr_ == other.ptr_) { return; } if (ptr_) ptr_->DonateRef(this, &other); if (other.ptr_) other.ptr_->DonateRef(&other, this); std::swap(ptr_, other.ptr_); } T& operator*() const { UPB_ASSERT(ptr_); return *ptr_; } T* operator->() const { UPB_ASSERT(ptr_); return ptr_; } T* get() const { return ptr_; } /* If ref_donor is NULL, takes a new ref, otherwise adopts from ref_donor. */ template void reset(U* ptr = NULL, const void* ref_donor = NULL) { reffed_ptr(ptr, ref_donor).swap(*this); } template reffed_ptr down_cast() { return reffed_ptr(upb::down_cast(get())); } template reffed_ptr dyn_cast() { return reffed_ptr(upb::dyn_cast(get())); } /* Plain release() is unsafe; if we were the only owner, it would leak the * object. Instead we provide this: */ T* ReleaseTo(const void* new_owner) { T* ret = NULL; ptr_->DonateRef(this, new_owner); std::swap(ret, ptr_); return ret; } private: T* ptr_; }; #endif /* __cplusplus */ #endif /* UPB_REFCOUNT_H_ */ #ifdef __cplusplus #include #include #include namespace upb { class Def; class EnumDef; class FieldDef; class FileDef; class MessageDef; class OneofDef; class SymbolTable; } #endif UPB_DECLARE_DERIVED_TYPE(upb::Def, upb::RefCounted, upb_def, upb_refcounted) UPB_DECLARE_DERIVED_TYPE(upb::OneofDef, upb::RefCounted, upb_oneofdef, upb_refcounted) UPB_DECLARE_DERIVED_TYPE(upb::FileDef, upb::RefCounted, upb_filedef, upb_refcounted) UPB_DECLARE_TYPE(upb::SymbolTable, upb_symtab) /* The maximum message depth that the type graph can have. This is a resource * limit for the C stack since we sometimes need to recursively traverse the * graph. Cycles are ok; the traversal will stop when it detects a cycle, but * we must hit the cycle before the maximum depth is reached. * * If having a single static limit is too inflexible, we can add another variant * of Def::Freeze that allows specifying this as a parameter. */ #define UPB_MAX_MESSAGE_DEPTH 64 /* upb::Def: base class for top-level defs ***********************************/ /* All the different kind of defs that can be defined at the top-level and put * in a SymbolTable or appear in a FileDef::defs() list. This excludes some * defs (like oneofs and files). It only includes fields because they can be * defined as extensions. */ typedef enum { UPB_DEF_MSG, UPB_DEF_FIELD, UPB_DEF_ENUM, UPB_DEF_SERVICE, /* Not yet implemented. */ UPB_DEF_ANY = -1 /* Wildcard for upb_symtab_get*() */ } upb_deftype_t; #ifdef __cplusplus /* The base class of all defs. Its base is upb::RefCounted (use upb::upcast() * to convert). */ class upb::Def { public: typedef upb_deftype_t Type; /* upb::RefCounted methods like Ref()/Unref(). */ UPB_REFCOUNTED_CPPMETHODS Type def_type() const; /* "fullname" is the def's fully-qualified name (eg. foo.bar.Message). */ const char *full_name() const; /* The final part of a def's name (eg. Message). */ const char *name() const; /* The def must be mutable. Caller retains ownership of fullname. Defs are * not required to have a name; if a def has no name when it is frozen, it * will remain an anonymous def. On failure, returns false and details in "s" * if non-NULL. */ bool set_full_name(const char* fullname, upb::Status* s); bool set_full_name(const std::string &fullname, upb::Status* s); /* The file in which this def appears. It is not necessary to add a def to a * file (and consequently the accessor may return NULL). Set this by calling * file->Add(def). */ FileDef* file() const; /* Freezes the given defs; this validates all constraints and marks the defs * as frozen (read-only). "defs" may not contain any fielddefs, but fields * of any msgdefs will be frozen. * * Symbolic references to sub-types and enum defaults must have already been * resolved. Any mutable defs reachable from any of "defs" must also be in * the list; more formally, "defs" must be a transitive closure of mutable * defs. * * After this operation succeeds, the finalized defs must only be accessed * through a const pointer! */ static bool Freeze(Def* const* defs, size_t n, Status* status); static bool Freeze(const std::vector& defs, Status* status); private: UPB_DISALLOW_POD_OPS(Def, upb::Def) }; #endif /* __cplusplus */ UPB_BEGIN_EXTERN_C /* Include upb_refcounted methods like upb_def_ref()/upb_def_unref(). */ UPB_REFCOUNTED_CMETHODS(upb_def, upb_def_upcast) upb_deftype_t upb_def_type(const upb_def *d); const char *upb_def_fullname(const upb_def *d); const char *upb_def_name(const upb_def *d); const upb_filedef *upb_def_file(const upb_def *d); bool upb_def_setfullname(upb_def *def, const char *fullname, upb_status *s); bool upb_def_freeze(upb_def *const *defs, size_t n, upb_status *s); /* Temporary API: for internal use only. */ bool _upb_def_validate(upb_def *const*defs, size_t n, upb_status *s); UPB_END_EXTERN_C /* upb::Def casts *************************************************************/ #ifdef __cplusplus #define UPB_CPP_CASTS(cname, cpptype) \ namespace upb { \ template <> \ inline cpptype *down_cast(Def * def) { \ return upb_downcast_##cname##_mutable(def); \ } \ template <> \ inline cpptype *dyn_cast(Def * def) { \ return upb_dyncast_##cname##_mutable(def); \ } \ template <> \ inline const cpptype *down_cast( \ const Def *def) { \ return upb_downcast_##cname(def); \ } \ template <> \ inline const cpptype *dyn_cast(const Def *def) { \ return upb_dyncast_##cname(def); \ } \ template <> \ inline const cpptype *down_cast(Def * def) { \ return upb_downcast_##cname(def); \ } \ template <> \ inline const cpptype *dyn_cast(Def * def) { \ return upb_dyncast_##cname(def); \ } \ } /* namespace upb */ #else #define UPB_CPP_CASTS(cname, cpptype) #endif /* __cplusplus */ /* Dynamic casts, for determining if a def is of a particular type at runtime. * Downcasts, for when some wants to assert that a def is of a particular type. * These are only checked if we are building debug. */ #define UPB_DEF_CASTS(lower, upper, cpptype) \ UPB_INLINE const upb_##lower *upb_dyncast_##lower(const upb_def *def) { \ if (upb_def_type(def) != UPB_DEF_##upper) return NULL; \ return (upb_##lower *)def; \ } \ UPB_INLINE const upb_##lower *upb_downcast_##lower(const upb_def *def) { \ UPB_ASSERT(upb_def_type(def) == UPB_DEF_##upper); \ return (const upb_##lower *)def; \ } \ UPB_INLINE upb_##lower *upb_dyncast_##lower##_mutable(upb_def *def) { \ return (upb_##lower *)upb_dyncast_##lower(def); \ } \ UPB_INLINE upb_##lower *upb_downcast_##lower##_mutable(upb_def *def) { \ return (upb_##lower *)upb_downcast_##lower(def); \ } \ UPB_CPP_CASTS(lower, cpptype) #define UPB_DEFINE_DEF(cppname, lower, upper, cppmethods, members) \ UPB_DEFINE_CLASS2(cppname, upb::Def, upb::RefCounted, cppmethods, \ members) \ UPB_DEF_CASTS(lower, upper, cppname) #define UPB_DECLARE_DEF_TYPE(cppname, lower, upper) \ UPB_DECLARE_DERIVED_TYPE2(cppname, upb::Def, upb::RefCounted, \ upb_ ## lower, upb_def, upb_refcounted) \ UPB_DEF_CASTS(lower, upper, cppname) UPB_DECLARE_DEF_TYPE(upb::FieldDef, fielddef, FIELD) UPB_DECLARE_DEF_TYPE(upb::MessageDef, msgdef, MSG) UPB_DECLARE_DEF_TYPE(upb::EnumDef, enumdef, ENUM) #undef UPB_DECLARE_DEF_TYPE #undef UPB_DEF_CASTS #undef UPB_CPP_CASTS /* upb::FieldDef **************************************************************/ /* The types a field can have. Note that this list is not identical to the * types defined in descriptor.proto, which gives INT32 and SINT32 separate * types (we distinguish the two with the "integer encoding" enum below). */ typedef enum { /* Types stored in 1 byte. */ UPB_TYPE_BOOL = 1, /* Types stored in 4 bytes. */ UPB_TYPE_FLOAT = 2, UPB_TYPE_INT32 = 3, UPB_TYPE_UINT32 = 4, UPB_TYPE_ENUM = 5, /* Enum values are int32. */ /* Types stored as pointers (probably 4 or 8 bytes). */ UPB_TYPE_STRING = 6, UPB_TYPE_BYTES = 7, UPB_TYPE_MESSAGE = 8, /* Types stored as 8 bytes. */ UPB_TYPE_DOUBLE = 9, UPB_TYPE_INT64 = 10, UPB_TYPE_UINT64 = 11 } upb_fieldtype_t; /* The repeated-ness of each field; this matches descriptor.proto. */ typedef enum { UPB_LABEL_OPTIONAL = 1, UPB_LABEL_REQUIRED = 2, UPB_LABEL_REPEATED = 3 } upb_label_t; /* How integers should be encoded in serializations that offer multiple * integer encoding methods. */ typedef enum { UPB_INTFMT_VARIABLE = 1, UPB_INTFMT_FIXED = 2, UPB_INTFMT_ZIGZAG = 3 /* Only for signed types (INT32/INT64). */ } upb_intfmt_t; /* Descriptor types, as defined in descriptor.proto. */ typedef enum { UPB_DESCRIPTOR_TYPE_DOUBLE = 1, UPB_DESCRIPTOR_TYPE_FLOAT = 2, UPB_DESCRIPTOR_TYPE_INT64 = 3, UPB_DESCRIPTOR_TYPE_UINT64 = 4, UPB_DESCRIPTOR_TYPE_INT32 = 5, UPB_DESCRIPTOR_TYPE_FIXED64 = 6, UPB_DESCRIPTOR_TYPE_FIXED32 = 7, UPB_DESCRIPTOR_TYPE_BOOL = 8, UPB_DESCRIPTOR_TYPE_STRING = 9, UPB_DESCRIPTOR_TYPE_GROUP = 10, UPB_DESCRIPTOR_TYPE_MESSAGE = 11, UPB_DESCRIPTOR_TYPE_BYTES = 12, UPB_DESCRIPTOR_TYPE_UINT32 = 13, UPB_DESCRIPTOR_TYPE_ENUM = 14, UPB_DESCRIPTOR_TYPE_SFIXED32 = 15, UPB_DESCRIPTOR_TYPE_SFIXED64 = 16, UPB_DESCRIPTOR_TYPE_SINT32 = 17, UPB_DESCRIPTOR_TYPE_SINT64 = 18 } upb_descriptortype_t; typedef enum { UPB_SYNTAX_PROTO2 = 2, UPB_SYNTAX_PROTO3 = 3 } upb_syntax_t; /* Maximum field number allowed for FieldDefs. This is an inherent limit of the * protobuf wire format. */ #define UPB_MAX_FIELDNUMBER ((1 << 29) - 1) #ifdef __cplusplus /* A upb_fielddef describes a single field in a message. It is most often * found as a part of a upb_msgdef, but can also stand alone to represent * an extension. * * Its base class is upb::Def (use upb::upcast() to convert). */ class upb::FieldDef { public: typedef upb_fieldtype_t Type; typedef upb_label_t Label; typedef upb_intfmt_t IntegerFormat; typedef upb_descriptortype_t DescriptorType; /* These return true if the given value is a valid member of the enumeration. */ static bool CheckType(int32_t val); static bool CheckLabel(int32_t val); static bool CheckDescriptorType(int32_t val); static bool CheckIntegerFormat(int32_t val); /* These convert to the given enumeration; they require that the value is * valid. */ static Type ConvertType(int32_t val); static Label ConvertLabel(int32_t val); static DescriptorType ConvertDescriptorType(int32_t val); static IntegerFormat ConvertIntegerFormat(int32_t val); /* Returns NULL if memory allocation failed. */ static reffed_ptr New(); /* upb::RefCounted methods like Ref()/Unref(). */ UPB_REFCOUNTED_CPPMETHODS /* Functionality from upb::Def. */ const char* full_name() const; bool type_is_set() const; /* set_[descriptor_]type() has been called? */ Type type() const; /* Requires that type_is_set() == true. */ Label label() const; /* Defaults to UPB_LABEL_OPTIONAL. */ const char* name() const; /* NULL if uninitialized. */ uint32_t number() const; /* Returns 0 if uninitialized. */ bool is_extension() const; /* Copies the JSON name for this field into the given buffer. Returns the * actual size of the JSON name, including the NULL terminator. If the * return value is 0, the JSON name is unset. If the return value is * greater than len, the JSON name was truncated. The buffer is always * NULL-terminated if len > 0. * * The JSON name always defaults to a camelCased version of the regular * name. However if the regular name is unset, the JSON name will be unset * also. */ size_t GetJsonName(char* buf, size_t len) const; /* Convenience version of the above function which copies the JSON name * into the given string, returning false if the name is not set. */ template bool GetJsonName(T* str) { str->resize(GetJsonName(NULL, 0)); GetJsonName(&(*str)[0], str->size()); return str->size() > 0; } /* For UPB_TYPE_MESSAGE fields only where is_tag_delimited() == false, * indicates whether this field should have lazy parsing handlers that yield * the unparsed string for the submessage. * * TODO(haberman): I think we want to move this into a FieldOptions container * when we add support for custom options (the FieldOptions struct will * contain both regular FieldOptions like "lazy" *and* custom options). */ bool lazy() const; /* For non-string, non-submessage fields, this indicates whether binary * protobufs are encoded in packed or non-packed format. * * TODO(haberman): see note above about putting options like this into a * FieldOptions container. */ bool packed() const; /* An integer that can be used as an index into an array of fields for * whatever message this field belongs to. Guaranteed to be less than * f->containing_type()->field_count(). May only be accessed once the def has * been finalized. */ uint32_t index() const; /* The MessageDef to which this field belongs. * * If this field has been added to a MessageDef, that message can be retrieved * directly (this is always the case for frozen FieldDefs). * * If the field has not yet been added to a MessageDef, you can set the name * of the containing type symbolically instead. This is mostly useful for * extensions, where the extension is declared separately from the message. */ const MessageDef* containing_type() const; const char* containing_type_name(); /* The OneofDef to which this field belongs, or NULL if this field is not part * of a oneof. */ const OneofDef* containing_oneof() const; /* The field's type according to the enum in descriptor.proto. This is not * the same as UPB_TYPE_*, because it distinguishes between (for example) * INT32 and SINT32, whereas our "type" enum does not. This return of * descriptor_type() is a function of type(), integer_format(), and * is_tag_delimited(). Likewise set_descriptor_type() sets all three * appropriately. */ DescriptorType descriptor_type() const; /* Convenient field type tests. */ bool IsSubMessage() const; bool IsString() const; bool IsSequence() const; bool IsPrimitive() const; bool IsMap() const; /* Returns whether this field explicitly represents presence. * * For proto2 messages: Returns true for any scalar (non-repeated) field. * For proto3 messages: Returns true for scalar submessage or oneof fields. */ bool HasPresence() const; /* How integers are encoded. Only meaningful for integer types. * Defaults to UPB_INTFMT_VARIABLE, and is reset when "type" changes. */ IntegerFormat integer_format() const; /* Whether a submessage field is tag-delimited or not (if false, then * length-delimited). May only be set when type() == UPB_TYPE_MESSAGE. */ bool is_tag_delimited() const; /* Returns the non-string default value for this fielddef, which may either * be something the client set explicitly or the "default default" (0 for * numbers, empty for strings). The field's type indicates the type of the * returned value, except for enum fields that are still mutable. * * Requires that the given function matches the field's current type. */ int64_t default_int64() const; int32_t default_int32() const; uint64_t default_uint64() const; uint32_t default_uint32() const; bool default_bool() const; float default_float() const; double default_double() const; /* The resulting string is always NULL-terminated. If non-NULL, the length * will be stored in *len. */ const char *default_string(size_t* len) const; /* For frozen UPB_TYPE_ENUM fields, enum defaults can always be read as either * string or int32, and both of these methods will always return true. * * For mutable UPB_TYPE_ENUM fields, the story is a bit more complicated. * Enum defaults are unusual. They can be specified either as string or int32, * but to be valid the enum must have that value as a member. And if no * default is specified, the "default default" comes from the EnumDef. * * We allow reading the default as either an int32 or a string, but only if * we have a meaningful value to report. We have a meaningful value if it was * set explicitly, or if we could get the "default default" from the EnumDef. * Also if you explicitly set the name and we find the number in the EnumDef */ bool EnumHasStringDefault() const; bool EnumHasInt32Default() const; /* Submessage and enum fields must reference a "subdef", which is the * upb::MessageDef or upb::EnumDef that defines their type. Note that when * the FieldDef is mutable it may not have a subdef *yet*, but this function * still returns true to indicate that the field's type requires a subdef. */ bool HasSubDef() const; /* Returns the enum or submessage def for this field, if any. The field's * type must match (ie. you may only call enum_subdef() for fields where * type() == UPB_TYPE_ENUM). Returns NULL if the subdef has not been set or * is currently set symbolically. */ const EnumDef* enum_subdef() const; const MessageDef* message_subdef() const; /* Returns the generic subdef for this field. Requires that HasSubDef() (ie. * only works for UPB_TYPE_ENUM and UPB_TYPE_MESSAGE fields). */ const Def* subdef() const; /* Returns the symbolic name of the subdef. If the subdef is currently set * unresolved (ie. set symbolically) returns the symbolic name. If it has * been resolved to a specific subdef, returns the name from that subdef. */ const char* subdef_name() const; /* Setters (non-const methods), only valid for mutable FieldDefs! ***********/ bool set_full_name(const char* fullname, upb::Status* s); bool set_full_name(const std::string& fullname, upb::Status* s); /* This may only be called if containing_type() == NULL (ie. the field has not * been added to a message yet). */ bool set_containing_type_name(const char *name, Status* status); bool set_containing_type_name(const std::string& name, Status* status); /* Defaults to false. When we freeze, we ensure that this can only be true * for length-delimited message fields. Prior to freezing this can be true or * false with no restrictions. */ void set_lazy(bool lazy); /* Defaults to true. Sets whether this field is encoded in packed format. */ void set_packed(bool packed); /* "type" or "descriptor_type" MUST be set explicitly before the fielddef is * finalized. These setters require that the enum value is valid; if the * value did not come directly from an enum constant, the caller should * validate it first with the functions above (CheckFieldType(), etc). */ void set_type(Type type); void set_label(Label label); void set_descriptor_type(DescriptorType type); void set_is_extension(bool is_extension); /* "number" and "name" must be set before the FieldDef is added to a * MessageDef, and may not be set after that. * * "name" is the same as full_name()/set_full_name(), but since fielddefs * most often use simple, non-qualified names, we provide this accessor * also. Generally only extensions will want to think of this name as * fully-qualified. */ bool set_number(uint32_t number, upb::Status* s); bool set_name(const char* name, upb::Status* s); bool set_name(const std::string& name, upb::Status* s); /* Sets the JSON name to the given string. */ /* TODO(haberman): implement. Right now only default json_name (camelCase) * is supported. */ bool set_json_name(const char* json_name, upb::Status* s); bool set_json_name(const std::string& name, upb::Status* s); /* Clears the JSON name. This will make it revert to its default, which is * a camelCased version of the regular field name. */ void clear_json_name(); void set_integer_format(IntegerFormat format); bool set_tag_delimited(bool tag_delimited, upb::Status* s); /* Sets default value for the field. The call must exactly match the type * of the field. Enum fields may use either setint32 or setstring to set * the default numerically or symbolically, respectively, but symbolic * defaults must be resolved before finalizing (see ResolveEnumDefault()). * * Changing the type of a field will reset its default. */ void set_default_int64(int64_t val); void set_default_int32(int32_t val); void set_default_uint64(uint64_t val); void set_default_uint32(uint32_t val); void set_default_bool(bool val); void set_default_float(float val); void set_default_double(double val); bool set_default_string(const void *str, size_t len, Status *s); bool set_default_string(const std::string &str, Status *s); void set_default_cstr(const char *str, Status *s); /* Before a fielddef is frozen, its subdef may be set either directly (with a * upb::Def*) or symbolically. Symbolic refs must be resolved before the * containing msgdef can be frozen (see upb_resolve() above). upb always * guarantees that any def reachable from a live def will also be kept alive. * * Both methods require that upb_hassubdef(f) (so the type must be set prior * to calling these methods). Returns false if this is not the case, or if * the given subdef is not of the correct type. The subdef is reset if the * field's type is changed. The subdef can be set to NULL to clear it. */ bool set_subdef(const Def* subdef, Status* s); bool set_enum_subdef(const EnumDef* subdef, Status* s); bool set_message_subdef(const MessageDef* subdef, Status* s); bool set_subdef_name(const char* name, Status* s); bool set_subdef_name(const std::string &name, Status* s); private: UPB_DISALLOW_POD_OPS(FieldDef, upb::FieldDef) }; # endif /* defined(__cplusplus) */ UPB_BEGIN_EXTERN_C /* Native C API. */ upb_fielddef *upb_fielddef_new(const void *owner); /* Include upb_refcounted methods like upb_fielddef_ref(). */ UPB_REFCOUNTED_CMETHODS(upb_fielddef, upb_fielddef_upcast2) /* Methods from upb_def. */ const char *upb_fielddef_fullname(const upb_fielddef *f); bool upb_fielddef_setfullname(upb_fielddef *f, const char *fullname, upb_status *s); bool upb_fielddef_typeisset(const upb_fielddef *f); upb_fieldtype_t upb_fielddef_type(const upb_fielddef *f); upb_descriptortype_t upb_fielddef_descriptortype(const upb_fielddef *f); upb_label_t upb_fielddef_label(const upb_fielddef *f); uint32_t upb_fielddef_number(const upb_fielddef *f); const char *upb_fielddef_name(const upb_fielddef *f); bool upb_fielddef_isextension(const upb_fielddef *f); bool upb_fielddef_lazy(const upb_fielddef *f); bool upb_fielddef_packed(const upb_fielddef *f); size_t upb_fielddef_getjsonname(const upb_fielddef *f, char *buf, size_t len); const upb_msgdef *upb_fielddef_containingtype(const upb_fielddef *f); const upb_oneofdef *upb_fielddef_containingoneof(const upb_fielddef *f); upb_msgdef *upb_fielddef_containingtype_mutable(upb_fielddef *f); const char *upb_fielddef_containingtypename(upb_fielddef *f); upb_intfmt_t upb_fielddef_intfmt(const upb_fielddef *f); uint32_t upb_fielddef_index(const upb_fielddef *f); bool upb_fielddef_istagdelim(const upb_fielddef *f); bool upb_fielddef_issubmsg(const upb_fielddef *f); bool upb_fielddef_isstring(const upb_fielddef *f); bool upb_fielddef_isseq(const upb_fielddef *f); bool upb_fielddef_isprimitive(const upb_fielddef *f); bool upb_fielddef_ismap(const upb_fielddef *f); bool upb_fielddef_haspresence(const upb_fielddef *f); int64_t upb_fielddef_defaultint64(const upb_fielddef *f); int32_t upb_fielddef_defaultint32(const upb_fielddef *f); uint64_t upb_fielddef_defaultuint64(const upb_fielddef *f); uint32_t upb_fielddef_defaultuint32(const upb_fielddef *f); bool upb_fielddef_defaultbool(const upb_fielddef *f); float upb_fielddef_defaultfloat(const upb_fielddef *f); double upb_fielddef_defaultdouble(const upb_fielddef *f); const char *upb_fielddef_defaultstr(const upb_fielddef *f, size_t *len); bool upb_fielddef_enumhasdefaultint32(const upb_fielddef *f); bool upb_fielddef_enumhasdefaultstr(const upb_fielddef *f); bool upb_fielddef_hassubdef(const upb_fielddef *f); const upb_def *upb_fielddef_subdef(const upb_fielddef *f); const upb_msgdef *upb_fielddef_msgsubdef(const upb_fielddef *f); const upb_enumdef *upb_fielddef_enumsubdef(const upb_fielddef *f); const char *upb_fielddef_subdefname(const upb_fielddef *f); void upb_fielddef_settype(upb_fielddef *f, upb_fieldtype_t type); void upb_fielddef_setdescriptortype(upb_fielddef *f, int type); void upb_fielddef_setlabel(upb_fielddef *f, upb_label_t label); bool upb_fielddef_setnumber(upb_fielddef *f, uint32_t number, upb_status *s); bool upb_fielddef_setname(upb_fielddef *f, const char *name, upb_status *s); bool upb_fielddef_setjsonname(upb_fielddef *f, const char *name, upb_status *s); bool upb_fielddef_clearjsonname(upb_fielddef *f); bool upb_fielddef_setcontainingtypename(upb_fielddef *f, const char *name, upb_status *s); void upb_fielddef_setisextension(upb_fielddef *f, bool is_extension); void upb_fielddef_setlazy(upb_fielddef *f, bool lazy); void upb_fielddef_setpacked(upb_fielddef *f, bool packed); void upb_fielddef_setintfmt(upb_fielddef *f, upb_intfmt_t fmt); void upb_fielddef_settagdelim(upb_fielddef *f, bool tag_delim); void upb_fielddef_setdefaultint64(upb_fielddef *f, int64_t val); void upb_fielddef_setdefaultint32(upb_fielddef *f, int32_t val); void upb_fielddef_setdefaultuint64(upb_fielddef *f, uint64_t val); void upb_fielddef_setdefaultuint32(upb_fielddef *f, uint32_t val); void upb_fielddef_setdefaultbool(upb_fielddef *f, bool val); void upb_fielddef_setdefaultfloat(upb_fielddef *f, float val); void upb_fielddef_setdefaultdouble(upb_fielddef *f, double val); bool upb_fielddef_setdefaultstr(upb_fielddef *f, const void *str, size_t len, upb_status *s); void upb_fielddef_setdefaultcstr(upb_fielddef *f, const char *str, upb_status *s); bool upb_fielddef_setsubdef(upb_fielddef *f, const upb_def *subdef, upb_status *s); bool upb_fielddef_setmsgsubdef(upb_fielddef *f, const upb_msgdef *subdef, upb_status *s); bool upb_fielddef_setenumsubdef(upb_fielddef *f, const upb_enumdef *subdef, upb_status *s); bool upb_fielddef_setsubdefname(upb_fielddef *f, const char *name, upb_status *s); bool upb_fielddef_checklabel(int32_t label); bool upb_fielddef_checktype(int32_t type); bool upb_fielddef_checkdescriptortype(int32_t type); bool upb_fielddef_checkintfmt(int32_t fmt); UPB_END_EXTERN_C /* upb::MessageDef ************************************************************/ typedef upb_inttable_iter upb_msg_field_iter; typedef upb_strtable_iter upb_msg_oneof_iter; /* Well-known field tag numbers for map-entry messages. */ #define UPB_MAPENTRY_KEY 1 #define UPB_MAPENTRY_VALUE 2 #ifdef __cplusplus /* Structure that describes a single .proto message type. * * Its base class is upb::Def (use upb::upcast() to convert). */ class upb::MessageDef { public: /* Returns NULL if memory allocation failed. */ static reffed_ptr New(); /* upb::RefCounted methods like Ref()/Unref(). */ UPB_REFCOUNTED_CPPMETHODS /* Functionality from upb::Def. */ const char* full_name() const; const char* name() const; bool set_full_name(const char* fullname, Status* s); bool set_full_name(const std::string& fullname, Status* s); /* Call to freeze this MessageDef. * WARNING: this will fail if this message has any unfrozen submessages! * Messages with cycles must be frozen as a batch using upb::Def::Freeze(). */ bool Freeze(Status* s); /* The number of fields that belong to the MessageDef. */ int field_count() const; /* The number of oneofs that belong to the MessageDef. */ int oneof_count() const; /* Adds a field (upb_fielddef object) to a msgdef. Requires that the msgdef * and the fielddefs are mutable. The fielddef's name and number must be * set, and the message may not already contain any field with this name or * number, and this fielddef may not be part of another message. In error * cases false is returned and the msgdef is unchanged. * * If the given field is part of a oneof, this call succeeds if and only if * that oneof is already part of this msgdef. (Note that adding a oneof to a * msgdef automatically adds all of its fields to the msgdef at the time that * the oneof is added, so it is usually more idiomatic to add the oneof's * fields first then add the oneof to the msgdef. This case is supported for * convenience.) * * If |f| is already part of this MessageDef, this method performs no action * and returns true (success). Thus, this method is idempotent. */ bool AddField(FieldDef* f, Status* s); bool AddField(const reffed_ptr& f, Status* s); /* Adds a oneof (upb_oneofdef object) to a msgdef. Requires that the msgdef, * oneof, and any fielddefs are mutable, that the fielddefs contained in the * oneof do not have any name or number conflicts with existing fields in the * msgdef, and that the oneof's name is unique among all oneofs in the msgdef. * If the oneof is added successfully, all of its fields will be added * directly to the msgdef as well. In error cases, false is returned and the * msgdef is unchanged. */ bool AddOneof(OneofDef* o, Status* s); bool AddOneof(const reffed_ptr& o, Status* s); upb_syntax_t syntax() const; /* Returns false if we don't support this syntax value. */ bool set_syntax(upb_syntax_t syntax); /* Set this to false to indicate that primitive fields should not have * explicit presence information associated with them. This will affect all * fields added to this message. Defaults to true. */ void SetPrimitivesHavePresence(bool have_presence); /* These return NULL if the field is not found. */ FieldDef* FindFieldByNumber(uint32_t number); FieldDef* FindFieldByName(const char *name, size_t len); const FieldDef* FindFieldByNumber(uint32_t number) const; const FieldDef* FindFieldByName(const char* name, size_t len) const; FieldDef* FindFieldByName(const char *name) { return FindFieldByName(name, strlen(name)); } const FieldDef* FindFieldByName(const char *name) const { return FindFieldByName(name, strlen(name)); } template FieldDef* FindFieldByName(const T& str) { return FindFieldByName(str.c_str(), str.size()); } template const FieldDef* FindFieldByName(const T& str) const { return FindFieldByName(str.c_str(), str.size()); } OneofDef* FindOneofByName(const char* name, size_t len); const OneofDef* FindOneofByName(const char* name, size_t len) const; OneofDef* FindOneofByName(const char* name) { return FindOneofByName(name, strlen(name)); } const OneofDef* FindOneofByName(const char* name) const { return FindOneofByName(name, strlen(name)); } template OneofDef* FindOneofByName(const T& str) { return FindOneofByName(str.c_str(), str.size()); } template const OneofDef* FindOneofByName(const T& str) const { return FindOneofByName(str.c_str(), str.size()); } /* Is this message a map entry? */ void setmapentry(bool map_entry); bool mapentry() const; /* Iteration over fields. The order is undefined. */ class field_iterator : public std::iterator { public: explicit field_iterator(MessageDef* md); static field_iterator end(MessageDef* md); void operator++(); FieldDef* operator*() const; bool operator!=(const field_iterator& other) const; bool operator==(const field_iterator& other) const; private: upb_msg_field_iter iter_; }; class const_field_iterator : public std::iterator { public: explicit const_field_iterator(const MessageDef* md); static const_field_iterator end(const MessageDef* md); void operator++(); const FieldDef* operator*() const; bool operator!=(const const_field_iterator& other) const; bool operator==(const const_field_iterator& other) const; private: upb_msg_field_iter iter_; }; /* Iteration over oneofs. The order is undefined. */ class oneof_iterator : public std::iterator { public: explicit oneof_iterator(MessageDef* md); static oneof_iterator end(MessageDef* md); void operator++(); OneofDef* operator*() const; bool operator!=(const oneof_iterator& other) const; bool operator==(const oneof_iterator& other) const; private: upb_msg_oneof_iter iter_; }; class const_oneof_iterator : public std::iterator { public: explicit const_oneof_iterator(const MessageDef* md); static const_oneof_iterator end(const MessageDef* md); void operator++(); const OneofDef* operator*() const; bool operator!=(const const_oneof_iterator& other) const; bool operator==(const const_oneof_iterator& other) const; private: upb_msg_oneof_iter iter_; }; class FieldAccessor { public: explicit FieldAccessor(MessageDef* msg) : msg_(msg) {} field_iterator begin() { return msg_->field_begin(); } field_iterator end() { return msg_->field_end(); } private: MessageDef* msg_; }; class ConstFieldAccessor { public: explicit ConstFieldAccessor(const MessageDef* msg) : msg_(msg) {} const_field_iterator begin() { return msg_->field_begin(); } const_field_iterator end() { return msg_->field_end(); } private: const MessageDef* msg_; }; class OneofAccessor { public: explicit OneofAccessor(MessageDef* msg) : msg_(msg) {} oneof_iterator begin() { return msg_->oneof_begin(); } oneof_iterator end() { return msg_->oneof_end(); } private: MessageDef* msg_; }; class ConstOneofAccessor { public: explicit ConstOneofAccessor(const MessageDef* msg) : msg_(msg) {} const_oneof_iterator begin() { return msg_->oneof_begin(); } const_oneof_iterator end() { return msg_->oneof_end(); } private: const MessageDef* msg_; }; field_iterator field_begin(); field_iterator field_end(); const_field_iterator field_begin() const; const_field_iterator field_end() const; oneof_iterator oneof_begin(); oneof_iterator oneof_end(); const_oneof_iterator oneof_begin() const; const_oneof_iterator oneof_end() const; FieldAccessor fields() { return FieldAccessor(this); } ConstFieldAccessor fields() const { return ConstFieldAccessor(this); } OneofAccessor oneofs() { return OneofAccessor(this); } ConstOneofAccessor oneofs() const { return ConstOneofAccessor(this); } private: UPB_DISALLOW_POD_OPS(MessageDef, upb::MessageDef) }; #endif /* __cplusplus */ UPB_BEGIN_EXTERN_C /* Returns NULL if memory allocation failed. */ upb_msgdef *upb_msgdef_new(const void *owner); /* Include upb_refcounted methods like upb_msgdef_ref(). */ UPB_REFCOUNTED_CMETHODS(upb_msgdef, upb_msgdef_upcast2) bool upb_msgdef_freeze(upb_msgdef *m, upb_status *status); const char *upb_msgdef_fullname(const upb_msgdef *m); const char *upb_msgdef_name(const upb_msgdef *m); int upb_msgdef_numoneofs(const upb_msgdef *m); upb_syntax_t upb_msgdef_syntax(const upb_msgdef *m); bool upb_msgdef_addfield(upb_msgdef *m, upb_fielddef *f, const void *ref_donor, upb_status *s); bool upb_msgdef_addoneof(upb_msgdef *m, upb_oneofdef *o, const void *ref_donor, upb_status *s); bool upb_msgdef_setfullname(upb_msgdef *m, const char *fullname, upb_status *s); void upb_msgdef_setmapentry(upb_msgdef *m, bool map_entry); bool upb_msgdef_mapentry(const upb_msgdef *m); bool upb_msgdef_setsyntax(upb_msgdef *m, upb_syntax_t syntax); /* Field lookup in a couple of different variations: * - itof = int to field * - ntof = name to field * - ntofz = name to field, null-terminated string. */ const upb_fielddef *upb_msgdef_itof(const upb_msgdef *m, uint32_t i); const upb_fielddef *upb_msgdef_ntof(const upb_msgdef *m, const char *name, size_t len); int upb_msgdef_numfields(const upb_msgdef *m); UPB_INLINE const upb_fielddef *upb_msgdef_ntofz(const upb_msgdef *m, const char *name) { return upb_msgdef_ntof(m, name, strlen(name)); } UPB_INLINE upb_fielddef *upb_msgdef_itof_mutable(upb_msgdef *m, uint32_t i) { return (upb_fielddef*)upb_msgdef_itof(m, i); } UPB_INLINE upb_fielddef *upb_msgdef_ntof_mutable(upb_msgdef *m, const char *name, size_t len) { return (upb_fielddef *)upb_msgdef_ntof(m, name, len); } /* Oneof lookup: * - ntoo = name to oneof * - ntooz = name to oneof, null-terminated string. */ const upb_oneofdef *upb_msgdef_ntoo(const upb_msgdef *m, const char *name, size_t len); int upb_msgdef_numoneofs(const upb_msgdef *m); UPB_INLINE const upb_oneofdef *upb_msgdef_ntooz(const upb_msgdef *m, const char *name) { return upb_msgdef_ntoo(m, name, strlen(name)); } UPB_INLINE upb_oneofdef *upb_msgdef_ntoo_mutable(upb_msgdef *m, const char *name, size_t len) { return (upb_oneofdef *)upb_msgdef_ntoo(m, name, len); } /* Lookup of either field or oneof by name. Returns whether either was found. * If the return is true, then the found def will be set, and the non-found * one set to NULL. */ bool upb_msgdef_lookupname(const upb_msgdef *m, const char *name, size_t len, const upb_fielddef **f, const upb_oneofdef **o); UPB_INLINE bool upb_msgdef_lookupnamez(const upb_msgdef *m, const char *name, const upb_fielddef **f, const upb_oneofdef **o) { return upb_msgdef_lookupname(m, name, strlen(name), f, o); } /* Iteration over fields and oneofs. For example: * * upb_msg_field_iter i; * for(upb_msg_field_begin(&i, m); * !upb_msg_field_done(&i); * upb_msg_field_next(&i)) { * upb_fielddef *f = upb_msg_iter_field(&i); * // ... * } * * For C we don't have separate iterators for const and non-const. * It is the caller's responsibility to cast the upb_fielddef* to * const if the upb_msgdef* is const. */ void upb_msg_field_begin(upb_msg_field_iter *iter, const upb_msgdef *m); void upb_msg_field_next(upb_msg_field_iter *iter); bool upb_msg_field_done(const upb_msg_field_iter *iter); upb_fielddef *upb_msg_iter_field(const upb_msg_field_iter *iter); void upb_msg_field_iter_setdone(upb_msg_field_iter *iter); /* Similar to above, we also support iterating through the oneofs in a * msgdef. */ void upb_msg_oneof_begin(upb_msg_oneof_iter *iter, const upb_msgdef *m); void upb_msg_oneof_next(upb_msg_oneof_iter *iter); bool upb_msg_oneof_done(const upb_msg_oneof_iter *iter); upb_oneofdef *upb_msg_iter_oneof(const upb_msg_oneof_iter *iter); void upb_msg_oneof_iter_setdone(upb_msg_oneof_iter *iter); UPB_END_EXTERN_C /* upb::EnumDef ***************************************************************/ typedef upb_strtable_iter upb_enum_iter; #ifdef __cplusplus /* Class that represents an enum. Its base class is upb::Def (convert with * upb::upcast()). */ class upb::EnumDef { public: /* Returns NULL if memory allocation failed. */ static reffed_ptr New(); /* upb::RefCounted methods like Ref()/Unref(). */ UPB_REFCOUNTED_CPPMETHODS /* Functionality from upb::Def. */ const char* full_name() const; const char* name() const; bool set_full_name(const char* fullname, Status* s); bool set_full_name(const std::string& fullname, Status* s); /* Call to freeze this EnumDef. */ bool Freeze(Status* s); /* The value that is used as the default when no field default is specified. * If not set explicitly, the first value that was added will be used. * The default value must be a member of the enum. * Requires that value_count() > 0. */ int32_t default_value() const; /* Sets the default value. If this value is not valid, returns false and an * error message in status. */ bool set_default_value(int32_t val, Status* status); /* Returns the number of values currently defined in the enum. Note that * multiple names can refer to the same number, so this may be greater than * the total number of unique numbers. */ int value_count() const; /* Adds a single name/number pair to the enum. Fails if this name has * already been used by another value. */ bool AddValue(const char* name, int32_t num, Status* status); bool AddValue(const std::string& name, int32_t num, Status* status); /* Lookups from name to integer, returning true if found. */ bool FindValueByName(const char* name, int32_t* num) const; /* Finds the name corresponding to the given number, or NULL if none was * found. If more than one name corresponds to this number, returns the * first one that was added. */ const char* FindValueByNumber(int32_t num) const; /* Iteration over name/value pairs. The order is undefined. * Adding an enum val invalidates any iterators. * * TODO: make compatible with range-for, with elements as pairs? */ class Iterator { public: explicit Iterator(const EnumDef*); int32_t number(); const char *name(); bool Done(); void Next(); private: upb_enum_iter iter_; }; private: UPB_DISALLOW_POD_OPS(EnumDef, upb::EnumDef) }; #endif /* __cplusplus */ UPB_BEGIN_EXTERN_C /* Native C API. */ upb_enumdef *upb_enumdef_new(const void *owner); /* Include upb_refcounted methods like upb_enumdef_ref(). */ UPB_REFCOUNTED_CMETHODS(upb_enumdef, upb_enumdef_upcast2) bool upb_enumdef_freeze(upb_enumdef *e, upb_status *status); /* From upb_def. */ const char *upb_enumdef_fullname(const upb_enumdef *e); const char *upb_enumdef_name(const upb_enumdef *e); bool upb_enumdef_setfullname(upb_enumdef *e, const char *fullname, upb_status *s); int32_t upb_enumdef_default(const upb_enumdef *e); bool upb_enumdef_setdefault(upb_enumdef *e, int32_t val, upb_status *s); int upb_enumdef_numvals(const upb_enumdef *e); bool upb_enumdef_addval(upb_enumdef *e, const char *name, int32_t num, upb_status *status); /* Enum lookups: * - ntoi: look up a name with specified length. * - ntoiz: look up a name provided as a null-terminated string. * - iton: look up an integer, returning the name as a null-terminated * string. */ bool upb_enumdef_ntoi(const upb_enumdef *e, const char *name, size_t len, int32_t *num); UPB_INLINE bool upb_enumdef_ntoiz(const upb_enumdef *e, const char *name, int32_t *num) { return upb_enumdef_ntoi(e, name, strlen(name), num); } const char *upb_enumdef_iton(const upb_enumdef *e, int32_t num); /* upb_enum_iter i; * for(upb_enum_begin(&i, e); !upb_enum_done(&i); upb_enum_next(&i)) { * // ... * } */ void upb_enum_begin(upb_enum_iter *iter, const upb_enumdef *e); void upb_enum_next(upb_enum_iter *iter); bool upb_enum_done(upb_enum_iter *iter); const char *upb_enum_iter_name(upb_enum_iter *iter); int32_t upb_enum_iter_number(upb_enum_iter *iter); UPB_END_EXTERN_C /* upb::OneofDef **************************************************************/ typedef upb_inttable_iter upb_oneof_iter; #ifdef __cplusplus /* Class that represents a oneof. */ class upb::OneofDef { public: /* Returns NULL if memory allocation failed. */ static reffed_ptr New(); /* upb::RefCounted methods like Ref()/Unref(). */ UPB_REFCOUNTED_CPPMETHODS /* Returns the MessageDef that owns this OneofDef. */ const MessageDef* containing_type() const; /* Returns the name of this oneof. This is the name used to look up the oneof * by name once added to a message def. */ const char* name() const; bool set_name(const char* name, Status* s); bool set_name(const std::string& name, Status* s); /* Returns the number of fields currently defined in the oneof. */ int field_count() const; /* Adds a field to the oneof. The field must not have been added to any other * oneof or msgdef. If the oneof is not yet part of a msgdef, then when the * oneof is eventually added to a msgdef, all fields added to the oneof will * also be added to the msgdef at that time. If the oneof is already part of a * msgdef, the field must either be a part of that msgdef already, or must not * be a part of any msgdef; in the latter case, the field is added to the * msgdef as a part of this operation. * * The field may only have an OPTIONAL label, never REQUIRED or REPEATED. * * If |f| is already part of this MessageDef, this method performs no action * and returns true (success). Thus, this method is idempotent. */ bool AddField(FieldDef* field, Status* s); bool AddField(const reffed_ptr& field, Status* s); /* Looks up by name. */ const FieldDef* FindFieldByName(const char* name, size_t len) const; FieldDef* FindFieldByName(const char* name, size_t len); const FieldDef* FindFieldByName(const char* name) const { return FindFieldByName(name, strlen(name)); } FieldDef* FindFieldByName(const char* name) { return FindFieldByName(name, strlen(name)); } template FieldDef* FindFieldByName(const T& str) { return FindFieldByName(str.c_str(), str.size()); } template const FieldDef* FindFieldByName(const T& str) const { return FindFieldByName(str.c_str(), str.size()); } /* Looks up by tag number. */ const FieldDef* FindFieldByNumber(uint32_t num) const; /* Iteration over fields. The order is undefined. */ class iterator : public std::iterator { public: explicit iterator(OneofDef* md); static iterator end(OneofDef* md); void operator++(); FieldDef* operator*() const; bool operator!=(const iterator& other) const; bool operator==(const iterator& other) const; private: upb_oneof_iter iter_; }; class const_iterator : public std::iterator { public: explicit const_iterator(const OneofDef* md); static const_iterator end(const OneofDef* md); void operator++(); const FieldDef* operator*() const; bool operator!=(const const_iterator& other) const; bool operator==(const const_iterator& other) const; private: upb_oneof_iter iter_; }; iterator begin(); iterator end(); const_iterator begin() const; const_iterator end() const; private: UPB_DISALLOW_POD_OPS(OneofDef, upb::OneofDef) }; #endif /* __cplusplus */ UPB_BEGIN_EXTERN_C /* Native C API. */ upb_oneofdef *upb_oneofdef_new(const void *owner); /* Include upb_refcounted methods like upb_oneofdef_ref(). */ UPB_REFCOUNTED_CMETHODS(upb_oneofdef, upb_oneofdef_upcast) const char *upb_oneofdef_name(const upb_oneofdef *o); const upb_msgdef *upb_oneofdef_containingtype(const upb_oneofdef *o); int upb_oneofdef_numfields(const upb_oneofdef *o); uint32_t upb_oneofdef_index(const upb_oneofdef *o); bool upb_oneofdef_setname(upb_oneofdef *o, const char *name, upb_status *s); bool upb_oneofdef_addfield(upb_oneofdef *o, upb_fielddef *f, const void *ref_donor, upb_status *s); /* Oneof lookups: * - ntof: look up a field by name. * - ntofz: look up a field by name (as a null-terminated string). * - itof: look up a field by number. */ const upb_fielddef *upb_oneofdef_ntof(const upb_oneofdef *o, const char *name, size_t length); UPB_INLINE const upb_fielddef *upb_oneofdef_ntofz(const upb_oneofdef *o, const char *name) { return upb_oneofdef_ntof(o, name, strlen(name)); } const upb_fielddef *upb_oneofdef_itof(const upb_oneofdef *o, uint32_t num); /* upb_oneof_iter i; * for(upb_oneof_begin(&i, e); !upb_oneof_done(&i); upb_oneof_next(&i)) { * // ... * } */ void upb_oneof_begin(upb_oneof_iter *iter, const upb_oneofdef *o); void upb_oneof_next(upb_oneof_iter *iter); bool upb_oneof_done(upb_oneof_iter *iter); upb_fielddef *upb_oneof_iter_field(const upb_oneof_iter *iter); void upb_oneof_iter_setdone(upb_oneof_iter *iter); UPB_END_EXTERN_C /* upb::FileDef ***************************************************************/ #ifdef __cplusplus /* Class that represents a .proto file with some things defined in it. * * Many users won't care about FileDefs, but they are necessary if you want to * read the values of file-level options. */ class upb::FileDef { public: /* Returns NULL if memory allocation failed. */ static reffed_ptr New(); /* upb::RefCounted methods like Ref()/Unref(). */ UPB_REFCOUNTED_CPPMETHODS /* Get/set name of the file (eg. "foo/bar.proto"). */ const char* name() const; bool set_name(const char* name, Status* s); bool set_name(const std::string& name, Status* s); /* Package name for definitions inside the file (eg. "foo.bar"). */ const char* package() const; bool set_package(const char* package, Status* s); /* Syntax for the file. Defaults to proto2. */ upb_syntax_t syntax() const; void set_syntax(upb_syntax_t syntax); /* Get the list of defs from the file. These are returned in the order that * they were added to the FileDef. */ int def_count() const; const Def* def(int index) const; Def* def(int index); /* Get the list of dependencies from the file. These are returned in the * order that they were added to the FileDef. */ int dependency_count() const; const FileDef* dependency(int index) const; /* Adds defs to this file. The def must not already belong to another * file. * * Note: this does *not* ensure that this def's name is unique in this file! * Use a SymbolTable if you want to check this property. Especially since * properly checking uniqueness would require a check across *all* files * (including dependencies). */ bool AddDef(Def* def, Status* s); bool AddMessage(MessageDef* m, Status* s); bool AddEnum(EnumDef* e, Status* s); bool AddExtension(FieldDef* f, Status* s); /* Adds a dependency of this file. */ bool AddDependency(const FileDef* file); /* Freezes this FileDef and all messages/enums under it. All subdefs must be * resolved and all messages/enums must validate. Returns true if this * succeeded. * * TODO(haberman): should we care whether the file's dependencies are frozen * already? */ bool Freeze(Status* s); private: UPB_DISALLOW_POD_OPS(FileDef, upb::FileDef) }; #endif UPB_BEGIN_EXTERN_C upb_filedef *upb_filedef_new(const void *owner); /* Include upb_refcounted methods like upb_msgdef_ref(). */ UPB_REFCOUNTED_CMETHODS(upb_filedef, upb_filedef_upcast) const char *upb_filedef_name(const upb_filedef *f); const char *upb_filedef_package(const upb_filedef *f); upb_syntax_t upb_filedef_syntax(const upb_filedef *f); size_t upb_filedef_defcount(const upb_filedef *f); size_t upb_filedef_depcount(const upb_filedef *f); const upb_def *upb_filedef_def(const upb_filedef *f, size_t i); const upb_filedef *upb_filedef_dep(const upb_filedef *f, size_t i); bool upb_filedef_freeze(upb_filedef *f, upb_status *s); bool upb_filedef_setname(upb_filedef *f, const char *name, upb_status *s); bool upb_filedef_setpackage(upb_filedef *f, const char *package, upb_status *s); bool upb_filedef_setsyntax(upb_filedef *f, upb_syntax_t syntax, upb_status *s); bool upb_filedef_adddef(upb_filedef *f, upb_def *def, const void *ref_donor, upb_status *s); bool upb_filedef_adddep(upb_filedef *f, const upb_filedef *dep); UPB_INLINE bool upb_filedef_addmsg(upb_filedef *f, upb_msgdef *m, const void *ref_donor, upb_status *s) { return upb_filedef_adddef(f, upb_msgdef_upcast_mutable(m), ref_donor, s); } UPB_INLINE bool upb_filedef_addenum(upb_filedef *f, upb_enumdef *e, const void *ref_donor, upb_status *s) { return upb_filedef_adddef(f, upb_enumdef_upcast_mutable(e), ref_donor, s); } UPB_INLINE bool upb_filedef_addext(upb_filedef *file, upb_fielddef *f, const void *ref_donor, upb_status *s) { return upb_filedef_adddef(file, upb_fielddef_upcast_mutable(f), ref_donor, s); } UPB_INLINE upb_def *upb_filedef_mutabledef(upb_filedef *f, int i) { return (upb_def*)upb_filedef_def(f, i); } UPB_END_EXTERN_C typedef struct { UPB_PRIVATE_FOR_CPP upb_strtable_iter iter; upb_deftype_t type; } upb_symtab_iter; #ifdef __cplusplus /* Non-const methods in upb::SymbolTable are NOT thread-safe. */ class upb::SymbolTable { public: /* Returns a new symbol table with a single ref owned by "owner." * Returns NULL if memory allocation failed. */ static SymbolTable* New(); static void Free(upb::SymbolTable* table); /* For all lookup functions, the returned pointer is not owned by the * caller; it may be invalidated by any non-const call or unref of the * SymbolTable! To protect against this, take a ref if desired. */ /* Freezes the symbol table: prevents further modification of it. * After the Freeze() operation is successful, the SymbolTable must only be * accessed via a const pointer. * * Unlike with upb::MessageDef/upb::EnumDef/etc, freezing a SymbolTable is not * a necessary step in using a SymbolTable. If you have no need for it to be * immutable, there is no need to freeze it ever. However sometimes it is * useful, and SymbolTables that are statically compiled into the binary are * always frozen by nature. */ void Freeze(); /* Resolves the given symbol using the rules described in descriptor.proto, * namely: * * If the name starts with a '.', it is fully-qualified. Otherwise, * C++-like scoping rules are used to find the type (i.e. first the nested * types within this message are searched, then within the parent, on up * to the root namespace). * * If not found, returns NULL. */ const Def* Resolve(const char* base, const char* sym) const; /* Finds an entry in the symbol table with this exact name. If not found, * returns NULL. */ const Def* Lookup(const char *sym) const; const MessageDef* LookupMessage(const char *sym) const; const EnumDef* LookupEnum(const char *sym) const; /* TODO: introduce a C++ iterator, but make it nice and templated so that if * you ask for an iterator of MessageDef the iterated elements are strongly * typed as MessageDef*. */ /* Adds the given mutable defs to the symtab, resolving all symbols (including * enum default values) and finalizing the defs. Only one def per name may be * in the list, and the defs may not duplicate any name already in the symtab. * All defs must have a name -- anonymous defs are not allowed. Anonymous * defs can still be frozen by calling upb_def_freeze() directly. * * The entire operation either succeeds or fails. If the operation fails, * the symtab is unchanged, false is returned, and status indicates the * error. The caller passes a ref on all defs to the symtab (even if the * operation fails). * * TODO(haberman): currently failure will leave the symtab unchanged, but may * leave the defs themselves partially resolved. Does this matter? If so we * could do a prepass that ensures that all symbols are resolvable and bail * if not, so we don't mutate anything until we know the operation will * succeed. */ bool Add(Def*const* defs, size_t n, void* ref_donor, Status* status); bool Add(const std::vector& defs, void *owner, Status* status) { return Add((Def*const*)&defs[0], defs.size(), owner, status); } /* Resolves all subdefs for messages in this file and attempts to freeze the * file. If this succeeds, adds all the symbols to this SymbolTable * (replacing any existing ones with the same names). */ bool AddFile(FileDef* file, Status* s); private: UPB_DISALLOW_POD_OPS(SymbolTable, upb::SymbolTable) }; #endif /* __cplusplus */ UPB_BEGIN_EXTERN_C /* Native C API. */ upb_symtab *upb_symtab_new(); void upb_symtab_free(upb_symtab* s); const upb_def *upb_symtab_resolve(const upb_symtab *s, const char *base, const char *sym); const upb_def *upb_symtab_lookup(const upb_symtab *s, const char *sym); const upb_msgdef *upb_symtab_lookupmsg(const upb_symtab *s, const char *sym); const upb_enumdef *upb_symtab_lookupenum(const upb_symtab *s, const char *sym); bool upb_symtab_add(upb_symtab *s, upb_def *const*defs, size_t n, void *ref_donor, upb_status *status); bool upb_symtab_addfile(upb_symtab *s, upb_filedef *file, upb_status* status); /* upb_symtab_iter i; * for(upb_symtab_begin(&i, s, type); !upb_symtab_done(&i); * upb_symtab_next(&i)) { * const upb_def *def = upb_symtab_iter_def(&i); * // ... * } * * For C we don't have separate iterators for const and non-const. * It is the caller's responsibility to cast the upb_fielddef* to * const if the upb_msgdef* is const. */ void upb_symtab_begin(upb_symtab_iter *iter, const upb_symtab *s, upb_deftype_t type); void upb_symtab_next(upb_symtab_iter *iter); bool upb_symtab_done(const upb_symtab_iter *iter); const upb_def *upb_symtab_iter_def(const upb_symtab_iter *iter); UPB_END_EXTERN_C #ifdef __cplusplus /* C++ inline wrappers. */ namespace upb { inline SymbolTable* SymbolTable::New() { return upb_symtab_new(); } inline void SymbolTable::Free(SymbolTable* s) { upb_symtab_free(s); } inline const Def *SymbolTable::Resolve(const char *base, const char *sym) const { return upb_symtab_resolve(this, base, sym); } inline const Def* SymbolTable::Lookup(const char *sym) const { return upb_symtab_lookup(this, sym); } inline const MessageDef *SymbolTable::LookupMessage(const char *sym) const { return upb_symtab_lookupmsg(this, sym); } inline bool SymbolTable::Add( Def*const* defs, size_t n, void* ref_donor, Status* status) { return upb_symtab_add(this, (upb_def*const*)defs, n, ref_donor, status); } inline bool SymbolTable::AddFile(FileDef* file, Status* s) { return upb_symtab_addfile(this, file, s); } } /* namespace upb */ #endif #ifdef __cplusplus UPB_INLINE const char* upb_safecstr(const std::string& str) { UPB_ASSERT(str.size() == std::strlen(str.c_str())); return str.c_str(); } /* Inline C++ wrappers. */ namespace upb { inline Def::Type Def::def_type() const { return upb_def_type(this); } inline const char* Def::full_name() const { return upb_def_fullname(this); } inline const char* Def::name() const { return upb_def_name(this); } inline bool Def::set_full_name(const char* fullname, Status* s) { return upb_def_setfullname(this, fullname, s); } inline bool Def::set_full_name(const std::string& fullname, Status* s) { return upb_def_setfullname(this, upb_safecstr(fullname), s); } inline bool Def::Freeze(Def* const* defs, size_t n, Status* status) { return upb_def_freeze(defs, n, status); } inline bool Def::Freeze(const std::vector& defs, Status* status) { return upb_def_freeze((Def* const*)&defs[0], defs.size(), status); } inline bool FieldDef::CheckType(int32_t val) { return upb_fielddef_checktype(val); } inline bool FieldDef::CheckLabel(int32_t val) { return upb_fielddef_checklabel(val); } inline bool FieldDef::CheckDescriptorType(int32_t val) { return upb_fielddef_checkdescriptortype(val); } inline bool FieldDef::CheckIntegerFormat(int32_t val) { return upb_fielddef_checkintfmt(val); } inline FieldDef::Type FieldDef::ConvertType(int32_t val) { UPB_ASSERT(CheckType(val)); return static_cast(val); } inline FieldDef::Label FieldDef::ConvertLabel(int32_t val) { UPB_ASSERT(CheckLabel(val)); return static_cast(val); } inline FieldDef::DescriptorType FieldDef::ConvertDescriptorType(int32_t val) { UPB_ASSERT(CheckDescriptorType(val)); return static_cast(val); } inline FieldDef::IntegerFormat FieldDef::ConvertIntegerFormat(int32_t val) { UPB_ASSERT(CheckIntegerFormat(val)); return static_cast(val); } inline reffed_ptr FieldDef::New() { upb_fielddef *f = upb_fielddef_new(&f); return reffed_ptr(f, &f); } inline const char* FieldDef::full_name() const { return upb_fielddef_fullname(this); } inline bool FieldDef::set_full_name(const char* fullname, Status* s) { return upb_fielddef_setfullname(this, fullname, s); } inline bool FieldDef::set_full_name(const std::string& fullname, Status* s) { return upb_fielddef_setfullname(this, upb_safecstr(fullname), s); } inline bool FieldDef::type_is_set() const { return upb_fielddef_typeisset(this); } inline FieldDef::Type FieldDef::type() const { return upb_fielddef_type(this); } inline FieldDef::DescriptorType FieldDef::descriptor_type() const { return upb_fielddef_descriptortype(this); } inline FieldDef::Label FieldDef::label() const { return upb_fielddef_label(this); } inline uint32_t FieldDef::number() const { return upb_fielddef_number(this); } inline const char* FieldDef::name() const { return upb_fielddef_name(this); } inline bool FieldDef::is_extension() const { return upb_fielddef_isextension(this); } inline size_t FieldDef::GetJsonName(char* buf, size_t len) const { return upb_fielddef_getjsonname(this, buf, len); } inline bool FieldDef::lazy() const { return upb_fielddef_lazy(this); } inline void FieldDef::set_lazy(bool lazy) { upb_fielddef_setlazy(this, lazy); } inline bool FieldDef::packed() const { return upb_fielddef_packed(this); } inline uint32_t FieldDef::index() const { return upb_fielddef_index(this); } inline void FieldDef::set_packed(bool packed) { upb_fielddef_setpacked(this, packed); } inline const MessageDef* FieldDef::containing_type() const { return upb_fielddef_containingtype(this); } inline const OneofDef* FieldDef::containing_oneof() const { return upb_fielddef_containingoneof(this); } inline const char* FieldDef::containing_type_name() { return upb_fielddef_containingtypename(this); } inline bool FieldDef::set_number(uint32_t number, Status* s) { return upb_fielddef_setnumber(this, number, s); } inline bool FieldDef::set_name(const char *name, Status* s) { return upb_fielddef_setname(this, name, s); } inline bool FieldDef::set_name(const std::string& name, Status* s) { return upb_fielddef_setname(this, upb_safecstr(name), s); } inline bool FieldDef::set_json_name(const char *name, Status* s) { return upb_fielddef_setjsonname(this, name, s); } inline bool FieldDef::set_json_name(const std::string& name, Status* s) { return upb_fielddef_setjsonname(this, upb_safecstr(name), s); } inline void FieldDef::clear_json_name() { upb_fielddef_clearjsonname(this); } inline bool FieldDef::set_containing_type_name(const char *name, Status* s) { return upb_fielddef_setcontainingtypename(this, name, s); } inline bool FieldDef::set_containing_type_name(const std::string &name, Status *s) { return upb_fielddef_setcontainingtypename(this, upb_safecstr(name), s); } inline void FieldDef::set_type(upb_fieldtype_t type) { upb_fielddef_settype(this, type); } inline void FieldDef::set_is_extension(bool is_extension) { upb_fielddef_setisextension(this, is_extension); } inline void FieldDef::set_descriptor_type(FieldDef::DescriptorType type) { upb_fielddef_setdescriptortype(this, type); } inline void FieldDef::set_label(upb_label_t label) { upb_fielddef_setlabel(this, label); } inline bool FieldDef::IsSubMessage() const { return upb_fielddef_issubmsg(this); } inline bool FieldDef::IsString() const { return upb_fielddef_isstring(this); } inline bool FieldDef::IsSequence() const { return upb_fielddef_isseq(this); } inline bool FieldDef::IsMap() const { return upb_fielddef_ismap(this); } inline int64_t FieldDef::default_int64() const { return upb_fielddef_defaultint64(this); } inline int32_t FieldDef::default_int32() const { return upb_fielddef_defaultint32(this); } inline uint64_t FieldDef::default_uint64() const { return upb_fielddef_defaultuint64(this); } inline uint32_t FieldDef::default_uint32() const { return upb_fielddef_defaultuint32(this); } inline bool FieldDef::default_bool() const { return upb_fielddef_defaultbool(this); } inline float FieldDef::default_float() const { return upb_fielddef_defaultfloat(this); } inline double FieldDef::default_double() const { return upb_fielddef_defaultdouble(this); } inline const char* FieldDef::default_string(size_t* len) const { return upb_fielddef_defaultstr(this, len); } inline void FieldDef::set_default_int64(int64_t value) { upb_fielddef_setdefaultint64(this, value); } inline void FieldDef::set_default_int32(int32_t value) { upb_fielddef_setdefaultint32(this, value); } inline void FieldDef::set_default_uint64(uint64_t value) { upb_fielddef_setdefaultuint64(this, value); } inline void FieldDef::set_default_uint32(uint32_t value) { upb_fielddef_setdefaultuint32(this, value); } inline void FieldDef::set_default_bool(bool value) { upb_fielddef_setdefaultbool(this, value); } inline void FieldDef::set_default_float(float value) { upb_fielddef_setdefaultfloat(this, value); } inline void FieldDef::set_default_double(double value) { upb_fielddef_setdefaultdouble(this, value); } inline bool FieldDef::set_default_string(const void *str, size_t len, Status *s) { return upb_fielddef_setdefaultstr(this, str, len, s); } inline bool FieldDef::set_default_string(const std::string& str, Status* s) { return upb_fielddef_setdefaultstr(this, str.c_str(), str.size(), s); } inline void FieldDef::set_default_cstr(const char* str, Status* s) { return upb_fielddef_setdefaultcstr(this, str, s); } inline bool FieldDef::HasSubDef() const { return upb_fielddef_hassubdef(this); } inline const Def* FieldDef::subdef() const { return upb_fielddef_subdef(this); } inline const MessageDef *FieldDef::message_subdef() const { return upb_fielddef_msgsubdef(this); } inline const EnumDef *FieldDef::enum_subdef() const { return upb_fielddef_enumsubdef(this); } inline const char* FieldDef::subdef_name() const { return upb_fielddef_subdefname(this); } inline bool FieldDef::set_subdef(const Def* subdef, Status* s) { return upb_fielddef_setsubdef(this, subdef, s); } inline bool FieldDef::set_enum_subdef(const EnumDef* subdef, Status* s) { return upb_fielddef_setenumsubdef(this, subdef, s); } inline bool FieldDef::set_message_subdef(const MessageDef* subdef, Status* s) { return upb_fielddef_setmsgsubdef(this, subdef, s); } inline bool FieldDef::set_subdef_name(const char* name, Status* s) { return upb_fielddef_setsubdefname(this, name, s); } inline bool FieldDef::set_subdef_name(const std::string& name, Status* s) { return upb_fielddef_setsubdefname(this, upb_safecstr(name), s); } inline reffed_ptr MessageDef::New() { upb_msgdef *m = upb_msgdef_new(&m); return reffed_ptr(m, &m); } inline const char *MessageDef::full_name() const { return upb_msgdef_fullname(this); } inline const char *MessageDef::name() const { return upb_msgdef_name(this); } inline upb_syntax_t MessageDef::syntax() const { return upb_msgdef_syntax(this); } inline bool MessageDef::set_full_name(const char* fullname, Status* s) { return upb_msgdef_setfullname(this, fullname, s); } inline bool MessageDef::set_full_name(const std::string& fullname, Status* s) { return upb_msgdef_setfullname(this, upb_safecstr(fullname), s); } inline bool MessageDef::set_syntax(upb_syntax_t syntax) { return upb_msgdef_setsyntax(this, syntax); } inline bool MessageDef::Freeze(Status* status) { return upb_msgdef_freeze(this, status); } inline int MessageDef::field_count() const { return upb_msgdef_numfields(this); } inline int MessageDef::oneof_count() const { return upb_msgdef_numoneofs(this); } inline bool MessageDef::AddField(upb_fielddef* f, Status* s) { return upb_msgdef_addfield(this, f, NULL, s); } inline bool MessageDef::AddField(const reffed_ptr& f, Status* s) { return upb_msgdef_addfield(this, f.get(), NULL, s); } inline bool MessageDef::AddOneof(upb_oneofdef* o, Status* s) { return upb_msgdef_addoneof(this, o, NULL, s); } inline bool MessageDef::AddOneof(const reffed_ptr& o, Status* s) { return upb_msgdef_addoneof(this, o.get(), NULL, s); } inline FieldDef* MessageDef::FindFieldByNumber(uint32_t number) { return upb_msgdef_itof_mutable(this, number); } inline FieldDef* MessageDef::FindFieldByName(const char* name, size_t len) { return upb_msgdef_ntof_mutable(this, name, len); } inline const FieldDef* MessageDef::FindFieldByNumber(uint32_t number) const { return upb_msgdef_itof(this, number); } inline const FieldDef *MessageDef::FindFieldByName(const char *name, size_t len) const { return upb_msgdef_ntof(this, name, len); } inline OneofDef* MessageDef::FindOneofByName(const char* name, size_t len) { return upb_msgdef_ntoo_mutable(this, name, len); } inline const OneofDef* MessageDef::FindOneofByName(const char* name, size_t len) const { return upb_msgdef_ntoo(this, name, len); } inline void MessageDef::setmapentry(bool map_entry) { upb_msgdef_setmapentry(this, map_entry); } inline bool MessageDef::mapentry() const { return upb_msgdef_mapentry(this); } inline MessageDef::field_iterator MessageDef::field_begin() { return field_iterator(this); } inline MessageDef::field_iterator MessageDef::field_end() { return field_iterator::end(this); } inline MessageDef::const_field_iterator MessageDef::field_begin() const { return const_field_iterator(this); } inline MessageDef::const_field_iterator MessageDef::field_end() const { return const_field_iterator::end(this); } inline MessageDef::oneof_iterator MessageDef::oneof_begin() { return oneof_iterator(this); } inline MessageDef::oneof_iterator MessageDef::oneof_end() { return oneof_iterator::end(this); } inline MessageDef::const_oneof_iterator MessageDef::oneof_begin() const { return const_oneof_iterator(this); } inline MessageDef::const_oneof_iterator MessageDef::oneof_end() const { return const_oneof_iterator::end(this); } inline MessageDef::field_iterator::field_iterator(MessageDef* md) { upb_msg_field_begin(&iter_, md); } inline MessageDef::field_iterator MessageDef::field_iterator::end( MessageDef* md) { MessageDef::field_iterator iter(md); upb_msg_field_iter_setdone(&iter.iter_); return iter; } inline FieldDef* MessageDef::field_iterator::operator*() const { return upb_msg_iter_field(&iter_); } inline void MessageDef::field_iterator::operator++() { return upb_msg_field_next(&iter_); } inline bool MessageDef::field_iterator::operator==( const field_iterator &other) const { return upb_inttable_iter_isequal(&iter_, &other.iter_); } inline bool MessageDef::field_iterator::operator!=( const field_iterator &other) const { return !(*this == other); } inline MessageDef::const_field_iterator::const_field_iterator( const MessageDef* md) { upb_msg_field_begin(&iter_, md); } inline MessageDef::const_field_iterator MessageDef::const_field_iterator::end( const MessageDef *md) { MessageDef::const_field_iterator iter(md); upb_msg_field_iter_setdone(&iter.iter_); return iter; } inline const FieldDef* MessageDef::const_field_iterator::operator*() const { return upb_msg_iter_field(&iter_); } inline void MessageDef::const_field_iterator::operator++() { return upb_msg_field_next(&iter_); } inline bool MessageDef::const_field_iterator::operator==( const const_field_iterator &other) const { return upb_inttable_iter_isequal(&iter_, &other.iter_); } inline bool MessageDef::const_field_iterator::operator!=( const const_field_iterator &other) const { return !(*this == other); } inline MessageDef::oneof_iterator::oneof_iterator(MessageDef* md) { upb_msg_oneof_begin(&iter_, md); } inline MessageDef::oneof_iterator MessageDef::oneof_iterator::end( MessageDef* md) { MessageDef::oneof_iterator iter(md); upb_msg_oneof_iter_setdone(&iter.iter_); return iter; } inline OneofDef* MessageDef::oneof_iterator::operator*() const { return upb_msg_iter_oneof(&iter_); } inline void MessageDef::oneof_iterator::operator++() { return upb_msg_oneof_next(&iter_); } inline bool MessageDef::oneof_iterator::operator==( const oneof_iterator &other) const { return upb_strtable_iter_isequal(&iter_, &other.iter_); } inline bool MessageDef::oneof_iterator::operator!=( const oneof_iterator &other) const { return !(*this == other); } inline MessageDef::const_oneof_iterator::const_oneof_iterator( const MessageDef* md) { upb_msg_oneof_begin(&iter_, md); } inline MessageDef::const_oneof_iterator MessageDef::const_oneof_iterator::end( const MessageDef *md) { MessageDef::const_oneof_iterator iter(md); upb_msg_oneof_iter_setdone(&iter.iter_); return iter; } inline const OneofDef* MessageDef::const_oneof_iterator::operator*() const { return upb_msg_iter_oneof(&iter_); } inline void MessageDef::const_oneof_iterator::operator++() { return upb_msg_oneof_next(&iter_); } inline bool MessageDef::const_oneof_iterator::operator==( const const_oneof_iterator &other) const { return upb_strtable_iter_isequal(&iter_, &other.iter_); } inline bool MessageDef::const_oneof_iterator::operator!=( const const_oneof_iterator &other) const { return !(*this == other); } inline reffed_ptr EnumDef::New() { upb_enumdef *e = upb_enumdef_new(&e); return reffed_ptr(e, &e); } inline const char* EnumDef::full_name() const { return upb_enumdef_fullname(this); } inline const char* EnumDef::name() const { return upb_enumdef_name(this); } inline bool EnumDef::set_full_name(const char* fullname, Status* s) { return upb_enumdef_setfullname(this, fullname, s); } inline bool EnumDef::set_full_name(const std::string& fullname, Status* s) { return upb_enumdef_setfullname(this, upb_safecstr(fullname), s); } inline bool EnumDef::Freeze(Status* status) { return upb_enumdef_freeze(this, status); } inline int32_t EnumDef::default_value() const { return upb_enumdef_default(this); } inline bool EnumDef::set_default_value(int32_t val, Status* status) { return upb_enumdef_setdefault(this, val, status); } inline int EnumDef::value_count() const { return upb_enumdef_numvals(this); } inline bool EnumDef::AddValue(const char* name, int32_t num, Status* status) { return upb_enumdef_addval(this, name, num, status); } inline bool EnumDef::AddValue(const std::string& name, int32_t num, Status* status) { return upb_enumdef_addval(this, upb_safecstr(name), num, status); } inline bool EnumDef::FindValueByName(const char* name, int32_t *num) const { return upb_enumdef_ntoiz(this, name, num); } inline const char* EnumDef::FindValueByNumber(int32_t num) const { return upb_enumdef_iton(this, num); } inline EnumDef::Iterator::Iterator(const EnumDef* e) { upb_enum_begin(&iter_, e); } inline int32_t EnumDef::Iterator::number() { return upb_enum_iter_number(&iter_); } inline const char* EnumDef::Iterator::name() { return upb_enum_iter_name(&iter_); } inline bool EnumDef::Iterator::Done() { return upb_enum_done(&iter_); } inline void EnumDef::Iterator::Next() { return upb_enum_next(&iter_); } inline reffed_ptr OneofDef::New() { upb_oneofdef *o = upb_oneofdef_new(&o); return reffed_ptr(o, &o); } inline const MessageDef* OneofDef::containing_type() const { return upb_oneofdef_containingtype(this); } inline const char* OneofDef::name() const { return upb_oneofdef_name(this); } inline bool OneofDef::set_name(const char* name, Status* s) { return upb_oneofdef_setname(this, name, s); } inline bool OneofDef::set_name(const std::string& name, Status* s) { return upb_oneofdef_setname(this, upb_safecstr(name), s); } inline int OneofDef::field_count() const { return upb_oneofdef_numfields(this); } inline bool OneofDef::AddField(FieldDef* field, Status* s) { return upb_oneofdef_addfield(this, field, NULL, s); } inline bool OneofDef::AddField(const reffed_ptr& field, Status* s) { return upb_oneofdef_addfield(this, field.get(), NULL, s); } inline const FieldDef* OneofDef::FindFieldByName(const char* name, size_t len) const { return upb_oneofdef_ntof(this, name, len); } inline const FieldDef* OneofDef::FindFieldByNumber(uint32_t num) const { return upb_oneofdef_itof(this, num); } inline OneofDef::iterator OneofDef::begin() { return iterator(this); } inline OneofDef::iterator OneofDef::end() { return iterator::end(this); } inline OneofDef::const_iterator OneofDef::begin() const { return const_iterator(this); } inline OneofDef::const_iterator OneofDef::end() const { return const_iterator::end(this); } inline OneofDef::iterator::iterator(OneofDef* o) { upb_oneof_begin(&iter_, o); } inline OneofDef::iterator OneofDef::iterator::end(OneofDef* o) { OneofDef::iterator iter(o); upb_oneof_iter_setdone(&iter.iter_); return iter; } inline FieldDef* OneofDef::iterator::operator*() const { return upb_oneof_iter_field(&iter_); } inline void OneofDef::iterator::operator++() { return upb_oneof_next(&iter_); } inline bool OneofDef::iterator::operator==(const iterator &other) const { return upb_inttable_iter_isequal(&iter_, &other.iter_); } inline bool OneofDef::iterator::operator!=(const iterator &other) const { return !(*this == other); } inline OneofDef::const_iterator::const_iterator(const OneofDef* md) { upb_oneof_begin(&iter_, md); } inline OneofDef::const_iterator OneofDef::const_iterator::end( const OneofDef *md) { OneofDef::const_iterator iter(md); upb_oneof_iter_setdone(&iter.iter_); return iter; } inline const FieldDef* OneofDef::const_iterator::operator*() const { return upb_msg_iter_field(&iter_); } inline void OneofDef::const_iterator::operator++() { return upb_oneof_next(&iter_); } inline bool OneofDef::const_iterator::operator==( const const_iterator &other) const { return upb_inttable_iter_isequal(&iter_, &other.iter_); } inline bool OneofDef::const_iterator::operator!=( const const_iterator &other) const { return !(*this == other); } inline reffed_ptr FileDef::New() { upb_filedef *f = upb_filedef_new(&f); return reffed_ptr(f, &f); } inline const char* FileDef::name() const { return upb_filedef_name(this); } inline bool FileDef::set_name(const char* name, Status* s) { return upb_filedef_setname(this, name, s); } inline bool FileDef::set_name(const std::string& name, Status* s) { return upb_filedef_setname(this, upb_safecstr(name), s); } inline const char* FileDef::package() const { return upb_filedef_package(this); } inline bool FileDef::set_package(const char* package, Status* s) { return upb_filedef_setpackage(this, package, s); } inline int FileDef::def_count() const { return upb_filedef_defcount(this); } inline const Def* FileDef::def(int index) const { return upb_filedef_def(this, index); } inline Def* FileDef::def(int index) { return const_cast(upb_filedef_def(this, index)); } inline int FileDef::dependency_count() const { return upb_filedef_depcount(this); } inline const FileDef* FileDef::dependency(int index) const { return upb_filedef_dep(this, index); } inline bool FileDef::AddDef(Def* def, Status* s) { return upb_filedef_adddef(this, def, NULL, s); } inline bool FileDef::AddMessage(MessageDef* m, Status* s) { return upb_filedef_addmsg(this, m, NULL, s); } inline bool FileDef::AddEnum(EnumDef* e, Status* s) { return upb_filedef_addenum(this, e, NULL, s); } inline bool FileDef::AddExtension(FieldDef* f, Status* s) { return upb_filedef_addext(this, f, NULL, s); } inline bool FileDef::AddDependency(const FileDef* file) { return upb_filedef_adddep(this, file); } } /* namespace upb */ #endif #endif /* UPB_DEF_H_ */ /* ** This file contains definitions of structs that should be considered private ** and NOT stable across versions of upb. ** ** The only reason they are declared here and not in .c files is to allow upb ** and the application (if desired) to embed statically-initialized instances ** of structures like defs. ** ** If you include this file, all guarantees of ABI compatibility go out the ** window! Any code that includes this file needs to recompile against the ** exact same version of upb that they are linking against. ** ** You also need to recompile if you change the value of the UPB_DEBUG_REFS ** flag. */ #ifndef UPB_STATICINIT_H_ #define UPB_STATICINIT_H_ #ifdef __cplusplus /* Because of how we do our typedefs, this header can't be included from C++. */ #error This file cannot be included from C++ #endif /* upb_refcounted *************************************************************/ /* upb_def ********************************************************************/ struct upb_def { upb_refcounted base; const char *fullname; const upb_filedef* file; char type; /* A upb_deftype_t (char to save space) */ /* Used as a flag during the def's mutable stage. Must be false unless * it is currently being used by a function on the stack. This allows * us to easily determine which defs were passed into the function's * current invocation. */ bool came_from_user; }; #define UPB_DEF_INIT(name, type, vtbl, refs, ref2s) \ { UPB_REFCOUNT_INIT(vtbl, refs, ref2s), name, NULL, type, false } /* upb_fielddef ***************************************************************/ struct upb_fielddef { upb_def base; union { int64_t sint; uint64_t uint; double dbl; float flt; void *bytes; } defaultval; union { const upb_msgdef *def; /* If !msg_is_symbolic. */ char *name; /* If msg_is_symbolic. */ } msg; union { const upb_def *def; /* If !subdef_is_symbolic. */ char *name; /* If subdef_is_symbolic. */ } sub; /* The msgdef or enumdef for this field, if upb_hassubdef(f). */ bool subdef_is_symbolic; bool msg_is_symbolic; const upb_oneofdef *oneof; bool default_is_string; bool type_is_set_; /* False until type is explicitly set. */ bool is_extension_; bool lazy_; bool packed_; upb_intfmt_t intfmt; bool tagdelim; upb_fieldtype_t type_; upb_label_t label_; uint32_t number_; uint32_t selector_base; /* Used to index into a upb::Handlers table. */ uint32_t index_; }; extern const struct upb_refcounted_vtbl upb_fielddef_vtbl; #define UPB_FIELDDEF_INIT(label, type, intfmt, tagdelim, is_extension, lazy, \ packed, name, num, msgdef, subdef, selector_base, \ index, defaultval, refs, ref2s) \ { \ UPB_DEF_INIT(name, UPB_DEF_FIELD, &upb_fielddef_vtbl, refs, ref2s), \ defaultval, {msgdef}, {subdef}, NULL, false, false, \ type == UPB_TYPE_STRING || type == UPB_TYPE_BYTES, true, is_extension, \ lazy, packed, intfmt, tagdelim, type, label, num, selector_base, index \ } /* upb_msgdef *****************************************************************/ struct upb_msgdef { upb_def base; size_t selector_count; uint32_t submsg_field_count; /* Tables for looking up fields by number and name. */ upb_inttable itof; /* int to field */ upb_strtable ntof; /* name to field/oneof */ /* Is this a map-entry message? */ bool map_entry; /* Whether this message has proto2 or proto3 semantics. */ upb_syntax_t syntax; /* TODO(haberman): proper extension ranges (there can be multiple). */ }; extern const struct upb_refcounted_vtbl upb_msgdef_vtbl; /* TODO: also support static initialization of the oneofs table. This will be * needed if we compile in descriptors that contain oneofs. */ #define UPB_MSGDEF_INIT(name, selector_count, submsg_field_count, itof, ntof, \ map_entry, syntax, refs, ref2s) \ { \ UPB_DEF_INIT(name, UPB_DEF_MSG, &upb_fielddef_vtbl, refs, ref2s), \ selector_count, submsg_field_count, itof, ntof, map_entry, syntax \ } /* upb_enumdef ****************************************************************/ struct upb_enumdef { upb_def base; upb_strtable ntoi; upb_inttable iton; int32_t defaultval; }; extern const struct upb_refcounted_vtbl upb_enumdef_vtbl; #define UPB_ENUMDEF_INIT(name, ntoi, iton, defaultval, refs, ref2s) \ { UPB_DEF_INIT(name, UPB_DEF_ENUM, &upb_enumdef_vtbl, refs, ref2s), ntoi, \ iton, defaultval } /* upb_oneofdef ***************************************************************/ struct upb_oneofdef { upb_refcounted base; uint32_t index; /* Index within oneofs. */ const char *name; upb_strtable ntof; upb_inttable itof; const upb_msgdef *parent; }; extern const struct upb_refcounted_vtbl upb_oneofdef_vtbl; #define UPB_ONEOFDEF_INIT(name, ntof, itof, refs, ref2s) \ { UPB_REFCOUNT_INIT(&upb_oneofdef_vtbl, refs, ref2s), 0, name, ntof, itof } /* upb_symtab *****************************************************************/ struct upb_symtab { upb_refcounted base; upb_strtable symtab; }; struct upb_filedef { upb_refcounted base; const char *name; const char *package; upb_syntax_t syntax; upb_inttable defs; upb_inttable deps; }; extern const struct upb_refcounted_vtbl upb_filedef_vtbl; #endif /* UPB_STATICINIT_H_ */ /* ** upb::Handlers (upb_handlers) ** ** A upb_handlers is like a virtual table for a upb_msgdef. Each field of the ** message can have associated functions that will be called when we are ** parsing or visiting a stream of data. This is similar to how handlers work ** in SAX (the Simple API for XML). ** ** The handlers have no idea where the data is coming from, so a single set of ** handlers could be used with two completely different data sources (for ** example, a parser and a visitor over in-memory objects). This decoupling is ** the most important feature of upb, because it allows parsers and serializers ** to be highly reusable. ** ** This is a mixed C/C++ interface that offers a full API to both languages. ** See the top-level README for more information. */ #ifndef UPB_HANDLERS_H #define UPB_HANDLERS_H #ifdef __cplusplus namespace upb { class BufferHandle; class BytesHandler; class HandlerAttributes; class Handlers; template class Handler; template struct CanonicalType; } /* namespace upb */ #endif UPB_DECLARE_TYPE(upb::BufferHandle, upb_bufhandle) UPB_DECLARE_TYPE(upb::BytesHandler, upb_byteshandler) UPB_DECLARE_TYPE(upb::HandlerAttributes, upb_handlerattr) UPB_DECLARE_DERIVED_TYPE(upb::Handlers, upb::RefCounted, upb_handlers, upb_refcounted) /* The maximum depth that the handler graph can have. This is a resource limit * for the C stack since we sometimes need to recursively traverse the graph. * Cycles are ok; the traversal will stop when it detects a cycle, but we must * hit the cycle before the maximum depth is reached. * * If having a single static limit is too inflexible, we can add another variant * of Handlers::Freeze that allows specifying this as a parameter. */ #define UPB_MAX_HANDLER_DEPTH 64 /* All the different types of handlers that can be registered. * Only needed for the advanced functions in upb::Handlers. */ typedef enum { UPB_HANDLER_INT32, UPB_HANDLER_INT64, UPB_HANDLER_UINT32, UPB_HANDLER_UINT64, UPB_HANDLER_FLOAT, UPB_HANDLER_DOUBLE, UPB_HANDLER_BOOL, UPB_HANDLER_STARTSTR, UPB_HANDLER_STRING, UPB_HANDLER_ENDSTR, UPB_HANDLER_STARTSUBMSG, UPB_HANDLER_ENDSUBMSG, UPB_HANDLER_STARTSEQ, UPB_HANDLER_ENDSEQ } upb_handlertype_t; #define UPB_HANDLER_MAX (UPB_HANDLER_ENDSEQ+1) #define UPB_BREAK NULL /* A convenient definition for when no closure is needed. */ extern char _upb_noclosure; #define UPB_NO_CLOSURE &_upb_noclosure /* A selector refers to a specific field handler in the Handlers object * (for example: the STARTSUBMSG handler for field "field15"). */ typedef int32_t upb_selector_t; UPB_BEGIN_EXTERN_C /* Forward-declares for C inline accessors. We need to declare these here * so we can "friend" them in the class declarations in C++. */ UPB_INLINE upb_func *upb_handlers_gethandler(const upb_handlers *h, upb_selector_t s); UPB_INLINE const void *upb_handlerattr_handlerdata(const upb_handlerattr *attr); UPB_INLINE const void *upb_handlers_gethandlerdata(const upb_handlers *h, upb_selector_t s); UPB_INLINE void upb_bufhandle_init(upb_bufhandle *h); UPB_INLINE void upb_bufhandle_setobj(upb_bufhandle *h, const void *obj, const void *type); UPB_INLINE void upb_bufhandle_setbuf(upb_bufhandle *h, const char *buf, size_t ofs); UPB_INLINE const void *upb_bufhandle_obj(const upb_bufhandle *h); UPB_INLINE const void *upb_bufhandle_objtype(const upb_bufhandle *h); UPB_INLINE const char *upb_bufhandle_buf(const upb_bufhandle *h); UPB_END_EXTERN_C /* Static selectors for upb::Handlers. */ #define UPB_STARTMSG_SELECTOR 0 #define UPB_ENDMSG_SELECTOR 1 #define UPB_STATIC_SELECTOR_COUNT 2 /* Static selectors for upb::BytesHandler. */ #define UPB_STARTSTR_SELECTOR 0 #define UPB_STRING_SELECTOR 1 #define UPB_ENDSTR_SELECTOR 2 typedef void upb_handlerfree(void *d); #ifdef __cplusplus /* A set of attributes that accompanies a handler's function pointer. */ class upb::HandlerAttributes { public: HandlerAttributes(); ~HandlerAttributes(); /* Sets the handler data that will be passed as the second parameter of the * handler. To free this pointer when the handlers are freed, call * Handlers::AddCleanup(). */ bool SetHandlerData(const void *handler_data); const void* handler_data() const; /* Use this to specify the type of the closure. This will be checked against * all other closure types for handler that use the same closure. * Registration will fail if this does not match all other non-NULL closure * types. */ bool SetClosureType(const void *closure_type); const void* closure_type() const; /* Use this to specify the type of the returned closure. Only used for * Start*{String,SubMessage,Sequence} handlers. This must match the closure * type of any handlers that use it (for example, the StringBuf handler must * match the closure returned from StartString). */ bool SetReturnClosureType(const void *return_closure_type); const void* return_closure_type() const; /* Set to indicate that the handler always returns "ok" (either "true" or a * non-NULL closure). This is a hint that can allow code generators to * generate more efficient code. */ bool SetAlwaysOk(bool always_ok); bool always_ok() const; private: friend UPB_INLINE const void * ::upb_handlerattr_handlerdata( const upb_handlerattr *attr); #else struct upb_handlerattr { #endif const void *handler_data_; const void *closure_type_; const void *return_closure_type_; bool alwaysok_; }; #define UPB_HANDLERATTR_INITIALIZER {NULL, NULL, NULL, false} typedef struct { upb_func *func; /* It is wasteful to include the entire attributes here: * * * Some of the information is redundant (like storing the closure type * separately for each handler that must match). * * Some of the info is only needed prior to freeze() (like closure types). * * alignment padding wastes a lot of space for alwaysok_. * * If/when the size and locality of handlers is an issue, we can optimize this * not to store the entire attr like this. We do not expose the table's * layout to allow this optimization in the future. */ upb_handlerattr attr; } upb_handlers_tabent; #ifdef __cplusplus /* Extra information about a buffer that is passed to a StringBuf handler. * TODO(haberman): allow the handle to be pinned so that it will outlive * the handler invocation. */ class upb::BufferHandle { public: BufferHandle(); ~BufferHandle(); /* The beginning of the buffer. This may be different than the pointer * passed to a StringBuf handler because the handler may receive data * that is from the middle or end of a larger buffer. */ const char* buffer() const; /* The offset within the attached object where this buffer begins. Only * meaningful if there is an attached object. */ size_t object_offset() const; /* Note that object_offset is the offset of "buf" within the attached * object. */ void SetBuffer(const char* buf, size_t object_offset); /* The BufferHandle can have an "attached object", which can be used to * tunnel through a pointer to the buffer's underlying representation. */ template void SetAttachedObject(const T* obj); /* Returns NULL if the attached object is not of this type. */ template const T* GetAttachedObject() const; private: friend UPB_INLINE void ::upb_bufhandle_init(upb_bufhandle *h); friend UPB_INLINE void ::upb_bufhandle_setobj(upb_bufhandle *h, const void *obj, const void *type); friend UPB_INLINE void ::upb_bufhandle_setbuf(upb_bufhandle *h, const char *buf, size_t ofs); friend UPB_INLINE const void* ::upb_bufhandle_obj(const upb_bufhandle *h); friend UPB_INLINE const void* ::upb_bufhandle_objtype( const upb_bufhandle *h); friend UPB_INLINE const char* ::upb_bufhandle_buf(const upb_bufhandle *h); #else struct upb_bufhandle { #endif const char *buf_; const void *obj_; const void *objtype_; size_t objofs_; }; #ifdef __cplusplus /* A upb::Handlers object represents the set of handlers associated with a * message in the graph of messages. You can think of it as a big virtual * table with functions corresponding to all the events that can fire while * parsing or visiting a message of a specific type. * * Any handlers that are not set behave as if they had successfully consumed * the value. Any unset Start* handlers will propagate their closure to the * inner frame. * * The easiest way to create the *Handler objects needed by the Set* methods is * with the UpbBind() and UpbMakeHandler() macros; see below. */ class upb::Handlers { public: typedef upb_selector_t Selector; typedef upb_handlertype_t Type; typedef Handler StartFieldHandler; typedef Handler EndFieldHandler; typedef Handler StartMessageHandler; typedef Handler EndMessageHandler; typedef Handler StartStringHandler; typedef Handler StringHandler; template struct ValueHandler { typedef Handler H; }; typedef ValueHandler::H Int32Handler; typedef ValueHandler::H Int64Handler; typedef ValueHandler::H UInt32Handler; typedef ValueHandler::H UInt64Handler; typedef ValueHandler::H FloatHandler; typedef ValueHandler::H DoubleHandler; typedef ValueHandler::H BoolHandler; /* Any function pointer can be converted to this and converted back to its * correct type. */ typedef void GenericFunction(); typedef void HandlersCallback(const void *closure, upb_handlers *h); /* Returns a new handlers object for the given frozen msgdef. * Returns NULL if memory allocation failed. */ static reffed_ptr New(const MessageDef *m); /* Convenience function for registering a graph of handlers that mirrors the * graph of msgdefs for some message. For "m" and all its children a new set * of handlers will be created and the given callback will be invoked, * allowing the client to register handlers for this message. Note that any * subhandlers set by the callback will be overwritten. */ static reffed_ptr NewFrozen(const MessageDef *m, HandlersCallback *callback, const void *closure); /* Functionality from upb::RefCounted. */ UPB_REFCOUNTED_CPPMETHODS /* All handler registration functions return bool to indicate success or * failure; details about failures are stored in this status object. If a * failure does occur, it must be cleared before the Handlers are frozen, * otherwise the freeze() operation will fail. The functions may *only* be * used while the Handlers are mutable. */ const Status* status(); void ClearError(); /* Call to freeze these Handlers. Requires that any SubHandlers are already * frozen. For cycles, you must use the static version below and freeze the * whole graph at once. */ bool Freeze(Status* s); /* Freezes the given set of handlers. You may not freeze a handler without * also freezing any handlers they point to. */ static bool Freeze(Handlers*const* handlers, int n, Status* s); static bool Freeze(const std::vector& handlers, Status* s); /* Returns the msgdef associated with this handlers object. */ const MessageDef* message_def() const; /* Adds the given pointer and function to the list of cleanup functions that * will be run when these handlers are freed. If this pointer has previously * been registered, the function returns false and does nothing. */ bool AddCleanup(void *ptr, upb_handlerfree *cleanup); /* Sets the startmsg handler for the message, which is defined as follows: * * bool startmsg(MyType* closure) { * // Called when the message begins. Returns true if processing should * // continue. * return true; * } */ bool SetStartMessageHandler(const StartMessageHandler& handler); /* Sets the endmsg handler for the message, which is defined as follows: * * bool endmsg(MyType* closure, upb_status *status) { * // Called when processing of this message ends, whether in success or * // failure. "status" indicates the final status of processing, and * // can also be modified in-place to update the final status. * } */ bool SetEndMessageHandler(const EndMessageHandler& handler); /* Sets the value handler for the given field, which is defined as follows * (this is for an int32 field; other field types will pass their native * C/C++ type for "val"): * * bool OnValue(MyClosure* c, const MyHandlerData* d, int32_t val) { * // Called when the field's value is encountered. "d" contains * // whatever data was bound to this field when it was registered. * // Returns true if processing should continue. * return true; * } * * handers->SetInt32Handler(f, UpbBind(OnValue, new MyHandlerData(...))); * * The value type must exactly match f->type(). * For example, a handler that takes an int32_t parameter may only be used for * fields of type UPB_TYPE_INT32 and UPB_TYPE_ENUM. * * Returns false if the handler failed to register; in this case the cleanup * handler (if any) will be called immediately. */ bool SetInt32Handler (const FieldDef* f, const Int32Handler& h); bool SetInt64Handler (const FieldDef* f, const Int64Handler& h); bool SetUInt32Handler(const FieldDef* f, const UInt32Handler& h); bool SetUInt64Handler(const FieldDef* f, const UInt64Handler& h); bool SetFloatHandler (const FieldDef* f, const FloatHandler& h); bool SetDoubleHandler(const FieldDef* f, const DoubleHandler& h); bool SetBoolHandler (const FieldDef* f, const BoolHandler& h); /* Like the previous, but templated on the type on the value (ie. int32). * This is mostly useful to call from other templates. To call this you must * specify the template parameter explicitly, ie: * h->SetValueHandler(f, UpbBind(MyHandler, MyData)); */ template bool SetValueHandler( const FieldDef *f, const typename ValueHandler::Type>::H& handler); /* Sets handlers for a string field, which are defined as follows: * * MySubClosure* startstr(MyClosure* c, const MyHandlerData* d, * size_t size_hint) { * // Called when a string value begins. The return value indicates the * // closure for the string. "size_hint" indicates the size of the * // string if it is known, however if the string is length-delimited * // and the end-of-string is not available size_hint will be zero. * // This case is indistinguishable from the case where the size is * // known to be zero. * // * // TODO(haberman): is it important to distinguish these cases? * // If we had ssize_t as a type we could make -1 "unknown", but * // ssize_t is POSIX (not ANSI) and therefore less portable. * // In practice I suspect it won't be important to distinguish. * return closure; * } * * size_t str(MyClosure* closure, const MyHandlerData* d, * const char *str, size_t len) { * // Called for each buffer of string data; the multiple physical buffers * // are all part of the same logical string. The return value indicates * // how many bytes were consumed. If this number is less than "len", * // this will also indicate that processing should be halted for now, * // like returning false or UPB_BREAK from any other callback. If * // number is greater than "len", the excess bytes will be skipped over * // and not passed to the callback. * return len; * } * * bool endstr(MyClosure* c, const MyHandlerData* d) { * // Called when a string value ends. Return value indicates whether * // processing should continue. * return true; * } */ bool SetStartStringHandler(const FieldDef* f, const StartStringHandler& h); bool SetStringHandler(const FieldDef* f, const StringHandler& h); bool SetEndStringHandler(const FieldDef* f, const EndFieldHandler& h); /* Sets the startseq handler, which is defined as follows: * * MySubClosure *startseq(MyClosure* c, const MyHandlerData* d) { * // Called when a sequence (repeated field) begins. The returned * // pointer indicates the closure for the sequence (or UPB_BREAK * // to interrupt processing). * return closure; * } * * h->SetStartSequenceHandler(f, UpbBind(startseq, new MyHandlerData(...))); * * Returns "false" if "f" does not belong to this message or is not a * repeated field. */ bool SetStartSequenceHandler(const FieldDef* f, const StartFieldHandler& h); /* Sets the startsubmsg handler for the given field, which is defined as * follows: * * MySubClosure* startsubmsg(MyClosure* c, const MyHandlerData* d) { * // Called when a submessage begins. The returned pointer indicates the * // closure for the sequence (or UPB_BREAK to interrupt processing). * return closure; * } * * h->SetStartSubMessageHandler(f, UpbBind(startsubmsg, * new MyHandlerData(...))); * * Returns "false" if "f" does not belong to this message or is not a * submessage/group field. */ bool SetStartSubMessageHandler(const FieldDef* f, const StartFieldHandler& h); /* Sets the endsubmsg handler for the given field, which is defined as * follows: * * bool endsubmsg(MyClosure* c, const MyHandlerData* d) { * // Called when a submessage ends. Returns true to continue processing. * return true; * } * * Returns "false" if "f" does not belong to this message or is not a * submessage/group field. */ bool SetEndSubMessageHandler(const FieldDef *f, const EndFieldHandler &h); /* Starts the endsubseq handler for the given field, which is defined as * follows: * * bool endseq(MyClosure* c, const MyHandlerData* d) { * // Called when a sequence ends. Returns true continue processing. * return true; * } * * Returns "false" if "f" does not belong to this message or is not a * repeated field. */ bool SetEndSequenceHandler(const FieldDef* f, const EndFieldHandler& h); /* Sets or gets the object that specifies handlers for the given field, which * must be a submessage or group. Returns NULL if no handlers are set. */ bool SetSubHandlers(const FieldDef* f, const Handlers* sub); const Handlers* GetSubHandlers(const FieldDef* f) const; /* Equivalent to GetSubHandlers, but takes the STARTSUBMSG selector for the * field. */ const Handlers* GetSubHandlers(Selector startsubmsg) const; /* A selector refers to a specific field handler in the Handlers object * (for example: the STARTSUBMSG handler for field "field15"). * On success, returns true and stores the selector in "s". * If the FieldDef or Type are invalid, returns false. * The returned selector is ONLY valid for Handlers whose MessageDef * contains this FieldDef. */ static bool GetSelector(const FieldDef* f, Type type, Selector* s); /* Given a START selector of any kind, returns the corresponding END selector. */ static Selector GetEndSelector(Selector start_selector); /* Returns the function pointer for this handler. It is the client's * responsibility to cast to the correct function type before calling it. */ GenericFunction* GetHandler(Selector selector); /* Sets the given attributes to the attributes for this selector. */ bool GetAttributes(Selector selector, HandlerAttributes* attr); /* Returns the handler data that was registered with this handler. */ const void* GetHandlerData(Selector selector); /* Could add any of the following functions as-needed, with some minor * implementation changes: * * const FieldDef* GetFieldDef(Selector selector); * static bool IsSequence(Selector selector); */ private: UPB_DISALLOW_POD_OPS(Handlers, upb::Handlers) friend UPB_INLINE GenericFunction *::upb_handlers_gethandler( const upb_handlers *h, upb_selector_t s); friend UPB_INLINE const void *::upb_handlers_gethandlerdata( const upb_handlers *h, upb_selector_t s); #else struct upb_handlers { #endif upb_refcounted base; const upb_msgdef *msg; const upb_handlers **sub; const void *top_closure_type; upb_inttable cleanup_; upb_status status_; /* Used only when mutable. */ upb_handlers_tabent table[1]; /* Dynamically-sized field handler array. */ }; #ifdef __cplusplus namespace upb { /* Convenience macros for creating a Handler object that is wrapped with a * type-safe wrapper function that converts the "void*" parameters/returns * of the underlying C API into nice C++ function. * * Sample usage: * void OnValue1(MyClosure* c, const MyHandlerData* d, int32_t val) { * // do stuff ... * } * * // Handler that doesn't need any data bound to it. * void OnValue2(MyClosure* c, int32_t val) { * // do stuff ... * } * * // Handler that returns bool so it can return failure if necessary. * bool OnValue3(MyClosure* c, int32_t val) { * // do stuff ... * return ok; * } * * // Member function handler. * class MyClosure { * public: * void OnValue(int32_t val) { * // do stuff ... * } * }; * * // Takes ownership of the MyHandlerData. * handlers->SetInt32Handler(f1, UpbBind(OnValue1, new MyHandlerData(...))); * handlers->SetInt32Handler(f2, UpbMakeHandler(OnValue2)); * handlers->SetInt32Handler(f1, UpbMakeHandler(OnValue3)); * handlers->SetInt32Handler(f2, UpbMakeHandler(&MyClosure::OnValue)); */ #ifdef UPB_CXX11 /* In C++11, the "template" disambiguator can appear even outside templates, * so all calls can safely use this pair of macros. */ #define UpbMakeHandler(f) upb::MatchFunc(f).template GetFunc() /* We have to be careful to only evaluate "d" once. */ #define UpbBind(f, d) upb::MatchFunc(f).template GetFunc((d)) #else /* Prior to C++11, the "template" disambiguator may only appear inside a * template, so the regular macro must not use "template" */ #define UpbMakeHandler(f) upb::MatchFunc(f).GetFunc() #define UpbBind(f, d) upb::MatchFunc(f).GetFunc((d)) #endif /* UPB_CXX11 */ /* This macro must be used in C++98 for calls from inside a template. But we * define this variant in all cases; code that wants to be compatible with both * C++98 and C++11 should always use this macro when calling from a template. */ #define UpbMakeHandlerT(f) upb::MatchFunc(f).template GetFunc() /* We have to be careful to only evaluate "d" once. */ #define UpbBindT(f, d) upb::MatchFunc(f).template GetFunc((d)) /* Handler: a struct that contains the (handler, data, deleter) tuple that is * used to register all handlers. Users can Make() these directly but it's * more convenient to use the UpbMakeHandler/UpbBind macros above. */ template class Handler { public: /* The underlying, handler function signature that upb uses internally. */ typedef T FuncPtr; /* Intentionally implicit. */ template Handler(F func); ~Handler(); private: void AddCleanup(Handlers* h) const { if (cleanup_func_) { bool ok = h->AddCleanup(cleanup_data_, cleanup_func_); UPB_ASSERT(ok); } } UPB_DISALLOW_COPY_AND_ASSIGN(Handler) friend class Handlers; FuncPtr handler_; mutable HandlerAttributes attr_; mutable bool registered_; void *cleanup_data_; upb_handlerfree *cleanup_func_; }; } /* namespace upb */ #endif /* __cplusplus */ UPB_BEGIN_EXTERN_C /* Native C API. */ /* Handler function typedefs. */ typedef bool upb_startmsg_handlerfunc(void *c, const void*); typedef bool upb_endmsg_handlerfunc(void *c, const void *, upb_status *status); typedef void* upb_startfield_handlerfunc(void *c, const void *hd); typedef bool upb_endfield_handlerfunc(void *c, const void *hd); typedef bool upb_int32_handlerfunc(void *c, const void *hd, int32_t val); typedef bool upb_int64_handlerfunc(void *c, const void *hd, int64_t val); typedef bool upb_uint32_handlerfunc(void *c, const void *hd, uint32_t val); typedef bool upb_uint64_handlerfunc(void *c, const void *hd, uint64_t val); typedef bool upb_float_handlerfunc(void *c, const void *hd, float val); typedef bool upb_double_handlerfunc(void *c, const void *hd, double val); typedef bool upb_bool_handlerfunc(void *c, const void *hd, bool val); typedef void *upb_startstr_handlerfunc(void *c, const void *hd, size_t size_hint); typedef size_t upb_string_handlerfunc(void *c, const void *hd, const char *buf, size_t n, const upb_bufhandle* handle); /* upb_bufhandle */ size_t upb_bufhandle_objofs(const upb_bufhandle *h); /* upb_handlerattr */ void upb_handlerattr_init(upb_handlerattr *attr); void upb_handlerattr_uninit(upb_handlerattr *attr); bool upb_handlerattr_sethandlerdata(upb_handlerattr *attr, const void *hd); bool upb_handlerattr_setclosuretype(upb_handlerattr *attr, const void *type); const void *upb_handlerattr_closuretype(const upb_handlerattr *attr); bool upb_handlerattr_setreturnclosuretype(upb_handlerattr *attr, const void *type); const void *upb_handlerattr_returnclosuretype(const upb_handlerattr *attr); bool upb_handlerattr_setalwaysok(upb_handlerattr *attr, bool alwaysok); bool upb_handlerattr_alwaysok(const upb_handlerattr *attr); UPB_INLINE const void *upb_handlerattr_handlerdata( const upb_handlerattr *attr) { return attr->handler_data_; } /* upb_handlers */ typedef void upb_handlers_callback(const void *closure, upb_handlers *h); upb_handlers *upb_handlers_new(const upb_msgdef *m, const void *owner); const upb_handlers *upb_handlers_newfrozen(const upb_msgdef *m, const void *owner, upb_handlers_callback *callback, const void *closure); /* Include refcounted methods like upb_handlers_ref(). */ UPB_REFCOUNTED_CMETHODS(upb_handlers, upb_handlers_upcast) const upb_status *upb_handlers_status(upb_handlers *h); void upb_handlers_clearerr(upb_handlers *h); const upb_msgdef *upb_handlers_msgdef(const upb_handlers *h); bool upb_handlers_addcleanup(upb_handlers *h, void *p, upb_handlerfree *hfree); bool upb_handlers_setstartmsg(upb_handlers *h, upb_startmsg_handlerfunc *func, upb_handlerattr *attr); bool upb_handlers_setendmsg(upb_handlers *h, upb_endmsg_handlerfunc *func, upb_handlerattr *attr); bool upb_handlers_setint32(upb_handlers *h, const upb_fielddef *f, upb_int32_handlerfunc *func, upb_handlerattr *attr); bool upb_handlers_setint64(upb_handlers *h, const upb_fielddef *f, upb_int64_handlerfunc *func, upb_handlerattr *attr); bool upb_handlers_setuint32(upb_handlers *h, const upb_fielddef *f, upb_uint32_handlerfunc *func, upb_handlerattr *attr); bool upb_handlers_setuint64(upb_handlers *h, const upb_fielddef *f, upb_uint64_handlerfunc *func, upb_handlerattr *attr); bool upb_handlers_setfloat(upb_handlers *h, const upb_fielddef *f, upb_float_handlerfunc *func, upb_handlerattr *attr); bool upb_handlers_setdouble(upb_handlers *h, const upb_fielddef *f, upb_double_handlerfunc *func, upb_handlerattr *attr); bool upb_handlers_setbool(upb_handlers *h, const upb_fielddef *f, upb_bool_handlerfunc *func, upb_handlerattr *attr); bool upb_handlers_setstartstr(upb_handlers *h, const upb_fielddef *f, upb_startstr_handlerfunc *func, upb_handlerattr *attr); bool upb_handlers_setstring(upb_handlers *h, const upb_fielddef *f, upb_string_handlerfunc *func, upb_handlerattr *attr); bool upb_handlers_setendstr(upb_handlers *h, const upb_fielddef *f, upb_endfield_handlerfunc *func, upb_handlerattr *attr); bool upb_handlers_setstartseq(upb_handlers *h, const upb_fielddef *f, upb_startfield_handlerfunc *func, upb_handlerattr *attr); bool upb_handlers_setstartsubmsg(upb_handlers *h, const upb_fielddef *f, upb_startfield_handlerfunc *func, upb_handlerattr *attr); bool upb_handlers_setendsubmsg(upb_handlers *h, const upb_fielddef *f, upb_endfield_handlerfunc *func, upb_handlerattr *attr); bool upb_handlers_setendseq(upb_handlers *h, const upb_fielddef *f, upb_endfield_handlerfunc *func, upb_handlerattr *attr); bool upb_handlers_setsubhandlers(upb_handlers *h, const upb_fielddef *f, const upb_handlers *sub); const upb_handlers *upb_handlers_getsubhandlers(const upb_handlers *h, const upb_fielddef *f); const upb_handlers *upb_handlers_getsubhandlers_sel(const upb_handlers *h, upb_selector_t sel); UPB_INLINE upb_func *upb_handlers_gethandler(const upb_handlers *h, upb_selector_t s) { return (upb_func *)h->table[s].func; } bool upb_handlers_getattr(const upb_handlers *h, upb_selector_t s, upb_handlerattr *attr); UPB_INLINE const void *upb_handlers_gethandlerdata(const upb_handlers *h, upb_selector_t s) { return upb_handlerattr_handlerdata(&h->table[s].attr); } #ifdef __cplusplus /* Handler types for single fields. * Right now we only have one for TYPE_BYTES but ones for other types * should follow. * * These follow the same handlers protocol for fields of a message. */ class upb::BytesHandler { public: BytesHandler(); ~BytesHandler(); #else struct upb_byteshandler { #endif upb_handlers_tabent table[3]; }; void upb_byteshandler_init(upb_byteshandler *h); /* Caller must ensure that "d" outlives the handlers. * TODO(haberman): should this have a "freeze" operation? It's not necessary * for memory management, but could be useful to force immutability and provide * a convenient moment to verify that all registration succeeded. */ bool upb_byteshandler_setstartstr(upb_byteshandler *h, upb_startstr_handlerfunc *func, void *d); bool upb_byteshandler_setstring(upb_byteshandler *h, upb_string_handlerfunc *func, void *d); bool upb_byteshandler_setendstr(upb_byteshandler *h, upb_endfield_handlerfunc *func, void *d); /* "Static" methods */ bool upb_handlers_freeze(upb_handlers *const *handlers, int n, upb_status *s); upb_handlertype_t upb_handlers_getprimitivehandlertype(const upb_fielddef *f); bool upb_handlers_getselector(const upb_fielddef *f, upb_handlertype_t type, upb_selector_t *s); UPB_INLINE upb_selector_t upb_handlers_getendselector(upb_selector_t start) { return start + 1; } /* Internal-only. */ uint32_t upb_handlers_selectorbaseoffset(const upb_fielddef *f); uint32_t upb_handlers_selectorcount(const upb_fielddef *f); UPB_END_EXTERN_C /* ** Inline definitions for handlers.h, which are particularly long and a bit ** tricky. */ #ifndef UPB_HANDLERS_INL_H_ #define UPB_HANDLERS_INL_H_ #include /* C inline methods. */ /* upb_bufhandle */ UPB_INLINE void upb_bufhandle_init(upb_bufhandle *h) { h->obj_ = NULL; h->objtype_ = NULL; h->buf_ = NULL; h->objofs_ = 0; } UPB_INLINE void upb_bufhandle_uninit(upb_bufhandle *h) { UPB_UNUSED(h); } UPB_INLINE void upb_bufhandle_setobj(upb_bufhandle *h, const void *obj, const void *type) { h->obj_ = obj; h->objtype_ = type; } UPB_INLINE void upb_bufhandle_setbuf(upb_bufhandle *h, const char *buf, size_t ofs) { h->buf_ = buf; h->objofs_ = ofs; } UPB_INLINE const void *upb_bufhandle_obj(const upb_bufhandle *h) { return h->obj_; } UPB_INLINE const void *upb_bufhandle_objtype(const upb_bufhandle *h) { return h->objtype_; } UPB_INLINE const char *upb_bufhandle_buf(const upb_bufhandle *h) { return h->buf_; } #ifdef __cplusplus /* Type detection and typedefs for integer types. * For platforms where there are multiple 32-bit or 64-bit types, we need to be * able to enumerate them so we can properly create overloads for all variants. * * If any platform existed where there were three integer types with the same * size, this would have to become more complicated. For example, short, int, * and long could all be 32-bits. Even more diabolically, short, int, long, * and long long could all be 64 bits and still be standard-compliant. * However, few platforms are this strange, and it's unlikely that upb will be * used on the strangest ones. */ /* Can't count on stdint.h limits like INT32_MAX, because in C++ these are * only defined when __STDC_LIMIT_MACROS are defined before the *first* include * of stdint.h. We can't guarantee that someone else didn't include these first * without defining __STDC_LIMIT_MACROS. */ #define UPB_INT32_MAX 0x7fffffffLL #define UPB_INT32_MIN (-UPB_INT32_MAX - 1) #define UPB_INT64_MAX 0x7fffffffffffffffLL #define UPB_INT64_MIN (-UPB_INT64_MAX - 1) #if INT_MAX == UPB_INT32_MAX && INT_MIN == UPB_INT32_MIN #define UPB_INT_IS_32BITS 1 #endif #if LONG_MAX == UPB_INT32_MAX && LONG_MIN == UPB_INT32_MIN #define UPB_LONG_IS_32BITS 1 #endif #if LONG_MAX == UPB_INT64_MAX && LONG_MIN == UPB_INT64_MIN #define UPB_LONG_IS_64BITS 1 #endif #if LLONG_MAX == UPB_INT64_MAX && LLONG_MIN == UPB_INT64_MIN #define UPB_LLONG_IS_64BITS 1 #endif /* We use macros instead of typedefs so we can undefine them later and avoid * leaking them outside this header file. */ #if UPB_INT_IS_32BITS #define UPB_INT32_T int #define UPB_UINT32_T unsigned int #if UPB_LONG_IS_32BITS #define UPB_TWO_32BIT_TYPES 1 #define UPB_INT32ALT_T long #define UPB_UINT32ALT_T unsigned long #endif /* UPB_LONG_IS_32BITS */ #elif UPB_LONG_IS_32BITS /* && !UPB_INT_IS_32BITS */ #define UPB_INT32_T long #define UPB_UINT32_T unsigned long #endif /* UPB_INT_IS_32BITS */ #if UPB_LONG_IS_64BITS #define UPB_INT64_T long #define UPB_UINT64_T unsigned long #if UPB_LLONG_IS_64BITS #define UPB_TWO_64BIT_TYPES 1 #define UPB_INT64ALT_T long long #define UPB_UINT64ALT_T unsigned long long #endif /* UPB_LLONG_IS_64BITS */ #elif UPB_LLONG_IS_64BITS /* && !UPB_LONG_IS_64BITS */ #define UPB_INT64_T long long #define UPB_UINT64_T unsigned long long #endif /* UPB_LONG_IS_64BITS */ #undef UPB_INT32_MAX #undef UPB_INT32_MIN #undef UPB_INT64_MAX #undef UPB_INT64_MIN #undef UPB_INT_IS_32BITS #undef UPB_LONG_IS_32BITS #undef UPB_LONG_IS_64BITS #undef UPB_LLONG_IS_64BITS namespace upb { typedef void CleanupFunc(void *ptr); /* Template to remove "const" from "const T*" and just return "T*". * * We define a nonsense default because otherwise it will fail to instantiate as * a function parameter type even in cases where we don't expect any caller to * actually match the overload. */ class CouldntRemoveConst {}; template struct remove_constptr { typedef CouldntRemoveConst type; }; template struct remove_constptr { typedef T *type; }; /* Template that we use below to remove a template specialization from * consideration if it matches a specific type. */ template struct disable_if_same { typedef void Type; }; template struct disable_if_same {}; template void DeletePointer(void *p) { delete static_cast(p); } template struct FirstUnlessVoidOrBool { typedef T1 value; }; template struct FirstUnlessVoidOrBool { typedef T2 value; }; template struct FirstUnlessVoidOrBool { typedef T2 value; }; template struct is_same { static bool value; }; template struct is_same { static bool value; }; template bool is_same::value = false; template bool is_same::value = true; /* FuncInfo *******************************************************************/ /* Info about the user's original, pre-wrapped function. */ template struct FuncInfo { /* The type of the closure that the function takes (its first param). */ typedef C Closure; /* The return type. */ typedef R Return; }; /* Func ***********************************************************************/ /* Func1, Func2, Func3: Template classes representing a function and its * signature. * * Since the function is a template parameter, calling the function can be * inlined at compile-time and does not require a function pointer at runtime. * These functions are not bound to a handler data so have no data or cleanup * handler. */ struct UnboundFunc { CleanupFunc *GetCleanup() { return NULL; } void *GetData() { return NULL; } }; template struct Func1 : public UnboundFunc { typedef R Return; typedef I FuncInfo; static R Call(P1 p1) { return F(p1); } }; template struct Func2 : public UnboundFunc { typedef R Return; typedef I FuncInfo; static R Call(P1 p1, P2 p2) { return F(p1, p2); } }; template struct Func3 : public UnboundFunc { typedef R Return; typedef I FuncInfo; static R Call(P1 p1, P2 p2, P3 p3) { return F(p1, p2, p3); } }; template struct Func4 : public UnboundFunc { typedef R Return; typedef I FuncInfo; static R Call(P1 p1, P2 p2, P3 p3, P4 p4) { return F(p1, p2, p3, p4); } }; template struct Func5 : public UnboundFunc { typedef R Return; typedef I FuncInfo; static R Call(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) { return F(p1, p2, p3, p4, p5); } }; /* BoundFunc ******************************************************************/ /* BoundFunc2, BoundFunc3: Like Func2/Func3 except also contains a value that * shall be bound to the function's second parameter. * * Note that the second parameter is a const pointer, but our stored bound value * is non-const so we can free it when the handlers are destroyed. */ template struct BoundFunc { typedef typename remove_constptr::type MutableP2; explicit BoundFunc(MutableP2 data_) : data(data_) {} CleanupFunc *GetCleanup() { return &DeletePointer; } MutableP2 GetData() { return data; } MutableP2 data; }; template struct BoundFunc2 : public BoundFunc { typedef BoundFunc Base; typedef I FuncInfo; explicit BoundFunc2(typename Base::MutableP2 arg) : Base(arg) {} }; template struct BoundFunc3 : public BoundFunc { typedef BoundFunc Base; typedef I FuncInfo; explicit BoundFunc3(typename Base::MutableP2 arg) : Base(arg) {} }; template struct BoundFunc4 : public BoundFunc { typedef BoundFunc Base; typedef I FuncInfo; explicit BoundFunc4(typename Base::MutableP2 arg) : Base(arg) {} }; template struct BoundFunc5 : public BoundFunc { typedef BoundFunc Base; typedef I FuncInfo; explicit BoundFunc5(typename Base::MutableP2 arg) : Base(arg) {} }; /* FuncSig ********************************************************************/ /* FuncSig1, FuncSig2, FuncSig3: template classes reflecting a function * *signature*, but without a specific function attached. * * These classes contain member functions that can be invoked with a * specific function to return a Func/BoundFunc class. */ template struct FuncSig1 { template Func1 > GetFunc() { return Func1 >(); } }; template struct FuncSig2 { template Func2 > GetFunc() { return Func2 >(); } template BoundFunc2 > GetFunc( typename remove_constptr::type param2) { return BoundFunc2 >(param2); } }; template struct FuncSig3 { template Func3 > GetFunc() { return Func3 >(); } template BoundFunc3 > GetFunc( typename remove_constptr::type param2) { return BoundFunc3 >(param2); } }; template struct FuncSig4 { template Func4 > GetFunc() { return Func4 >(); } template BoundFunc4 > GetFunc( typename remove_constptr::type param2) { return BoundFunc4 >(param2); } }; template struct FuncSig5 { template Func5 > GetFunc() { return Func5 >(); } template BoundFunc5 > GetFunc( typename remove_constptr::type param2) { return BoundFunc5 >(param2); } }; /* Overloaded template function that can construct the appropriate FuncSig* * class given a function pointer by deducing the template parameters. */ template inline FuncSig1 MatchFunc(R (*f)(P1)) { UPB_UNUSED(f); /* Only used for template parameter deduction. */ return FuncSig1(); } template inline FuncSig2 MatchFunc(R (*f)(P1, P2)) { UPB_UNUSED(f); /* Only used for template parameter deduction. */ return FuncSig2(); } template inline FuncSig3 MatchFunc(R (*f)(P1, P2, P3)) { UPB_UNUSED(f); /* Only used for template parameter deduction. */ return FuncSig3(); } template inline FuncSig4 MatchFunc(R (*f)(P1, P2, P3, P4)) { UPB_UNUSED(f); /* Only used for template parameter deduction. */ return FuncSig4(); } template inline FuncSig5 MatchFunc(R (*f)(P1, P2, P3, P4, P5)) { UPB_UNUSED(f); /* Only used for template parameter deduction. */ return FuncSig5(); } /* MethodSig ******************************************************************/ /* CallMethod*: a function template that calls a given method. */ template R CallMethod0(C *obj) { return ((*obj).*F)(); } template R CallMethod1(C *obj, P1 arg1) { return ((*obj).*F)(arg1); } template R CallMethod2(C *obj, P1 arg1, P2 arg2) { return ((*obj).*F)(arg1, arg2); } template R CallMethod3(C *obj, P1 arg1, P2 arg2, P3 arg3) { return ((*obj).*F)(arg1, arg2, arg3); } template R CallMethod4(C *obj, P1 arg1, P2 arg2, P3 arg3, P4 arg4) { return ((*obj).*F)(arg1, arg2, arg3, arg4); } /* MethodSig: like FuncSig, but for member functions. * * GetFunc() returns a normal FuncN object, so after calling GetFunc() no * more logic is required to special-case methods. */ template struct MethodSig0 { template Func1, FuncInfo > GetFunc() { return Func1, FuncInfo >(); } }; template struct MethodSig1 { template Func2, FuncInfo > GetFunc() { return Func2, FuncInfo >(); } template BoundFunc2, FuncInfo > GetFunc( typename remove_constptr::type param1) { return BoundFunc2, FuncInfo >( param1); } }; template struct MethodSig2 { template Func3, FuncInfo > GetFunc() { return Func3, FuncInfo >(); } template BoundFunc3, FuncInfo > GetFunc(typename remove_constptr::type param1) { return BoundFunc3, FuncInfo >(param1); } }; template struct MethodSig3 { template Func4, FuncInfo > GetFunc() { return Func4, FuncInfo >(); } template BoundFunc4, FuncInfo > GetFunc(typename remove_constptr::type param1) { return BoundFunc4, FuncInfo >(param1); } }; template struct MethodSig4 { template Func5, FuncInfo > GetFunc() { return Func5, FuncInfo >(); } template BoundFunc5, FuncInfo > GetFunc(typename remove_constptr::type param1) { return BoundFunc5, FuncInfo >( param1); } }; template inline MethodSig0 MatchFunc(R (C::*f)()) { UPB_UNUSED(f); /* Only used for template parameter deduction. */ return MethodSig0(); } template inline MethodSig1 MatchFunc(R (C::*f)(P1)) { UPB_UNUSED(f); /* Only used for template parameter deduction. */ return MethodSig1(); } template inline MethodSig2 MatchFunc(R (C::*f)(P1, P2)) { UPB_UNUSED(f); /* Only used for template parameter deduction. */ return MethodSig2(); } template inline MethodSig3 MatchFunc(R (C::*f)(P1, P2, P3)) { UPB_UNUSED(f); /* Only used for template parameter deduction. */ return MethodSig3(); } template inline MethodSig4 MatchFunc(R (C::*f)(P1, P2, P3, P4)) { UPB_UNUSED(f); /* Only used for template parameter deduction. */ return MethodSig4(); } /* MaybeWrapReturn ************************************************************/ /* Template class that attempts to wrap the return value of the function so it * matches the expected type. There are two main adjustments it may make: * * 1. If the function returns void, make it return the expected type and with * a value that always indicates success. * 2. If the function returns bool, make it return the expected type with a * value that indicates success or failure. * * The "expected type" for return is: * 1. void* for start handlers. If the closure parameter has a different type * we will cast it to void* for the return in the success case. * 2. size_t for string buffer handlers. * 3. bool for everything else. */ /* Template parameters are FuncN type and desired return type. */ template struct MaybeWrapReturn; /* If the return type matches, return the given function unwrapped. */ template struct MaybeWrapReturn { typedef F Func; }; /* Function wrapper that munges the return value from void to (bool)true. */ template bool ReturnTrue2(P1 p1, P2 p2) { F(p1, p2); return true; } template bool ReturnTrue3(P1 p1, P2 p2, P3 p3) { F(p1, p2, p3); return true; } /* Function wrapper that munges the return value from void to (void*)arg1 */ template void *ReturnClosure2(P1 p1, P2 p2) { F(p1, p2); return p1; } template void *ReturnClosure3(P1 p1, P2 p2, P3 p3) { F(p1, p2, p3); return p1; } /* Function wrapper that munges the return value from R to void*. */ template void *CastReturnToVoidPtr2(P1 p1, P2 p2) { return F(p1, p2); } template void *CastReturnToVoidPtr3(P1 p1, P2 p2, P3 p3) { return F(p1, p2, p3); } /* Function wrapper that munges the return value from bool to void*. */ template void *ReturnClosureOrBreak2(P1 p1, P2 p2) { return F(p1, p2) ? p1 : UPB_BREAK; } template void *ReturnClosureOrBreak3(P1 p1, P2 p2, P3 p3) { return F(p1, p2, p3) ? p1 : UPB_BREAK; } /* For the string callback, which takes five params, returns the size param. */ template size_t ReturnStringLen(P1 p1, P2 p2, const char *p3, size_t p4, const BufferHandle *p5) { F(p1, p2, p3, p4, p5); return p4; } /* For the string callback, which takes five params, returns the size param or * zero. */ template size_t ReturnNOr0(P1 p1, P2 p2, const char *p3, size_t p4, const BufferHandle *p5) { return F(p1, p2, p3, p4, p5) ? p4 : 0; } /* If we have a function returning void but want a function returning bool, wrap * it in a function that returns true. */ template struct MaybeWrapReturn, bool> { typedef Func2, I> Func; }; template struct MaybeWrapReturn, bool> { typedef Func3, I> Func; }; /* If our function returns void but we want one returning void*, wrap it in a * function that returns the first argument. */ template struct MaybeWrapReturn, void *> { typedef Func2, I> Func; }; template struct MaybeWrapReturn, void *> { typedef Func3, I> Func; }; /* If our function returns R* but we want one returning void*, wrap it in a * function that casts to void*. */ template struct MaybeWrapReturn, void *, typename disable_if_same::Type> { typedef Func2, I> Func; }; template struct MaybeWrapReturn, void *, typename disable_if_same::Type> { typedef Func3, I> Func; }; /* If our function returns bool but we want one returning void*, wrap it in a * function that returns either the first param or UPB_BREAK. */ template struct MaybeWrapReturn, void *> { typedef Func2, I> Func; }; template struct MaybeWrapReturn, void *> { typedef Func3, I> Func; }; /* If our function returns void but we want one returning size_t, wrap it in a * function that returns the size argument. */ template struct MaybeWrapReturn< Func5, size_t> { typedef Func5, I> Func; }; /* If our function returns bool but we want one returning size_t, wrap it in a * function that returns either 0 or the buf size. */ template struct MaybeWrapReturn< Func5, size_t> { typedef Func5, I> Func; }; /* ConvertParams **************************************************************/ /* Template class that converts the function parameters if necessary, and * ignores the HandlerData parameter if appropriate. * * Template parameter is the are FuncN function type. */ template struct ConvertParams; /* Function that discards the handler data parameter. */ template R IgnoreHandlerData2(void *p1, const void *hd) { UPB_UNUSED(hd); return F(static_cast(p1)); } template R IgnoreHandlerData3(void *p1, const void *hd, P2Wrapper p2) { UPB_UNUSED(hd); return F(static_cast(p1), p2); } template R IgnoreHandlerData4(void *p1, const void *hd, P2 p2, P3 p3) { UPB_UNUSED(hd); return F(static_cast(p1), p2, p3); } template R IgnoreHandlerData5(void *p1, const void *hd, P2 p2, P3 p3, P4 p4) { UPB_UNUSED(hd); return F(static_cast(p1), p2, p3, p4); } template R IgnoreHandlerDataIgnoreHandle(void *p1, const void *hd, const char *p2, size_t p3, const BufferHandle *handle) { UPB_UNUSED(hd); UPB_UNUSED(handle); return F(static_cast(p1), p2, p3); } /* Function that casts the handler data parameter. */ template R CastHandlerData2(void *c, const void *hd) { return F(static_cast(c), static_cast(hd)); } template R CastHandlerData3(void *c, const void *hd, P3Wrapper p3) { return F(static_cast(c), static_cast(hd), p3); } template R CastHandlerData5(void *c, const void *hd, P3 p3, P4 p4, P5 p5) { return F(static_cast(c), static_cast(hd), p3, p4, p5); } template R CastHandlerDataIgnoreHandle(void *c, const void *hd, const char *p3, size_t p4, const BufferHandle *handle) { UPB_UNUSED(handle); return F(static_cast(c), static_cast(hd), p3, p4); } /* For unbound functions, ignore the handler data. */ template struct ConvertParams, T> { typedef Func2, I> Func; }; template struct ConvertParams, R2 (*)(P1_2, P2_2, P3_2)> { typedef Func3, I> Func; }; /* For StringBuffer only; this ignores both the handler data and the * BufferHandle. */ template struct ConvertParams, T> { typedef Func5, I> Func; }; template struct ConvertParams, T> { typedef Func5, I> Func; }; /* For bound functions, cast the handler data. */ template struct ConvertParams, T> { typedef Func2, I> Func; }; template struct ConvertParams, R2 (*)(P1_2, P2_2, P3_2)> { typedef Func3, I> Func; }; /* For StringBuffer only; this ignores the BufferHandle. */ template struct ConvertParams, T> { typedef Func5, I> Func; }; template struct ConvertParams, T> { typedef Func5, I> Func; }; /* utype/ltype are upper/lower-case, ctype is canonical C type, vtype is * variant C type. */ #define TYPE_METHODS(utype, ltype, ctype, vtype) \ template <> struct CanonicalType { \ typedef ctype Type; \ }; \ template <> \ inline bool Handlers::SetValueHandler( \ const FieldDef *f, \ const Handlers::utype ## Handler& handler) { \ UPB_ASSERT(!handler.registered_); \ handler.AddCleanup(this); \ handler.registered_ = true; \ return upb_handlers_set##ltype(this, f, handler.handler_, &handler.attr_); \ } \ TYPE_METHODS(Double, double, double, double) TYPE_METHODS(Float, float, float, float) TYPE_METHODS(UInt64, uint64, uint64_t, UPB_UINT64_T) TYPE_METHODS(UInt32, uint32, uint32_t, UPB_UINT32_T) TYPE_METHODS(Int64, int64, int64_t, UPB_INT64_T) TYPE_METHODS(Int32, int32, int32_t, UPB_INT32_T) TYPE_METHODS(Bool, bool, bool, bool) #ifdef UPB_TWO_32BIT_TYPES TYPE_METHODS(Int32, int32, int32_t, UPB_INT32ALT_T) TYPE_METHODS(UInt32, uint32, uint32_t, UPB_UINT32ALT_T) #endif #ifdef UPB_TWO_64BIT_TYPES TYPE_METHODS(Int64, int64, int64_t, UPB_INT64ALT_T) TYPE_METHODS(UInt64, uint64, uint64_t, UPB_UINT64ALT_T) #endif #undef TYPE_METHODS template <> struct CanonicalType { typedef Status* Type; }; /* Type methods that are only one-per-canonical-type and not * one-per-cvariant. */ #define TYPE_METHODS(utype, ctype) \ inline bool Handlers::Set##utype##Handler(const FieldDef *f, \ const utype##Handler &h) { \ return SetValueHandler(f, h); \ } \ TYPE_METHODS(Double, double) TYPE_METHODS(Float, float) TYPE_METHODS(UInt64, uint64_t) TYPE_METHODS(UInt32, uint32_t) TYPE_METHODS(Int64, int64_t) TYPE_METHODS(Int32, int32_t) TYPE_METHODS(Bool, bool) #undef TYPE_METHODS template struct ReturnOf; template struct ReturnOf { typedef R Return; }; template struct ReturnOf { typedef R Return; }; template struct ReturnOf { typedef R Return; }; template struct ReturnOf { typedef R Return; }; template const void *UniquePtrForType() { static const char ch = 0; return &ch; } template template inline Handler::Handler(F func) : registered_(false), cleanup_data_(func.GetData()), cleanup_func_(func.GetCleanup()) { upb_handlerattr_sethandlerdata(&attr_, func.GetData()); typedef typename ReturnOf::Return Return; typedef typename ConvertParams::Func ConvertedParamsFunc; typedef typename MaybeWrapReturn::Func ReturnWrappedFunc; handler_ = ReturnWrappedFunc().Call; /* Set attributes based on what templates can statically tell us about the * user's function. */ /* If the original function returns void, then we know that we wrapped it to * always return ok. */ bool always_ok = is_same::value; attr_.SetAlwaysOk(always_ok); /* Closure parameter and return type. */ attr_.SetClosureType(UniquePtrForType()); /* We use the closure type (from the first parameter) if the return type is * void or bool, since these are the two cases we wrap to return the closure's * type anyway. * * This is all nonsense for non START* handlers, but it doesn't matter because * in that case the value will be ignored. */ typedef typename FirstUnlessVoidOrBool::value EffectiveReturn; attr_.SetReturnClosureType(UniquePtrForType()); } template inline Handler::~Handler() { UPB_ASSERT(registered_); } inline HandlerAttributes::HandlerAttributes() { upb_handlerattr_init(this); } inline HandlerAttributes::~HandlerAttributes() { upb_handlerattr_uninit(this); } inline bool HandlerAttributes::SetHandlerData(const void *hd) { return upb_handlerattr_sethandlerdata(this, hd); } inline const void* HandlerAttributes::handler_data() const { return upb_handlerattr_handlerdata(this); } inline bool HandlerAttributes::SetClosureType(const void *type) { return upb_handlerattr_setclosuretype(this, type); } inline const void* HandlerAttributes::closure_type() const { return upb_handlerattr_closuretype(this); } inline bool HandlerAttributes::SetReturnClosureType(const void *type) { return upb_handlerattr_setreturnclosuretype(this, type); } inline const void* HandlerAttributes::return_closure_type() const { return upb_handlerattr_returnclosuretype(this); } inline bool HandlerAttributes::SetAlwaysOk(bool always_ok) { return upb_handlerattr_setalwaysok(this, always_ok); } inline bool HandlerAttributes::always_ok() const { return upb_handlerattr_alwaysok(this); } inline BufferHandle::BufferHandle() { upb_bufhandle_init(this); } inline BufferHandle::~BufferHandle() { upb_bufhandle_uninit(this); } inline const char* BufferHandle::buffer() const { return upb_bufhandle_buf(this); } inline size_t BufferHandle::object_offset() const { return upb_bufhandle_objofs(this); } inline void BufferHandle::SetBuffer(const char* buf, size_t ofs) { upb_bufhandle_setbuf(this, buf, ofs); } template void BufferHandle::SetAttachedObject(const T* obj) { upb_bufhandle_setobj(this, obj, UniquePtrForType()); } template const T* BufferHandle::GetAttachedObject() const { return upb_bufhandle_objtype(this) == UniquePtrForType() ? static_cast(upb_bufhandle_obj(this)) : NULL; } inline reffed_ptr Handlers::New(const MessageDef *m) { upb_handlers *h = upb_handlers_new(m, &h); return reffed_ptr(h, &h); } inline reffed_ptr Handlers::NewFrozen( const MessageDef *m, upb_handlers_callback *callback, const void *closure) { const upb_handlers *h = upb_handlers_newfrozen(m, &h, callback, closure); return reffed_ptr(h, &h); } inline const Status* Handlers::status() { return upb_handlers_status(this); } inline void Handlers::ClearError() { return upb_handlers_clearerr(this); } inline bool Handlers::Freeze(Status *s) { upb::Handlers* h = this; return upb_handlers_freeze(&h, 1, s); } inline bool Handlers::Freeze(Handlers *const *handlers, int n, Status *s) { return upb_handlers_freeze(handlers, n, s); } inline bool Handlers::Freeze(const std::vector& h, Status* status) { return upb_handlers_freeze((Handlers* const*)&h[0], h.size(), status); } inline const MessageDef *Handlers::message_def() const { return upb_handlers_msgdef(this); } inline bool Handlers::AddCleanup(void *p, upb_handlerfree *func) { return upb_handlers_addcleanup(this, p, func); } inline bool Handlers::SetStartMessageHandler( const Handlers::StartMessageHandler &handler) { UPB_ASSERT(!handler.registered_); handler.registered_ = true; handler.AddCleanup(this); return upb_handlers_setstartmsg(this, handler.handler_, &handler.attr_); } inline bool Handlers::SetEndMessageHandler( const Handlers::EndMessageHandler &handler) { UPB_ASSERT(!handler.registered_); handler.registered_ = true; handler.AddCleanup(this); return upb_handlers_setendmsg(this, handler.handler_, &handler.attr_); } inline bool Handlers::SetStartStringHandler(const FieldDef *f, const StartStringHandler &handler) { UPB_ASSERT(!handler.registered_); handler.registered_ = true; handler.AddCleanup(this); return upb_handlers_setstartstr(this, f, handler.handler_, &handler.attr_); } inline bool Handlers::SetEndStringHandler(const FieldDef *f, const EndFieldHandler &handler) { UPB_ASSERT(!handler.registered_); handler.registered_ = true; handler.AddCleanup(this); return upb_handlers_setendstr(this, f, handler.handler_, &handler.attr_); } inline bool Handlers::SetStringHandler(const FieldDef *f, const StringHandler& handler) { UPB_ASSERT(!handler.registered_); handler.registered_ = true; handler.AddCleanup(this); return upb_handlers_setstring(this, f, handler.handler_, &handler.attr_); } inline bool Handlers::SetStartSequenceHandler( const FieldDef *f, const StartFieldHandler &handler) { UPB_ASSERT(!handler.registered_); handler.registered_ = true; handler.AddCleanup(this); return upb_handlers_setstartseq(this, f, handler.handler_, &handler.attr_); } inline bool Handlers::SetStartSubMessageHandler( const FieldDef *f, const StartFieldHandler &handler) { UPB_ASSERT(!handler.registered_); handler.registered_ = true; handler.AddCleanup(this); return upb_handlers_setstartsubmsg(this, f, handler.handler_, &handler.attr_); } inline bool Handlers::SetEndSubMessageHandler(const FieldDef *f, const EndFieldHandler &handler) { UPB_ASSERT(!handler.registered_); handler.registered_ = true; handler.AddCleanup(this); return upb_handlers_setendsubmsg(this, f, handler.handler_, &handler.attr_); } inline bool Handlers::SetEndSequenceHandler(const FieldDef *f, const EndFieldHandler &handler) { UPB_ASSERT(!handler.registered_); handler.registered_ = true; handler.AddCleanup(this); return upb_handlers_setendseq(this, f, handler.handler_, &handler.attr_); } inline bool Handlers::SetSubHandlers(const FieldDef *f, const Handlers *sub) { return upb_handlers_setsubhandlers(this, f, sub); } inline const Handlers *Handlers::GetSubHandlers(const FieldDef *f) const { return upb_handlers_getsubhandlers(this, f); } inline const Handlers *Handlers::GetSubHandlers(Handlers::Selector sel) const { return upb_handlers_getsubhandlers_sel(this, sel); } inline bool Handlers::GetSelector(const FieldDef *f, Handlers::Type type, Handlers::Selector *s) { return upb_handlers_getselector(f, type, s); } inline Handlers::Selector Handlers::GetEndSelector(Handlers::Selector start) { return upb_handlers_getendselector(start); } inline Handlers::GenericFunction *Handlers::GetHandler( Handlers::Selector selector) { return upb_handlers_gethandler(this, selector); } inline const void *Handlers::GetHandlerData(Handlers::Selector selector) { return upb_handlers_gethandlerdata(this, selector); } inline BytesHandler::BytesHandler() { upb_byteshandler_init(this); } inline BytesHandler::~BytesHandler() {} } /* namespace upb */ #endif /* __cplusplus */ #undef UPB_TWO_32BIT_TYPES #undef UPB_TWO_64BIT_TYPES #undef UPB_INT32_T #undef UPB_UINT32_T #undef UPB_INT32ALT_T #undef UPB_UINT32ALT_T #undef UPB_INT64_T #undef UPB_UINT64_T #undef UPB_INT64ALT_T #undef UPB_UINT64ALT_T #endif /* UPB_HANDLERS_INL_H_ */ #endif /* UPB_HANDLERS_H */ /* ** upb::Sink (upb_sink) ** upb::BytesSink (upb_bytessink) ** ** A upb_sink is an object that binds a upb_handlers object to some runtime ** state. It is the object that can actually receive data via the upb_handlers ** interface. ** ** Unlike upb_def and upb_handlers, upb_sink is never frozen, immutable, or ** thread-safe. You can create as many of them as you want, but each one may ** only be used in a single thread at a time. ** ** If we compare with class-based OOP, a you can think of a upb_def as an ** abstract base class, a upb_handlers as a concrete derived class, and a ** upb_sink as an object (class instance). */ #ifndef UPB_SINK_H #define UPB_SINK_H #ifdef __cplusplus namespace upb { class BufferSink; class BufferSource; class BytesSink; class Sink; } #endif UPB_DECLARE_TYPE(upb::BufferSink, upb_bufsink) UPB_DECLARE_TYPE(upb::BufferSource, upb_bufsrc) UPB_DECLARE_TYPE(upb::BytesSink, upb_bytessink) UPB_DECLARE_TYPE(upb::Sink, upb_sink) #ifdef __cplusplus /* A upb::Sink is an object that binds a upb::Handlers object to some runtime * state. It represents an endpoint to which data can be sent. * * TODO(haberman): right now all of these functions take selectors. Should they * take selectorbase instead? * * ie. instead of calling: * sink->StartString(FOO_FIELD_START_STRING, ...) * a selector base would let you say: * sink->StartString(FOO_FIELD, ...) * * This would make call sites a little nicer and require emitting fewer selector * definitions in .h files. * * But the current scheme has the benefit that you can retrieve a function * pointer for any handler with handlers->GetHandler(selector), without having * to have a separate GetHandler() function for each handler type. The JIT * compiler uses this. To accommodate we'd have to expose a separate * GetHandler() for every handler type. * * Also to ponder: selectors right now are independent of a specific Handlers * instance. In other words, they allocate a number to every possible handler * that *could* be registered, without knowing anything about what handlers * *are* registered. That means that using selectors as table offsets prohibits * us from compacting the handler table at Freeze() time. If the table is very * sparse, this could be wasteful. * * Having another selector-like thing that is specific to a Handlers instance * would allow this compacting, but then it would be impossible to write code * ahead-of-time that can be bound to any Handlers instance at runtime. For * example, a .proto file parser written as straight C will not know what * Handlers it will be bound to, so when it calls sink->StartString() what * selector will it pass? It needs a selector like we have today, that is * independent of any particular upb::Handlers. * * Is there a way then to allow Handlers table compaction? */ class upb::Sink { public: /* Constructor with no initialization; must be Reset() before use. */ Sink() {} /* Constructs a new sink for the given frozen handlers and closure. * * TODO: once the Handlers know the expected closure type, verify that T * matches it. */ template Sink(const Handlers* handlers, T* closure); /* Resets the value of the sink. */ template void Reset(const Handlers* handlers, T* closure); /* Returns the top-level object that is bound to this sink. * * TODO: once the Handlers know the expected closure type, verify that T * matches it. */ template T* GetObject() const; /* Functions for pushing data into the sink. * * These return false if processing should stop (either due to error or just * to suspend). * * These may not be called from within one of the same sink's handlers (in * other words, handlers are not re-entrant). */ /* Should be called at the start and end of every message; both the top-level * message and submessages. This means that submessages should use the * following sequence: * sink->StartSubMessage(startsubmsg_selector); * sink->StartMessage(); * // ... * sink->EndMessage(&status); * sink->EndSubMessage(endsubmsg_selector); */ bool StartMessage(); bool EndMessage(Status* status); /* Putting of individual values. These work for both repeated and * non-repeated fields, but for repeated fields you must wrap them in * calls to StartSequence()/EndSequence(). */ bool PutInt32(Handlers::Selector s, int32_t val); bool PutInt64(Handlers::Selector s, int64_t val); bool PutUInt32(Handlers::Selector s, uint32_t val); bool PutUInt64(Handlers::Selector s, uint64_t val); bool PutFloat(Handlers::Selector s, float val); bool PutDouble(Handlers::Selector s, double val); bool PutBool(Handlers::Selector s, bool val); /* Putting of string/bytes values. Each string can consist of zero or more * non-contiguous buffers of data. * * For StartString(), the function will write a sink for the string to "sub." * The sub-sink must be used for any/all PutStringBuffer() calls. */ bool StartString(Handlers::Selector s, size_t size_hint, Sink* sub); size_t PutStringBuffer(Handlers::Selector s, const char *buf, size_t len, const BufferHandle *handle); bool EndString(Handlers::Selector s); /* For submessage fields. * * For StartSubMessage(), the function will write a sink for the string to * "sub." The sub-sink must be used for any/all handlers called within the * submessage. */ bool StartSubMessage(Handlers::Selector s, Sink* sub); bool EndSubMessage(Handlers::Selector s); /* For repeated fields of any type, the sequence of values must be wrapped in * these calls. * * For StartSequence(), the function will write a sink for the string to * "sub." The sub-sink must be used for any/all handlers called within the * sequence. */ bool StartSequence(Handlers::Selector s, Sink* sub); bool EndSequence(Handlers::Selector s); /* Copy and assign specifically allowed. * We don't even bother making these members private because so many * functions need them and this is mainly just a dumb data container anyway. */ #else struct upb_sink { #endif const upb_handlers *handlers; void *closure; }; #ifdef __cplusplus class upb::BytesSink { public: BytesSink() {} /* Constructs a new sink for the given frozen handlers and closure. * * TODO(haberman): once the Handlers know the expected closure type, verify * that T matches it. */ template BytesSink(const BytesHandler* handler, T* closure); /* Resets the value of the sink. */ template void Reset(const BytesHandler* handler, T* closure); bool Start(size_t size_hint, void **subc); size_t PutBuffer(void *subc, const char *buf, size_t len, const BufferHandle *handle); bool End(); #else struct upb_bytessink { #endif const upb_byteshandler *handler; void *closure; }; #ifdef __cplusplus /* A class for pushing a flat buffer of data to a BytesSink. * You can construct an instance of this to get a resumable source, * or just call the static PutBuffer() to do a non-resumable push all in one * go. */ class upb::BufferSource { public: BufferSource(); BufferSource(const char* buf, size_t len, BytesSink* sink); /* Returns true if the entire buffer was pushed successfully. Otherwise the * next call to PutNext() will resume where the previous one left off. * TODO(haberman): implement this. */ bool PutNext(); /* A static version; with this version is it not possible to resume in the * case of failure or a partially-consumed buffer. */ static bool PutBuffer(const char* buf, size_t len, BytesSink* sink); template static bool PutBuffer(const T& str, BytesSink* sink) { return PutBuffer(str.c_str(), str.size(), sink); } #else struct upb_bufsrc { char dummy; #endif }; UPB_BEGIN_EXTERN_C /* A class for accumulating output string data in a flat buffer. */ upb_bufsink *upb_bufsink_new(upb_env *env); void upb_bufsink_free(upb_bufsink *sink); upb_bytessink *upb_bufsink_sink(upb_bufsink *sink); const char *upb_bufsink_getdata(const upb_bufsink *sink, size_t *len); /* Inline definitions. */ UPB_INLINE void upb_bytessink_reset(upb_bytessink *s, const upb_byteshandler *h, void *closure) { s->handler = h; s->closure = closure; } UPB_INLINE bool upb_bytessink_start(upb_bytessink *s, size_t size_hint, void **subc) { typedef upb_startstr_handlerfunc func; func *start; *subc = s->closure; if (!s->handler) return true; start = (func *)s->handler->table[UPB_STARTSTR_SELECTOR].func; if (!start) return true; *subc = start(s->closure, upb_handlerattr_handlerdata( &s->handler->table[UPB_STARTSTR_SELECTOR].attr), size_hint); return *subc != NULL; } UPB_INLINE size_t upb_bytessink_putbuf(upb_bytessink *s, void *subc, const char *buf, size_t size, const upb_bufhandle* handle) { typedef upb_string_handlerfunc func; func *putbuf; if (!s->handler) return true; putbuf = (func *)s->handler->table[UPB_STRING_SELECTOR].func; if (!putbuf) return true; return putbuf(subc, upb_handlerattr_handlerdata( &s->handler->table[UPB_STRING_SELECTOR].attr), buf, size, handle); } UPB_INLINE bool upb_bytessink_end(upb_bytessink *s) { typedef upb_endfield_handlerfunc func; func *end; if (!s->handler) return true; end = (func *)s->handler->table[UPB_ENDSTR_SELECTOR].func; if (!end) return true; return end(s->closure, upb_handlerattr_handlerdata( &s->handler->table[UPB_ENDSTR_SELECTOR].attr)); } bool upb_bufsrc_putbuf(const char *buf, size_t len, upb_bytessink *sink); #define PUTVAL(type, ctype) \ UPB_INLINE bool upb_sink_put##type(upb_sink *s, upb_selector_t sel, \ ctype val) { \ typedef upb_##type##_handlerfunc functype; \ functype *func; \ const void *hd; \ if (!s->handlers) return true; \ func = (functype *)upb_handlers_gethandler(s->handlers, sel); \ if (!func) return true; \ hd = upb_handlers_gethandlerdata(s->handlers, sel); \ return func(s->closure, hd, val); \ } PUTVAL(int32, int32_t) PUTVAL(int64, int64_t) PUTVAL(uint32, uint32_t) PUTVAL(uint64, uint64_t) PUTVAL(float, float) PUTVAL(double, double) PUTVAL(bool, bool) #undef PUTVAL UPB_INLINE void upb_sink_reset(upb_sink *s, const upb_handlers *h, void *c) { s->handlers = h; s->closure = c; } UPB_INLINE size_t upb_sink_putstring(upb_sink *s, upb_selector_t sel, const char *buf, size_t n, const upb_bufhandle *handle) { typedef upb_string_handlerfunc func; func *handler; const void *hd; if (!s->handlers) return n; handler = (func *)upb_handlers_gethandler(s->handlers, sel); if (!handler) return n; hd = upb_handlers_gethandlerdata(s->handlers, sel); return handler(s->closure, hd, buf, n, handle); } UPB_INLINE bool upb_sink_startmsg(upb_sink *s) { typedef upb_startmsg_handlerfunc func; func *startmsg; const void *hd; if (!s->handlers) return true; startmsg = (func*)upb_handlers_gethandler(s->handlers, UPB_STARTMSG_SELECTOR); if (!startmsg) return true; hd = upb_handlers_gethandlerdata(s->handlers, UPB_STARTMSG_SELECTOR); return startmsg(s->closure, hd); } UPB_INLINE bool upb_sink_endmsg(upb_sink *s, upb_status *status) { typedef upb_endmsg_handlerfunc func; func *endmsg; const void *hd; if (!s->handlers) return true; endmsg = (func *)upb_handlers_gethandler(s->handlers, UPB_ENDMSG_SELECTOR); if (!endmsg) return true; hd = upb_handlers_gethandlerdata(s->handlers, UPB_ENDMSG_SELECTOR); return endmsg(s->closure, hd, status); } UPB_INLINE bool upb_sink_startseq(upb_sink *s, upb_selector_t sel, upb_sink *sub) { typedef upb_startfield_handlerfunc func; func *startseq; const void *hd; sub->closure = s->closure; sub->handlers = s->handlers; if (!s->handlers) return true; startseq = (func*)upb_handlers_gethandler(s->handlers, sel); if (!startseq) return true; hd = upb_handlers_gethandlerdata(s->handlers, sel); sub->closure = startseq(s->closure, hd); return sub->closure ? true : false; } UPB_INLINE bool upb_sink_endseq(upb_sink *s, upb_selector_t sel) { typedef upb_endfield_handlerfunc func; func *endseq; const void *hd; if (!s->handlers) return true; endseq = (func*)upb_handlers_gethandler(s->handlers, sel); if (!endseq) return true; hd = upb_handlers_gethandlerdata(s->handlers, sel); return endseq(s->closure, hd); } UPB_INLINE bool upb_sink_startstr(upb_sink *s, upb_selector_t sel, size_t size_hint, upb_sink *sub) { typedef upb_startstr_handlerfunc func; func *startstr; const void *hd; sub->closure = s->closure; sub->handlers = s->handlers; if (!s->handlers) return true; startstr = (func*)upb_handlers_gethandler(s->handlers, sel); if (!startstr) return true; hd = upb_handlers_gethandlerdata(s->handlers, sel); sub->closure = startstr(s->closure, hd, size_hint); return sub->closure ? true : false; } UPB_INLINE bool upb_sink_endstr(upb_sink *s, upb_selector_t sel) { typedef upb_endfield_handlerfunc func; func *endstr; const void *hd; if (!s->handlers) return true; endstr = (func*)upb_handlers_gethandler(s->handlers, sel); if (!endstr) return true; hd = upb_handlers_gethandlerdata(s->handlers, sel); return endstr(s->closure, hd); } UPB_INLINE bool upb_sink_startsubmsg(upb_sink *s, upb_selector_t sel, upb_sink *sub) { typedef upb_startfield_handlerfunc func; func *startsubmsg; const void *hd; sub->closure = s->closure; if (!s->handlers) { sub->handlers = NULL; return true; } sub->handlers = upb_handlers_getsubhandlers_sel(s->handlers, sel); startsubmsg = (func*)upb_handlers_gethandler(s->handlers, sel); if (!startsubmsg) return true; hd = upb_handlers_gethandlerdata(s->handlers, sel); sub->closure = startsubmsg(s->closure, hd); return sub->closure ? true : false; } UPB_INLINE bool upb_sink_endsubmsg(upb_sink *s, upb_selector_t sel) { typedef upb_endfield_handlerfunc func; func *endsubmsg; const void *hd; if (!s->handlers) return true; endsubmsg = (func*)upb_handlers_gethandler(s->handlers, sel); if (!endsubmsg) return s->closure; hd = upb_handlers_gethandlerdata(s->handlers, sel); return endsubmsg(s->closure, hd); } UPB_END_EXTERN_C #ifdef __cplusplus namespace upb { template Sink::Sink(const Handlers* handlers, T* closure) { upb_sink_reset(this, handlers, closure); } template inline void Sink::Reset(const Handlers* handlers, T* closure) { upb_sink_reset(this, handlers, closure); } inline bool Sink::StartMessage() { return upb_sink_startmsg(this); } inline bool Sink::EndMessage(Status* status) { return upb_sink_endmsg(this, status); } inline bool Sink::PutInt32(Handlers::Selector sel, int32_t val) { return upb_sink_putint32(this, sel, val); } inline bool Sink::PutInt64(Handlers::Selector sel, int64_t val) { return upb_sink_putint64(this, sel, val); } inline bool Sink::PutUInt32(Handlers::Selector sel, uint32_t val) { return upb_sink_putuint32(this, sel, val); } inline bool Sink::PutUInt64(Handlers::Selector sel, uint64_t val) { return upb_sink_putuint64(this, sel, val); } inline bool Sink::PutFloat(Handlers::Selector sel, float val) { return upb_sink_putfloat(this, sel, val); } inline bool Sink::PutDouble(Handlers::Selector sel, double val) { return upb_sink_putdouble(this, sel, val); } inline bool Sink::PutBool(Handlers::Selector sel, bool val) { return upb_sink_putbool(this, sel, val); } inline bool Sink::StartString(Handlers::Selector sel, size_t size_hint, Sink *sub) { return upb_sink_startstr(this, sel, size_hint, sub); } inline size_t Sink::PutStringBuffer(Handlers::Selector sel, const char *buf, size_t len, const BufferHandle* handle) { return upb_sink_putstring(this, sel, buf, len, handle); } inline bool Sink::EndString(Handlers::Selector sel) { return upb_sink_endstr(this, sel); } inline bool Sink::StartSubMessage(Handlers::Selector sel, Sink* sub) { return upb_sink_startsubmsg(this, sel, sub); } inline bool Sink::EndSubMessage(Handlers::Selector sel) { return upb_sink_endsubmsg(this, sel); } inline bool Sink::StartSequence(Handlers::Selector sel, Sink* sub) { return upb_sink_startseq(this, sel, sub); } inline bool Sink::EndSequence(Handlers::Selector sel) { return upb_sink_endseq(this, sel); } template BytesSink::BytesSink(const BytesHandler* handler, T* closure) { Reset(handler, closure); } template void BytesSink::Reset(const BytesHandler *handler, T *closure) { upb_bytessink_reset(this, handler, closure); } inline bool BytesSink::Start(size_t size_hint, void **subc) { return upb_bytessink_start(this, size_hint, subc); } inline size_t BytesSink::PutBuffer(void *subc, const char *buf, size_t len, const BufferHandle *handle) { return upb_bytessink_putbuf(this, subc, buf, len, handle); } inline bool BytesSink::End() { return upb_bytessink_end(this); } inline bool BufferSource::PutBuffer(const char *buf, size_t len, BytesSink *sink) { return upb_bufsrc_putbuf(buf, len, sink); } } /* namespace upb */ #endif #endif /* ** upb::Message is a representation for protobuf messages. ** ** However it differs from other common representations like ** google::protobuf::Message in one key way: it does not prescribe any ** ownership between messages and submessages, and it relies on the ** client to delete each message/submessage/array/map at the appropriate ** time. ** ** A client can access a upb::Message without knowing anything about ** ownership semantics, but to create or mutate a message a user needs ** to implement the memory management themselves. ** ** Currently all messages, arrays, and maps store a upb_alloc* internally. ** Mutating operations use this when they require dynamically-allocated ** memory. We could potentially eliminate this size overhead later by ** letting the user flip a bit on the factory that prevents this from ** being stored. The user would then need to use separate functions where ** the upb_alloc* is passed explicitly. However for handlers to populate ** such structures, they would need a place to store this upb_alloc* during ** parsing; upb_handlers don't currently have a good way to accommodate this. ** ** TODO: UTF-8 checking? **/ #ifndef UPB_MSG_H_ #define UPB_MSG_H_ #ifdef __cplusplus namespace upb { class Array; class Map; class MapIterator; class MessageFactory; class MessageLayout; class Visitor; class VisitorPlan; } #endif UPB_DECLARE_TYPE(upb::MessageFactory, upb_msgfactory) UPB_DECLARE_TYPE(upb::MessageLayout, upb_msglayout) UPB_DECLARE_TYPE(upb::Array, upb_array) UPB_DECLARE_TYPE(upb::Map, upb_map) UPB_DECLARE_TYPE(upb::MapIterator, upb_mapiter) UPB_DECLARE_TYPE(upb::Visitor, upb_visitor) UPB_DECLARE_TYPE(upb::VisitorPlan, upb_visitorplan) /* TODO(haberman): C++ accessors */ UPB_BEGIN_EXTERN_C typedef void upb_msg; /** upb_msglayout *************************************************************/ /* upb_msglayout represents the memory layout of a given upb_msgdef. You get * instances of this from a upb_msgfactory, and the factory always owns the * msglayout. */ /* Gets the factory for this layout */ upb_msgfactory *upb_msglayout_factory(const upb_msglayout *l); /* Get the msglayout for a submessage. This requires that this field is a * submessage, ie. upb_fielddef_issubmsg(upb_msglayout_msgdef(l)) == true. * * Since map entry messages don't have layouts, if upb_fielddef_ismap(f) == true * then this function will return the layout for the map's value. It requires * that the value type of the map field is a submessage. */ const upb_msglayout *upb_msglayout_sublayout(const upb_msglayout *l, const upb_fielddef *f); /* Returns the msgdef for this msglayout. */ const upb_msgdef *upb_msglayout_msgdef(const upb_msglayout *l); /** upb_visitor ***************************************************************/ /* upb_visitor will visit all the fields of a message and its submessages. It * uses a upb_visitorplan which you can obtain from a upb_msgfactory. */ upb_visitor *upb_visitor_create(upb_env *e, const upb_visitorplan *vp, upb_sink *output); bool upb_visitor_visitmsg(upb_visitor *v, const upb_msg *msg); /** upb_msgfactory ************************************************************/ /* A upb_msgfactory contains a cache of upb_msglayout, upb_handlers, and * upb_visitorplan objects. These are the objects necessary to represent, * populate, and and visit upb_msg objects. * * These caches are all populated by upb_msgdef, and lazily created on demand. */ /* Creates and destroys a msgfactory, respectively. The messages for this * msgfactory must come from |symtab| (which should outlive the msgfactory). */ upb_msgfactory *upb_msgfactory_new(const upb_symtab *symtab); void upb_msgfactory_free(upb_msgfactory *f); const upb_symtab *upb_msgfactory_symtab(const upb_msgfactory *f); /* The functions to get cached objects, lazily creating them on demand. These * all require: * * - m is in upb_msgfactory_symtab(f) * - upb_msgdef_mapentry(m) == false (since map messages can't have layouts). * * The returned objects will live for as long as the msgfactory does. * * TODO(haberman): consider making this thread-safe and take a const * upb_msgfactory. */ const upb_msglayout *upb_msgfactory_getlayout(upb_msgfactory *f, const upb_msgdef *m); const upb_handlers *upb_msgfactory_getmergehandlers(upb_msgfactory *f, const upb_msgdef *m); const upb_visitorplan *upb_msgfactory_getvisitorplan(upb_msgfactory *f, const upb_handlers *h); /** upb_msgval ****************************************************************/ /* A union representing all possible protobuf values. Used for generic get/set * operations. */ typedef union { bool b; float flt; double dbl; int32_t i32; int64_t i64; uint32_t u32; uint64_t u64; const upb_map* map; const upb_msg* msg; const upb_array* arr; const void* ptr; struct { const char *ptr; size_t len; } str; } upb_msgval; #define ACCESSORS(name, membername, ctype) \ UPB_INLINE ctype upb_msgval_get ## name(upb_msgval v) { \ return v.membername; \ } \ UPB_INLINE void upb_msgval_set ## name(upb_msgval *v, ctype cval) { \ v->membername = cval; \ } \ UPB_INLINE upb_msgval upb_msgval_ ## name(ctype v) { \ upb_msgval ret; \ ret.membername = v; \ return ret; \ } ACCESSORS(bool, b, bool) ACCESSORS(float, flt, float) ACCESSORS(double, dbl, double) ACCESSORS(int32, i32, int32_t) ACCESSORS(int64, i64, int64_t) ACCESSORS(uint32, u32, uint32_t) ACCESSORS(uint64, u64, uint64_t) ACCESSORS(map, map, const upb_map*) ACCESSORS(msg, msg, const upb_msg*) ACCESSORS(ptr, ptr, const void*) ACCESSORS(arr, arr, const upb_array*) #undef ACCESSORS UPB_INLINE upb_msgval upb_msgval_str(const char *ptr, size_t len) { upb_msgval ret; ret.str.ptr = ptr; ret.str.len = len; return ret; } UPB_INLINE const char* upb_msgval_getstr(upb_msgval val) { return val.str.ptr; } UPB_INLINE size_t upb_msgval_getstrlen(upb_msgval val) { return val.str.len; } /** upb_msg *******************************************************************/ /* A upb_msg represents a protobuf message. It always corresponds to a specific * upb_msglayout, which describes how it is laid out in memory. * * The message will have a fixed size, as returned by upb_msg_sizeof(), which * will be used to store fixed-length fields. The upb_msg may also allocate * dynamic memory internally to store data such as: * * - extensions * - unknown fields */ /* Returns the size of a message given this layout. */ size_t upb_msg_sizeof(const upb_msglayout *l); /* upb_msg_init() / upb_msg_uninit() allow the user to use a pre-allocated * block of memory as a message. The block's size should be upb_msg_sizeof(). * upb_msg_uninit() must be called to release internally-allocated memory * unless the allocator is an arena that does not require freeing. * * Please note that upb_msg_uninit() does *not* free any submessages, maps, * or arrays referred to by this message's fields. You must free them manually * yourself. */ void upb_msg_init(upb_msg *msg, const upb_msglayout *l, upb_alloc *a); void upb_msg_uninit(upb_msg *msg, const upb_msglayout *l); /* Like upb_msg_init() / upb_msg_uninit(), except the message's memory is * allocated / freed from the given upb_alloc. */ upb_msg *upb_msg_new(const upb_msglayout *l, upb_alloc *a); void upb_msg_free(upb_msg *msg, const upb_msglayout *l); /* Returns the upb_alloc for the given message. */ upb_alloc *upb_msg_alloc(const upb_msg *msg, const upb_msglayout *l); /* Packs the tree of messages rooted at "msg" into a single hunk of memory, * allocated from the given allocator. */ void *upb_msg_pack(const upb_msg *msg, const upb_msglayout *l, void *p, size_t *ofs, size_t size); /* Read-only message API. Can be safely called by anyone. */ /* Returns the value associated with this field: * - for scalar fields (including strings), the value directly. * - return upb_msg*, or upb_map* for msg/map. * If the field is unset for these field types, returns NULL. * * TODO(haberman): should we let users store cached array/map/msg * pointers here for fields that are unset? Could be useful for the * strongly-owned submessage model (ie. generated C API that doesn't use * arenas). */ upb_msgval upb_msg_get(const upb_msg *msg, const upb_fielddef *f, const upb_msglayout *l); /* May only be called for fields where upb_fielddef_haspresence(f) == true. */ bool upb_msg_has(const upb_msg *msg, const upb_fielddef *f, const upb_msglayout *l); /* Returns NULL if no field in the oneof is set. */ const upb_fielddef *upb_msg_getoneofcase(const upb_msg *msg, const upb_oneofdef *o, const upb_msglayout *l); /* Returns true if any field in the oneof is set. */ bool upb_msg_hasoneof(const upb_msg *msg, const upb_oneofdef *o, const upb_msglayout *l); /* Mutable message API. May only be called by the owner of the message who * knows its ownership scheme and how to keep it consistent. */ /* Sets the given field to the given value. Does not perform any memory * management: if you overwrite a pointer to a msg/array/map/string without * cleaning it up (or using an arena) it will leak. */ bool upb_msg_set(upb_msg *msg, const upb_fielddef *f, upb_msgval val, const upb_msglayout *l); /* For a primitive field, set it back to its default. For repeated, string, and * submessage fields set it back to NULL. This could involve releasing some * internal memory (for example, from an extension dictionary), but it is not * recursive in any way and will not recover any memory that may be used by * arrays/maps/strings/msgs that this field may have pointed to. */ bool upb_msg_clearfield(upb_msg *msg, const upb_fielddef *f, const upb_msglayout *l); /* Clears all fields in the oneof such that none of them are set. */ bool upb_msg_clearoneof(upb_msg *msg, const upb_oneofdef *o, const upb_msglayout *l); /* TODO(haberman): copyfrom()/mergefrom()? */ /** upb_array *****************************************************************/ /* A upb_array stores data for a repeated field. The memory management * semantics are the same as upb_msg. A upb_array allocates dynamic * memory internally for the array elements. */ size_t upb_array_sizeof(upb_fieldtype_t type); void upb_array_init(upb_array *arr, upb_fieldtype_t type, upb_alloc *a); void upb_array_uninit(upb_array *arr); upb_array *upb_array_new(upb_fieldtype_t type, upb_alloc *a); void upb_array_free(upb_array *arr); /* Read-only interface. Safe for anyone to call. */ size_t upb_array_size(const upb_array *arr); upb_fieldtype_t upb_array_type(const upb_array *arr); upb_msgval upb_array_get(const upb_array *arr, size_t i); /* Write interface. May only be called by the message's owner who can enforce * its memory management invariants. */ bool upb_array_set(upb_array *arr, size_t i, upb_msgval val); /** upb_map *******************************************************************/ /* A upb_map stores data for a map field. The memory management semantics are * the same as upb_msg, with one notable exception. upb_map will internally * store a copy of all string keys, but *not* any string values or submessages. * So you must ensure that any string or message values outlive the map, and you * must delete them manually when they are no longer required. */ size_t upb_map_sizeof(upb_fieldtype_t ktype, upb_fieldtype_t vtype); bool upb_map_init(upb_map *map, upb_fieldtype_t ktype, upb_fieldtype_t vtype, upb_alloc *a); void upb_map_uninit(upb_map *map); upb_map *upb_map_new(upb_fieldtype_t ktype, upb_fieldtype_t vtype, upb_alloc *a); void upb_map_free(upb_map *map); /* Read-only interface. Safe for anyone to call. */ size_t upb_map_size(const upb_map *map); upb_fieldtype_t upb_map_keytype(const upb_map *map); upb_fieldtype_t upb_map_valuetype(const upb_map *map); bool upb_map_get(const upb_map *map, upb_msgval key, upb_msgval *val); /* Write interface. May only be called by the message's owner who can enforce * its memory management invariants. */ /* Sets or overwrites an entry in the map. Return value indicates whether * the operation succeeded or failed with OOM, and also whether an existing * key was replaced or not. */ bool upb_map_set(upb_map *map, upb_msgval key, upb_msgval val, upb_msgval *valremoved); /* Deletes an entry in the map. Returns true if the key was present. */ bool upb_map_del(upb_map *map, upb_msgval key); /** upb_mapiter ***************************************************************/ /* For iterating over a map. Map iterators are invalidated by mutations to the * map, but an invalidated iterator will never return junk or crash the process. * An invalidated iterator may return entries that were already returned though, * and if you keep invalidating the iterator during iteration, the program may * enter an infinite loop. */ size_t upb_mapiter_sizeof(); void upb_mapiter_begin(upb_mapiter *i, const upb_map *t); upb_mapiter *upb_mapiter_new(const upb_map *t, upb_alloc *a); void upb_mapiter_free(upb_mapiter *i, upb_alloc *a); void upb_mapiter_next(upb_mapiter *i); bool upb_mapiter_done(const upb_mapiter *i); upb_msgval upb_mapiter_key(const upb_mapiter *i); upb_msgval upb_mapiter_value(const upb_mapiter *i); void upb_mapiter_setdone(upb_mapiter *i); bool upb_mapiter_isequal(const upb_mapiter *i1, const upb_mapiter *i2); /** Handlers ******************************************************************/ /* These are the handlers used internally by upb_msgfactory_getmergehandlers(). * They write scalar data to a known offset from the message pointer. * * These would be trivial for anyone to implement themselves, but it's better * to use these because some JITs will recognize and specialize these instead * of actually calling the function. */ /* Sets a handler for the given primitive field that will write the data at the * given offset. If hasbit > 0, also sets a hasbit at the given bit offset * (addressing each byte low to high). */ bool upb_msg_setscalarhandler(upb_handlers *h, const upb_fielddef *f, size_t offset, int32_t hasbit); /* If the given handler is a msghandlers_primitive field, returns true and sets * *type, *offset and *hasbit. Otherwise returns false. */ bool upb_msg_getscalarhandlerdata(const upb_handlers *h, upb_selector_t s, upb_fieldtype_t *type, size_t *offset, int32_t *hasbit); UPB_END_EXTERN_C #endif /* UPB_MSG_H_ */ /* ** upb::descriptor::Reader (upb_descreader) ** ** Provides a way of building upb::Defs from data in descriptor.proto format. */ #ifndef UPB_DESCRIPTOR_H #define UPB_DESCRIPTOR_H #ifdef __cplusplus namespace upb { namespace descriptor { class Reader; } /* namespace descriptor */ } /* namespace upb */ #endif UPB_DECLARE_TYPE(upb::descriptor::Reader, upb_descreader) #ifdef __cplusplus /* Class that receives descriptor data according to the descriptor.proto schema * and use it to build upb::Defs corresponding to that schema. */ class upb::descriptor::Reader { public: /* These handlers must have come from NewHandlers() and must outlive the * Reader. * * TODO: generate the handlers statically (like we do with the * descriptor.proto defs) so that there is no need to pass this parameter (or * to build/memory-manage the handlers at runtime at all). Unfortunately this * is a bit tricky to implement for Handlers, but necessary to simplify this * interface. */ static Reader* Create(Environment* env, const Handlers* handlers); /* The reader's input; this is where descriptor.proto data should be sent. */ Sink* input(); /* Use to get the FileDefs that have been parsed. */ size_t file_count() const; FileDef* file(size_t i) const; /* Builds and returns handlers for the reader, owned by "owner." */ static Handlers* NewHandlers(const void* owner); private: UPB_DISALLOW_POD_OPS(Reader, upb::descriptor::Reader) }; #endif UPB_BEGIN_EXTERN_C /* C API. */ upb_descreader *upb_descreader_create(upb_env *e, const upb_handlers *h); upb_sink *upb_descreader_input(upb_descreader *r); size_t upb_descreader_filecount(const upb_descreader *r); upb_filedef *upb_descreader_file(const upb_descreader *r, size_t i); const upb_handlers *upb_descreader_newhandlers(const void *owner); UPB_END_EXTERN_C #ifdef __cplusplus /* C++ implementation details. ************************************************/ namespace upb { namespace descriptor { inline Reader* Reader::Create(Environment* e, const Handlers *h) { return upb_descreader_create(e, h); } inline Sink* Reader::input() { return upb_descreader_input(this); } inline size_t Reader::file_count() const { return upb_descreader_filecount(this); } inline FileDef* Reader::file(size_t i) const { return upb_descreader_file(this, i); } } /* namespace descriptor */ } /* namespace upb */ #endif #endif /* UPB_DESCRIPTOR_H */ /* This file contains accessors for a set of compiled-in defs. * Note that unlike Google's protobuf, it does *not* define * generated classes or any other kind of data structure for * actually storing protobufs. It only contains *defs* which * let you reflect over a protobuf *schema*. */ /* This file was generated by upbc (the upb compiler) from the input * file: * * upb/descriptor/descriptor.proto * * Do not edit -- your changes will be discarded when the file is * regenerated. */ #ifndef UPB_DESCRIPTOR_DESCRIPTOR_PROTO_UPB_H_ #define UPB_DESCRIPTOR_DESCRIPTOR_PROTO_UPB_H_ UPB_BEGIN_EXTERN_C /* Enums */ typedef enum { google_protobuf_FieldDescriptorProto_LABEL_OPTIONAL = 1, google_protobuf_FieldDescriptorProto_LABEL_REQUIRED = 2, google_protobuf_FieldDescriptorProto_LABEL_REPEATED = 3 } google_protobuf_FieldDescriptorProto_Label; typedef enum { google_protobuf_FieldDescriptorProto_TYPE_DOUBLE = 1, google_protobuf_FieldDescriptorProto_TYPE_FLOAT = 2, google_protobuf_FieldDescriptorProto_TYPE_INT64 = 3, google_protobuf_FieldDescriptorProto_TYPE_UINT64 = 4, google_protobuf_FieldDescriptorProto_TYPE_INT32 = 5, google_protobuf_FieldDescriptorProto_TYPE_FIXED64 = 6, google_protobuf_FieldDescriptorProto_TYPE_FIXED32 = 7, google_protobuf_FieldDescriptorProto_TYPE_BOOL = 8, google_protobuf_FieldDescriptorProto_TYPE_STRING = 9, google_protobuf_FieldDescriptorProto_TYPE_GROUP = 10, google_protobuf_FieldDescriptorProto_TYPE_MESSAGE = 11, google_protobuf_FieldDescriptorProto_TYPE_BYTES = 12, google_protobuf_FieldDescriptorProto_TYPE_UINT32 = 13, google_protobuf_FieldDescriptorProto_TYPE_ENUM = 14, google_protobuf_FieldDescriptorProto_TYPE_SFIXED32 = 15, google_protobuf_FieldDescriptorProto_TYPE_SFIXED64 = 16, google_protobuf_FieldDescriptorProto_TYPE_SINT32 = 17, google_protobuf_FieldDescriptorProto_TYPE_SINT64 = 18 } google_protobuf_FieldDescriptorProto_Type; typedef enum { google_protobuf_FieldOptions_STRING = 0, google_protobuf_FieldOptions_CORD = 1, google_protobuf_FieldOptions_STRING_PIECE = 2 } google_protobuf_FieldOptions_CType; typedef enum { google_protobuf_FieldOptions_JS_NORMAL = 0, google_protobuf_FieldOptions_JS_STRING = 1, google_protobuf_FieldOptions_JS_NUMBER = 2 } google_protobuf_FieldOptions_JSType; typedef enum { google_protobuf_FileOptions_SPEED = 1, google_protobuf_FileOptions_CODE_SIZE = 2, google_protobuf_FileOptions_LITE_RUNTIME = 3 } google_protobuf_FileOptions_OptimizeMode; /* MessageDefs: call these functions to get a ref to a msgdef. */ const upb_msgdef *upbdefs_google_protobuf_DescriptorProto_get(const void *owner); const upb_msgdef *upbdefs_google_protobuf_DescriptorProto_ExtensionRange_get(const void *owner); const upb_msgdef *upbdefs_google_protobuf_DescriptorProto_ReservedRange_get(const void *owner); const upb_msgdef *upbdefs_google_protobuf_EnumDescriptorProto_get(const void *owner); const upb_msgdef *upbdefs_google_protobuf_EnumOptions_get(const void *owner); const upb_msgdef *upbdefs_google_protobuf_EnumValueDescriptorProto_get(const void *owner); const upb_msgdef *upbdefs_google_protobuf_EnumValueOptions_get(const void *owner); const upb_msgdef *upbdefs_google_protobuf_FieldDescriptorProto_get(const void *owner); const upb_msgdef *upbdefs_google_protobuf_FieldOptions_get(const void *owner); const upb_msgdef *upbdefs_google_protobuf_FileDescriptorProto_get(const void *owner); const upb_msgdef *upbdefs_google_protobuf_FileDescriptorSet_get(const void *owner); const upb_msgdef *upbdefs_google_protobuf_FileOptions_get(const void *owner); const upb_msgdef *upbdefs_google_protobuf_MessageOptions_get(const void *owner); const upb_msgdef *upbdefs_google_protobuf_MethodDescriptorProto_get(const void *owner); const upb_msgdef *upbdefs_google_protobuf_MethodOptions_get(const void *owner); const upb_msgdef *upbdefs_google_protobuf_OneofDescriptorProto_get(const void *owner); const upb_msgdef *upbdefs_google_protobuf_ServiceDescriptorProto_get(const void *owner); const upb_msgdef *upbdefs_google_protobuf_ServiceOptions_get(const void *owner); const upb_msgdef *upbdefs_google_protobuf_SourceCodeInfo_get(const void *owner); const upb_msgdef *upbdefs_google_protobuf_SourceCodeInfo_Location_get(const void *owner); const upb_msgdef *upbdefs_google_protobuf_UninterpretedOption_get(const void *owner); const upb_msgdef *upbdefs_google_protobuf_UninterpretedOption_NamePart_get(const void *owner); /* EnumDefs: call these functions to get a ref to an enumdef. */ const upb_enumdef *upbdefs_google_protobuf_FieldDescriptorProto_Label_get(const void *owner); const upb_enumdef *upbdefs_google_protobuf_FieldDescriptorProto_Type_get(const void *owner); const upb_enumdef *upbdefs_google_protobuf_FieldOptions_CType_get(const void *owner); const upb_enumdef *upbdefs_google_protobuf_FieldOptions_JSType_get(const void *owner); const upb_enumdef *upbdefs_google_protobuf_FileOptions_OptimizeMode_get(const void *owner); /* Functions to test whether this message is of a certain type. */ UPB_INLINE bool upbdefs_google_protobuf_DescriptorProto_is(const upb_msgdef *m) { return strcmp(upb_msgdef_fullname(m), "google.protobuf.DescriptorProto") == 0; } UPB_INLINE bool upbdefs_google_protobuf_DescriptorProto_ExtensionRange_is(const upb_msgdef *m) { return strcmp(upb_msgdef_fullname(m), "google.protobuf.DescriptorProto.ExtensionRange") == 0; } UPB_INLINE bool upbdefs_google_protobuf_DescriptorProto_ReservedRange_is(const upb_msgdef *m) { return strcmp(upb_msgdef_fullname(m), "google.protobuf.DescriptorProto.ReservedRange") == 0; } UPB_INLINE bool upbdefs_google_protobuf_EnumDescriptorProto_is(const upb_msgdef *m) { return strcmp(upb_msgdef_fullname(m), "google.protobuf.EnumDescriptorProto") == 0; } UPB_INLINE bool upbdefs_google_protobuf_EnumOptions_is(const upb_msgdef *m) { return strcmp(upb_msgdef_fullname(m), "google.protobuf.EnumOptions") == 0; } UPB_INLINE bool upbdefs_google_protobuf_EnumValueDescriptorProto_is(const upb_msgdef *m) { return strcmp(upb_msgdef_fullname(m), "google.protobuf.EnumValueDescriptorProto") == 0; } UPB_INLINE bool upbdefs_google_protobuf_EnumValueOptions_is(const upb_msgdef *m) { return strcmp(upb_msgdef_fullname(m), "google.protobuf.EnumValueOptions") == 0; } UPB_INLINE bool upbdefs_google_protobuf_FieldDescriptorProto_is(const upb_msgdef *m) { return strcmp(upb_msgdef_fullname(m), "google.protobuf.FieldDescriptorProto") == 0; } UPB_INLINE bool upbdefs_google_protobuf_FieldOptions_is(const upb_msgdef *m) { return strcmp(upb_msgdef_fullname(m), "google.protobuf.FieldOptions") == 0; } UPB_INLINE bool upbdefs_google_protobuf_FileDescriptorProto_is(const upb_msgdef *m) { return strcmp(upb_msgdef_fullname(m), "google.protobuf.FileDescriptorProto") == 0; } UPB_INLINE bool upbdefs_google_protobuf_FileDescriptorSet_is(const upb_msgdef *m) { return strcmp(upb_msgdef_fullname(m), "google.protobuf.FileDescriptorSet") == 0; } UPB_INLINE bool upbdefs_google_protobuf_FileOptions_is(const upb_msgdef *m) { return strcmp(upb_msgdef_fullname(m), "google.protobuf.FileOptions") == 0; } UPB_INLINE bool upbdefs_google_protobuf_MessageOptions_is(const upb_msgdef *m) { return strcmp(upb_msgdef_fullname(m), "google.protobuf.MessageOptions") == 0; } UPB_INLINE bool upbdefs_google_protobuf_MethodDescriptorProto_is(const upb_msgdef *m) { return strcmp(upb_msgdef_fullname(m), "google.protobuf.MethodDescriptorProto") == 0; } UPB_INLINE bool upbdefs_google_protobuf_MethodOptions_is(const upb_msgdef *m) { return strcmp(upb_msgdef_fullname(m), "google.protobuf.MethodOptions") == 0; } UPB_INLINE bool upbdefs_google_protobuf_OneofDescriptorProto_is(const upb_msgdef *m) { return strcmp(upb_msgdef_fullname(m), "google.protobuf.OneofDescriptorProto") == 0; } UPB_INLINE bool upbdefs_google_protobuf_ServiceDescriptorProto_is(const upb_msgdef *m) { return strcmp(upb_msgdef_fullname(m), "google.protobuf.ServiceDescriptorProto") == 0; } UPB_INLINE bool upbdefs_google_protobuf_ServiceOptions_is(const upb_msgdef *m) { return strcmp(upb_msgdef_fullname(m), "google.protobuf.ServiceOptions") == 0; } UPB_INLINE bool upbdefs_google_protobuf_SourceCodeInfo_is(const upb_msgdef *m) { return strcmp(upb_msgdef_fullname(m), "google.protobuf.SourceCodeInfo") == 0; } UPB_INLINE bool upbdefs_google_protobuf_SourceCodeInfo_Location_is(const upb_msgdef *m) { return strcmp(upb_msgdef_fullname(m), "google.protobuf.SourceCodeInfo.Location") == 0; } UPB_INLINE bool upbdefs_google_protobuf_UninterpretedOption_is(const upb_msgdef *m) { return strcmp(upb_msgdef_fullname(m), "google.protobuf.UninterpretedOption") == 0; } UPB_INLINE bool upbdefs_google_protobuf_UninterpretedOption_NamePart_is(const upb_msgdef *m) { return strcmp(upb_msgdef_fullname(m), "google.protobuf.UninterpretedOption.NamePart") == 0; } /* Functions to test whether this enum is of a certain type. */ UPB_INLINE bool upbdefs_google_protobuf_FieldDescriptorProto_Label_is(const upb_enumdef *e) { return strcmp(upb_enumdef_fullname(e), "google.protobuf.FieldDescriptorProto.Label") == 0; } UPB_INLINE bool upbdefs_google_protobuf_FieldDescriptorProto_Type_is(const upb_enumdef *e) { return strcmp(upb_enumdef_fullname(e), "google.protobuf.FieldDescriptorProto.Type") == 0; } UPB_INLINE bool upbdefs_google_protobuf_FieldOptions_CType_is(const upb_enumdef *e) { return strcmp(upb_enumdef_fullname(e), "google.protobuf.FieldOptions.CType") == 0; } UPB_INLINE bool upbdefs_google_protobuf_FieldOptions_JSType_is(const upb_enumdef *e) { return strcmp(upb_enumdef_fullname(e), "google.protobuf.FieldOptions.JSType") == 0; } UPB_INLINE bool upbdefs_google_protobuf_FileOptions_OptimizeMode_is(const upb_enumdef *e) { return strcmp(upb_enumdef_fullname(e), "google.protobuf.FileOptions.OptimizeMode") == 0; } /* Functions to get a fielddef from a msgdef reference. */ UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_ExtensionRange_f_end(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_DescriptorProto_ExtensionRange_is(m)); return upb_msgdef_itof(m, 2); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_ExtensionRange_f_start(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_DescriptorProto_ExtensionRange_is(m)); return upb_msgdef_itof(m, 1); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_ReservedRange_f_end(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_DescriptorProto_ReservedRange_is(m)); return upb_msgdef_itof(m, 2); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_ReservedRange_f_start(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_DescriptorProto_ReservedRange_is(m)); return upb_msgdef_itof(m, 1); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_f_enum_type(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_DescriptorProto_is(m)); return upb_msgdef_itof(m, 4); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_f_extension(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_DescriptorProto_is(m)); return upb_msgdef_itof(m, 6); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_f_extension_range(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_DescriptorProto_is(m)); return upb_msgdef_itof(m, 5); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_f_field(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_DescriptorProto_is(m)); return upb_msgdef_itof(m, 2); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_f_name(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_DescriptorProto_is(m)); return upb_msgdef_itof(m, 1); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_f_nested_type(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_DescriptorProto_is(m)); return upb_msgdef_itof(m, 3); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_f_oneof_decl(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_DescriptorProto_is(m)); return upb_msgdef_itof(m, 8); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_f_options(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_DescriptorProto_is(m)); return upb_msgdef_itof(m, 7); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_f_reserved_name(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_DescriptorProto_is(m)); return upb_msgdef_itof(m, 10); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_f_reserved_range(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_DescriptorProto_is(m)); return upb_msgdef_itof(m, 9); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_EnumDescriptorProto_f_name(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_EnumDescriptorProto_is(m)); return upb_msgdef_itof(m, 1); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_EnumDescriptorProto_f_options(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_EnumDescriptorProto_is(m)); return upb_msgdef_itof(m, 3); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_EnumDescriptorProto_f_value(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_EnumDescriptorProto_is(m)); return upb_msgdef_itof(m, 2); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_EnumOptions_f_allow_alias(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_EnumOptions_is(m)); return upb_msgdef_itof(m, 2); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_EnumOptions_f_deprecated(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_EnumOptions_is(m)); return upb_msgdef_itof(m, 3); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_EnumOptions_f_uninterpreted_option(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_EnumOptions_is(m)); return upb_msgdef_itof(m, 999); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_EnumValueDescriptorProto_f_name(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_EnumValueDescriptorProto_is(m)); return upb_msgdef_itof(m, 1); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_EnumValueDescriptorProto_f_number(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_EnumValueDescriptorProto_is(m)); return upb_msgdef_itof(m, 2); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_EnumValueDescriptorProto_f_options(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_EnumValueDescriptorProto_is(m)); return upb_msgdef_itof(m, 3); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_EnumValueOptions_f_deprecated(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_EnumValueOptions_is(m)); return upb_msgdef_itof(m, 1); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_EnumValueOptions_f_uninterpreted_option(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_EnumValueOptions_is(m)); return upb_msgdef_itof(m, 999); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldDescriptorProto_f_default_value(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FieldDescriptorProto_is(m)); return upb_msgdef_itof(m, 7); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldDescriptorProto_f_extendee(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FieldDescriptorProto_is(m)); return upb_msgdef_itof(m, 2); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldDescriptorProto_f_json_name(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FieldDescriptorProto_is(m)); return upb_msgdef_itof(m, 10); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldDescriptorProto_f_label(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FieldDescriptorProto_is(m)); return upb_msgdef_itof(m, 4); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldDescriptorProto_f_name(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FieldDescriptorProto_is(m)); return upb_msgdef_itof(m, 1); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldDescriptorProto_f_number(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FieldDescriptorProto_is(m)); return upb_msgdef_itof(m, 3); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldDescriptorProto_f_oneof_index(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FieldDescriptorProto_is(m)); return upb_msgdef_itof(m, 9); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldDescriptorProto_f_options(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FieldDescriptorProto_is(m)); return upb_msgdef_itof(m, 8); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldDescriptorProto_f_type(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FieldDescriptorProto_is(m)); return upb_msgdef_itof(m, 5); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldDescriptorProto_f_type_name(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FieldDescriptorProto_is(m)); return upb_msgdef_itof(m, 6); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldOptions_f_ctype(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FieldOptions_is(m)); return upb_msgdef_itof(m, 1); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldOptions_f_deprecated(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FieldOptions_is(m)); return upb_msgdef_itof(m, 3); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldOptions_f_jstype(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FieldOptions_is(m)); return upb_msgdef_itof(m, 6); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldOptions_f_lazy(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FieldOptions_is(m)); return upb_msgdef_itof(m, 5); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldOptions_f_packed(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FieldOptions_is(m)); return upb_msgdef_itof(m, 2); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldOptions_f_uninterpreted_option(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FieldOptions_is(m)); return upb_msgdef_itof(m, 999); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldOptions_f_weak(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FieldOptions_is(m)); return upb_msgdef_itof(m, 10); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_f_dependency(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FileDescriptorProto_is(m)); return upb_msgdef_itof(m, 3); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_f_enum_type(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FileDescriptorProto_is(m)); return upb_msgdef_itof(m, 5); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_f_extension(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FileDescriptorProto_is(m)); return upb_msgdef_itof(m, 7); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_f_message_type(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FileDescriptorProto_is(m)); return upb_msgdef_itof(m, 4); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_f_name(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FileDescriptorProto_is(m)); return upb_msgdef_itof(m, 1); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_f_options(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FileDescriptorProto_is(m)); return upb_msgdef_itof(m, 8); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_f_package(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FileDescriptorProto_is(m)); return upb_msgdef_itof(m, 2); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_f_public_dependency(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FileDescriptorProto_is(m)); return upb_msgdef_itof(m, 10); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_f_service(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FileDescriptorProto_is(m)); return upb_msgdef_itof(m, 6); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_f_source_code_info(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FileDescriptorProto_is(m)); return upb_msgdef_itof(m, 9); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_f_syntax(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FileDescriptorProto_is(m)); return upb_msgdef_itof(m, 12); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_f_weak_dependency(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FileDescriptorProto_is(m)); return upb_msgdef_itof(m, 11); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorSet_f_file(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FileDescriptorSet_is(m)); return upb_msgdef_itof(m, 1); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_f_cc_enable_arenas(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FileOptions_is(m)); return upb_msgdef_itof(m, 31); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_f_cc_generic_services(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FileOptions_is(m)); return upb_msgdef_itof(m, 16); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_f_csharp_namespace(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FileOptions_is(m)); return upb_msgdef_itof(m, 37); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_f_deprecated(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FileOptions_is(m)); return upb_msgdef_itof(m, 23); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_f_go_package(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FileOptions_is(m)); return upb_msgdef_itof(m, 11); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_f_java_generate_equals_and_hash(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FileOptions_is(m)); return upb_msgdef_itof(m, 20); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_f_java_generic_services(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FileOptions_is(m)); return upb_msgdef_itof(m, 17); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_f_java_multiple_files(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FileOptions_is(m)); return upb_msgdef_itof(m, 10); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_f_java_outer_classname(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FileOptions_is(m)); return upb_msgdef_itof(m, 8); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_f_java_package(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FileOptions_is(m)); return upb_msgdef_itof(m, 1); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_f_java_string_check_utf8(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FileOptions_is(m)); return upb_msgdef_itof(m, 27); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_f_javanano_use_deprecated_package(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FileOptions_is(m)); return upb_msgdef_itof(m, 38); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_f_objc_class_prefix(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FileOptions_is(m)); return upb_msgdef_itof(m, 36); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_f_optimize_for(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FileOptions_is(m)); return upb_msgdef_itof(m, 9); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_f_py_generic_services(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FileOptions_is(m)); return upb_msgdef_itof(m, 18); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_f_uninterpreted_option(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FileOptions_is(m)); return upb_msgdef_itof(m, 999); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MessageOptions_f_deprecated(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_MessageOptions_is(m)); return upb_msgdef_itof(m, 3); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MessageOptions_f_map_entry(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_MessageOptions_is(m)); return upb_msgdef_itof(m, 7); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MessageOptions_f_message_set_wire_format(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_MessageOptions_is(m)); return upb_msgdef_itof(m, 1); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MessageOptions_f_no_standard_descriptor_accessor(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_MessageOptions_is(m)); return upb_msgdef_itof(m, 2); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MessageOptions_f_uninterpreted_option(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_MessageOptions_is(m)); return upb_msgdef_itof(m, 999); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MethodDescriptorProto_f_client_streaming(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_MethodDescriptorProto_is(m)); return upb_msgdef_itof(m, 5); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MethodDescriptorProto_f_input_type(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_MethodDescriptorProto_is(m)); return upb_msgdef_itof(m, 2); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MethodDescriptorProto_f_name(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_MethodDescriptorProto_is(m)); return upb_msgdef_itof(m, 1); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MethodDescriptorProto_f_options(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_MethodDescriptorProto_is(m)); return upb_msgdef_itof(m, 4); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MethodDescriptorProto_f_output_type(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_MethodDescriptorProto_is(m)); return upb_msgdef_itof(m, 3); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MethodDescriptorProto_f_server_streaming(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_MethodDescriptorProto_is(m)); return upb_msgdef_itof(m, 6); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MethodOptions_f_deprecated(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_MethodOptions_is(m)); return upb_msgdef_itof(m, 33); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MethodOptions_f_uninterpreted_option(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_MethodOptions_is(m)); return upb_msgdef_itof(m, 999); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_OneofDescriptorProto_f_name(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_OneofDescriptorProto_is(m)); return upb_msgdef_itof(m, 1); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_ServiceDescriptorProto_f_method(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_ServiceDescriptorProto_is(m)); return upb_msgdef_itof(m, 2); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_ServiceDescriptorProto_f_name(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_ServiceDescriptorProto_is(m)); return upb_msgdef_itof(m, 1); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_ServiceDescriptorProto_f_options(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_ServiceDescriptorProto_is(m)); return upb_msgdef_itof(m, 3); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_ServiceOptions_f_deprecated(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_ServiceOptions_is(m)); return upb_msgdef_itof(m, 33); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_ServiceOptions_f_uninterpreted_option(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_ServiceOptions_is(m)); return upb_msgdef_itof(m, 999); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_SourceCodeInfo_Location_f_leading_comments(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_SourceCodeInfo_Location_is(m)); return upb_msgdef_itof(m, 3); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_SourceCodeInfo_Location_f_leading_detached_comments(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_SourceCodeInfo_Location_is(m)); return upb_msgdef_itof(m, 6); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_SourceCodeInfo_Location_f_path(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_SourceCodeInfo_Location_is(m)); return upb_msgdef_itof(m, 1); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_SourceCodeInfo_Location_f_span(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_SourceCodeInfo_Location_is(m)); return upb_msgdef_itof(m, 2); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_SourceCodeInfo_Location_f_trailing_comments(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_SourceCodeInfo_Location_is(m)); return upb_msgdef_itof(m, 4); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_SourceCodeInfo_f_location(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_SourceCodeInfo_is(m)); return upb_msgdef_itof(m, 1); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_UninterpretedOption_NamePart_f_is_extension(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_UninterpretedOption_NamePart_is(m)); return upb_msgdef_itof(m, 2); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_UninterpretedOption_NamePart_f_name_part(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_UninterpretedOption_NamePart_is(m)); return upb_msgdef_itof(m, 1); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_UninterpretedOption_f_aggregate_value(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_UninterpretedOption_is(m)); return upb_msgdef_itof(m, 8); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_UninterpretedOption_f_double_value(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_UninterpretedOption_is(m)); return upb_msgdef_itof(m, 6); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_UninterpretedOption_f_identifier_value(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_UninterpretedOption_is(m)); return upb_msgdef_itof(m, 3); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_UninterpretedOption_f_name(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_UninterpretedOption_is(m)); return upb_msgdef_itof(m, 2); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_UninterpretedOption_f_negative_int_value(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_UninterpretedOption_is(m)); return upb_msgdef_itof(m, 5); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_UninterpretedOption_f_positive_int_value(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_UninterpretedOption_is(m)); return upb_msgdef_itof(m, 4); } UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_UninterpretedOption_f_string_value(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_UninterpretedOption_is(m)); return upb_msgdef_itof(m, 7); } UPB_END_EXTERN_C #ifdef __cplusplus namespace upbdefs { namespace google { namespace protobuf { class DescriptorProto : public ::upb::reffed_ptr { public: DescriptorProto(const ::upb::MessageDef* m, const void *ref_donor = NULL) : reffed_ptr(m, ref_donor) { UPB_ASSERT(upbdefs_google_protobuf_DescriptorProto_is(m)); } static DescriptorProto get() { const ::upb::MessageDef* m = upbdefs_google_protobuf_DescriptorProto_get(&m); return DescriptorProto(m, &m); } class ExtensionRange : public ::upb::reffed_ptr { public: ExtensionRange(const ::upb::MessageDef* m, const void *ref_donor = NULL) : reffed_ptr(m, ref_donor) { UPB_ASSERT(upbdefs_google_protobuf_DescriptorProto_ExtensionRange_is(m)); } static ExtensionRange get() { const ::upb::MessageDef* m = upbdefs_google_protobuf_DescriptorProto_ExtensionRange_get(&m); return ExtensionRange(m, &m); } }; class ReservedRange : public ::upb::reffed_ptr { public: ReservedRange(const ::upb::MessageDef* m, const void *ref_donor = NULL) : reffed_ptr(m, ref_donor) { UPB_ASSERT(upbdefs_google_protobuf_DescriptorProto_ReservedRange_is(m)); } static ReservedRange get() { const ::upb::MessageDef* m = upbdefs_google_protobuf_DescriptorProto_ReservedRange_get(&m); return ReservedRange(m, &m); } }; }; class EnumDescriptorProto : public ::upb::reffed_ptr { public: EnumDescriptorProto(const ::upb::MessageDef* m, const void *ref_donor = NULL) : reffed_ptr(m, ref_donor) { UPB_ASSERT(upbdefs_google_protobuf_EnumDescriptorProto_is(m)); } static EnumDescriptorProto get() { const ::upb::MessageDef* m = upbdefs_google_protobuf_EnumDescriptorProto_get(&m); return EnumDescriptorProto(m, &m); } }; class EnumOptions : public ::upb::reffed_ptr { public: EnumOptions(const ::upb::MessageDef* m, const void *ref_donor = NULL) : reffed_ptr(m, ref_donor) { UPB_ASSERT(upbdefs_google_protobuf_EnumOptions_is(m)); } static EnumOptions get() { const ::upb::MessageDef* m = upbdefs_google_protobuf_EnumOptions_get(&m); return EnumOptions(m, &m); } }; class EnumValueDescriptorProto : public ::upb::reffed_ptr { public: EnumValueDescriptorProto(const ::upb::MessageDef* m, const void *ref_donor = NULL) : reffed_ptr(m, ref_donor) { UPB_ASSERT(upbdefs_google_protobuf_EnumValueDescriptorProto_is(m)); } static EnumValueDescriptorProto get() { const ::upb::MessageDef* m = upbdefs_google_protobuf_EnumValueDescriptorProto_get(&m); return EnumValueDescriptorProto(m, &m); } }; class EnumValueOptions : public ::upb::reffed_ptr { public: EnumValueOptions(const ::upb::MessageDef* m, const void *ref_donor = NULL) : reffed_ptr(m, ref_donor) { UPB_ASSERT(upbdefs_google_protobuf_EnumValueOptions_is(m)); } static EnumValueOptions get() { const ::upb::MessageDef* m = upbdefs_google_protobuf_EnumValueOptions_get(&m); return EnumValueOptions(m, &m); } }; class FieldDescriptorProto : public ::upb::reffed_ptr { public: FieldDescriptorProto(const ::upb::MessageDef* m, const void *ref_donor = NULL) : reffed_ptr(m, ref_donor) { UPB_ASSERT(upbdefs_google_protobuf_FieldDescriptorProto_is(m)); } static FieldDescriptorProto get() { const ::upb::MessageDef* m = upbdefs_google_protobuf_FieldDescriptorProto_get(&m); return FieldDescriptorProto(m, &m); } class Label : public ::upb::reffed_ptr { public: Label(const ::upb::EnumDef* e, const void *ref_donor = NULL) : reffed_ptr(e, ref_donor) { UPB_ASSERT(upbdefs_google_protobuf_FieldDescriptorProto_Label_is(e)); } static Label get() { const ::upb::EnumDef* e = upbdefs_google_protobuf_FieldDescriptorProto_Label_get(&e); return Label(e, &e); } }; class Type : public ::upb::reffed_ptr { public: Type(const ::upb::EnumDef* e, const void *ref_donor = NULL) : reffed_ptr(e, ref_donor) { UPB_ASSERT(upbdefs_google_protobuf_FieldDescriptorProto_Type_is(e)); } static Type get() { const ::upb::EnumDef* e = upbdefs_google_protobuf_FieldDescriptorProto_Type_get(&e); return Type(e, &e); } }; }; class FieldOptions : public ::upb::reffed_ptr { public: FieldOptions(const ::upb::MessageDef* m, const void *ref_donor = NULL) : reffed_ptr(m, ref_donor) { UPB_ASSERT(upbdefs_google_protobuf_FieldOptions_is(m)); } static FieldOptions get() { const ::upb::MessageDef* m = upbdefs_google_protobuf_FieldOptions_get(&m); return FieldOptions(m, &m); } class CType : public ::upb::reffed_ptr { public: CType(const ::upb::EnumDef* e, const void *ref_donor = NULL) : reffed_ptr(e, ref_donor) { UPB_ASSERT(upbdefs_google_protobuf_FieldOptions_CType_is(e)); } static CType get() { const ::upb::EnumDef* e = upbdefs_google_protobuf_FieldOptions_CType_get(&e); return CType(e, &e); } }; class JSType : public ::upb::reffed_ptr { public: JSType(const ::upb::EnumDef* e, const void *ref_donor = NULL) : reffed_ptr(e, ref_donor) { UPB_ASSERT(upbdefs_google_protobuf_FieldOptions_JSType_is(e)); } static JSType get() { const ::upb::EnumDef* e = upbdefs_google_protobuf_FieldOptions_JSType_get(&e); return JSType(e, &e); } }; }; class FileDescriptorProto : public ::upb::reffed_ptr { public: FileDescriptorProto(const ::upb::MessageDef* m, const void *ref_donor = NULL) : reffed_ptr(m, ref_donor) { UPB_ASSERT(upbdefs_google_protobuf_FileDescriptorProto_is(m)); } static FileDescriptorProto get() { const ::upb::MessageDef* m = upbdefs_google_protobuf_FileDescriptorProto_get(&m); return FileDescriptorProto(m, &m); } }; class FileDescriptorSet : public ::upb::reffed_ptr { public: FileDescriptorSet(const ::upb::MessageDef* m, const void *ref_donor = NULL) : reffed_ptr(m, ref_donor) { UPB_ASSERT(upbdefs_google_protobuf_FileDescriptorSet_is(m)); } static FileDescriptorSet get() { const ::upb::MessageDef* m = upbdefs_google_protobuf_FileDescriptorSet_get(&m); return FileDescriptorSet(m, &m); } }; class FileOptions : public ::upb::reffed_ptr { public: FileOptions(const ::upb::MessageDef* m, const void *ref_donor = NULL) : reffed_ptr(m, ref_donor) { UPB_ASSERT(upbdefs_google_protobuf_FileOptions_is(m)); } static FileOptions get() { const ::upb::MessageDef* m = upbdefs_google_protobuf_FileOptions_get(&m); return FileOptions(m, &m); } class OptimizeMode : public ::upb::reffed_ptr { public: OptimizeMode(const ::upb::EnumDef* e, const void *ref_donor = NULL) : reffed_ptr(e, ref_donor) { UPB_ASSERT(upbdefs_google_protobuf_FileOptions_OptimizeMode_is(e)); } static OptimizeMode get() { const ::upb::EnumDef* e = upbdefs_google_protobuf_FileOptions_OptimizeMode_get(&e); return OptimizeMode(e, &e); } }; }; class MessageOptions : public ::upb::reffed_ptr { public: MessageOptions(const ::upb::MessageDef* m, const void *ref_donor = NULL) : reffed_ptr(m, ref_donor) { UPB_ASSERT(upbdefs_google_protobuf_MessageOptions_is(m)); } static MessageOptions get() { const ::upb::MessageDef* m = upbdefs_google_protobuf_MessageOptions_get(&m); return MessageOptions(m, &m); } }; class MethodDescriptorProto : public ::upb::reffed_ptr { public: MethodDescriptorProto(const ::upb::MessageDef* m, const void *ref_donor = NULL) : reffed_ptr(m, ref_donor) { UPB_ASSERT(upbdefs_google_protobuf_MethodDescriptorProto_is(m)); } static MethodDescriptorProto get() { const ::upb::MessageDef* m = upbdefs_google_protobuf_MethodDescriptorProto_get(&m); return MethodDescriptorProto(m, &m); } }; class MethodOptions : public ::upb::reffed_ptr { public: MethodOptions(const ::upb::MessageDef* m, const void *ref_donor = NULL) : reffed_ptr(m, ref_donor) { UPB_ASSERT(upbdefs_google_protobuf_MethodOptions_is(m)); } static MethodOptions get() { const ::upb::MessageDef* m = upbdefs_google_protobuf_MethodOptions_get(&m); return MethodOptions(m, &m); } }; class OneofDescriptorProto : public ::upb::reffed_ptr { public: OneofDescriptorProto(const ::upb::MessageDef* m, const void *ref_donor = NULL) : reffed_ptr(m, ref_donor) { UPB_ASSERT(upbdefs_google_protobuf_OneofDescriptorProto_is(m)); } static OneofDescriptorProto get() { const ::upb::MessageDef* m = upbdefs_google_protobuf_OneofDescriptorProto_get(&m); return OneofDescriptorProto(m, &m); } }; class ServiceDescriptorProto : public ::upb::reffed_ptr { public: ServiceDescriptorProto(const ::upb::MessageDef* m, const void *ref_donor = NULL) : reffed_ptr(m, ref_donor) { UPB_ASSERT(upbdefs_google_protobuf_ServiceDescriptorProto_is(m)); } static ServiceDescriptorProto get() { const ::upb::MessageDef* m = upbdefs_google_protobuf_ServiceDescriptorProto_get(&m); return ServiceDescriptorProto(m, &m); } }; class ServiceOptions : public ::upb::reffed_ptr { public: ServiceOptions(const ::upb::MessageDef* m, const void *ref_donor = NULL) : reffed_ptr(m, ref_donor) { UPB_ASSERT(upbdefs_google_protobuf_ServiceOptions_is(m)); } static ServiceOptions get() { const ::upb::MessageDef* m = upbdefs_google_protobuf_ServiceOptions_get(&m); return ServiceOptions(m, &m); } }; class SourceCodeInfo : public ::upb::reffed_ptr { public: SourceCodeInfo(const ::upb::MessageDef* m, const void *ref_donor = NULL) : reffed_ptr(m, ref_donor) { UPB_ASSERT(upbdefs_google_protobuf_SourceCodeInfo_is(m)); } static SourceCodeInfo get() { const ::upb::MessageDef* m = upbdefs_google_protobuf_SourceCodeInfo_get(&m); return SourceCodeInfo(m, &m); } class Location : public ::upb::reffed_ptr { public: Location(const ::upb::MessageDef* m, const void *ref_donor = NULL) : reffed_ptr(m, ref_donor) { UPB_ASSERT(upbdefs_google_protobuf_SourceCodeInfo_Location_is(m)); } static Location get() { const ::upb::MessageDef* m = upbdefs_google_protobuf_SourceCodeInfo_Location_get(&m); return Location(m, &m); } }; }; class UninterpretedOption : public ::upb::reffed_ptr { public: UninterpretedOption(const ::upb::MessageDef* m, const void *ref_donor = NULL) : reffed_ptr(m, ref_donor) { UPB_ASSERT(upbdefs_google_protobuf_UninterpretedOption_is(m)); } static UninterpretedOption get() { const ::upb::MessageDef* m = upbdefs_google_protobuf_UninterpretedOption_get(&m); return UninterpretedOption(m, &m); } class NamePart : public ::upb::reffed_ptr { public: NamePart(const ::upb::MessageDef* m, const void *ref_donor = NULL) : reffed_ptr(m, ref_donor) { UPB_ASSERT(upbdefs_google_protobuf_UninterpretedOption_NamePart_is(m)); } static NamePart get() { const ::upb::MessageDef* m = upbdefs_google_protobuf_UninterpretedOption_NamePart_get(&m); return NamePart(m, &m); } }; }; } /* namespace protobuf */ } /* namespace google */ } /* namespace upbdefs */ #endif /* __cplusplus */ #endif /* UPB_DESCRIPTOR_DESCRIPTOR_PROTO_UPB_H_ */ /* ** Internal-only definitions for the decoder. */ #ifndef UPB_DECODER_INT_H_ #define UPB_DECODER_INT_H_ /* ** upb::pb::Decoder ** ** A high performance, streaming, resumable decoder for the binary protobuf ** format. ** ** This interface works the same regardless of what decoder backend is being ** used. A client of this class does not need to know whether decoding is using ** a JITted decoder (DynASM, LLVM, etc) or an interpreted decoder. By default, ** it will always use the fastest available decoder. However, you can call ** set_allow_jit(false) to disable any JIT decoder that might be available. ** This is primarily useful for testing purposes. */ #ifndef UPB_DECODER_H_ #define UPB_DECODER_H_ #ifdef __cplusplus namespace upb { namespace pb { class CodeCache; class Decoder; class DecoderMethod; class DecoderMethodOptions; } /* namespace pb */ } /* namespace upb */ #endif UPB_DECLARE_TYPE(upb::pb::CodeCache, upb_pbcodecache) UPB_DECLARE_TYPE(upb::pb::Decoder, upb_pbdecoder) UPB_DECLARE_TYPE(upb::pb::DecoderMethodOptions, upb_pbdecodermethodopts) UPB_DECLARE_DERIVED_TYPE(upb::pb::DecoderMethod, upb::RefCounted, upb_pbdecodermethod, upb_refcounted) /* The maximum number of bytes we are required to buffer internally between * calls to the decoder. The value is 14: a 5 byte unknown tag plus ten-byte * varint, less one because we are buffering an incomplete value. * * Should only be used by unit tests. */ #define UPB_DECODER_MAX_RESIDUAL_BYTES 14 #ifdef __cplusplus /* The parameters one uses to construct a DecoderMethod. * TODO(haberman): move allowjit here? Seems more convenient for users. * TODO(haberman): move this to be heap allocated for ABI stability. */ class upb::pb::DecoderMethodOptions { public: /* Parameter represents the destination handlers that this method will push * to. */ explicit DecoderMethodOptions(const Handlers* dest_handlers); /* Should the decoder push submessages to lazy handlers for fields that have * them? The caller should set this iff the lazy handlers expect data that is * in protobuf binary format and the caller wishes to lazy parse it. */ void set_lazy(bool lazy); #else struct upb_pbdecodermethodopts { #endif const upb_handlers *handlers; bool lazy; }; #ifdef __cplusplus /* Represents the code to parse a protobuf according to a destination * Handlers. */ class upb::pb::DecoderMethod { public: /* Include base methods from upb::ReferenceCounted. */ UPB_REFCOUNTED_CPPMETHODS /* The destination handlers that are statically bound to this method. * This method is only capable of outputting to a sink that uses these * handlers. */ const Handlers* dest_handlers() const; /* The input handlers for this decoder method. */ const BytesHandler* input_handler() const; /* Whether this method is native. */ bool is_native() const; /* Convenience method for generating a DecoderMethod without explicitly * creating a CodeCache. */ static reffed_ptr New(const DecoderMethodOptions& opts); private: UPB_DISALLOW_POD_OPS(DecoderMethod, upb::pb::DecoderMethod) }; #endif /* Preallocation hint: decoder won't allocate more bytes than this when first * constructed. This hint may be an overestimate for some build configurations. * But if the decoder library is upgraded without recompiling the application, * it may be an underestimate. */ #define UPB_PB_DECODER_SIZE 4416 #ifdef __cplusplus /* A Decoder receives binary protobuf data on its input sink and pushes the * decoded data to its output sink. */ class upb::pb::Decoder { public: /* Constructs a decoder instance for the given method, which must outlive this * decoder. Any errors during parsing will be set on the given status, which * must also outlive this decoder. * * The sink must match the given method. */ static Decoder* Create(Environment* env, const DecoderMethod* method, Sink* output); /* Returns the DecoderMethod this decoder is parsing from. */ const DecoderMethod* method() const; /* The sink on which this decoder receives input. */ BytesSink* input(); /* Returns number of bytes successfully parsed. * * This can be useful for determining the stream position where an error * occurred. * * This value may not be up-to-date when called from inside a parsing * callback. */ uint64_t BytesParsed() const; /* Gets/sets the parsing nexting limit. If the total number of nested * submessages and repeated fields hits this limit, parsing will fail. This * is a resource limit that controls the amount of memory used by the parsing * stack. * * Setting the limit will fail if the parser is currently suspended at a depth * greater than this, or if memory allocation of the stack fails. */ size_t max_nesting() const; bool set_max_nesting(size_t max); void Reset(); static const size_t kSize = UPB_PB_DECODER_SIZE; private: UPB_DISALLOW_POD_OPS(Decoder, upb::pb::Decoder) }; #endif /* __cplusplus */ #ifdef __cplusplus /* A class for caching protobuf processing code, whether bytecode for the * interpreted decoder or machine code for the JIT. * * This class is not thread-safe. * * TODO(haberman): move this to be heap allocated for ABI stability. */ class upb::pb::CodeCache { public: CodeCache(); ~CodeCache(); /* Whether the cache is allowed to generate machine code. Defaults to true. * There is no real reason to turn it off except for testing or if you are * having a specific problem with the JIT. * * Note that allow_jit = true does not *guarantee* that the code will be JIT * compiled. If this platform is not supported or the JIT was not compiled * in, the code may still be interpreted. */ bool allow_jit() const; /* This may only be called when the object is first constructed, and prior to * any code generation, otherwise returns false and does nothing. */ bool set_allow_jit(bool allow); /* Returns a DecoderMethod that can push data to the given handlers. * If a suitable method already exists, it will be returned from the cache. * * Specifying the destination handlers here allows the DecoderMethod to be * statically bound to the destination handlers if possible, which can allow * more efficient decoding. However the returned method may or may not * actually be statically bound. But in all cases, the returned method can * push data to the given handlers. */ const DecoderMethod *GetDecoderMethod(const DecoderMethodOptions& opts); /* If/when someone needs to explicitly create a dynamically-bound * DecoderMethod*, we can add a method to get it here. */ private: UPB_DISALLOW_COPY_AND_ASSIGN(CodeCache) #else struct upb_pbcodecache { #endif bool allow_jit_; /* Array of mgroups. */ upb_inttable groups; }; UPB_BEGIN_EXTERN_C upb_pbdecoder *upb_pbdecoder_create(upb_env *e, const upb_pbdecodermethod *method, upb_sink *output); const upb_pbdecodermethod *upb_pbdecoder_method(const upb_pbdecoder *d); upb_bytessink *upb_pbdecoder_input(upb_pbdecoder *d); uint64_t upb_pbdecoder_bytesparsed(const upb_pbdecoder *d); size_t upb_pbdecoder_maxnesting(const upb_pbdecoder *d); bool upb_pbdecoder_setmaxnesting(upb_pbdecoder *d, size_t max); void upb_pbdecoder_reset(upb_pbdecoder *d); void upb_pbdecodermethodopts_init(upb_pbdecodermethodopts *opts, const upb_handlers *h); void upb_pbdecodermethodopts_setlazy(upb_pbdecodermethodopts *opts, bool lazy); /* Include refcounted methods like upb_pbdecodermethod_ref(). */ UPB_REFCOUNTED_CMETHODS(upb_pbdecodermethod, upb_pbdecodermethod_upcast) const upb_handlers *upb_pbdecodermethod_desthandlers( const upb_pbdecodermethod *m); const upb_byteshandler *upb_pbdecodermethod_inputhandler( const upb_pbdecodermethod *m); bool upb_pbdecodermethod_isnative(const upb_pbdecodermethod *m); const upb_pbdecodermethod *upb_pbdecodermethod_new( const upb_pbdecodermethodopts *opts, const void *owner); void upb_pbcodecache_init(upb_pbcodecache *c); void upb_pbcodecache_uninit(upb_pbcodecache *c); bool upb_pbcodecache_allowjit(const upb_pbcodecache *c); bool upb_pbcodecache_setallowjit(upb_pbcodecache *c, bool allow); const upb_pbdecodermethod *upb_pbcodecache_getdecodermethod( upb_pbcodecache *c, const upb_pbdecodermethodopts *opts); UPB_END_EXTERN_C #ifdef __cplusplus namespace upb { namespace pb { /* static */ inline Decoder* Decoder::Create(Environment* env, const DecoderMethod* m, Sink* sink) { return upb_pbdecoder_create(env, m, sink); } inline const DecoderMethod* Decoder::method() const { return upb_pbdecoder_method(this); } inline BytesSink* Decoder::input() { return upb_pbdecoder_input(this); } inline uint64_t Decoder::BytesParsed() const { return upb_pbdecoder_bytesparsed(this); } inline size_t Decoder::max_nesting() const { return upb_pbdecoder_maxnesting(this); } inline bool Decoder::set_max_nesting(size_t max) { return upb_pbdecoder_setmaxnesting(this, max); } inline void Decoder::Reset() { upb_pbdecoder_reset(this); } inline DecoderMethodOptions::DecoderMethodOptions(const Handlers* h) { upb_pbdecodermethodopts_init(this, h); } inline void DecoderMethodOptions::set_lazy(bool lazy) { upb_pbdecodermethodopts_setlazy(this, lazy); } inline const Handlers* DecoderMethod::dest_handlers() const { return upb_pbdecodermethod_desthandlers(this); } inline const BytesHandler* DecoderMethod::input_handler() const { return upb_pbdecodermethod_inputhandler(this); } inline bool DecoderMethod::is_native() const { return upb_pbdecodermethod_isnative(this); } /* static */ inline reffed_ptr DecoderMethod::New( const DecoderMethodOptions &opts) { const upb_pbdecodermethod *m = upb_pbdecodermethod_new(&opts, &m); return reffed_ptr(m, &m); } inline CodeCache::CodeCache() { upb_pbcodecache_init(this); } inline CodeCache::~CodeCache() { upb_pbcodecache_uninit(this); } inline bool CodeCache::allow_jit() const { return upb_pbcodecache_allowjit(this); } inline bool CodeCache::set_allow_jit(bool allow) { return upb_pbcodecache_setallowjit(this, allow); } inline const DecoderMethod *CodeCache::GetDecoderMethod( const DecoderMethodOptions& opts) { return upb_pbcodecache_getdecodermethod(this, &opts); } } /* namespace pb */ } /* namespace upb */ #endif /* __cplusplus */ #endif /* UPB_DECODER_H_ */ /* C++ names are not actually used since this type isn't exposed to users. */ #ifdef __cplusplus namespace upb { namespace pb { class MessageGroup; } /* namespace pb */ } /* namespace upb */ #endif UPB_DECLARE_DERIVED_TYPE(upb::pb::MessageGroup, upb::RefCounted, mgroup, upb_refcounted) /* Opcode definitions. The canonical meaning of each opcode is its * implementation in the interpreter (the JIT is written to match this). * * All instructions have the opcode in the low byte. * Instruction format for most instructions is: * * +-------------------+--------+ * | arg (24) | op (8) | * +-------------------+--------+ * * Exceptions are indicated below. A few opcodes are multi-word. */ typedef enum { /* Opcodes 1-8, 13, 15-18 parse their respective descriptor types. * Arg for all of these is the upb selector for this field. */ #define T(type) OP_PARSE_ ## type = UPB_DESCRIPTOR_TYPE_ ## type T(DOUBLE), T(FLOAT), T(INT64), T(UINT64), T(INT32), T(FIXED64), T(FIXED32), T(BOOL), T(UINT32), T(SFIXED32), T(SFIXED64), T(SINT32), T(SINT64), #undef T OP_STARTMSG = 9, /* No arg. */ OP_ENDMSG = 10, /* No arg. */ OP_STARTSEQ = 11, OP_ENDSEQ = 12, OP_STARTSUBMSG = 14, OP_ENDSUBMSG = 19, OP_STARTSTR = 20, OP_STRING = 21, OP_ENDSTR = 22, OP_PUSHTAGDELIM = 23, /* No arg. */ OP_PUSHLENDELIM = 24, /* No arg. */ OP_POP = 25, /* No arg. */ OP_SETDELIM = 26, /* No arg. */ OP_SETBIGGROUPNUM = 27, /* two words: * | unused (24) | opc (8) | * | groupnum (32) | */ OP_CHECKDELIM = 28, OP_CALL = 29, OP_RET = 30, OP_BRANCH = 31, /* Different opcodes depending on how many bytes expected. */ OP_TAG1 = 32, /* | match tag (16) | jump target (8) | opc (8) | */ OP_TAG2 = 33, /* | match tag (16) | jump target (8) | opc (8) | */ OP_TAGN = 34, /* three words: */ /* | unused (16) | jump target(8) | opc (8) | */ /* | match tag 1 (32) | */ /* | match tag 2 (32) | */ OP_SETDISPATCH = 35, /* N words: */ /* | unused (24) | opc | */ /* | upb_inttable* (32 or 64) | */ OP_DISPATCH = 36, /* No arg. */ OP_HALT = 37 /* No arg. */ } opcode; #define OP_MAX OP_HALT UPB_INLINE opcode getop(uint32_t instr) { return instr & 0xff; } /* Method group; represents a set of decoder methods that had their code * emitted together, and must therefore be freed together. Immutable once * created. It is possible we may want to expose this to users at some point. * * Overall ownership of Decoder objects looks like this: * * +----------+ * | | <---> DecoderMethod * | method | * CodeCache ---> | group | <---> DecoderMethod * | | * | (mgroup) | <---> DecoderMethod * +----------+ */ struct mgroup { upb_refcounted base; /* Maps upb_msgdef/upb_handlers -> upb_pbdecodermethod. We own refs on the * methods. */ upb_inttable methods; /* When we add the ability to link to previously existing mgroups, we'll * need an array of mgroups we reference here, and own refs on them. */ /* The bytecode for our methods, if any exists. Owned by us. */ uint32_t *bytecode; uint32_t *bytecode_end; #ifdef UPB_USE_JIT_X64 /* JIT-generated machine code, if any. */ upb_string_handlerfunc *jit_code; /* The size of the jit_code (required to munmap()). */ size_t jit_size; char *debug_info; void *dl; #endif }; /* The maximum that any submessages can be nested. Matches proto2's limit. * This specifies the size of the decoder's statically-sized array and therefore * setting it high will cause the upb::pb::Decoder object to be larger. * * If necessary we can add a runtime-settable property to Decoder that allow * this to be larger than the compile-time setting, but this would add * complexity, particularly since we would have to decide how/if to give users * the ability to set a custom memory allocation function. */ #define UPB_DECODER_MAX_NESTING 64 /* Internal-only struct used by the decoder. */ typedef struct { /* Space optimization note: we store two pointers here that the JIT * doesn't need at all; the upb_handlers* inside the sink and * the dispatch table pointer. We can optimze so that the JIT uses * smaller stack frames than the interpreter. The only thing we need * to guarantee is that the fallback routines can find end_ofs. */ upb_sink sink; /* The absolute stream offset of the end-of-frame delimiter. * Non-delimited frames (groups and non-packed repeated fields) reuse the * delimiter of their parent, even though the frame may not end there. * * NOTE: the JIT stores a slightly different value here for non-top frames. * It stores the value relative to the end of the enclosed message. But the * top frame is still stored the same way, which is important for ensuring * that calls from the JIT into C work correctly. */ uint64_t end_ofs; const uint32_t *base; /* 0 indicates a length-delimited field. * A positive number indicates a known group. * A negative number indicates an unknown group. */ int32_t groupnum; upb_inttable *dispatch; /* Not used by the JIT. */ } upb_pbdecoder_frame; struct upb_pbdecodermethod { upb_refcounted base; /* While compiling, the base is relative in "ofs", after compiling it is * absolute in "ptr". */ union { uint32_t ofs; /* PC offset of method. */ void *ptr; /* Pointer to bytecode or machine code for this method. */ } code_base; /* The decoder method group to which this method belongs. We own a ref. * Owning a ref on the entire group is more coarse-grained than is strictly * necessary; all we truly require is that methods we directly reference * outlive us, while the group could contain many other messages we don't * require. But the group represents the messages that were * allocated+compiled together, so it makes the most sense to free them * together also. */ const upb_refcounted *group; /* Whether this method is native code or bytecode. */ bool is_native_; /* The handler one calls to invoke this method. */ upb_byteshandler input_handler_; /* The destination handlers this method is bound to. We own a ref. */ const upb_handlers *dest_handlers_; /* Dispatch table -- used by both bytecode decoder and JIT when encountering a * field number that wasn't the one we were expecting to see. See * decoder.int.h for the layout of this table. */ upb_inttable dispatch; }; struct upb_pbdecoder { upb_env *env; /* Our input sink. */ upb_bytessink input_; /* The decoder method we are parsing with (owned). */ const upb_pbdecodermethod *method_; size_t call_len; const uint32_t *pc, *last; /* Current input buffer and its stream offset. */ const char *buf, *ptr, *end, *checkpoint; /* End of the delimited region, relative to ptr, NULL if not in this buf. */ const char *delim_end; /* End of the delimited region, relative to ptr, end if not in this buf. */ const char *data_end; /* Overall stream offset of "buf." */ uint64_t bufstart_ofs; /* Buffer for residual bytes not parsed from the previous buffer. */ char residual[UPB_DECODER_MAX_RESIDUAL_BYTES]; char *residual_end; /* Bytes of data that should be discarded from the input beore we start * parsing again. We set this when we internally determine that we can * safely skip the next N bytes, but this region extends past the current * user buffer. */ size_t skip; /* Stores the user buffer passed to our decode function. */ const char *buf_param; size_t size_param; const upb_bufhandle *handle; /* Our internal stack. */ upb_pbdecoder_frame *stack, *top, *limit; const uint32_t **callstack; size_t stack_size; upb_status *status; #ifdef UPB_USE_JIT_X64 /* Used momentarily by the generated code to store a value while a user * function is called. */ uint32_t tmp_len; const void *saved_rsp; #endif }; /* Decoder entry points; used as handlers. */ void *upb_pbdecoder_startbc(void *closure, const void *pc, size_t size_hint); void *upb_pbdecoder_startjit(void *closure, const void *hd, size_t size_hint); size_t upb_pbdecoder_decode(void *closure, const void *hd, const char *buf, size_t size, const upb_bufhandle *handle); bool upb_pbdecoder_end(void *closure, const void *handler_data); /* Decoder-internal functions that the JIT calls to handle fallback paths. */ int32_t upb_pbdecoder_resume(upb_pbdecoder *d, void *p, const char *buf, size_t size, const upb_bufhandle *handle); size_t upb_pbdecoder_suspend(upb_pbdecoder *d); int32_t upb_pbdecoder_skipunknown(upb_pbdecoder *d, int32_t fieldnum, uint8_t wire_type); int32_t upb_pbdecoder_checktag_slow(upb_pbdecoder *d, uint64_t expected); int32_t upb_pbdecoder_decode_varint_slow(upb_pbdecoder *d, uint64_t *u64); int32_t upb_pbdecoder_decode_f32(upb_pbdecoder *d, uint32_t *u32); int32_t upb_pbdecoder_decode_f64(upb_pbdecoder *d, uint64_t *u64); void upb_pbdecoder_seterr(upb_pbdecoder *d, const char *msg); /* Error messages that are shared between the bytecode and JIT decoders. */ extern const char *kPbDecoderStackOverflow; extern const char *kPbDecoderSubmessageTooLong; /* Access to decoderplan members needed by the decoder. */ const char *upb_pbdecoder_getopname(unsigned int op); /* JIT codegen entry point. */ void upb_pbdecoder_jit(mgroup *group); void upb_pbdecoder_freejit(mgroup *group); UPB_REFCOUNTED_CMETHODS(mgroup, mgroup_upcast) /* A special label that means "do field dispatch for this message and branch to * wherever that takes you." */ #define LABEL_DISPATCH 0 /* A special slot in the dispatch table that stores the epilogue (ENDMSG and/or * RET) for branching to when we find an appropriate ENDGROUP tag. */ #define DISPATCH_ENDMSG 0 /* It's important to use this invalid wire type instead of 0 (which is a valid * wire type). */ #define NO_WIRE_TYPE 0xff /* The dispatch table layout is: * [field number] -> [ 48-bit offset ][ 8-bit wt2 ][ 8-bit wt1 ] * * If wt1 matches, jump to the 48-bit offset. If wt2 matches, lookup * (UPB_MAX_FIELDNUMBER + fieldnum) and jump there. * * We need two wire types because of packed/non-packed compatibility. A * primitive repeated field can use either wire type and be valid. While we * could key the table on fieldnum+wiretype, the table would be 8x sparser. * * Storing two wire types in the primary value allows us to quickly rule out * the second wire type without needing to do a separate lookup (this case is * less common than an unknown field). */ UPB_INLINE uint64_t upb_pbdecoder_packdispatch(uint64_t ofs, uint8_t wt1, uint8_t wt2) { return (ofs << 16) | (wt2 << 8) | wt1; } UPB_INLINE void upb_pbdecoder_unpackdispatch(uint64_t dispatch, uint64_t *ofs, uint8_t *wt1, uint8_t *wt2) { *wt1 = (uint8_t)dispatch; *wt2 = (uint8_t)(dispatch >> 8); *ofs = dispatch >> 16; } /* All of the functions in decoder.c that return int32_t return values according * to the following scheme: * 1. negative values indicate a return code from the following list. * 2. positive values indicate that error or end of buffer was hit, and * that the decode function should immediately return the given value * (the decoder state has already been suspended and is ready to be * resumed). */ #define DECODE_OK -1 #define DECODE_MISMATCH -2 /* Used only from checktag_slow(). */ #define DECODE_ENDGROUP -3 /* Used only from checkunknown(). */ #define CHECK_RETURN(x) { int32_t ret = x; if (ret >= 0) return ret; } #endif /* UPB_DECODER_INT_H_ */ /* ** A number of routines for varint manipulation (we keep them all around to ** have multiple approaches available for benchmarking). */ #ifndef UPB_VARINT_DECODER_H_ #define UPB_VARINT_DECODER_H_ #include #include #include #ifdef __cplusplus extern "C" { #endif /* A list of types as they are encoded on-the-wire. */ typedef enum { UPB_WIRE_TYPE_VARINT = 0, UPB_WIRE_TYPE_64BIT = 1, UPB_WIRE_TYPE_DELIMITED = 2, UPB_WIRE_TYPE_START_GROUP = 3, UPB_WIRE_TYPE_END_GROUP = 4, UPB_WIRE_TYPE_32BIT = 5 } upb_wiretype_t; #define UPB_MAX_WIRE_TYPE 5 /* The maximum number of bytes that it takes to encode a 64-bit varint. * Note that with a better encoding this could be 9 (TODO: write up a * wiki document about this). */ #define UPB_PB_VARINT_MAX_LEN 10 /* Array of the "native" (ie. non-packed-repeated) wire type for the given a * descriptor type (upb_descriptortype_t). */ extern const uint8_t upb_pb_native_wire_types[]; /* Zig-zag encoding/decoding **************************************************/ UPB_INLINE int32_t upb_zzdec_32(uint32_t n) { return (n >> 1) ^ -(int32_t)(n & 1); } UPB_INLINE int64_t upb_zzdec_64(uint64_t n) { return (n >> 1) ^ -(int64_t)(n & 1); } UPB_INLINE uint32_t upb_zzenc_32(int32_t n) { return (n << 1) ^ (n >> 31); } UPB_INLINE uint64_t upb_zzenc_64(int64_t n) { return (n << 1) ^ (n >> 63); } /* Decoding *******************************************************************/ /* All decoding functions return this struct by value. */ typedef struct { const char *p; /* NULL if the varint was unterminated. */ uint64_t val; } upb_decoderet; UPB_INLINE upb_decoderet upb_decoderet_make(const char *p, uint64_t val) { upb_decoderet ret; ret.p = p; ret.val = val; return ret; } /* Four functions for decoding a varint of at most eight bytes. They are all * functionally identical, but are implemented in different ways and likely have * different performance profiles. We keep them around for performance testing. * * Note that these functions may not read byte-by-byte, so they must not be used * unless there are at least eight bytes left in the buffer! */ upb_decoderet upb_vdecode_max8_branch32(upb_decoderet r); upb_decoderet upb_vdecode_max8_branch64(upb_decoderet r); upb_decoderet upb_vdecode_max8_wright(upb_decoderet r); upb_decoderet upb_vdecode_max8_massimino(upb_decoderet r); /* Template for a function that checks the first two bytes with branching * and dispatches 2-10 bytes with a separate function. Note that this may read * up to 10 bytes, so it must not be used unless there are at least ten bytes * left in the buffer! */ #define UPB_VARINT_DECODER_CHECK2(name, decode_max8_function) \ UPB_INLINE upb_decoderet upb_vdecode_check2_ ## name(const char *_p) { \ uint8_t *p = (uint8_t*)_p; \ upb_decoderet r; \ if ((*p & 0x80) == 0) { \ /* Common case: one-byte varint. */ \ return upb_decoderet_make(_p + 1, *p & 0x7fU); \ } \ r = upb_decoderet_make(_p + 2, (*p & 0x7fU) | ((*(p + 1) & 0x7fU) << 7)); \ if ((*(p + 1) & 0x80) == 0) { \ /* Two-byte varint. */ \ return r; \ } \ /* Longer varint, fallback to out-of-line function. */ \ return decode_max8_function(r); \ } UPB_VARINT_DECODER_CHECK2(branch32, upb_vdecode_max8_branch32) UPB_VARINT_DECODER_CHECK2(branch64, upb_vdecode_max8_branch64) UPB_VARINT_DECODER_CHECK2(wright, upb_vdecode_max8_wright) UPB_VARINT_DECODER_CHECK2(massimino, upb_vdecode_max8_massimino) #undef UPB_VARINT_DECODER_CHECK2 /* Our canonical functions for decoding varints, based on the currently * favored best-performing implementations. */ UPB_INLINE upb_decoderet upb_vdecode_fast(const char *p) { if (sizeof(long) == 8) return upb_vdecode_check2_branch64(p); else return upb_vdecode_check2_branch32(p); } UPB_INLINE upb_decoderet upb_vdecode_max8_fast(upb_decoderet r) { return upb_vdecode_max8_massimino(r); } /* Encoding *******************************************************************/ UPB_INLINE int upb_value_size(uint64_t val) { #ifdef __GNUC__ int high_bit = 63 - __builtin_clzll(val); /* 0-based, undef if val == 0. */ #else int high_bit = 0; uint64_t tmp = val; while(tmp >>= 1) high_bit++; #endif return val == 0 ? 1 : high_bit / 8 + 1; } /* Encodes a 64-bit varint into buf (which must be >=UPB_PB_VARINT_MAX_LEN * bytes long), returning how many bytes were used. * * TODO: benchmark and optimize if necessary. */ UPB_INLINE size_t upb_vencode64(uint64_t val, char *buf) { size_t i; if (val == 0) { buf[0] = 0; return 1; } i = 0; while (val) { uint8_t byte = val & 0x7fU; val >>= 7; if (val) byte |= 0x80U; buf[i++] = byte; } return i; } UPB_INLINE size_t upb_varint_size(uint64_t val) { char buf[UPB_PB_VARINT_MAX_LEN]; return upb_vencode64(val, buf); } /* Encodes a 32-bit varint, *not* sign-extended. */ UPB_INLINE uint64_t upb_vencode32(uint32_t val) { char buf[UPB_PB_VARINT_MAX_LEN]; size_t bytes = upb_vencode64(val, buf); uint64_t ret = 0; UPB_ASSERT(bytes <= 5); memcpy(&ret, buf, bytes); UPB_ASSERT(ret <= 0xffffffffffU); return ret; } #ifdef __cplusplus } /* extern "C" */ #endif #endif /* UPB_VARINT_DECODER_H_ */ /* ** upb::pb::Encoder (upb_pb_encoder) ** ** Implements a set of upb_handlers that write protobuf data to the binary wire ** format. ** ** This encoder implementation does not have any access to any out-of-band or ** precomputed lengths for submessages, so it must buffer submessages internally ** before it can emit the first byte. */ #ifndef UPB_ENCODER_H_ #define UPB_ENCODER_H_ #ifdef __cplusplus namespace upb { namespace pb { class Encoder; } /* namespace pb */ } /* namespace upb */ #endif UPB_DECLARE_TYPE(upb::pb::Encoder, upb_pb_encoder) #define UPB_PBENCODER_MAX_NESTING 100 /* upb::pb::Encoder ***********************************************************/ /* Preallocation hint: decoder won't allocate more bytes than this when first * constructed. This hint may be an overestimate for some build configurations. * But if the decoder library is upgraded without recompiling the application, * it may be an underestimate. */ #define UPB_PB_ENCODER_SIZE 768 #ifdef __cplusplus class upb::pb::Encoder { public: /* Creates a new encoder in the given environment. The Handlers must have * come from NewHandlers() below. */ static Encoder* Create(Environment* env, const Handlers* handlers, BytesSink* output); /* The input to the encoder. */ Sink* input(); /* Creates a new set of handlers for this MessageDef. */ static reffed_ptr NewHandlers(const MessageDef* msg); static const size_t kSize = UPB_PB_ENCODER_SIZE; private: UPB_DISALLOW_POD_OPS(Encoder, upb::pb::Encoder) }; #endif UPB_BEGIN_EXTERN_C const upb_handlers *upb_pb_encoder_newhandlers(const upb_msgdef *m, const void *owner); upb_sink *upb_pb_encoder_input(upb_pb_encoder *p); upb_pb_encoder* upb_pb_encoder_create(upb_env* e, const upb_handlers* h, upb_bytessink* output); UPB_END_EXTERN_C #ifdef __cplusplus namespace upb { namespace pb { inline Encoder* Encoder::Create(Environment* env, const Handlers* handlers, BytesSink* output) { return upb_pb_encoder_create(env, handlers, output); } inline Sink* Encoder::input() { return upb_pb_encoder_input(this); } inline reffed_ptr Encoder::NewHandlers( const upb::MessageDef *md) { const Handlers* h = upb_pb_encoder_newhandlers(md, &h); return reffed_ptr(h, &h); } } /* namespace pb */ } /* namespace upb */ #endif #endif /* UPB_ENCODER_H_ */ /* ** upb's core components like upb_decoder and upb_msg are carefully designed to ** avoid depending on each other for maximum orthogonality. In other words, ** you can use a upb_decoder to decode into *any* kind of structure; upb_msg is ** just one such structure. A upb_msg can be serialized/deserialized into any ** format, protobuf binary format is just one such format. ** ** However, for convenience we provide functions here for doing common ** operations like deserializing protobuf binary format into a upb_msg. The ** compromise is that this file drags in almost all of upb as a dependency, ** which could be undesirable if you're trying to use a trimmed-down build of ** upb. ** ** While these routines are convenient, they do not reuse any encoding/decoding ** state. For example, if a decoder is JIT-based, it will be re-JITted every ** time these functions are called. For this reason, if you are parsing lots ** of data and efficiency is an issue, these may not be the best functions to ** use (though they are useful for prototyping, before optimizing). */ #ifndef UPB_GLUE_H #define UPB_GLUE_H #include #ifdef __cplusplus #include extern "C" { #endif /* Loads a binary descriptor and returns a NULL-terminated array of unfrozen * filedefs. The caller owns the returned array, which must be freed with * upb_gfree(). */ upb_filedef **upb_loaddescriptor(const char *buf, size_t n, const void *owner, upb_status *status); #ifdef __cplusplus } /* extern "C" */ namespace upb { inline bool LoadDescriptor(const char* buf, size_t n, Status* status, std::vector >* files) { FileDef** parsed_files = upb_loaddescriptor(buf, n, &parsed_files, status); if (parsed_files) { FileDef** p = parsed_files; while (*p) { files->push_back(reffed_ptr(*p, &parsed_files)); ++p; } free(parsed_files); return true; } else { return false; } } /* Templated so it can accept both string and std::string. */ template bool LoadDescriptor(const T& desc, Status* status, std::vector >* files) { return LoadDescriptor(desc.c_str(), desc.size(), status, files); } } /* namespace upb */ #endif #endif /* UPB_GLUE_H */ /* ** upb::pb::TextPrinter (upb_textprinter) ** ** Handlers for writing to protobuf text format. */ #ifndef UPB_TEXT_H_ #define UPB_TEXT_H_ #ifdef __cplusplus namespace upb { namespace pb { class TextPrinter; } /* namespace pb */ } /* namespace upb */ #endif UPB_DECLARE_TYPE(upb::pb::TextPrinter, upb_textprinter) #ifdef __cplusplus class upb::pb::TextPrinter { public: /* The given handlers must have come from NewHandlers(). It must outlive the * TextPrinter. */ static TextPrinter *Create(Environment *env, const upb::Handlers *handlers, BytesSink *output); void SetSingleLineMode(bool single_line); Sink* input(); /* If handler caching becomes a requirement we can add a code cache as in * decoder.h */ static reffed_ptr NewHandlers(const MessageDef* md); }; #endif UPB_BEGIN_EXTERN_C /* C API. */ upb_textprinter *upb_textprinter_create(upb_env *env, const upb_handlers *h, upb_bytessink *output); void upb_textprinter_setsingleline(upb_textprinter *p, bool single_line); upb_sink *upb_textprinter_input(upb_textprinter *p); const upb_handlers *upb_textprinter_newhandlers(const upb_msgdef *m, const void *owner); UPB_END_EXTERN_C #ifdef __cplusplus namespace upb { namespace pb { inline TextPrinter *TextPrinter::Create(Environment *env, const upb::Handlers *handlers, BytesSink *output) { return upb_textprinter_create(env, handlers, output); } inline void TextPrinter::SetSingleLineMode(bool single_line) { upb_textprinter_setsingleline(this, single_line); } inline Sink* TextPrinter::input() { return upb_textprinter_input(this); } inline reffed_ptr TextPrinter::NewHandlers( const MessageDef *md) { const Handlers* h = upb_textprinter_newhandlers(md, &h); return reffed_ptr(h, &h); } } /* namespace pb */ } /* namespace upb */ #endif #endif /* UPB_TEXT_H_ */ /* ** upb::json::Parser (upb_json_parser) ** ** Parses JSON according to a specific schema. ** Support for parsing arbitrary JSON (schema-less) will be added later. */ #ifndef UPB_JSON_PARSER_H_ #define UPB_JSON_PARSER_H_ #ifdef __cplusplus namespace upb { namespace json { class Parser; class ParserMethod; } /* namespace json */ } /* namespace upb */ #endif UPB_DECLARE_TYPE(upb::json::Parser, upb_json_parser) UPB_DECLARE_DERIVED_TYPE(upb::json::ParserMethod, upb::RefCounted, upb_json_parsermethod, upb_refcounted) /* upb::json::Parser **********************************************************/ /* Preallocation hint: parser won't allocate more bytes than this when first * constructed. This hint may be an overestimate for some build configurations. * But if the parser library is upgraded without recompiling the application, * it may be an underestimate. */ #define UPB_JSON_PARSER_SIZE 4112 #ifdef __cplusplus /* Parses an incoming BytesStream, pushing the results to the destination * sink. */ class upb::json::Parser { public: static Parser* Create(Environment* env, const ParserMethod* method, Sink* output); BytesSink* input(); private: UPB_DISALLOW_POD_OPS(Parser, upb::json::Parser) }; class upb::json::ParserMethod { public: /* Include base methods from upb::ReferenceCounted. */ UPB_REFCOUNTED_CPPMETHODS /* Returns handlers for parsing according to the specified schema. */ static reffed_ptr New(const upb::MessageDef* md); /* The destination handlers that are statically bound to this method. * This method is only capable of outputting to a sink that uses these * handlers. */ const Handlers* dest_handlers() const; /* The input handlers for this decoder method. */ const BytesHandler* input_handler() const; private: UPB_DISALLOW_POD_OPS(ParserMethod, upb::json::ParserMethod) }; #endif UPB_BEGIN_EXTERN_C upb_json_parser* upb_json_parser_create(upb_env* e, const upb_json_parsermethod* m, upb_sink* output); upb_bytessink *upb_json_parser_input(upb_json_parser *p); upb_json_parsermethod* upb_json_parsermethod_new(const upb_msgdef* md, const void* owner); const upb_handlers *upb_json_parsermethod_desthandlers( const upb_json_parsermethod *m); const upb_byteshandler *upb_json_parsermethod_inputhandler( const upb_json_parsermethod *m); /* Include refcounted methods like upb_json_parsermethod_ref(). */ UPB_REFCOUNTED_CMETHODS(upb_json_parsermethod, upb_json_parsermethod_upcast) UPB_END_EXTERN_C #ifdef __cplusplus namespace upb { namespace json { inline Parser* Parser::Create(Environment* env, const ParserMethod* method, Sink* output) { return upb_json_parser_create(env, method, output); } inline BytesSink* Parser::input() { return upb_json_parser_input(this); } inline const Handlers* ParserMethod::dest_handlers() const { return upb_json_parsermethod_desthandlers(this); } inline const BytesHandler* ParserMethod::input_handler() const { return upb_json_parsermethod_inputhandler(this); } /* static */ inline reffed_ptr ParserMethod::New( const MessageDef* md) { const upb_json_parsermethod *m = upb_json_parsermethod_new(md, &m); return reffed_ptr(m, &m); } } /* namespace json */ } /* namespace upb */ #endif #endif /* UPB_JSON_PARSER_H_ */ /* ** upb::json::Printer ** ** Handlers that emit JSON according to a specific protobuf schema. */ #ifndef UPB_JSON_TYPED_PRINTER_H_ #define UPB_JSON_TYPED_PRINTER_H_ #ifdef __cplusplus namespace upb { namespace json { class Printer; } /* namespace json */ } /* namespace upb */ #endif UPB_DECLARE_TYPE(upb::json::Printer, upb_json_printer) /* upb::json::Printer *********************************************************/ #define UPB_JSON_PRINTER_SIZE 176 #ifdef __cplusplus /* Prints an incoming stream of data to a BytesSink in JSON format. */ class upb::json::Printer { public: static Printer* Create(Environment* env, const upb::Handlers* handlers, BytesSink* output); /* The input to the printer. */ Sink* input(); /* Returns handlers for printing according to the specified schema. * If preserve_proto_fieldnames is true, the output JSON will use the * original .proto field names (ie. {"my_field":3}) instead of using * camelCased names, which is the default: (eg. {"myField":3}). */ static reffed_ptr NewHandlers(const upb::MessageDef* md, bool preserve_proto_fieldnames); static const size_t kSize = UPB_JSON_PRINTER_SIZE; private: UPB_DISALLOW_POD_OPS(Printer, upb::json::Printer) }; #endif UPB_BEGIN_EXTERN_C /* Native C API. */ upb_json_printer *upb_json_printer_create(upb_env *e, const upb_handlers *h, upb_bytessink *output); upb_sink *upb_json_printer_input(upb_json_printer *p); const upb_handlers *upb_json_printer_newhandlers(const upb_msgdef *md, bool preserve_fieldnames, const void *owner); UPB_END_EXTERN_C #ifdef __cplusplus namespace upb { namespace json { inline Printer* Printer::Create(Environment* env, const upb::Handlers* handlers, BytesSink* output) { return upb_json_printer_create(env, handlers, output); } inline Sink* Printer::input() { return upb_json_printer_input(this); } inline reffed_ptr Printer::NewHandlers( const upb::MessageDef *md, bool preserve_proto_fieldnames) { const Handlers* h = upb_json_printer_newhandlers( md, preserve_proto_fieldnames, &h); return reffed_ptr(h, &h); } } /* namespace json */ } /* namespace upb */ #endif #endif /* UPB_JSON_TYPED_PRINTER_H_ */ google-protobuf-3.2.0/ext/google/protobuf_c/message.c0000644000175000017500000004662513042756211021676 0ustar pravipravi// 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" // ----------------------------------------------------------------------------- // Class/module creation from msgdefs and enumdefs, respectively. // ----------------------------------------------------------------------------- void* Message_data(void* msg) { return ((uint8_t *)msg) + sizeof(MessageHeader); } void Message_mark(void* _self) { MessageHeader* self = (MessageHeader *)_self; layout_mark(self->descriptor->layout, Message_data(self)); } void Message_free(void* self) { xfree(self); } rb_data_type_t Message_type = { "Message", { Message_mark, Message_free, NULL }, }; VALUE Message_alloc(VALUE klass) { VALUE descriptor = rb_ivar_get(klass, descriptor_instancevar_interned); Descriptor* desc = ruby_to_Descriptor(descriptor); MessageHeader* msg = (MessageHeader*)ALLOC_N( uint8_t, sizeof(MessageHeader) + desc->layout->size); VALUE ret; memset(Message_data(msg), 0, desc->layout->size); // We wrap first so that everything in the message object is GC-rooted in case // a collection happens during object creation in layout_init(). ret = TypedData_Wrap_Struct(klass, &Message_type, msg); msg->descriptor = desc; rb_ivar_set(ret, descriptor_instancevar_interned, descriptor); layout_init(desc->layout, Message_data(msg)); return ret; } static VALUE which_oneof_field(MessageHeader* self, const upb_oneofdef* o) { upb_oneof_iter it; size_t case_ofs; uint32_t oneof_case; const upb_fielddef* first_field; const upb_fielddef* f; // If no fields in the oneof, always nil. if (upb_oneofdef_numfields(o) == 0) { return Qnil; } // Grab the first field in the oneof so we can get its layout info to find the // oneof_case field. upb_oneof_begin(&it, o); assert(!upb_oneof_done(&it)); first_field = upb_oneof_iter_field(&it); assert(upb_fielddef_containingoneof(first_field) != NULL); case_ofs = self->descriptor->layout-> fields[upb_fielddef_index(first_field)].case_offset; oneof_case = *((uint32_t*)((char*)Message_data(self) + case_ofs)); if (oneof_case == ONEOF_CASE_NONE) { return Qnil; } // oneof_case is a field index, so find that field. f = upb_oneofdef_itof(o, oneof_case); assert(f != NULL); return ID2SYM(rb_intern(upb_fielddef_name(f))); } /* * call-seq: * Message.method_missing(*args) * * Provides accessors and setters for message fields according to their field * names. For any field whose name does not conflict with a built-in method, an * accessor is provided with the same name as the field, and a setter is * provided with the name of the field plus the '=' suffix. Thus, given a * message instance 'msg' with field 'foo', the following code is valid: * * msg.foo = 42 * puts msg.foo * * This method also provides read-only accessors for oneofs. If a oneof exists * with name 'my_oneof', then msg.my_oneof will return a Ruby symbol equal to * the name of the field in that oneof that is currently set, or nil if none. */ VALUE Message_method_missing(int argc, VALUE* argv, VALUE _self) { MessageHeader* self; VALUE method_name, method_str; char* name; size_t name_len; bool setter; const upb_oneofdef* o; const upb_fielddef* f; TypedData_Get_Struct(_self, MessageHeader, &Message_type, self); if (argc < 1) { rb_raise(rb_eArgError, "Expected method name as first argument."); } method_name = argv[0]; if (!SYMBOL_P(method_name)) { rb_raise(rb_eArgError, "Expected symbol as method name."); } method_str = rb_id2str(SYM2ID(method_name)); name = RSTRING_PTR(method_str); name_len = RSTRING_LEN(method_str); setter = false; // Setters have names that end in '='. if (name[name_len - 1] == '=') { setter = true; name_len--; } // See if this name corresponds to either a oneof or field in this message. if (!upb_msgdef_lookupname(self->descriptor->msgdef, name, name_len, &f, &o)) { return rb_call_super(argc, argv); } if (o != NULL) { // This is a oneof -- return which field inside the oneof is set. if (setter) { rb_raise(rb_eRuntimeError, "Oneof accessors are read-only."); } return which_oneof_field(self, o); } else { // This is a field -- get or set the field's value. assert(f); if (setter) { if (argc < 2) { rb_raise(rb_eArgError, "No value provided to setter."); } layout_set(self->descriptor->layout, Message_data(self), f, argv[1]); return Qnil; } else { return layout_get(self->descriptor->layout, Message_data(self), f); } } } VALUE Message_respond_to_missing(int argc, VALUE* argv, VALUE _self) { MessageHeader* self; VALUE method_name, method_str; char* name; size_t name_len; bool setter; const upb_oneofdef* o; const upb_fielddef* f; TypedData_Get_Struct(_self, MessageHeader, &Message_type, self); if (argc < 1) { rb_raise(rb_eArgError, "Expected method name as first argument."); } method_name = argv[0]; if (!SYMBOL_P(method_name)) { rb_raise(rb_eArgError, "Expected symbol as method name."); } method_str = rb_id2str(SYM2ID(method_name)); name = RSTRING_PTR(method_str); name_len = RSTRING_LEN(method_str); setter = false; // Setters have names that end in '='. if (name[name_len - 1] == '=') { setter = true; name_len--; } // See if this name corresponds to either a oneof or field in this message. if (!upb_msgdef_lookupname(self->descriptor->msgdef, name, name_len, &f, &o)) { return rb_call_super(argc, argv); } if (o != NULL) { return setter ? Qfalse : Qtrue; } return Qtrue; } int Message_initialize_kwarg(VALUE key, VALUE val, VALUE _self) { MessageHeader* self; VALUE method_str; char* name; const upb_fielddef* f; TypedData_Get_Struct(_self, MessageHeader, &Message_type, self); if (!SYMBOL_P(key)) { rb_raise(rb_eArgError, "Expected symbols as hash keys in initialization map."); } method_str = rb_id2str(SYM2ID(key)); name = RSTRING_PTR(method_str); f = upb_msgdef_ntofz(self->descriptor->msgdef, name); if (f == NULL) { rb_raise(rb_eArgError, "Unknown field name '%s' in initialization map entry.", name); } if (is_map_field(f)) { VALUE map; if (TYPE(val) != T_HASH) { rb_raise(rb_eArgError, "Expected Hash object as initializer value for map field '%s'.", name); } map = layout_get(self->descriptor->layout, Message_data(self), f); Map_merge_into_self(map, val); } else if (upb_fielddef_label(f) == UPB_LABEL_REPEATED) { VALUE ary; if (TYPE(val) != T_ARRAY) { rb_raise(rb_eArgError, "Expected array as initializer value for repeated field '%s'.", name); } ary = layout_get(self->descriptor->layout, Message_data(self), f); for (int i = 0; i < RARRAY_LEN(val); i++) { RepeatedField_push(ary, rb_ary_entry(val, i)); } } else { layout_set(self->descriptor->layout, Message_data(self), f, val); } return 0; } /* * call-seq: * Message.new(kwargs) => new_message * * Creates a new instance of the given message class. Keyword arguments may be * provided with keywords corresponding to field names. * * Note that no literal Message class exists. Only concrete classes per message * type exist, as provided by the #msgclass method on Descriptors after they * have been added to a pool. The method definitions described here on the * Message class are provided on each concrete message class. */ VALUE Message_initialize(int argc, VALUE* argv, VALUE _self) { VALUE hash_args; if (argc == 0) { return Qnil; } if (argc != 1) { rb_raise(rb_eArgError, "Expected 0 or 1 arguments."); } hash_args = argv[0]; if (TYPE(hash_args) != T_HASH) { rb_raise(rb_eArgError, "Expected hash arguments."); } rb_hash_foreach(hash_args, Message_initialize_kwarg, _self); return Qnil; } /* * call-seq: * Message.dup => new_message * * Performs a shallow copy of this message and returns the new copy. */ VALUE Message_dup(VALUE _self) { MessageHeader* self; VALUE new_msg; MessageHeader* new_msg_self; TypedData_Get_Struct(_self, MessageHeader, &Message_type, self); new_msg = rb_class_new_instance(0, NULL, CLASS_OF(_self)); TypedData_Get_Struct(new_msg, MessageHeader, &Message_type, new_msg_self); layout_dup(self->descriptor->layout, Message_data(new_msg_self), Message_data(self)); return new_msg; } // Internal only; used by Google::Protobuf.deep_copy. VALUE Message_deep_copy(VALUE _self) { MessageHeader* self; MessageHeader* new_msg_self; VALUE new_msg; TypedData_Get_Struct(_self, MessageHeader, &Message_type, self); new_msg = rb_class_new_instance(0, NULL, CLASS_OF(_self)); TypedData_Get_Struct(new_msg, MessageHeader, &Message_type, new_msg_self); layout_deep_copy(self->descriptor->layout, Message_data(new_msg_self), Message_data(self)); return new_msg; } /* * call-seq: * Message.==(other) => boolean * * Performs a deep comparison of this message with another. Messages are equal * if they have the same type and if each field is equal according to the :== * method's semantics (a more efficient comparison may actually be done if the * field is of a primitive type). */ VALUE Message_eq(VALUE _self, VALUE _other) { MessageHeader* self; MessageHeader* other; if (TYPE(_self) != TYPE(_other)) { return Qfalse; } TypedData_Get_Struct(_self, MessageHeader, &Message_type, self); TypedData_Get_Struct(_other, MessageHeader, &Message_type, other); if (self->descriptor != other->descriptor) { return Qfalse; } return layout_eq(self->descriptor->layout, Message_data(self), Message_data(other)); } /* * call-seq: * Message.hash => hash_value * * Returns a hash value that represents this message's field values. */ VALUE Message_hash(VALUE _self) { MessageHeader* self; TypedData_Get_Struct(_self, MessageHeader, &Message_type, self); return layout_hash(self->descriptor->layout, Message_data(self)); } /* * call-seq: * Message.inspect => string * * Returns a human-readable string representing this message. It will be * formatted as "". Each * field's value is represented according to its own #inspect method. */ VALUE Message_inspect(VALUE _self) { MessageHeader* self; VALUE str; TypedData_Get_Struct(_self, MessageHeader, &Message_type, self); str = rb_str_new2("<"); str = rb_str_append(str, rb_str_new2(rb_class2name(CLASS_OF(_self)))); str = rb_str_cat2(str, ": "); str = rb_str_append(str, layout_inspect( self->descriptor->layout, Message_data(self))); str = rb_str_cat2(str, ">"); return str; } VALUE Message_to_h(VALUE _self) { MessageHeader* self; VALUE hash; upb_msg_field_iter it; TypedData_Get_Struct(_self, MessageHeader, &Message_type, self); hash = rb_hash_new(); for (upb_msg_field_begin(&it, self->descriptor->msgdef); !upb_msg_field_done(&it); upb_msg_field_next(&it)) { const upb_fielddef* field = upb_msg_iter_field(&it); VALUE msg_value = layout_get(self->descriptor->layout, Message_data(self), field); VALUE msg_key = ID2SYM(rb_intern(upb_fielddef_name(field))); if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) { msg_value = RepeatedField_to_ary(msg_value); } rb_hash_aset(hash, msg_key, msg_value); } return hash; } /* * call-seq: * Message.[](index) => value * * Accesses a field's value by field name. The provided field name should be a * string. */ VALUE Message_index(VALUE _self, VALUE field_name) { MessageHeader* self; const upb_fielddef* field; TypedData_Get_Struct(_self, MessageHeader, &Message_type, self); Check_Type(field_name, T_STRING); field = upb_msgdef_ntofz(self->descriptor->msgdef, RSTRING_PTR(field_name)); if (field == NULL) { return Qnil; } return layout_get(self->descriptor->layout, Message_data(self), field); } /* * call-seq: * Message.[]=(index, value) * * Sets a field's value by field name. The provided field name should be a * string. */ VALUE Message_index_set(VALUE _self, VALUE field_name, VALUE value) { MessageHeader* self; const upb_fielddef* field; TypedData_Get_Struct(_self, MessageHeader, &Message_type, self); Check_Type(field_name, T_STRING); field = upb_msgdef_ntofz(self->descriptor->msgdef, RSTRING_PTR(field_name)); if (field == NULL) { rb_raise(rb_eArgError, "Unknown field: %s", RSTRING_PTR(field_name)); } layout_set(self->descriptor->layout, Message_data(self), field, value); return Qnil; } /* * call-seq: * Message.descriptor => descriptor * * Class method that returns the Descriptor instance corresponding to this * message class's type. */ VALUE Message_descriptor(VALUE klass) { return rb_ivar_get(klass, descriptor_instancevar_interned); } VALUE build_class_from_descriptor(Descriptor* desc) { const char *name; VALUE klass; if (desc->layout == NULL) { desc->layout = create_layout(desc->msgdef); } if (desc->fill_method == NULL) { desc->fill_method = new_fillmsg_decodermethod(desc, &desc->fill_method); } name = upb_msgdef_fullname(desc->msgdef); if (name == NULL) { rb_raise(rb_eRuntimeError, "Descriptor does not have assigned name."); } klass = rb_define_class_id( // Docs say this parameter is ignored. User will assign return value to // their own toplevel constant class name. rb_intern("Message"), rb_cObject); rb_ivar_set(klass, descriptor_instancevar_interned, get_def_obj(desc->msgdef)); rb_define_alloc_func(klass, Message_alloc); rb_require("google/protobuf/message_exts"); rb_include_module(klass, rb_eval_string("Google::Protobuf::MessageExts")); rb_extend_object( klass, rb_eval_string("Google::Protobuf::MessageExts::ClassMethods")); rb_define_method(klass, "method_missing", Message_method_missing, -1); rb_define_method(klass, "respond_to_missing?", Message_respond_to_missing, -1); rb_define_method(klass, "initialize", Message_initialize, -1); rb_define_method(klass, "dup", Message_dup, 0); // Also define #clone so that we don't inherit Object#clone. rb_define_method(klass, "clone", Message_dup, 0); rb_define_method(klass, "==", Message_eq, 1); rb_define_method(klass, "hash", Message_hash, 0); rb_define_method(klass, "to_h", Message_to_h, 0); rb_define_method(klass, "to_hash", Message_to_h, 0); rb_define_method(klass, "inspect", Message_inspect, 0); rb_define_method(klass, "[]", Message_index, 1); rb_define_method(klass, "[]=", Message_index_set, 2); rb_define_singleton_method(klass, "decode", Message_decode, 1); rb_define_singleton_method(klass, "encode", Message_encode, 1); rb_define_singleton_method(klass, "decode_json", Message_decode_json, 1); rb_define_singleton_method(klass, "encode_json", Message_encode_json, -1); rb_define_singleton_method(klass, "descriptor", Message_descriptor, 0); return klass; } /* * 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. */ VALUE enum_lookup(VALUE self, VALUE number) { int32_t num = NUM2INT(number); VALUE desc = rb_ivar_get(self, descriptor_instancevar_interned); EnumDescriptor* enumdesc = ruby_to_EnumDescriptor(desc); const char* name = upb_enumdef_iton(enumdesc->enumdef, num); if (name == NULL) { return Qnil; } else { return ID2SYM(rb_intern(name)); } } /* * 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. */ VALUE enum_resolve(VALUE self, VALUE sym) { const char* name = rb_id2name(SYM2ID(sym)); VALUE desc = rb_ivar_get(self, descriptor_instancevar_interned); EnumDescriptor* enumdesc = ruby_to_EnumDescriptor(desc); int32_t num = 0; bool found = upb_enumdef_ntoiz(enumdesc->enumdef, name, &num); if (!found) { return Qnil; } else { return INT2NUM(num); } } /* * call-seq: * Enum.descriptor * * This module method, provided on each generated enum module, returns the * EnumDescriptor corresponding to this enum type. */ VALUE enum_descriptor(VALUE self) { return rb_ivar_get(self, descriptor_instancevar_interned); } VALUE build_module_from_enumdesc(EnumDescriptor* enumdesc) { VALUE mod = rb_define_module_id( rb_intern(upb_enumdef_fullname(enumdesc->enumdef))); upb_enum_iter it; for (upb_enum_begin(&it, enumdesc->enumdef); !upb_enum_done(&it); upb_enum_next(&it)) { const char* name = upb_enum_iter_name(&it); int32_t value = upb_enum_iter_number(&it); if (name[0] < 'A' || name[0] > 'Z') { rb_raise(rb_eTypeError, "Enum value '%s' does not start with an uppercase letter " "as is required for Ruby constants.", name); } rb_define_const(mod, name, INT2NUM(value)); } rb_define_singleton_method(mod, "lookup", enum_lookup, 1); rb_define_singleton_method(mod, "resolve", enum_resolve, 1); rb_define_singleton_method(mod, "descriptor", enum_descriptor, 0); rb_ivar_set(mod, descriptor_instancevar_interned, get_def_obj(enumdesc->enumdef)); return mod; } /* * call-seq: * Google::Protobuf.deep_copy(obj) => copy_of_obj * * Performs a deep copy of a RepeatedField instance, a Map instance, or a * message object, recursively copying its members. */ VALUE Google_Protobuf_deep_copy(VALUE self, VALUE obj) { VALUE klass = CLASS_OF(obj); if (klass == cRepeatedField) { return RepeatedField_deep_copy(obj); } else if (klass == cMap) { return Map_deep_copy(obj); } else { return Message_deep_copy(obj); } } google-protobuf-3.2.0/ext/google/protobuf_c/defs.c0000644000175000017500000016402313042777744021202 0ustar pravipravi// 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" // ----------------------------------------------------------------------------- // Common utilities. // ----------------------------------------------------------------------------- static const char* get_str(VALUE str) { Check_Type(str, T_STRING); return RSTRING_PTR(str); } static VALUE rb_str_maybe_null(const char* s) { if (s == NULL) { s = ""; } return rb_str_new2(s); } static upb_def* check_notfrozen(const upb_def* def) { if (upb_def_isfrozen(def)) { rb_raise(rb_eRuntimeError, "Attempt to modify a frozen descriptor. Once descriptors are " "added to the descriptor pool, they may not be modified."); } return (upb_def*)def; } static upb_msgdef* check_msg_notfrozen(const upb_msgdef* def) { return upb_downcast_msgdef_mutable(check_notfrozen((const upb_def*)def)); } static upb_fielddef* check_field_notfrozen(const upb_fielddef* def) { return upb_downcast_fielddef_mutable(check_notfrozen((const upb_def*)def)); } static upb_oneofdef* check_oneof_notfrozen(const upb_oneofdef* def) { return (upb_oneofdef*)check_notfrozen((const upb_def*)def); } static upb_enumdef* check_enum_notfrozen(const upb_enumdef* def) { return (upb_enumdef*)check_notfrozen((const upb_def*)def); } // ----------------------------------------------------------------------------- // DescriptorPool. // ----------------------------------------------------------------------------- #define DEFINE_CLASS(name, string_name) \ VALUE c ## name; \ const rb_data_type_t _ ## name ## _type = { \ string_name, \ { name ## _mark, name ## _free, NULL }, \ }; \ name* ruby_to_ ## name(VALUE val) { \ name* ret; \ TypedData_Get_Struct(val, name, &_ ## name ## _type, ret); \ return ret; \ } \ #define DEFINE_SELF(type, var, rb_var) \ type* var = ruby_to_ ## type(rb_var) // Global singleton DescriptorPool. The user is free to create others, but this // is used by generated code. VALUE generated_pool; DEFINE_CLASS(DescriptorPool, "Google::Protobuf::DescriptorPool"); void DescriptorPool_mark(void* _self) { } void DescriptorPool_free(void* _self) { DescriptorPool* self = _self; upb_symtab_free(self->symtab); xfree(self); } /* * call-seq: * DescriptorPool.new => pool * * Creates a new, empty, descriptor pool. */ VALUE DescriptorPool_alloc(VALUE klass) { DescriptorPool* self = ALLOC(DescriptorPool); self->symtab = upb_symtab_new(); return TypedData_Wrap_Struct(klass, &_DescriptorPool_type, self); } void DescriptorPool_register(VALUE module) { VALUE klass = rb_define_class_under( module, "DescriptorPool", rb_cObject); rb_define_alloc_func(klass, DescriptorPool_alloc); rb_define_method(klass, "add", DescriptorPool_add, 1); rb_define_method(klass, "build", DescriptorPool_build, 0); rb_define_method(klass, "lookup", DescriptorPool_lookup, 1); rb_define_singleton_method(klass, "generated_pool", DescriptorPool_generated_pool, 0); cDescriptorPool = klass; rb_gc_register_address(&cDescriptorPool); generated_pool = rb_class_new_instance(0, NULL, klass); rb_gc_register_address(&generated_pool); } static void add_descriptor_to_pool(DescriptorPool* self, Descriptor* descriptor) { CHECK_UPB( upb_symtab_add(self->symtab, (upb_def**)&descriptor->msgdef, 1, NULL, &status), "Adding Descriptor to DescriptorPool failed"); } static void add_enumdesc_to_pool(DescriptorPool* self, EnumDescriptor* enumdesc) { CHECK_UPB( upb_symtab_add(self->symtab, (upb_def**)&enumdesc->enumdef, 1, NULL, &status), "Adding EnumDescriptor to DescriptorPool failed"); } /* * call-seq: * DescriptorPool.add(descriptor) * * Adds the given Descriptor or EnumDescriptor to this pool. All references to * other types in a Descriptor's fields must be resolvable within this pool or * an exception will be raised. */ VALUE DescriptorPool_add(VALUE _self, VALUE def) { DEFINE_SELF(DescriptorPool, self, _self); VALUE def_klass = rb_obj_class(def); if (def_klass == cDescriptor) { add_descriptor_to_pool(self, ruby_to_Descriptor(def)); } else if (def_klass == cEnumDescriptor) { add_enumdesc_to_pool(self, ruby_to_EnumDescriptor(def)); } else { rb_raise(rb_eArgError, "Second argument must be a Descriptor or EnumDescriptor."); } return Qnil; } /* * call-seq: * DescriptorPool.build(&block) * * Invokes the block with a Builder instance as self. All message and enum types * added within the block are committed to the pool atomically, and may refer * (co)recursively to each other. The user should call Builder#add_message and * Builder#add_enum within the block as appropriate. This is the recommended, * idiomatic way to define new message and enum types. */ VALUE DescriptorPool_build(VALUE _self) { VALUE ctx = rb_class_new_instance(0, NULL, cBuilder); VALUE block = rb_block_proc(); rb_funcall_with_block(ctx, rb_intern("instance_eval"), 0, NULL, block); rb_funcall(ctx, rb_intern("finalize_to_pool"), 1, _self); return Qnil; } /* * 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. */ VALUE DescriptorPool_lookup(VALUE _self, VALUE name) { DEFINE_SELF(DescriptorPool, self, _self); const char* name_str = get_str(name); const upb_def* def = upb_symtab_lookup(self->symtab, name_str); if (!def) { return Qnil; } return get_def_obj(def); } /* * 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. */ VALUE DescriptorPool_generated_pool(VALUE _self) { return generated_pool; } // ----------------------------------------------------------------------------- // Descriptor. // ----------------------------------------------------------------------------- DEFINE_CLASS(Descriptor, "Google::Protobuf::Descriptor"); void Descriptor_mark(void* _self) { Descriptor* self = _self; rb_gc_mark(self->klass); rb_gc_mark(self->typeclass_references); } void Descriptor_free(void* _self) { Descriptor* self = _self; upb_msgdef_unref(self->msgdef, &self->msgdef); if (self->layout) { free_layout(self->layout); } if (self->fill_handlers) { upb_handlers_unref(self->fill_handlers, &self->fill_handlers); } if (self->fill_method) { upb_pbdecodermethod_unref(self->fill_method, &self->fill_method); } if (self->json_fill_method) { upb_json_parsermethod_unref(self->json_fill_method, &self->json_fill_method); } if (self->pb_serialize_handlers) { upb_handlers_unref(self->pb_serialize_handlers, &self->pb_serialize_handlers); } if (self->json_serialize_handlers) { upb_handlers_unref(self->json_serialize_handlers, &self->json_serialize_handlers); } if (self->json_serialize_handlers_preserve) { upb_handlers_unref(self->json_serialize_handlers_preserve, &self->json_serialize_handlers_preserve); } xfree(self); } /* * call-seq: * Descriptor.new => descriptor * * Creates a new, empty, message type descriptor. At a minimum, its name must be * set before it is added to a pool. It cannot be used to create messages until * it is added to a pool, after which it becomes immutable (as part of a * finalization process). */ VALUE Descriptor_alloc(VALUE klass) { Descriptor* self = ALLOC(Descriptor); VALUE ret = TypedData_Wrap_Struct(klass, &_Descriptor_type, self); self->msgdef = upb_msgdef_new(&self->msgdef); self->klass = Qnil; self->layout = NULL; self->fill_handlers = NULL; self->fill_method = NULL; self->json_fill_method = NULL; self->pb_serialize_handlers = NULL; self->json_serialize_handlers = NULL; self->json_serialize_handlers_preserve = NULL; self->typeclass_references = rb_ary_new(); return ret; } void Descriptor_register(VALUE module) { VALUE klass = rb_define_class_under( module, "Descriptor", rb_cObject); rb_define_alloc_func(klass, Descriptor_alloc); rb_define_method(klass, "each", Descriptor_each, 0); rb_define_method(klass, "lookup", Descriptor_lookup, 1); rb_define_method(klass, "add_field", Descriptor_add_field, 1); rb_define_method(klass, "add_oneof", Descriptor_add_oneof, 1); rb_define_method(klass, "each_oneof", Descriptor_each_oneof, 0); rb_define_method(klass, "lookup_oneof", Descriptor_lookup_oneof, 1); rb_define_method(klass, "msgclass", Descriptor_msgclass, 0); rb_define_method(klass, "name", Descriptor_name, 0); rb_define_method(klass, "name=", Descriptor_name_set, 1); rb_include_module(klass, rb_mEnumerable); cDescriptor = klass; rb_gc_register_address(&cDescriptor); } /* * call-seq: * Descriptor.name => name * * Returns the name of this message type as a fully-qualfied string (e.g., * My.Package.MessageType). */ VALUE Descriptor_name(VALUE _self) { DEFINE_SELF(Descriptor, self, _self); return rb_str_maybe_null(upb_msgdef_fullname(self->msgdef)); } /* * call-seq: * Descriptor.name = name * * Assigns a name to this message type. The descriptor must not have been added * to a pool yet. */ VALUE Descriptor_name_set(VALUE _self, VALUE str) { DEFINE_SELF(Descriptor, self, _self); upb_msgdef* mut_def = check_msg_notfrozen(self->msgdef); const char* name = get_str(str); CHECK_UPB( upb_msgdef_setfullname(mut_def, name, &status), "Error setting Descriptor name"); return Qnil; } /* * call-seq: * Descriptor.each(&block) * * Iterates over fields in this message type, yielding to the block on each one. */ VALUE Descriptor_each(VALUE _self) { DEFINE_SELF(Descriptor, self, _self); upb_msg_field_iter it; for (upb_msg_field_begin(&it, self->msgdef); !upb_msg_field_done(&it); upb_msg_field_next(&it)) { const upb_fielddef* field = upb_msg_iter_field(&it); VALUE obj = get_def_obj(field); rb_yield(obj); } return Qnil; } /* * call-seq: * Descriptor.lookup(name) => FieldDescriptor * * Returns the field descriptor for the field with the given name, if present, * or nil if none. */ VALUE Descriptor_lookup(VALUE _self, VALUE name) { DEFINE_SELF(Descriptor, self, _self); const char* s = get_str(name); const upb_fielddef* field = upb_msgdef_ntofz(self->msgdef, s); if (field == NULL) { return Qnil; } return get_def_obj(field); } /* * call-seq: * Descriptor.add_field(field) => nil * * Adds the given FieldDescriptor to this message type. This descriptor must not * have been added to a pool yet. Raises an exception if a field with the same * name or number already exists. Sub-type references (e.g. for fields of type * message) are not resolved at this point. */ VALUE Descriptor_add_field(VALUE _self, VALUE obj) { DEFINE_SELF(Descriptor, self, _self); upb_msgdef* mut_def = check_msg_notfrozen(self->msgdef); FieldDescriptor* def = ruby_to_FieldDescriptor(obj); upb_fielddef* mut_field_def = check_field_notfrozen(def->fielddef); CHECK_UPB( upb_msgdef_addfield(mut_def, mut_field_def, NULL, &status), "Adding field to Descriptor failed"); add_def_obj(def->fielddef, obj); return Qnil; } /* * call-seq: * Descriptor.add_oneof(oneof) => nil * * Adds the given OneofDescriptor to this message type. This descriptor must not * have been added to a pool yet. Raises an exception if a oneof with the same * name already exists, or if any of the oneof's fields' names or numbers * conflict with an existing field in this message type. All fields in the oneof * are added to the message descriptor. Sub-type references (e.g. for fields of * type message) are not resolved at this point. */ VALUE Descriptor_add_oneof(VALUE _self, VALUE obj) { DEFINE_SELF(Descriptor, self, _self); upb_msgdef* mut_def = check_msg_notfrozen(self->msgdef); OneofDescriptor* def = ruby_to_OneofDescriptor(obj); upb_oneofdef* mut_oneof_def = check_oneof_notfrozen(def->oneofdef); CHECK_UPB( upb_msgdef_addoneof(mut_def, mut_oneof_def, NULL, &status), "Adding oneof to Descriptor failed"); add_def_obj(def->oneofdef, obj); return Qnil; } /* * call-seq: * Descriptor.each_oneof(&block) => nil * * Invokes the given block for each oneof in this message type, passing the * corresponding OneofDescriptor. */ VALUE Descriptor_each_oneof(VALUE _self) { DEFINE_SELF(Descriptor, self, _self); upb_msg_oneof_iter it; for (upb_msg_oneof_begin(&it, self->msgdef); !upb_msg_oneof_done(&it); upb_msg_oneof_next(&it)) { const upb_oneofdef* oneof = upb_msg_iter_oneof(&it); VALUE obj = get_def_obj(oneof); rb_yield(obj); } return Qnil; } /* * call-seq: * Descriptor.lookup_oneof(name) => OneofDescriptor * * Returns the oneof descriptor for the oneof with the given name, if present, * or nil if none. */ VALUE Descriptor_lookup_oneof(VALUE _self, VALUE name) { DEFINE_SELF(Descriptor, self, _self); const char* s = get_str(name); const upb_oneofdef* oneof = upb_msgdef_ntooz(self->msgdef, s); if (oneof == NULL) { return Qnil; } return get_def_obj(oneof); } /* * 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. */ VALUE Descriptor_msgclass(VALUE _self) { DEFINE_SELF(Descriptor, self, _self); if (!upb_def_isfrozen((const upb_def*)self->msgdef)) { rb_raise(rb_eRuntimeError, "Cannot fetch message class from a Descriptor not yet in a pool."); } if (self->klass == Qnil) { self->klass = build_class_from_descriptor(self); } return self->klass; } // ----------------------------------------------------------------------------- // FieldDescriptor. // ----------------------------------------------------------------------------- DEFINE_CLASS(FieldDescriptor, "Google::Protobuf::FieldDescriptor"); void FieldDescriptor_mark(void* _self) { } void FieldDescriptor_free(void* _self) { FieldDescriptor* self = _self; upb_fielddef_unref(self->fielddef, &self->fielddef); xfree(self); } /* * call-seq: * FieldDescriptor.new => field * * Returns a new field descriptor. Its name, type, etc. must be set before it is * added to a message type. */ VALUE FieldDescriptor_alloc(VALUE klass) { FieldDescriptor* self = ALLOC(FieldDescriptor); VALUE ret = TypedData_Wrap_Struct(klass, &_FieldDescriptor_type, self); upb_fielddef* fielddef = upb_fielddef_new(&self->fielddef); upb_fielddef_setpacked(fielddef, false); self->fielddef = fielddef; return ret; } void FieldDescriptor_register(VALUE module) { VALUE klass = rb_define_class_under( module, "FieldDescriptor", rb_cObject); rb_define_alloc_func(klass, FieldDescriptor_alloc); rb_define_method(klass, "name", FieldDescriptor_name, 0); rb_define_method(klass, "name=", FieldDescriptor_name_set, 1); rb_define_method(klass, "type", FieldDescriptor_type, 0); rb_define_method(klass, "type=", FieldDescriptor_type_set, 1); rb_define_method(klass, "label", FieldDescriptor_label, 0); rb_define_method(klass, "label=", FieldDescriptor_label_set, 1); rb_define_method(klass, "number", FieldDescriptor_number, 0); rb_define_method(klass, "number=", FieldDescriptor_number_set, 1); rb_define_method(klass, "submsg_name", FieldDescriptor_submsg_name, 0); rb_define_method(klass, "submsg_name=", FieldDescriptor_submsg_name_set, 1); rb_define_method(klass, "subtype", FieldDescriptor_subtype, 0); rb_define_method(klass, "get", FieldDescriptor_get, 1); rb_define_method(klass, "set", FieldDescriptor_set, 2); cFieldDescriptor = klass; rb_gc_register_address(&cFieldDescriptor); } /* * call-seq: * FieldDescriptor.name => name * * Returns the name of this field. */ VALUE FieldDescriptor_name(VALUE _self) { DEFINE_SELF(FieldDescriptor, self, _self); return rb_str_maybe_null(upb_fielddef_name(self->fielddef)); } /* * call-seq: * FieldDescriptor.name = name * * Sets the name of this field. Cannot be called once the containing message * type, if any, is added to a pool. */ VALUE FieldDescriptor_name_set(VALUE _self, VALUE str) { DEFINE_SELF(FieldDescriptor, self, _self); upb_fielddef* mut_def = check_field_notfrozen(self->fielddef); const char* name = get_str(str); CHECK_UPB(upb_fielddef_setname(mut_def, name, &status), "Error setting FieldDescriptor name"); return Qnil; } upb_fieldtype_t ruby_to_fieldtype(VALUE type) { if (TYPE(type) != T_SYMBOL) { rb_raise(rb_eArgError, "Expected symbol for field type."); } #define CONVERT(upb, ruby) \ if (SYM2ID(type) == rb_intern( # ruby )) { \ return UPB_TYPE_ ## upb; \ } CONVERT(FLOAT, float); CONVERT(DOUBLE, double); CONVERT(BOOL, bool); CONVERT(STRING, string); CONVERT(BYTES, bytes); CONVERT(MESSAGE, message); CONVERT(ENUM, enum); CONVERT(INT32, int32); CONVERT(INT64, int64); CONVERT(UINT32, uint32); CONVERT(UINT64, uint64); #undef CONVERT rb_raise(rb_eArgError, "Unknown field type."); return 0; } VALUE fieldtype_to_ruby(upb_fieldtype_t type) { switch (type) { #define CONVERT(upb, ruby) \ case UPB_TYPE_ ## upb : return ID2SYM(rb_intern( # ruby )); CONVERT(FLOAT, float); CONVERT(DOUBLE, double); CONVERT(BOOL, bool); CONVERT(STRING, string); CONVERT(BYTES, bytes); CONVERT(MESSAGE, message); CONVERT(ENUM, enum); CONVERT(INT32, int32); CONVERT(INT64, int64); CONVERT(UINT32, uint32); CONVERT(UINT64, uint64); #undef CONVERT } return Qnil; } upb_descriptortype_t ruby_to_descriptortype(VALUE type) { if (TYPE(type) != T_SYMBOL) { rb_raise(rb_eArgError, "Expected symbol for field type."); } #define CONVERT(upb, ruby) \ if (SYM2ID(type) == rb_intern( # ruby )) { \ return UPB_DESCRIPTOR_TYPE_ ## upb; \ } CONVERT(FLOAT, float); CONVERT(DOUBLE, double); CONVERT(BOOL, bool); CONVERT(STRING, string); CONVERT(BYTES, bytes); CONVERT(MESSAGE, message); CONVERT(GROUP, group); CONVERT(ENUM, enum); CONVERT(INT32, int32); CONVERT(INT64, int64); CONVERT(UINT32, uint32); CONVERT(UINT64, uint64); CONVERT(SINT32, sint32); CONVERT(SINT64, sint64); CONVERT(FIXED32, fixed32); CONVERT(FIXED64, fixed64); CONVERT(SFIXED32, sfixed32); CONVERT(SFIXED64, sfixed64); #undef CONVERT rb_raise(rb_eArgError, "Unknown field type."); return 0; } VALUE descriptortype_to_ruby(upb_descriptortype_t type) { switch (type) { #define CONVERT(upb, ruby) \ case UPB_DESCRIPTOR_TYPE_ ## upb : return ID2SYM(rb_intern( # ruby )); CONVERT(FLOAT, float); CONVERT(DOUBLE, double); CONVERT(BOOL, bool); CONVERT(STRING, string); CONVERT(BYTES, bytes); CONVERT(MESSAGE, message); CONVERT(GROUP, group); CONVERT(ENUM, enum); CONVERT(INT32, int32); CONVERT(INT64, int64); CONVERT(UINT32, uint32); CONVERT(UINT64, uint64); CONVERT(SINT32, sint32); CONVERT(SINT64, sint64); CONVERT(FIXED32, fixed32); CONVERT(FIXED64, fixed64); CONVERT(SFIXED32, sfixed32); CONVERT(SFIXED64, sfixed64); #undef CONVERT } return Qnil; } /* * 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. */ VALUE FieldDescriptor_type(VALUE _self) { DEFINE_SELF(FieldDescriptor, self, _self); if (!upb_fielddef_typeisset(self->fielddef)) { return Qnil; } return descriptortype_to_ruby(upb_fielddef_descriptortype(self->fielddef)); } /* * call-seq: * FieldDescriptor.type = type * * Sets this field's type. Cannot be called if field is part of a message type * already in a pool. */ VALUE FieldDescriptor_type_set(VALUE _self, VALUE type) { DEFINE_SELF(FieldDescriptor, self, _self); upb_fielddef* mut_def = check_field_notfrozen(self->fielddef); upb_fielddef_setdescriptortype(mut_def, ruby_to_descriptortype(type)); return Qnil; } /* * call-seq: * FieldDescriptor.label => label * * Returns this field's label (i.e., plurality), as a Ruby symbol. * * Valid field labels are: * :optional, :repeated */ VALUE FieldDescriptor_label(VALUE _self) { DEFINE_SELF(FieldDescriptor, self, _self); switch (upb_fielddef_label(self->fielddef)) { #define CONVERT(upb, ruby) \ case UPB_LABEL_ ## upb : return ID2SYM(rb_intern( # ruby )); CONVERT(OPTIONAL, optional); CONVERT(REQUIRED, required); CONVERT(REPEATED, repeated); #undef CONVERT } return Qnil; } /* * call-seq: * FieldDescriptor.label = label * * Sets the label on this field. Cannot be called if field is part of a message * type already in a pool. */ VALUE FieldDescriptor_label_set(VALUE _self, VALUE label) { DEFINE_SELF(FieldDescriptor, self, _self); upb_fielddef* mut_def = check_field_notfrozen(self->fielddef); upb_label_t upb_label = -1; bool converted = false; if (TYPE(label) != T_SYMBOL) { rb_raise(rb_eArgError, "Expected symbol for field label."); } #define CONVERT(upb, ruby) \ if (SYM2ID(label) == rb_intern( # ruby )) { \ upb_label = UPB_LABEL_ ## upb; \ converted = true; \ } CONVERT(OPTIONAL, optional); CONVERT(REQUIRED, required); CONVERT(REPEATED, repeated); #undef CONVERT if (!converted) { rb_raise(rb_eArgError, "Unknown field label."); } upb_fielddef_setlabel(mut_def, upb_label); return Qnil; } /* * call-seq: * FieldDescriptor.number => number * * Returns the tag number for this field. */ VALUE FieldDescriptor_number(VALUE _self) { DEFINE_SELF(FieldDescriptor, self, _self); return INT2NUM(upb_fielddef_number(self->fielddef)); } /* * call-seq: * FieldDescriptor.number = number * * Sets the tag number for this field. Cannot be called if field is part of a * message type already in a pool. */ VALUE FieldDescriptor_number_set(VALUE _self, VALUE number) { DEFINE_SELF(FieldDescriptor, self, _self); upb_fielddef* mut_def = check_field_notfrozen(self->fielddef); CHECK_UPB(upb_fielddef_setnumber(mut_def, NUM2INT(number), &status), "Error setting field number"); return Qnil; } /* * 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); if (!upb_fielddef_hassubdef(self->fielddef)) { return Qnil; } return rb_str_maybe_null(upb_fielddef_subdefname(self->fielddef)); } /* * 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. */ VALUE FieldDescriptor_submsg_name_set(VALUE _self, VALUE value) { DEFINE_SELF(FieldDescriptor, self, _self); upb_fielddef* mut_def = check_field_notfrozen(self->fielddef); const char* str = get_str(value); if (!upb_fielddef_hassubdef(self->fielddef)) { rb_raise(rb_eTypeError, "FieldDescriptor does not have subdef."); } CHECK_UPB(upb_fielddef_setsubdefname(mut_def, str, &status), "Error setting submessage name"); return Qnil; } /* * 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). */ VALUE FieldDescriptor_subtype(VALUE _self) { DEFINE_SELF(FieldDescriptor, self, _self); const upb_def* def; if (!upb_fielddef_hassubdef(self->fielddef)) { return Qnil; } def = upb_fielddef_subdef(self->fielddef); if (def == NULL) { return Qnil; } return get_def_obj(def); } /* * 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. */ VALUE FieldDescriptor_get(VALUE _self, VALUE msg_rb) { DEFINE_SELF(FieldDescriptor, self, _self); MessageHeader* msg; TypedData_Get_Struct(msg_rb, MessageHeader, &Message_type, msg); if (msg->descriptor->msgdef != upb_fielddef_containingtype(self->fielddef)) { rb_raise(rb_eTypeError, "get method called on wrong message type"); } return layout_get(msg->descriptor->layout, Message_data(msg), self->fielddef); } /* * 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. */ VALUE FieldDescriptor_set(VALUE _self, VALUE msg_rb, VALUE value) { DEFINE_SELF(FieldDescriptor, self, _self); MessageHeader* msg; TypedData_Get_Struct(msg_rb, MessageHeader, &Message_type, msg); if (msg->descriptor->msgdef != upb_fielddef_containingtype(self->fielddef)) { rb_raise(rb_eTypeError, "set method called on wrong message type"); } layout_set(msg->descriptor->layout, Message_data(msg), self->fielddef, value); return Qnil; } // ----------------------------------------------------------------------------- // OneofDescriptor. // ----------------------------------------------------------------------------- DEFINE_CLASS(OneofDescriptor, "Google::Protobuf::OneofDescriptor"); void OneofDescriptor_mark(void* _self) { } void OneofDescriptor_free(void* _self) { OneofDescriptor* self = _self; upb_oneofdef_unref(self->oneofdef, &self->oneofdef); xfree(self); } /* * call-seq: * OneofDescriptor.new => oneof_descriptor * * Creates a new, empty, oneof descriptor. The oneof may only be modified prior * to being added to a message descriptor which is subsequently added to a pool. */ VALUE OneofDescriptor_alloc(VALUE klass) { OneofDescriptor* self = ALLOC(OneofDescriptor); VALUE ret = TypedData_Wrap_Struct(klass, &_OneofDescriptor_type, self); self->oneofdef = upb_oneofdef_new(&self->oneofdef); return ret; } void OneofDescriptor_register(VALUE module) { VALUE klass = rb_define_class_under( module, "OneofDescriptor", rb_cObject); rb_define_alloc_func(klass, OneofDescriptor_alloc); rb_define_method(klass, "name", OneofDescriptor_name, 0); rb_define_method(klass, "name=", OneofDescriptor_name_set, 1); rb_define_method(klass, "add_field", OneofDescriptor_add_field, 1); rb_define_method(klass, "each", OneofDescriptor_each, 0); rb_include_module(klass, rb_mEnumerable); cOneofDescriptor = klass; rb_gc_register_address(&cOneofDescriptor); } /* * call-seq: * OneofDescriptor.name => name * * Returns the name of this oneof. */ VALUE OneofDescriptor_name(VALUE _self) { DEFINE_SELF(OneofDescriptor, self, _self); return rb_str_maybe_null(upb_oneofdef_name(self->oneofdef)); } /* * call-seq: * OneofDescriptor.name = name * * Sets a new name for this oneof. The oneof must not have been added to a * message descriptor yet. */ VALUE OneofDescriptor_name_set(VALUE _self, VALUE value) { DEFINE_SELF(OneofDescriptor, self, _self); upb_oneofdef* mut_def = check_oneof_notfrozen(self->oneofdef); const char* str = get_str(value); CHECK_UPB(upb_oneofdef_setname(mut_def, str, &status), "Error setting oneof name"); return Qnil; } /* * call-seq: * OneofDescriptor.add_field(field) => nil * * Adds a field to this oneof. The field may have been added to this oneof in * the past, or the message to which this oneof belongs (if any), but may not * have already been added to any other oneof or message. Otherwise, an * exception is raised. * * All fields added to the oneof via this method will be automatically added to * the message to which this oneof belongs, if it belongs to one currently, or * else will be added to any message to which the oneof is later added at the * time that it is added. */ VALUE OneofDescriptor_add_field(VALUE _self, VALUE obj) { DEFINE_SELF(OneofDescriptor, self, _self); upb_oneofdef* mut_def = check_oneof_notfrozen(self->oneofdef); FieldDescriptor* def = ruby_to_FieldDescriptor(obj); upb_fielddef* mut_field_def = check_field_notfrozen(def->fielddef); CHECK_UPB( upb_oneofdef_addfield(mut_def, mut_field_def, NULL, &status), "Adding field to OneofDescriptor failed"); add_def_obj(def->fielddef, obj); return Qnil; } /* * call-seq: * OneofDescriptor.each(&block) => nil * * Iterates through fields in this oneof, yielding to the block on each one. */ VALUE OneofDescriptor_each(VALUE _self, VALUE field) { DEFINE_SELF(OneofDescriptor, self, _self); upb_oneof_iter it; for (upb_oneof_begin(&it, self->oneofdef); !upb_oneof_done(&it); upb_oneof_next(&it)) { const upb_fielddef* f = upb_oneof_iter_field(&it); VALUE obj = get_def_obj(f); rb_yield(obj); } return Qnil; } // ----------------------------------------------------------------------------- // EnumDescriptor. // ----------------------------------------------------------------------------- DEFINE_CLASS(EnumDescriptor, "Google::Protobuf::EnumDescriptor"); void EnumDescriptor_mark(void* _self) { EnumDescriptor* self = _self; rb_gc_mark(self->module); } void EnumDescriptor_free(void* _self) { EnumDescriptor* self = _self; upb_enumdef_unref(self->enumdef, &self->enumdef); xfree(self); } /* * call-seq: * EnumDescriptor.new => enum_descriptor * * Creates a new, empty, enum descriptor. Must be added to a pool before the * enum type can be used. The enum type may only be modified prior to adding to * a pool. */ VALUE EnumDescriptor_alloc(VALUE klass) { EnumDescriptor* self = ALLOC(EnumDescriptor); VALUE ret = TypedData_Wrap_Struct(klass, &_EnumDescriptor_type, self); self->enumdef = upb_enumdef_new(&self->enumdef); self->module = Qnil; return ret; } void EnumDescriptor_register(VALUE module) { VALUE klass = rb_define_class_under( module, "EnumDescriptor", rb_cObject); rb_define_alloc_func(klass, EnumDescriptor_alloc); rb_define_method(klass, "name", EnumDescriptor_name, 0); rb_define_method(klass, "name=", EnumDescriptor_name_set, 1); rb_define_method(klass, "add_value", EnumDescriptor_add_value, 2); rb_define_method(klass, "lookup_name", EnumDescriptor_lookup_name, 1); rb_define_method(klass, "lookup_value", EnumDescriptor_lookup_value, 1); rb_define_method(klass, "each", EnumDescriptor_each, 0); rb_define_method(klass, "enummodule", EnumDescriptor_enummodule, 0); rb_include_module(klass, rb_mEnumerable); cEnumDescriptor = klass; rb_gc_register_address(&cEnumDescriptor); } /* * call-seq: * EnumDescriptor.name => name * * Returns the name of this enum type. */ VALUE EnumDescriptor_name(VALUE _self) { DEFINE_SELF(EnumDescriptor, self, _self); return rb_str_maybe_null(upb_enumdef_fullname(self->enumdef)); } /* * call-seq: * EnumDescriptor.name = name * * Sets the name of this enum type. Cannot be called if the enum type has * already been added to a pool. */ VALUE EnumDescriptor_name_set(VALUE _self, VALUE str) { DEFINE_SELF(EnumDescriptor, self, _self); upb_enumdef* mut_def = check_enum_notfrozen(self->enumdef); const char* name = get_str(str); CHECK_UPB(upb_enumdef_setfullname(mut_def, name, &status), "Error setting EnumDescriptor name"); return Qnil; } /* * call-seq: * EnumDescriptor.add_value(key, value) * * Adds a new key => value mapping to this enum type. Key must be given as a * Ruby symbol. Cannot be called if the enum type has already been added to a * pool. Will raise an exception if the key or value is already in use. */ VALUE EnumDescriptor_add_value(VALUE _self, VALUE name, VALUE number) { DEFINE_SELF(EnumDescriptor, self, _self); upb_enumdef* mut_def = check_enum_notfrozen(self->enumdef); const char* name_str = rb_id2name(SYM2ID(name)); int32_t val = NUM2INT(number); CHECK_UPB(upb_enumdef_addval(mut_def, name_str, val, &status), "Error adding value to enum"); return Qnil; } /* * call-seq: * EnumDescriptor.lookup_name(name) => value * * Returns the numeric value corresponding to the given key name (as a Ruby * symbol), or nil if none. */ VALUE EnumDescriptor_lookup_name(VALUE _self, VALUE name) { DEFINE_SELF(EnumDescriptor, self, _self); const char* name_str= rb_id2name(SYM2ID(name)); int32_t val = 0; if (upb_enumdef_ntoiz(self->enumdef, name_str, &val)) { return INT2NUM(val); } else { return Qnil; } } /* * call-seq: * EnumDescriptor.lookup_value(name) => value * * Returns the key name (as a Ruby symbol) corresponding to the integer value, * or nil if none. */ VALUE EnumDescriptor_lookup_value(VALUE _self, VALUE number) { DEFINE_SELF(EnumDescriptor, self, _self); int32_t val = NUM2INT(number); const char* name = upb_enumdef_iton(self->enumdef, val); if (name != NULL) { return ID2SYM(rb_intern(name)); } else { return Qnil; } } /* * 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. */ VALUE EnumDescriptor_each(VALUE _self) { DEFINE_SELF(EnumDescriptor, self, _self); upb_enum_iter it; for (upb_enum_begin(&it, self->enumdef); !upb_enum_done(&it); upb_enum_next(&it)) { VALUE key = ID2SYM(rb_intern(upb_enum_iter_name(&it))); VALUE number = INT2NUM(upb_enum_iter_number(&it)); rb_yield_values(2, key, number); } return Qnil; } /* * 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. */ VALUE EnumDescriptor_enummodule(VALUE _self) { DEFINE_SELF(EnumDescriptor, self, _self); if (!upb_def_isfrozen((const upb_def*)self->enumdef)) { rb_raise(rb_eRuntimeError, "Cannot fetch enum module from an EnumDescriptor not yet " "in a pool."); } if (self->module == Qnil) { self->module = build_module_from_enumdesc(self); } return self->module; } // ----------------------------------------------------------------------------- // MessageBuilderContext. // ----------------------------------------------------------------------------- DEFINE_CLASS(MessageBuilderContext, "Google::Protobuf::Internal::MessageBuilderContext"); void MessageBuilderContext_mark(void* _self) { MessageBuilderContext* self = _self; rb_gc_mark(self->descriptor); rb_gc_mark(self->builder); } void MessageBuilderContext_free(void* _self) { MessageBuilderContext* self = _self; xfree(self); } VALUE MessageBuilderContext_alloc(VALUE klass) { MessageBuilderContext* self = ALLOC(MessageBuilderContext); VALUE ret = TypedData_Wrap_Struct( klass, &_MessageBuilderContext_type, self); self->descriptor = Qnil; self->builder = Qnil; return ret; } void MessageBuilderContext_register(VALUE module) { VALUE klass = rb_define_class_under( module, "MessageBuilderContext", rb_cObject); rb_define_alloc_func(klass, MessageBuilderContext_alloc); rb_define_method(klass, "initialize", MessageBuilderContext_initialize, 2); rb_define_method(klass, "optional", MessageBuilderContext_optional, -1); rb_define_method(klass, "required", MessageBuilderContext_required, -1); rb_define_method(klass, "repeated", MessageBuilderContext_repeated, -1); rb_define_method(klass, "map", MessageBuilderContext_map, -1); rb_define_method(klass, "oneof", MessageBuilderContext_oneof, 1); cMessageBuilderContext = klass; rb_gc_register_address(&cMessageBuilderContext); } /* * call-seq: * MessageBuilderContext.new(desc, builder) => context * * Create a new message builder context around the given message descriptor and * builder context. This class is intended to serve as a DSL context to be used * with #instance_eval. */ VALUE MessageBuilderContext_initialize(VALUE _self, VALUE msgdef, VALUE builder) { DEFINE_SELF(MessageBuilderContext, self, _self); self->descriptor = msgdef; self->builder = builder; return Qnil; } static VALUE msgdef_add_field(VALUE msgdef, const char* label, VALUE name, VALUE type, VALUE number, VALUE type_class) { VALUE fielddef = rb_class_new_instance(0, NULL, cFieldDescriptor); VALUE name_str = rb_str_new2(rb_id2name(SYM2ID(name))); rb_funcall(fielddef, rb_intern("label="), 1, ID2SYM(rb_intern(label))); rb_funcall(fielddef, rb_intern("name="), 1, name_str); rb_funcall(fielddef, rb_intern("type="), 1, type); rb_funcall(fielddef, rb_intern("number="), 1, number); if (type_class != Qnil) { if (TYPE(type_class) != T_STRING) { rb_raise(rb_eArgError, "Expected string for type class"); } // Make it an absolute type name by prepending a dot. type_class = rb_str_append(rb_str_new2("."), type_class); rb_funcall(fielddef, rb_intern("submsg_name="), 1, type_class); } rb_funcall(msgdef, rb_intern("add_field"), 1, fielddef); return fielddef; } /* * call-seq: * MessageBuilderContext.optional(name, type, number, type_class = nil) * * Defines a new optional field on this message type with the given type, tag * number, and type class (for message and enum fields). The 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=). */ VALUE MessageBuilderContext_optional(int argc, VALUE* argv, VALUE _self) { DEFINE_SELF(MessageBuilderContext, self, _self); VALUE name, type, number, type_class; if (argc < 3) { rb_raise(rb_eArgError, "Expected at least 3 arguments."); } name = argv[0]; type = argv[1]; number = argv[2]; type_class = (argc > 3) ? argv[3] : Qnil; return msgdef_add_field(self->descriptor, "optional", name, type, number, type_class); } /* * call-seq: * MessageBuilderContext.required(name, type, number, type_class = nil) * * Defines a new required field on this message type with the given type, tag * number, and type class (for message and enum fields). The 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=). * * Proto3 does not have required fields, but this method exists for * completeness. Any attempt to add a message type with required fields to a * pool will currently result in an error. */ VALUE MessageBuilderContext_required(int argc, VALUE* argv, VALUE _self) { DEFINE_SELF(MessageBuilderContext, self, _self); VALUE name, type, number, type_class; if (argc < 3) { rb_raise(rb_eArgError, "Expected at least 3 arguments."); } name = argv[0]; type = argv[1]; number = argv[2]; type_class = (argc > 3) ? argv[3] : Qnil; return msgdef_add_field(self->descriptor, "required", name, type, number, type_class); } /* * call-seq: * MessageBuilderContext.repeated(name, type, number, type_class = nil) * * Defines a new repeated field on this message type with the given type, tag * number, and type class (for message and enum fields). The 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=). */ VALUE MessageBuilderContext_repeated(int argc, VALUE* argv, VALUE _self) { DEFINE_SELF(MessageBuilderContext, self, _self); VALUE name, type, number, type_class; if (argc < 3) { rb_raise(rb_eArgError, "Expected at least 3 arguments."); } name = argv[0]; type = argv[1]; number = argv[2]; type_class = (argc > 3) ? argv[3] : Qnil; return msgdef_add_field(self->descriptor, "repeated", name, type, number, type_class); } /* * call-seq: * MessageBuilderContext.map(name, key_type, value_type, number, * value_type_class = nil) * * 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=). */ VALUE MessageBuilderContext_map(int argc, VALUE* argv, VALUE _self) { DEFINE_SELF(MessageBuilderContext, self, _self); VALUE name, key_type, value_type, number, type_class; VALUE mapentry_desc, mapentry_desc_name; if (argc < 4) { rb_raise(rb_eArgError, "Expected at least 4 arguments."); } name = argv[0]; key_type = argv[1]; value_type = argv[2]; number = argv[3]; type_class = (argc > 4) ? argv[4] : Qnil; // Validate the key type. We can't accept enums, messages, or floats/doubles // as map keys. (We exclude these explicitly, and the field-descriptor setter // below then ensures that the type is one of the remaining valid options.) if (SYM2ID(key_type) == rb_intern("float") || SYM2ID(key_type) == rb_intern("double") || SYM2ID(key_type) == rb_intern("enum") || SYM2ID(key_type) == rb_intern("message")) { rb_raise(rb_eArgError, "Cannot add a map field with a float, double, enum, or message " "type."); } // Create a new message descriptor for the map entry message, and create a // repeated submessage field here with that type. mapentry_desc = rb_class_new_instance(0, NULL, cDescriptor); mapentry_desc_name = rb_funcall(self->descriptor, rb_intern("name"), 0); mapentry_desc_name = rb_str_cat2(mapentry_desc_name, "_MapEntry_"); mapentry_desc_name = rb_str_cat2(mapentry_desc_name, rb_id2name(SYM2ID(name))); Descriptor_name_set(mapentry_desc, mapentry_desc_name); { // The 'mapentry' attribute has no Ruby setter because we do not want the // user attempting to DIY the setup below; we want to ensure that the fields // are correct. So we reach into the msgdef here to set the bit manually. Descriptor* mapentry_desc_self = ruby_to_Descriptor(mapentry_desc); upb_msgdef_setmapentry((upb_msgdef*)mapentry_desc_self->msgdef, true); } { // optional key = 1; VALUE key_field = rb_class_new_instance(0, NULL, cFieldDescriptor); FieldDescriptor_name_set(key_field, rb_str_new2("key")); FieldDescriptor_label_set(key_field, ID2SYM(rb_intern("optional"))); FieldDescriptor_number_set(key_field, INT2NUM(1)); FieldDescriptor_type_set(key_field, key_type); Descriptor_add_field(mapentry_desc, key_field); } { // optional value = 2; VALUE value_field = rb_class_new_instance(0, NULL, cFieldDescriptor); FieldDescriptor_name_set(value_field, rb_str_new2("value")); FieldDescriptor_label_set(value_field, ID2SYM(rb_intern("optional"))); FieldDescriptor_number_set(value_field, INT2NUM(2)); FieldDescriptor_type_set(value_field, value_type); if (type_class != Qnil) { VALUE submsg_name = rb_str_new2("."); // prepend '.' to make absolute. submsg_name = rb_str_append(submsg_name, type_class); FieldDescriptor_submsg_name_set(value_field, submsg_name); } Descriptor_add_field(mapentry_desc, value_field); } { // Add the map-entry message type to the current builder, and use the type // to create the map field itself. Builder* builder_self = ruby_to_Builder(self->builder); rb_ary_push(builder_self->pending_list, mapentry_desc); } { VALUE map_field = rb_class_new_instance(0, NULL, cFieldDescriptor); VALUE name_str = rb_str_new2(rb_id2name(SYM2ID(name))); VALUE submsg_name; FieldDescriptor_name_set(map_field, name_str); FieldDescriptor_number_set(map_field, number); FieldDescriptor_label_set(map_field, ID2SYM(rb_intern("repeated"))); FieldDescriptor_type_set(map_field, ID2SYM(rb_intern("message"))); submsg_name = rb_str_new2("."); // prepend '.' to make name absolute. submsg_name = rb_str_append(submsg_name, mapentry_desc_name); FieldDescriptor_submsg_name_set(map_field, submsg_name); Descriptor_add_field(self->descriptor, map_field); } return Qnil; } /* * call-seq: * MessageBuilderContext.oneof(name, &block) => nil * * Creates a new OneofDescriptor with the given name, creates a * OneofBuilderContext attached to that OneofDescriptor, evaluates the given * block in the context of that OneofBuilderContext with #instance_eval, and * then adds the oneof to the message. * * This is the recommended, idiomatic way to build oneof definitions. */ VALUE MessageBuilderContext_oneof(VALUE _self, VALUE name) { DEFINE_SELF(MessageBuilderContext, self, _self); VALUE oneofdef = rb_class_new_instance(0, NULL, cOneofDescriptor); VALUE args[2] = { oneofdef, self->builder }; VALUE ctx = rb_class_new_instance(2, args, cOneofBuilderContext); VALUE block = rb_block_proc(); VALUE name_str = rb_str_new2(rb_id2name(SYM2ID(name))); rb_funcall(oneofdef, rb_intern("name="), 1, name_str); rb_funcall_with_block(ctx, rb_intern("instance_eval"), 0, NULL, block); Descriptor_add_oneof(self->descriptor, oneofdef); return Qnil; } // ----------------------------------------------------------------------------- // OneofBuilderContext. // ----------------------------------------------------------------------------- DEFINE_CLASS(OneofBuilderContext, "Google::Protobuf::Internal::OneofBuilderContext"); void OneofBuilderContext_mark(void* _self) { OneofBuilderContext* self = _self; rb_gc_mark(self->descriptor); rb_gc_mark(self->builder); } void OneofBuilderContext_free(void* _self) { OneofBuilderContext* self = _self; xfree(self); } VALUE OneofBuilderContext_alloc(VALUE klass) { OneofBuilderContext* self = ALLOC(OneofBuilderContext); VALUE ret = TypedData_Wrap_Struct( klass, &_OneofBuilderContext_type, self); self->descriptor = Qnil; self->builder = Qnil; return ret; } void OneofBuilderContext_register(VALUE module) { VALUE klass = rb_define_class_under( module, "OneofBuilderContext", rb_cObject); rb_define_alloc_func(klass, OneofBuilderContext_alloc); rb_define_method(klass, "initialize", OneofBuilderContext_initialize, 2); rb_define_method(klass, "optional", OneofBuilderContext_optional, -1); cOneofBuilderContext = klass; rb_gc_register_address(&cOneofBuilderContext); } /* * call-seq: * OneofBuilderContext.new(desc, builder) => context * * Create a new oneof builder context around the given oneof descriptor and * builder context. This class is intended to serve as a DSL context to be used * with #instance_eval. */ VALUE OneofBuilderContext_initialize(VALUE _self, VALUE oneofdef, VALUE builder) { DEFINE_SELF(OneofBuilderContext, self, _self); self->descriptor = oneofdef; self->builder = builder; return Qnil; } /* * call-seq: * OneofBuilderContext.optional(name, type, number, type_class = nil) * * Defines a new optional field in this oneof with the given type, tag number, * and type class (for message and enum fields). The 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=). */ VALUE OneofBuilderContext_optional(int argc, VALUE* argv, VALUE _self) { DEFINE_SELF(OneofBuilderContext, self, _self); VALUE name, type, number, type_class; if (argc < 3) { rb_raise(rb_eArgError, "Expected at least 3 arguments."); } name = argv[0]; type = argv[1]; number = argv[2]; type_class = (argc > 3) ? argv[3] : Qnil; return msgdef_add_field(self->descriptor, "optional", name, type, number, type_class); } // ----------------------------------------------------------------------------- // EnumBuilderContext. // ----------------------------------------------------------------------------- DEFINE_CLASS(EnumBuilderContext, "Google::Protobuf::Internal::EnumBuilderContext"); void EnumBuilderContext_mark(void* _self) { EnumBuilderContext* self = _self; rb_gc_mark(self->enumdesc); } void EnumBuilderContext_free(void* _self) { EnumBuilderContext* self = _self; xfree(self); } VALUE EnumBuilderContext_alloc(VALUE klass) { EnumBuilderContext* self = ALLOC(EnumBuilderContext); VALUE ret = TypedData_Wrap_Struct( klass, &_EnumBuilderContext_type, self); self->enumdesc = Qnil; return ret; } void EnumBuilderContext_register(VALUE module) { VALUE klass = rb_define_class_under( module, "EnumBuilderContext", rb_cObject); rb_define_alloc_func(klass, EnumBuilderContext_alloc); rb_define_method(klass, "initialize", EnumBuilderContext_initialize, 1); rb_define_method(klass, "value", EnumBuilderContext_value, 2); cEnumBuilderContext = klass; rb_gc_register_address(&cEnumBuilderContext); } /* * call-seq: * EnumBuilderContext.new(enumdesc) => context * * Create a new builder context around the given enum descriptor. This class is * intended to serve as a DSL context to be used with #instance_eval. */ VALUE EnumBuilderContext_initialize(VALUE _self, VALUE enumdef) { DEFINE_SELF(EnumBuilderContext, self, _self); self->enumdesc = enumdef; return Qnil; } static VALUE enumdef_add_value(VALUE enumdef, VALUE name, VALUE number) { rb_funcall(enumdef, rb_intern("add_value"), 2, name, number); return Qnil; } /* * call-seq: * EnumBuilder.add_value(name, number) * * Adds the given name => number mapping to the enum type. Name must be a Ruby * symbol. */ VALUE EnumBuilderContext_value(VALUE _self, VALUE name, VALUE number) { DEFINE_SELF(EnumBuilderContext, self, _self); return enumdef_add_value(self->enumdesc, name, number); } // ----------------------------------------------------------------------------- // Builder. // ----------------------------------------------------------------------------- DEFINE_CLASS(Builder, "Google::Protobuf::Internal::Builder"); void Builder_mark(void* _self) { Builder* self = _self; rb_gc_mark(self->pending_list); } void Builder_free(void* _self) { Builder* self = _self; xfree(self->defs); xfree(self); } /* * call-seq: * Builder.new => builder * * Creates a new Builder. A Builder can accumulate a set of new message and enum * descriptors and atomically register them into a pool in a way that allows for * (co)recursive type references. */ VALUE Builder_alloc(VALUE klass) { Builder* self = ALLOC(Builder); VALUE ret = TypedData_Wrap_Struct( klass, &_Builder_type, self); self->pending_list = rb_ary_new(); self->defs = NULL; return ret; } void Builder_register(VALUE module) { VALUE klass = rb_define_class_under(module, "Builder", rb_cObject); rb_define_alloc_func(klass, Builder_alloc); rb_define_method(klass, "add_message", Builder_add_message, 1); rb_define_method(klass, "add_enum", Builder_add_enum, 1); rb_define_method(klass, "finalize_to_pool", Builder_finalize_to_pool, 1); cBuilder = klass; rb_gc_register_address(&cBuilder); } /* * call-seq: * Builder.add_message(name, &block) * * Creates a new, empty descriptor with the given name, and invokes the block in * the context of a MessageBuilderContext on that descriptor. The block can then * call, e.g., MessageBuilderContext#optional and MessageBuilderContext#repeated * methods to define the message fields. * * This is the recommended, idiomatic way to build message definitions. */ VALUE Builder_add_message(VALUE _self, VALUE name) { DEFINE_SELF(Builder, self, _self); VALUE msgdef = rb_class_new_instance(0, NULL, cDescriptor); VALUE args[2] = { msgdef, _self }; VALUE ctx = rb_class_new_instance(2, args, cMessageBuilderContext); VALUE block = rb_block_proc(); rb_funcall(msgdef, rb_intern("name="), 1, name); rb_funcall_with_block(ctx, rb_intern("instance_eval"), 0, NULL, block); rb_ary_push(self->pending_list, msgdef); return Qnil; } /* * call-seq: * Builder.add_enum(name, &block) * * Creates a new, empty enum descriptor with the given name, and invokes the * block in the context of an EnumBuilderContext on that descriptor. The block * can then call EnumBuilderContext#add_value to define the enum values. * * This is the recommended, idiomatic way to build enum definitions. */ VALUE Builder_add_enum(VALUE _self, VALUE name) { DEFINE_SELF(Builder, self, _self); VALUE enumdef = rb_class_new_instance(0, NULL, cEnumDescriptor); VALUE ctx = rb_class_new_instance(1, &enumdef, cEnumBuilderContext); VALUE block = rb_block_proc(); rb_funcall(enumdef, rb_intern("name="), 1, name); rb_funcall_with_block(ctx, rb_intern("instance_eval"), 0, NULL, block); rb_ary_push(self->pending_list, enumdef); return Qnil; } static void validate_msgdef(const upb_msgdef* msgdef) { // Verify that no required fields exist. proto3 does not support these. upb_msg_field_iter it; for (upb_msg_field_begin(&it, msgdef); !upb_msg_field_done(&it); upb_msg_field_next(&it)) { const upb_fielddef* field = upb_msg_iter_field(&it); if (upb_fielddef_label(field) == UPB_LABEL_REQUIRED) { rb_raise(rb_eTypeError, "Required fields are unsupported in proto3."); } } } static void validate_enumdef(const upb_enumdef* enumdef) { // Verify that an entry exists with integer value 0. (This is the default // value.) const char* lookup = upb_enumdef_iton(enumdef, 0); if (lookup == NULL) { rb_raise(rb_eTypeError, "Enum definition does not contain a value for '0'."); } } /* * call-seq: * Builder.finalize_to_pool(pool) * * Adds all accumulated message and enum descriptors created in this builder * context to the given pool. The operation occurs atomically, and all * descriptors can refer to each other (including in cycles). This is the only * way to build (co)recursive message definitions. * * This method is usually called automatically by DescriptorPool#build after it * invokes the given user block in the context of the builder. The user should * not normally need to call this manually because a Builder is not normally * created manually. */ VALUE Builder_finalize_to_pool(VALUE _self, VALUE pool_rb) { DEFINE_SELF(Builder, self, _self); DescriptorPool* pool = ruby_to_DescriptorPool(pool_rb); REALLOC_N(self->defs, upb_def*, RARRAY_LEN(self->pending_list)); for (int i = 0; i < RARRAY_LEN(self->pending_list); i++) { VALUE def_rb = rb_ary_entry(self->pending_list, i); if (CLASS_OF(def_rb) == cDescriptor) { self->defs[i] = (upb_def*)ruby_to_Descriptor(def_rb)->msgdef; validate_msgdef((const upb_msgdef*)self->defs[i]); } else if (CLASS_OF(def_rb) == cEnumDescriptor) { self->defs[i] = (upb_def*)ruby_to_EnumDescriptor(def_rb)->enumdef; validate_enumdef((const upb_enumdef*)self->defs[i]); } } CHECK_UPB(upb_symtab_add(pool->symtab, (upb_def**)self->defs, RARRAY_LEN(self->pending_list), NULL, &status), "Unable to add defs to DescriptorPool"); for (int i = 0; i < RARRAY_LEN(self->pending_list); i++) { VALUE def_rb = rb_ary_entry(self->pending_list, i); add_def_obj(self->defs[i], def_rb); } self->pending_list = rb_ary_new(); return Qnil; } google-protobuf-3.2.0/ext/google/protobuf_c/protobuf.h0000644000175000017500000005136413042756211022113 0ustar pravipravi// 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 #include #include #include "upb.h" // Forward decls. struct DescriptorPool; struct Descriptor; struct FieldDescriptor; struct EnumDescriptor; struct MessageLayout; struct MessageField; struct MessageHeader; struct MessageBuilderContext; struct EnumBuilderContext; struct Builder; typedef struct DescriptorPool DescriptorPool; typedef struct Descriptor Descriptor; typedef struct FieldDescriptor FieldDescriptor; typedef struct OneofDescriptor OneofDescriptor; typedef struct EnumDescriptor EnumDescriptor; typedef struct MessageLayout MessageLayout; typedef struct MessageField MessageField; typedef struct MessageHeader MessageHeader; typedef struct MessageBuilderContext MessageBuilderContext; typedef struct OneofBuilderContext OneofBuilderContext; typedef struct EnumBuilderContext EnumBuilderContext; typedef struct Builder Builder; /* It can be a bit confusing how the C structs defined below and the Ruby objects interact and hold references to each other. First, a few principles: - Ruby's "TypedData" abstraction lets a Ruby VALUE hold a pointer to a C struct (or arbitrary memory chunk), own it, and free it when collected. Thus, each struct below will have a corresponding Ruby object wrapping/owning it. - To get back from an underlying upb {msg,enum}def to the Ruby object, we keep a global hashmap, accessed by get_def_obj/add_def_obj below. The in-memory structure is then something like: Ruby | upb | DescriptorPool ------------|-----------> upb_symtab____________________ | | (message types) \ | v \ Descriptor ---------------|-----------> upb_msgdef (enum types)| |--> msgclass | | ^ | | (dynamically built) | | | (submsg fields) | |--> MessageLayout | | | / |--------------------------|> decoder method| | / \--------------------------|> serialize | | / | handlers v | / FieldDescriptor -----------|-----------> upb_fielddef / | | / | v (enum fields) / EnumDescriptor ------------|-----------> upb_enumdef <----------' | | ^ | \___/ `---------------|-----------------' (get_def_obj map) */ // ----------------------------------------------------------------------------- // Ruby class structure definitions. // ----------------------------------------------------------------------------- struct DescriptorPool { upb_symtab* symtab; }; struct Descriptor { const upb_msgdef* msgdef; MessageLayout* layout; VALUE klass; // begins as nil const upb_handlers* fill_handlers; const upb_pbdecodermethod* fill_method; const upb_json_parsermethod* json_fill_method; const upb_handlers* pb_serialize_handlers; const upb_handlers* json_serialize_handlers; const upb_handlers* json_serialize_handlers_preserve; // Handlers hold type class references for sub-message fields directly in some // cases. We need to keep these rooted because they might otherwise be // collected. VALUE typeclass_references; }; struct FieldDescriptor { const upb_fielddef* fielddef; }; struct OneofDescriptor { const upb_oneofdef* oneofdef; }; struct EnumDescriptor { const upb_enumdef* enumdef; VALUE module; // begins as nil }; struct MessageBuilderContext { VALUE descriptor; VALUE builder; }; struct OneofBuilderContext { VALUE descriptor; VALUE builder; }; struct EnumBuilderContext { VALUE enumdesc; }; struct Builder { VALUE pending_list; upb_def** defs; // used only while finalizing }; extern VALUE cDescriptorPool; extern VALUE cDescriptor; extern VALUE cFieldDescriptor; extern VALUE cEnumDescriptor; extern VALUE cMessageBuilderContext; extern VALUE cOneofBuilderContext; extern VALUE cEnumBuilderContext; extern VALUE cBuilder; extern VALUE cError; extern VALUE cParseError; extern VALUE map_parse_frames; // We forward-declare all of the Ruby method implementations here because we // sometimes call the methods directly across .c files, rather than going // through Ruby's method dispatching (e.g. during message parse). It's cleaner // to keep the list of object methods together than to split them between // static-in-file definitions and header declarations. void DescriptorPool_mark(void* _self); void DescriptorPool_free(void* _self); VALUE DescriptorPool_alloc(VALUE klass); void DescriptorPool_register(VALUE module); DescriptorPool* ruby_to_DescriptorPool(VALUE value); VALUE DescriptorPool_add(VALUE _self, VALUE def); VALUE DescriptorPool_build(VALUE _self); VALUE DescriptorPool_lookup(VALUE _self, VALUE name); VALUE DescriptorPool_generated_pool(VALUE _self); void Descriptor_mark(void* _self); void Descriptor_free(void* _self); VALUE Descriptor_alloc(VALUE klass); void Descriptor_register(VALUE module); Descriptor* ruby_to_Descriptor(VALUE value); VALUE Descriptor_name(VALUE _self); VALUE Descriptor_name_set(VALUE _self, VALUE str); VALUE Descriptor_each(VALUE _self); VALUE Descriptor_lookup(VALUE _self, VALUE name); VALUE Descriptor_add_field(VALUE _self, VALUE obj); VALUE Descriptor_add_oneof(VALUE _self, VALUE obj); VALUE Descriptor_each_oneof(VALUE _self); VALUE Descriptor_lookup_oneof(VALUE _self, VALUE name); VALUE Descriptor_msgclass(VALUE _self); extern const rb_data_type_t _Descriptor_type; void FieldDescriptor_mark(void* _self); void FieldDescriptor_free(void* _self); VALUE FieldDescriptor_alloc(VALUE klass); void FieldDescriptor_register(VALUE module); FieldDescriptor* ruby_to_FieldDescriptor(VALUE value); VALUE FieldDescriptor_name(VALUE _self); VALUE FieldDescriptor_name_set(VALUE _self, VALUE str); VALUE FieldDescriptor_type(VALUE _self); VALUE FieldDescriptor_type_set(VALUE _self, VALUE type); VALUE FieldDescriptor_label(VALUE _self); VALUE FieldDescriptor_label_set(VALUE _self, VALUE label); VALUE FieldDescriptor_number(VALUE _self); VALUE FieldDescriptor_number_set(VALUE _self, VALUE number); VALUE FieldDescriptor_submsg_name(VALUE _self); VALUE FieldDescriptor_submsg_name_set(VALUE _self, VALUE value); VALUE FieldDescriptor_subtype(VALUE _self); VALUE FieldDescriptor_get(VALUE _self, VALUE msg_rb); VALUE FieldDescriptor_set(VALUE _self, VALUE msg_rb, VALUE value); upb_fieldtype_t ruby_to_fieldtype(VALUE type); VALUE fieldtype_to_ruby(upb_fieldtype_t type); void OneofDescriptor_mark(void* _self); void OneofDescriptor_free(void* _self); VALUE OneofDescriptor_alloc(VALUE klass); void OneofDescriptor_register(VALUE module); OneofDescriptor* ruby_to_OneofDescriptor(VALUE value); VALUE OneofDescriptor_name(VALUE _self); VALUE OneofDescriptor_name_set(VALUE _self, VALUE value); VALUE OneofDescriptor_add_field(VALUE _self, VALUE field); VALUE OneofDescriptor_each(VALUE _self, VALUE field); void EnumDescriptor_mark(void* _self); void EnumDescriptor_free(void* _self); VALUE EnumDescriptor_alloc(VALUE klass); void EnumDescriptor_register(VALUE module); EnumDescriptor* ruby_to_EnumDescriptor(VALUE value); VALUE EnumDescriptor_name(VALUE _self); VALUE EnumDescriptor_name_set(VALUE _self, VALUE str); VALUE EnumDescriptor_add_value(VALUE _self, VALUE name, VALUE number); VALUE EnumDescriptor_lookup_name(VALUE _self, VALUE name); VALUE EnumDescriptor_lookup_value(VALUE _self, VALUE number); VALUE EnumDescriptor_each(VALUE _self); VALUE EnumDescriptor_enummodule(VALUE _self); extern const rb_data_type_t _EnumDescriptor_type; void MessageBuilderContext_mark(void* _self); void MessageBuilderContext_free(void* _self); VALUE MessageBuilderContext_alloc(VALUE klass); void MessageBuilderContext_register(VALUE module); MessageBuilderContext* ruby_to_MessageBuilderContext(VALUE value); VALUE MessageBuilderContext_initialize(VALUE _self, VALUE descriptor, VALUE builder); VALUE MessageBuilderContext_optional(int argc, VALUE* argv, VALUE _self); VALUE MessageBuilderContext_required(int argc, VALUE* argv, VALUE _self); VALUE MessageBuilderContext_repeated(int argc, VALUE* argv, VALUE _self); VALUE MessageBuilderContext_map(int argc, VALUE* argv, VALUE _self); VALUE MessageBuilderContext_oneof(VALUE _self, VALUE name); void OneofBuilderContext_mark(void* _self); void OneofBuilderContext_free(void* _self); VALUE OneofBuilderContext_alloc(VALUE klass); void OneofBuilderContext_register(VALUE module); OneofBuilderContext* ruby_to_OneofBuilderContext(VALUE value); VALUE OneofBuilderContext_initialize(VALUE _self, VALUE descriptor, VALUE builder); VALUE OneofBuilderContext_optional(int argc, VALUE* argv, VALUE _self); void EnumBuilderContext_mark(void* _self); void EnumBuilderContext_free(void* _self); VALUE EnumBuilderContext_alloc(VALUE klass); void EnumBuilderContext_register(VALUE module); EnumBuilderContext* ruby_to_EnumBuilderContext(VALUE value); VALUE EnumBuilderContext_initialize(VALUE _self, VALUE enumdesc); VALUE EnumBuilderContext_value(VALUE _self, VALUE name, VALUE number); void Builder_mark(void* _self); void Builder_free(void* _self); VALUE Builder_alloc(VALUE klass); void Builder_register(VALUE module); Builder* ruby_to_Builder(VALUE value); VALUE Builder_add_message(VALUE _self, VALUE name); VALUE Builder_add_enum(VALUE _self, VALUE name); VALUE Builder_finalize_to_pool(VALUE _self, VALUE pool_rb); // ----------------------------------------------------------------------------- // Native slot storage abstraction. // ----------------------------------------------------------------------------- #define NATIVE_SLOT_MAX_SIZE sizeof(uint64_t) size_t native_slot_size(upb_fieldtype_t type); void native_slot_set(upb_fieldtype_t type, VALUE type_class, void* memory, VALUE value); // Atomically (with respect to Ruby VM calls) either update the value and set a // oneof case, or do neither. If |case_memory| is null, then no case value is // set. void native_slot_set_value_and_case(upb_fieldtype_t type, VALUE type_class, void* memory, VALUE value, uint32_t* case_memory, uint32_t case_number); VALUE native_slot_get(upb_fieldtype_t type, VALUE type_class, const void* memory); void native_slot_init(upb_fieldtype_t type, void* memory); void native_slot_mark(upb_fieldtype_t type, void* memory); void native_slot_dup(upb_fieldtype_t type, void* to, void* from); void native_slot_deep_copy(upb_fieldtype_t type, void* to, void* from); bool native_slot_eq(upb_fieldtype_t type, void* mem1, void* mem2); VALUE native_slot_encode_and_freeze_string(upb_fieldtype_t type, VALUE value); void native_slot_check_int_range_precision(upb_fieldtype_t type, VALUE value); extern rb_encoding* kRubyStringUtf8Encoding; extern rb_encoding* kRubyStringASCIIEncoding; extern rb_encoding* kRubyString8bitEncoding; VALUE field_type_class(const upb_fielddef* field); #define MAP_KEY_FIELD 1 #define MAP_VALUE_FIELD 2 // Oneof case slot value to indicate that no oneof case is set. The value `0` is // safe because field numbers are used as case identifiers, and no field can // have a number of 0. #define ONEOF_CASE_NONE 0 // These operate on a map field (i.e., a repeated field of submessages whose // submessage type is a map-entry msgdef). bool is_map_field(const upb_fielddef* field); const upb_fielddef* map_field_key(const upb_fielddef* field); const upb_fielddef* map_field_value(const upb_fielddef* field); // These operate on a map-entry msgdef. const upb_fielddef* map_entry_key(const upb_msgdef* msgdef); const upb_fielddef* map_entry_value(const upb_msgdef* msgdef); // ----------------------------------------------------------------------------- // Repeated field container type. // ----------------------------------------------------------------------------- typedef struct { upb_fieldtype_t field_type; VALUE field_type_class; void* elements; int size; int capacity; } RepeatedField; void RepeatedField_mark(void* self); void RepeatedField_free(void* self); VALUE RepeatedField_alloc(VALUE klass); VALUE RepeatedField_init(int argc, VALUE* argv, VALUE self); void RepeatedField_register(VALUE module); extern const rb_data_type_t RepeatedField_type; extern VALUE cRepeatedField; RepeatedField* ruby_to_RepeatedField(VALUE value); VALUE RepeatedField_each(VALUE _self); VALUE RepeatedField_index(int argc, VALUE* argv, VALUE _self); void* RepeatedField_index_native(VALUE _self, int index); int RepeatedField_size(VALUE _self); VALUE RepeatedField_index_set(VALUE _self, VALUE _index, VALUE val); void RepeatedField_reserve(RepeatedField* self, int new_size); VALUE RepeatedField_push(VALUE _self, VALUE val); void RepeatedField_push_native(VALUE _self, void* data); VALUE RepeatedField_pop_one(VALUE _self); VALUE RepeatedField_insert(int argc, VALUE* argv, VALUE _self); VALUE RepeatedField_replace(VALUE _self, VALUE list); VALUE RepeatedField_clear(VALUE _self); VALUE RepeatedField_length(VALUE _self); VALUE RepeatedField_dup(VALUE _self); VALUE RepeatedField_deep_copy(VALUE _self); VALUE RepeatedField_to_ary(VALUE _self); VALUE RepeatedField_eq(VALUE _self, VALUE _other); VALUE RepeatedField_hash(VALUE _self); VALUE RepeatedField_inspect(VALUE _self); VALUE RepeatedField_plus(VALUE _self, VALUE list); // Defined in repeated_field.c; also used by Map. void validate_type_class(upb_fieldtype_t type, VALUE klass); // ----------------------------------------------------------------------------- // Map container type. // ----------------------------------------------------------------------------- typedef struct { upb_fieldtype_t key_type; upb_fieldtype_t value_type; VALUE value_type_class; upb_strtable table; } Map; void Map_mark(void* self); void Map_free(void* self); VALUE Map_alloc(VALUE klass); VALUE Map_init(int argc, VALUE* argv, VALUE self); void Map_register(VALUE module); extern const rb_data_type_t Map_type; extern VALUE cMap; Map* ruby_to_Map(VALUE value); VALUE Map_each(VALUE _self); VALUE Map_keys(VALUE _self); VALUE Map_values(VALUE _self); VALUE Map_index(VALUE _self, VALUE key); VALUE Map_index_set(VALUE _self, VALUE key, VALUE value); VALUE Map_has_key(VALUE _self, VALUE key); VALUE Map_delete(VALUE _self, VALUE key); VALUE Map_clear(VALUE _self); VALUE Map_length(VALUE _self); VALUE Map_dup(VALUE _self); VALUE Map_deep_copy(VALUE _self); VALUE Map_eq(VALUE _self, VALUE _other); VALUE Map_hash(VALUE _self); VALUE Map_inspect(VALUE _self); VALUE Map_merge(VALUE _self, VALUE hashmap); VALUE Map_merge_into_self(VALUE _self, VALUE hashmap); typedef struct { Map* self; upb_strtable_iter it; } Map_iter; void Map_begin(VALUE _self, Map_iter* iter); void Map_next(Map_iter* iter); bool Map_done(Map_iter* iter); VALUE Map_iter_key(Map_iter* iter); VALUE Map_iter_value(Map_iter* iter); // ----------------------------------------------------------------------------- // Message layout / storage. // ----------------------------------------------------------------------------- #define MESSAGE_FIELD_NO_CASE ((size_t)-1) struct MessageField { size_t offset; size_t case_offset; // for oneofs, a uint32. Else, MESSAGE_FIELD_NO_CASE. }; struct MessageLayout { const upb_msgdef* msgdef; MessageField* fields; size_t size; }; MessageLayout* create_layout(const upb_msgdef* msgdef); void free_layout(MessageLayout* layout); VALUE layout_get(MessageLayout* layout, const void* storage, const upb_fielddef* field); void layout_set(MessageLayout* layout, void* storage, const upb_fielddef* field, VALUE val); void layout_init(MessageLayout* layout, void* storage); void layout_mark(MessageLayout* layout, void* storage); void layout_dup(MessageLayout* layout, void* to, void* from); void layout_deep_copy(MessageLayout* layout, void* to, void* from); VALUE layout_eq(MessageLayout* layout, void* msg1, void* msg2); VALUE layout_hash(MessageLayout* layout, void* storage); VALUE layout_inspect(MessageLayout* layout, void* storage); // ----------------------------------------------------------------------------- // Message class creation. // ----------------------------------------------------------------------------- struct MessageHeader { Descriptor* descriptor; // kept alive by self.class.descriptor reference. // Data comes after this. }; extern rb_data_type_t Message_type; VALUE build_class_from_descriptor(Descriptor* descriptor); void* Message_data(void* msg); void Message_mark(void* self); void Message_free(void* self); VALUE Message_alloc(VALUE klass); VALUE Message_method_missing(int argc, VALUE* argv, VALUE _self); VALUE Message_initialize(int argc, VALUE* argv, VALUE _self); VALUE Message_dup(VALUE _self); VALUE Message_deep_copy(VALUE _self); VALUE Message_eq(VALUE _self, VALUE _other); VALUE Message_hash(VALUE _self); VALUE Message_inspect(VALUE _self); VALUE Message_index(VALUE _self, VALUE field_name); VALUE Message_index_set(VALUE _self, VALUE field_name, VALUE value); VALUE Message_descriptor(VALUE klass); VALUE Message_decode(VALUE klass, VALUE data); VALUE Message_encode(VALUE klass, VALUE msg_rb); VALUE Message_decode_json(VALUE klass, VALUE data); VALUE Message_encode_json(int argc, VALUE* argv, VALUE klass); VALUE Google_Protobuf_deep_copy(VALUE self, VALUE obj); VALUE build_module_from_enumdesc(EnumDescriptor* enumdef); VALUE enum_lookup(VALUE self, VALUE number); VALUE enum_resolve(VALUE self, VALUE sym); const upb_pbdecodermethod *new_fillmsg_decodermethod( Descriptor* descriptor, const void *owner); // Maximum depth allowed during encoding, to avoid stack overflows due to // cycles. #define ENCODE_MAX_NESTING 63 // ----------------------------------------------------------------------------- // Global map from upb {msg,enum}defs to wrapper Descriptor/EnumDescriptor // instances. // ----------------------------------------------------------------------------- void add_def_obj(const void* def, VALUE value); VALUE get_def_obj(const void* def); // ----------------------------------------------------------------------------- // Utilities. // ----------------------------------------------------------------------------- void check_upb_status(const upb_status* status, const char* msg); #define CHECK_UPB(code, msg) do { \ upb_status status = UPB_STATUS_INIT; \ code; \ check_upb_status(&status, msg); \ } while (0) extern ID descriptor_instancevar_interned; #endif // __GOOGLE_PROTOBUF_RUBY_PROTOBUF_H__ google-protobuf-3.2.0/ext/google/protobuf_c/extconf.rb0000644000175000017500000000035113042756211022063 0ustar pravipravi#!/usr/bin/ruby require 'mkmf' $CFLAGS += " -std=c99 -O3 -DNDEBUG" $objs = ["protobuf.o", "defs.o", "storage.o", "message.o", "repeated_field.o", "map.o", "encode_decode.o", "upb.o"] create_makefile("google/protobuf_c") google-protobuf-3.2.0/ext/google/protobuf_c/upb.c0000644000175000017500000162035213042777744021052 0ustar pravipravi// Amalgamated source file #include "upb.h" #include #include #include typedef struct { size_t len; char str[1]; /* Null-terminated string data follows. */ } str_t; static str_t *newstr(const char *data, size_t len) { str_t *ret = upb_gmalloc(sizeof(*ret) + len); if (!ret) return NULL; ret->len = len; memcpy(ret->str, data, len); ret->str[len] = '\0'; return ret; } static void freestr(str_t *s) { upb_gfree(s); } /* isalpha() etc. from are locale-dependent, which we don't want. */ static bool upb_isbetween(char c, char low, char high) { return c >= low && c <= high; } static bool upb_isletter(char c) { return upb_isbetween(c, 'A', 'Z') || upb_isbetween(c, 'a', 'z') || c == '_'; } static bool upb_isalphanum(char c) { return upb_isletter(c) || upb_isbetween(c, '0', '9'); } static bool upb_isident(const char *str, size_t len, bool full, upb_status *s) { bool start = true; size_t i; for (i = 0; i < len; i++) { char c = str[i]; if (c == '.') { if (start || !full) { upb_status_seterrf(s, "invalid name: unexpected '.' (%s)", str); return false; } start = true; } else if (start) { if (!upb_isletter(c)) { upb_status_seterrf( s, "invalid name: path components must start with a letter (%s)", str); return false; } start = false; } else { if (!upb_isalphanum(c)) { upb_status_seterrf(s, "invalid name: non-alphanumeric character (%s)", str); return false; } } } return !start; } static bool upb_isoneof(const upb_refcounted *def) { return def->vtbl == &upb_oneofdef_vtbl; } static bool upb_isfield(const upb_refcounted *def) { return def->vtbl == &upb_fielddef_vtbl; } static const upb_oneofdef *upb_trygetoneof(const upb_refcounted *def) { return upb_isoneof(def) ? (const upb_oneofdef*)def : NULL; } static const upb_fielddef *upb_trygetfield(const upb_refcounted *def) { return upb_isfield(def) ? (const upb_fielddef*)def : NULL; } /* upb_def ********************************************************************/ upb_deftype_t upb_def_type(const upb_def *d) { return d->type; } const char *upb_def_fullname(const upb_def *d) { return d->fullname; } const char *upb_def_name(const upb_def *d) { const char *p; if (d->fullname == NULL) { return NULL; } else if ((p = strrchr(d->fullname, '.')) == NULL) { /* No '.' in the name, return the full string. */ return d->fullname; } else { /* Return one past the last '.'. */ return p + 1; } } bool upb_def_setfullname(upb_def *def, const char *fullname, upb_status *s) { UPB_ASSERT(!upb_def_isfrozen(def)); if (!upb_isident(fullname, strlen(fullname), true, s)) { return false; } fullname = upb_gstrdup(fullname); if (!fullname) { upb_upberr_setoom(s); return false; } upb_gfree((void*)def->fullname); def->fullname = fullname; return true; } const upb_filedef *upb_def_file(const upb_def *d) { return d->file; } static bool upb_def_init(upb_def *def, upb_deftype_t type, const struct upb_refcounted_vtbl *vtbl, const void *owner) { if (!upb_refcounted_init(upb_def_upcast_mutable(def), vtbl, owner)) return false; def->type = type; def->fullname = NULL; def->came_from_user = false; def->file = NULL; return true; } static void upb_def_uninit(upb_def *def) { upb_gfree((void*)def->fullname); } static const char *msgdef_name(const upb_msgdef *m) { const char *name = upb_def_fullname(upb_msgdef_upcast(m)); return name ? name : "(anonymous)"; } static bool upb_validate_field(upb_fielddef *f, upb_status *s) { if (upb_fielddef_name(f) == NULL || upb_fielddef_number(f) == 0) { upb_status_seterrmsg(s, "fielddef must have name and number set"); return false; } if (!f->type_is_set_) { upb_status_seterrmsg(s, "fielddef type was not initialized"); return false; } if (upb_fielddef_lazy(f) && upb_fielddef_descriptortype(f) != UPB_DESCRIPTOR_TYPE_MESSAGE) { upb_status_seterrmsg(s, "only length-delimited submessage fields may be lazy"); return false; } if (upb_fielddef_hassubdef(f)) { const upb_def *subdef; if (f->subdef_is_symbolic) { upb_status_seterrf(s, "field '%s.%s' has not been resolved", msgdef_name(f->msg.def), upb_fielddef_name(f)); return false; } subdef = upb_fielddef_subdef(f); if (subdef == NULL) { upb_status_seterrf(s, "field %s.%s is missing required subdef", msgdef_name(f->msg.def), upb_fielddef_name(f)); return false; } if (!upb_def_isfrozen(subdef) && !subdef->came_from_user) { upb_status_seterrf(s, "subdef of field %s.%s is not frozen or being frozen", msgdef_name(f->msg.def), upb_fielddef_name(f)); return false; } } if (upb_fielddef_type(f) == UPB_TYPE_ENUM) { bool has_default_name = upb_fielddef_enumhasdefaultstr(f); bool has_default_number = upb_fielddef_enumhasdefaultint32(f); /* Previously verified by upb_validate_enumdef(). */ UPB_ASSERT(upb_enumdef_numvals(upb_fielddef_enumsubdef(f)) > 0); /* We've already validated that we have an associated enumdef and that it * has at least one member, so at least one of these should be true. * Because if the user didn't set anything, we'll pick up the enum's * default, but if the user *did* set something we should at least pick up * the one they set (int32 or string). */ UPB_ASSERT(has_default_name || has_default_number); if (!has_default_name) { upb_status_seterrf(s, "enum default for field %s.%s (%d) is not in the enum", msgdef_name(f->msg.def), upb_fielddef_name(f), upb_fielddef_defaultint32(f)); return false; } if (!has_default_number) { upb_status_seterrf(s, "enum default for field %s.%s (%s) is not in the enum", msgdef_name(f->msg.def), upb_fielddef_name(f), upb_fielddef_defaultstr(f, NULL)); return false; } /* Lift the effective numeric default into the field's default slot, in case * we were only getting it "by reference" from the enumdef. */ upb_fielddef_setdefaultint32(f, upb_fielddef_defaultint32(f)); } /* Ensure that MapEntry submessages only appear as repeated fields, not * optional/required (singular) fields. */ if (upb_fielddef_type(f) == UPB_TYPE_MESSAGE && upb_fielddef_msgsubdef(f) != NULL) { const upb_msgdef *subdef = upb_fielddef_msgsubdef(f); if (upb_msgdef_mapentry(subdef) && !upb_fielddef_isseq(f)) { upb_status_seterrf(s, "Field %s refers to mapentry message but is not " "a repeated field", upb_fielddef_name(f) ? upb_fielddef_name(f) : "(unnamed)"); return false; } } return true; } static bool upb_validate_enumdef(const upb_enumdef *e, upb_status *s) { if (upb_enumdef_numvals(e) == 0) { upb_status_seterrf(s, "enum %s has no members (must have at least one)", upb_enumdef_fullname(e)); return false; } return true; } /* All submessage fields are lower than all other fields. * Secondly, fields are increasing in order. */ uint32_t field_rank(const upb_fielddef *f) { uint32_t ret = upb_fielddef_number(f); const uint32_t high_bit = 1 << 30; UPB_ASSERT(ret < high_bit); if (!upb_fielddef_issubmsg(f)) ret |= high_bit; return ret; } int cmp_fields(const void *p1, const void *p2) { const upb_fielddef *f1 = *(upb_fielddef*const*)p1; const upb_fielddef *f2 = *(upb_fielddef*const*)p2; return field_rank(f1) - field_rank(f2); } static bool assign_msg_indices(upb_msgdef *m, upb_status *s) { /* Sort fields. upb internally relies on UPB_TYPE_MESSAGE fields having the * lowest indexes, but we do not publicly guarantee this. */ upb_msg_field_iter j; upb_msg_oneof_iter k; int i; uint32_t selector; int n = upb_msgdef_numfields(m); upb_fielddef **fields; if (n == 0) { m->selector_count = UPB_STATIC_SELECTOR_COUNT; m->submsg_field_count = 0; return true; } fields = upb_gmalloc(n * sizeof(*fields)); if (!fields) { upb_upberr_setoom(s); return false; } m->submsg_field_count = 0; for(i = 0, upb_msg_field_begin(&j, m); !upb_msg_field_done(&j); upb_msg_field_next(&j), i++) { upb_fielddef *f = upb_msg_iter_field(&j); UPB_ASSERT(f->msg.def == m); if (!upb_validate_field(f, s)) { upb_gfree(fields); return false; } if (upb_fielddef_issubmsg(f)) { m->submsg_field_count++; } fields[i] = f; } qsort(fields, n, sizeof(*fields), cmp_fields); selector = UPB_STATIC_SELECTOR_COUNT + m->submsg_field_count; for (i = 0; i < n; i++) { upb_fielddef *f = fields[i]; f->index_ = i; f->selector_base = selector + upb_handlers_selectorbaseoffset(f); selector += upb_handlers_selectorcount(f); } m->selector_count = selector; #ifndef NDEBUG { /* Verify that all selectors for the message are distinct. */ #define TRY(type) \ if (upb_handlers_getselector(f, type, &sel)) upb_inttable_insert(&t, sel, v); upb_inttable t; upb_value v; upb_selector_t sel; upb_inttable_init(&t, UPB_CTYPE_BOOL); v = upb_value_bool(true); upb_inttable_insert(&t, UPB_STARTMSG_SELECTOR, v); upb_inttable_insert(&t, UPB_ENDMSG_SELECTOR, v); for(upb_msg_field_begin(&j, m); !upb_msg_field_done(&j); upb_msg_field_next(&j)) { upb_fielddef *f = upb_msg_iter_field(&j); /* These calls will assert-fail in upb_table if the value already * exists. */ TRY(UPB_HANDLER_INT32); TRY(UPB_HANDLER_INT64) TRY(UPB_HANDLER_UINT32) TRY(UPB_HANDLER_UINT64) TRY(UPB_HANDLER_FLOAT) TRY(UPB_HANDLER_DOUBLE) TRY(UPB_HANDLER_BOOL) TRY(UPB_HANDLER_STARTSTR) TRY(UPB_HANDLER_STRING) TRY(UPB_HANDLER_ENDSTR) TRY(UPB_HANDLER_STARTSUBMSG) TRY(UPB_HANDLER_ENDSUBMSG) TRY(UPB_HANDLER_STARTSEQ) TRY(UPB_HANDLER_ENDSEQ) } upb_inttable_uninit(&t); } #undef TRY #endif for(upb_msg_oneof_begin(&k, m), i = 0; !upb_msg_oneof_done(&k); upb_msg_oneof_next(&k), i++) { upb_oneofdef *o = upb_msg_iter_oneof(&k); o->index = i; } upb_gfree(fields); return true; } bool _upb_def_validate(upb_def *const*defs, size_t n, upb_status *s) { size_t i; /* First perform validation, in two passes so we can check that we have a * transitive closure without needing to search. */ for (i = 0; i < n; i++) { upb_def *def = defs[i]; if (upb_def_isfrozen(def)) { /* Could relax this requirement if it's annoying. */ upb_status_seterrmsg(s, "def is already frozen"); goto err; } else if (def->type == UPB_DEF_FIELD) { upb_status_seterrmsg(s, "standalone fielddefs can not be frozen"); goto err; } else if (def->type == UPB_DEF_ENUM) { if (!upb_validate_enumdef(upb_dyncast_enumdef(def), s)) { goto err; } } else { /* Set now to detect transitive closure in the second pass. */ def->came_from_user = true; } } /* Second pass of validation. Also assign selector bases and indexes, and * compact tables. */ for (i = 0; i < n; i++) { upb_def *def = defs[i]; upb_msgdef *m = upb_dyncast_msgdef_mutable(def); upb_enumdef *e = upb_dyncast_enumdef_mutable(def); if (m) { upb_inttable_compact(&m->itof); if (!assign_msg_indices(m, s)) { goto err; } } else if (e) { upb_inttable_compact(&e->iton); } } return true; err: for (i = 0; i < n; i++) { upb_def *def = defs[i]; def->came_from_user = false; } UPB_ASSERT(!(s && upb_ok(s))); return false; } bool upb_def_freeze(upb_def *const* defs, size_t n, upb_status *s) { /* Def graph contains FieldDefs between each MessageDef, so double the * limit. */ const size_t maxdepth = UPB_MAX_MESSAGE_DEPTH * 2; if (!_upb_def_validate(defs, n, s)) { return false; } /* Validation all passed; freeze the objects. */ return upb_refcounted_freeze((upb_refcounted *const*)defs, n, s, maxdepth); } /* upb_enumdef ****************************************************************/ static void visitenum(const upb_refcounted *r, upb_refcounted_visit *visit, void *closure) { const upb_enumdef *e = (const upb_enumdef*)r; const upb_def *def = upb_enumdef_upcast(e); if (upb_def_file(def)) { visit(r, upb_filedef_upcast(upb_def_file(def)), closure); } } static void freeenum(upb_refcounted *r) { upb_enumdef *e = (upb_enumdef*)r; upb_inttable_iter i; upb_inttable_begin(&i, &e->iton); for( ; !upb_inttable_done(&i); upb_inttable_next(&i)) { /* To clean up the upb_gstrdup() from upb_enumdef_addval(). */ upb_gfree(upb_value_getcstr(upb_inttable_iter_value(&i))); } upb_strtable_uninit(&e->ntoi); upb_inttable_uninit(&e->iton); upb_def_uninit(upb_enumdef_upcast_mutable(e)); upb_gfree(e); } const struct upb_refcounted_vtbl upb_enumdef_vtbl = {&visitenum, &freeenum}; upb_enumdef *upb_enumdef_new(const void *owner) { upb_enumdef *e = upb_gmalloc(sizeof(*e)); if (!e) return NULL; if (!upb_def_init(upb_enumdef_upcast_mutable(e), UPB_DEF_ENUM, &upb_enumdef_vtbl, owner)) { goto err2; } if (!upb_strtable_init(&e->ntoi, UPB_CTYPE_INT32)) goto err2; if (!upb_inttable_init(&e->iton, UPB_CTYPE_CSTR)) goto err1; return e; err1: upb_strtable_uninit(&e->ntoi); err2: upb_gfree(e); return NULL; } bool upb_enumdef_freeze(upb_enumdef *e, upb_status *status) { upb_def *d = upb_enumdef_upcast_mutable(e); return upb_def_freeze(&d, 1, status); } const char *upb_enumdef_fullname(const upb_enumdef *e) { return upb_def_fullname(upb_enumdef_upcast(e)); } const char *upb_enumdef_name(const upb_enumdef *e) { return upb_def_name(upb_enumdef_upcast(e)); } bool upb_enumdef_setfullname(upb_enumdef *e, const char *fullname, upb_status *s) { return upb_def_setfullname(upb_enumdef_upcast_mutable(e), fullname, s); } bool upb_enumdef_addval(upb_enumdef *e, const char *name, int32_t num, upb_status *status) { char *name2; if (!upb_isident(name, strlen(name), false, status)) { return false; } if (upb_enumdef_ntoiz(e, name, NULL)) { upb_status_seterrf(status, "name '%s' is already defined", name); return false; } if (!upb_strtable_insert(&e->ntoi, name, upb_value_int32(num))) { upb_status_seterrmsg(status, "out of memory"); return false; } if (!upb_inttable_lookup(&e->iton, num, NULL)) { name2 = upb_gstrdup(name); if (!name2 || !upb_inttable_insert(&e->iton, num, upb_value_cstr(name2))) { upb_status_seterrmsg(status, "out of memory"); upb_strtable_remove(&e->ntoi, name, NULL); return false; } } if (upb_enumdef_numvals(e) == 1) { bool ok = upb_enumdef_setdefault(e, num, NULL); UPB_ASSERT(ok); } return true; } int32_t upb_enumdef_default(const upb_enumdef *e) { UPB_ASSERT(upb_enumdef_iton(e, e->defaultval)); return e->defaultval; } bool upb_enumdef_setdefault(upb_enumdef *e, int32_t val, upb_status *s) { UPB_ASSERT(!upb_enumdef_isfrozen(e)); if (!upb_enumdef_iton(e, val)) { upb_status_seterrf(s, "number '%d' is not in the enum.", val); return false; } e->defaultval = val; return true; } int upb_enumdef_numvals(const upb_enumdef *e) { return upb_strtable_count(&e->ntoi); } void upb_enum_begin(upb_enum_iter *i, const upb_enumdef *e) { /* We iterate over the ntoi table, to account for duplicate numbers. */ upb_strtable_begin(i, &e->ntoi); } void upb_enum_next(upb_enum_iter *iter) { upb_strtable_next(iter); } bool upb_enum_done(upb_enum_iter *iter) { return upb_strtable_done(iter); } bool upb_enumdef_ntoi(const upb_enumdef *def, const char *name, size_t len, int32_t *num) { upb_value v; if (!upb_strtable_lookup2(&def->ntoi, name, len, &v)) { return false; } if (num) *num = upb_value_getint32(v); return true; } const char *upb_enumdef_iton(const upb_enumdef *def, int32_t num) { upb_value v; return upb_inttable_lookup32(&def->iton, num, &v) ? upb_value_getcstr(v) : NULL; } const char *upb_enum_iter_name(upb_enum_iter *iter) { return upb_strtable_iter_key(iter); } int32_t upb_enum_iter_number(upb_enum_iter *iter) { return upb_value_getint32(upb_strtable_iter_value(iter)); } /* upb_fielddef ***************************************************************/ static void upb_fielddef_init_default(upb_fielddef *f); static void upb_fielddef_uninit_default(upb_fielddef *f) { if (f->type_is_set_ && f->default_is_string && f->defaultval.bytes) freestr(f->defaultval.bytes); } const char *upb_fielddef_fullname(const upb_fielddef *e) { return upb_def_fullname(upb_fielddef_upcast(e)); } static void visitfield(const upb_refcounted *r, upb_refcounted_visit *visit, void *closure) { const upb_fielddef *f = (const upb_fielddef*)r; const upb_def *def = upb_fielddef_upcast(f); if (upb_fielddef_containingtype(f)) { visit(r, upb_msgdef_upcast2(upb_fielddef_containingtype(f)), closure); } if (upb_fielddef_containingoneof(f)) { visit(r, upb_oneofdef_upcast(upb_fielddef_containingoneof(f)), closure); } if (upb_fielddef_subdef(f)) { visit(r, upb_def_upcast(upb_fielddef_subdef(f)), closure); } if (upb_def_file(def)) { visit(r, upb_filedef_upcast(upb_def_file(def)), closure); } } static void freefield(upb_refcounted *r) { upb_fielddef *f = (upb_fielddef*)r; upb_fielddef_uninit_default(f); if (f->subdef_is_symbolic) upb_gfree(f->sub.name); upb_def_uninit(upb_fielddef_upcast_mutable(f)); upb_gfree(f); } static const char *enumdefaultstr(const upb_fielddef *f) { const upb_enumdef *e; UPB_ASSERT(f->type_is_set_ && f->type_ == UPB_TYPE_ENUM); e = upb_fielddef_enumsubdef(f); if (f->default_is_string && f->defaultval.bytes) { /* Default was explicitly set as a string. */ str_t *s = f->defaultval.bytes; return s->str; } else if (e) { if (!f->default_is_string) { /* Default was explicitly set as an integer; look it up in enumdef. */ const char *name = upb_enumdef_iton(e, f->defaultval.sint); if (name) { return name; } } else { /* Default is completely unset; pull enumdef default. */ if (upb_enumdef_numvals(e) > 0) { const char *name = upb_enumdef_iton(e, upb_enumdef_default(e)); UPB_ASSERT(name); return name; } } } return NULL; } static bool enumdefaultint32(const upb_fielddef *f, int32_t *val) { const upb_enumdef *e; UPB_ASSERT(f->type_is_set_ && f->type_ == UPB_TYPE_ENUM); e = upb_fielddef_enumsubdef(f); if (!f->default_is_string) { /* Default was explicitly set as an integer. */ *val = f->defaultval.sint; return true; } else if (e) { if (f->defaultval.bytes) { /* Default was explicitly set as a str; try to lookup corresponding int. */ str_t *s = f->defaultval.bytes; if (upb_enumdef_ntoiz(e, s->str, val)) { return true; } } else { /* Default is unset; try to pull in enumdef default. */ if (upb_enumdef_numvals(e) > 0) { *val = upb_enumdef_default(e); return true; } } } return false; } const struct upb_refcounted_vtbl upb_fielddef_vtbl = {visitfield, freefield}; upb_fielddef *upb_fielddef_new(const void *o) { upb_fielddef *f = upb_gmalloc(sizeof(*f)); if (!f) return NULL; if (!upb_def_init(upb_fielddef_upcast_mutable(f), UPB_DEF_FIELD, &upb_fielddef_vtbl, o)) { upb_gfree(f); return NULL; } f->msg.def = NULL; f->sub.def = NULL; f->oneof = NULL; f->subdef_is_symbolic = false; f->msg_is_symbolic = false; f->label_ = UPB_LABEL_OPTIONAL; f->type_ = UPB_TYPE_INT32; f->number_ = 0; f->type_is_set_ = false; f->tagdelim = false; f->is_extension_ = false; f->lazy_ = false; f->packed_ = true; /* For the moment we default this to UPB_INTFMT_VARIABLE, since it will work * with all integer types and is in some since more "default" since the most * normal-looking proto2 types int32/int64/uint32/uint64 use variable. * * Other options to consider: * - there is no default; users must set this manually (like type). * - default signed integers to UPB_INTFMT_ZIGZAG, since it's more likely to * be an optimal default for signed integers. */ f->intfmt = UPB_INTFMT_VARIABLE; return f; } static upb_fielddef *upb_fielddef_dup(const upb_fielddef *f, const void *owner) { const char *srcname; upb_fielddef *newf = upb_fielddef_new(owner); if (!newf) return NULL; upb_fielddef_settype(newf, upb_fielddef_type(f)); upb_fielddef_setlabel(newf, upb_fielddef_label(f)); upb_fielddef_setnumber(newf, upb_fielddef_number(f), NULL); upb_fielddef_setname(newf, upb_fielddef_name(f), NULL); if (f->default_is_string && f->defaultval.bytes) { str_t *s = f->defaultval.bytes; upb_fielddef_setdefaultstr(newf, s->str, s->len, NULL); } else { newf->default_is_string = f->default_is_string; newf->defaultval = f->defaultval; } if (f->subdef_is_symbolic) { srcname = f->sub.name; /* Might be NULL. */ } else { srcname = f->sub.def ? upb_def_fullname(f->sub.def) : NULL; } if (srcname) { char *newname = upb_gmalloc(strlen(f->sub.def->fullname) + 2); if (!newname) { upb_fielddef_unref(newf, owner); return NULL; } strcpy(newname, "."); strcat(newname, f->sub.def->fullname); upb_fielddef_setsubdefname(newf, newname, NULL); upb_gfree(newname); } return newf; } bool upb_fielddef_typeisset(const upb_fielddef *f) { return f->type_is_set_; } upb_fieldtype_t upb_fielddef_type(const upb_fielddef *f) { UPB_ASSERT(f->type_is_set_); return f->type_; } uint32_t upb_fielddef_index(const upb_fielddef *f) { return f->index_; } upb_label_t upb_fielddef_label(const upb_fielddef *f) { return f->label_; } upb_intfmt_t upb_fielddef_intfmt(const upb_fielddef *f) { return f->intfmt; } bool upb_fielddef_istagdelim(const upb_fielddef *f) { return f->tagdelim; } uint32_t upb_fielddef_number(const upb_fielddef *f) { return f->number_; } bool upb_fielddef_isextension(const upb_fielddef *f) { return f->is_extension_; } bool upb_fielddef_lazy(const upb_fielddef *f) { return f->lazy_; } bool upb_fielddef_packed(const upb_fielddef *f) { return f->packed_; } const char *upb_fielddef_name(const upb_fielddef *f) { return upb_def_fullname(upb_fielddef_upcast(f)); } size_t upb_fielddef_getjsonname(const upb_fielddef *f, char *buf, size_t len) { const char *name = upb_fielddef_name(f); size_t src, dst = 0; bool ucase_next = false; #define WRITE(byte) \ ++dst; \ if (dst < len) buf[dst - 1] = byte; \ else if (dst == len) buf[dst - 1] = '\0' if (!name) { WRITE('\0'); return 0; } /* Implement the transformation as described in the spec: * 1. upper case all letters after an underscore. * 2. remove all underscores. */ for (src = 0; name[src]; src++) { if (name[src] == '_') { ucase_next = true; continue; } if (ucase_next) { WRITE(toupper(name[src])); ucase_next = false; } else { WRITE(name[src]); } } WRITE('\0'); return dst; #undef WRITE } const upb_msgdef *upb_fielddef_containingtype(const upb_fielddef *f) { return f->msg_is_symbolic ? NULL : f->msg.def; } const upb_oneofdef *upb_fielddef_containingoneof(const upb_fielddef *f) { return f->oneof; } upb_msgdef *upb_fielddef_containingtype_mutable(upb_fielddef *f) { return (upb_msgdef*)upb_fielddef_containingtype(f); } const char *upb_fielddef_containingtypename(upb_fielddef *f) { return f->msg_is_symbolic ? f->msg.name : NULL; } static void release_containingtype(upb_fielddef *f) { if (f->msg_is_symbolic) upb_gfree(f->msg.name); } bool upb_fielddef_setcontainingtypename(upb_fielddef *f, const char *name, upb_status *s) { char *name_copy; UPB_ASSERT(!upb_fielddef_isfrozen(f)); if (upb_fielddef_containingtype(f)) { upb_status_seterrmsg(s, "field has already been added to a message."); return false; } /* TODO: validate name (upb_isident() doesn't quite work atm because this name * may have a leading "."). */ name_copy = upb_gstrdup(name); if (!name_copy) { upb_upberr_setoom(s); return false; } release_containingtype(f); f->msg.name = name_copy; f->msg_is_symbolic = true; return true; } bool upb_fielddef_setname(upb_fielddef *f, const char *name, upb_status *s) { if (upb_fielddef_containingtype(f) || upb_fielddef_containingoneof(f)) { upb_status_seterrmsg(s, "Already added to message or oneof"); return false; } return upb_def_setfullname(upb_fielddef_upcast_mutable(f), name, s); } static void chkdefaulttype(const upb_fielddef *f, upb_fieldtype_t type) { UPB_UNUSED(f); UPB_UNUSED(type); UPB_ASSERT(f->type_is_set_ && upb_fielddef_type(f) == type); } int64_t upb_fielddef_defaultint64(const upb_fielddef *f) { chkdefaulttype(f, UPB_TYPE_INT64); return f->defaultval.sint; } int32_t upb_fielddef_defaultint32(const upb_fielddef *f) { if (f->type_is_set_ && upb_fielddef_type(f) == UPB_TYPE_ENUM) { int32_t val; bool ok = enumdefaultint32(f, &val); UPB_ASSERT(ok); return val; } else { chkdefaulttype(f, UPB_TYPE_INT32); return f->defaultval.sint; } } uint64_t upb_fielddef_defaultuint64(const upb_fielddef *f) { chkdefaulttype(f, UPB_TYPE_UINT64); return f->defaultval.uint; } uint32_t upb_fielddef_defaultuint32(const upb_fielddef *f) { chkdefaulttype(f, UPB_TYPE_UINT32); return f->defaultval.uint; } bool upb_fielddef_defaultbool(const upb_fielddef *f) { chkdefaulttype(f, UPB_TYPE_BOOL); return f->defaultval.uint; } float upb_fielddef_defaultfloat(const upb_fielddef *f) { chkdefaulttype(f, UPB_TYPE_FLOAT); return f->defaultval.flt; } double upb_fielddef_defaultdouble(const upb_fielddef *f) { chkdefaulttype(f, UPB_TYPE_DOUBLE); return f->defaultval.dbl; } const char *upb_fielddef_defaultstr(const upb_fielddef *f, size_t *len) { UPB_ASSERT(f->type_is_set_); UPB_ASSERT(upb_fielddef_type(f) == UPB_TYPE_STRING || upb_fielddef_type(f) == UPB_TYPE_BYTES || upb_fielddef_type(f) == UPB_TYPE_ENUM); if (upb_fielddef_type(f) == UPB_TYPE_ENUM) { const char *ret = enumdefaultstr(f); UPB_ASSERT(ret); /* Enum defaults can't have embedded NULLs. */ if (len) *len = strlen(ret); return ret; } if (f->default_is_string) { str_t *str = f->defaultval.bytes; if (len) *len = str->len; return str->str; } return NULL; } static void upb_fielddef_init_default(upb_fielddef *f) { f->default_is_string = false; switch (upb_fielddef_type(f)) { case UPB_TYPE_DOUBLE: f->defaultval.dbl = 0; break; case UPB_TYPE_FLOAT: f->defaultval.flt = 0; break; case UPB_TYPE_INT32: case UPB_TYPE_INT64: f->defaultval.sint = 0; break; case UPB_TYPE_UINT64: case UPB_TYPE_UINT32: case UPB_TYPE_BOOL: f->defaultval.uint = 0; break; case UPB_TYPE_STRING: case UPB_TYPE_BYTES: f->defaultval.bytes = newstr("", 0); f->default_is_string = true; break; case UPB_TYPE_MESSAGE: break; case UPB_TYPE_ENUM: /* This is our special sentinel that indicates "not set" for an enum. */ f->default_is_string = true; f->defaultval.bytes = NULL; break; } } const upb_def *upb_fielddef_subdef(const upb_fielddef *f) { return f->subdef_is_symbolic ? NULL : f->sub.def; } const upb_msgdef *upb_fielddef_msgsubdef(const upb_fielddef *f) { const upb_def *def = upb_fielddef_subdef(f); return def ? upb_dyncast_msgdef(def) : NULL; } const upb_enumdef *upb_fielddef_enumsubdef(const upb_fielddef *f) { const upb_def *def = upb_fielddef_subdef(f); return def ? upb_dyncast_enumdef(def) : NULL; } upb_def *upb_fielddef_subdef_mutable(upb_fielddef *f) { return (upb_def*)upb_fielddef_subdef(f); } const char *upb_fielddef_subdefname(const upb_fielddef *f) { if (f->subdef_is_symbolic) { return f->sub.name; } else if (f->sub.def) { return upb_def_fullname(f->sub.def); } else { return NULL; } } bool upb_fielddef_setnumber(upb_fielddef *f, uint32_t number, upb_status *s) { if (upb_fielddef_containingtype(f)) { upb_status_seterrmsg( s, "cannot change field number after adding to a message"); return false; } if (number == 0 || number > UPB_MAX_FIELDNUMBER) { upb_status_seterrf(s, "invalid field number (%u)", number); return false; } f->number_ = number; return true; } void upb_fielddef_settype(upb_fielddef *f, upb_fieldtype_t type) { UPB_ASSERT(!upb_fielddef_isfrozen(f)); UPB_ASSERT(upb_fielddef_checktype(type)); upb_fielddef_uninit_default(f); f->type_ = type; f->type_is_set_ = true; upb_fielddef_init_default(f); } void upb_fielddef_setdescriptortype(upb_fielddef *f, int type) { UPB_ASSERT(!upb_fielddef_isfrozen(f)); switch (type) { case UPB_DESCRIPTOR_TYPE_DOUBLE: upb_fielddef_settype(f, UPB_TYPE_DOUBLE); break; case UPB_DESCRIPTOR_TYPE_FLOAT: upb_fielddef_settype(f, UPB_TYPE_FLOAT); break; case UPB_DESCRIPTOR_TYPE_INT64: case UPB_DESCRIPTOR_TYPE_SFIXED64: case UPB_DESCRIPTOR_TYPE_SINT64: upb_fielddef_settype(f, UPB_TYPE_INT64); break; case UPB_DESCRIPTOR_TYPE_UINT64: case UPB_DESCRIPTOR_TYPE_FIXED64: upb_fielddef_settype(f, UPB_TYPE_UINT64); break; case UPB_DESCRIPTOR_TYPE_INT32: case UPB_DESCRIPTOR_TYPE_SFIXED32: case UPB_DESCRIPTOR_TYPE_SINT32: upb_fielddef_settype(f, UPB_TYPE_INT32); break; case UPB_DESCRIPTOR_TYPE_UINT32: case UPB_DESCRIPTOR_TYPE_FIXED32: upb_fielddef_settype(f, UPB_TYPE_UINT32); break; case UPB_DESCRIPTOR_TYPE_BOOL: upb_fielddef_settype(f, UPB_TYPE_BOOL); break; case UPB_DESCRIPTOR_TYPE_STRING: upb_fielddef_settype(f, UPB_TYPE_STRING); break; case UPB_DESCRIPTOR_TYPE_BYTES: upb_fielddef_settype(f, UPB_TYPE_BYTES); break; case UPB_DESCRIPTOR_TYPE_GROUP: case UPB_DESCRIPTOR_TYPE_MESSAGE: upb_fielddef_settype(f, UPB_TYPE_MESSAGE); break; case UPB_DESCRIPTOR_TYPE_ENUM: upb_fielddef_settype(f, UPB_TYPE_ENUM); break; default: UPB_ASSERT(false); } if (type == UPB_DESCRIPTOR_TYPE_FIXED64 || type == UPB_DESCRIPTOR_TYPE_FIXED32 || type == UPB_DESCRIPTOR_TYPE_SFIXED64 || type == UPB_DESCRIPTOR_TYPE_SFIXED32) { upb_fielddef_setintfmt(f, UPB_INTFMT_FIXED); } else if (type == UPB_DESCRIPTOR_TYPE_SINT64 || type == UPB_DESCRIPTOR_TYPE_SINT32) { upb_fielddef_setintfmt(f, UPB_INTFMT_ZIGZAG); } else { upb_fielddef_setintfmt(f, UPB_INTFMT_VARIABLE); } upb_fielddef_settagdelim(f, type == UPB_DESCRIPTOR_TYPE_GROUP); } upb_descriptortype_t upb_fielddef_descriptortype(const upb_fielddef *f) { switch (upb_fielddef_type(f)) { case UPB_TYPE_FLOAT: return UPB_DESCRIPTOR_TYPE_FLOAT; case UPB_TYPE_DOUBLE: return UPB_DESCRIPTOR_TYPE_DOUBLE; case UPB_TYPE_BOOL: return UPB_DESCRIPTOR_TYPE_BOOL; case UPB_TYPE_STRING: return UPB_DESCRIPTOR_TYPE_STRING; case UPB_TYPE_BYTES: return UPB_DESCRIPTOR_TYPE_BYTES; case UPB_TYPE_ENUM: return UPB_DESCRIPTOR_TYPE_ENUM; case UPB_TYPE_INT32: switch (upb_fielddef_intfmt(f)) { case UPB_INTFMT_VARIABLE: return UPB_DESCRIPTOR_TYPE_INT32; case UPB_INTFMT_FIXED: return UPB_DESCRIPTOR_TYPE_SFIXED32; case UPB_INTFMT_ZIGZAG: return UPB_DESCRIPTOR_TYPE_SINT32; } case UPB_TYPE_INT64: switch (upb_fielddef_intfmt(f)) { case UPB_INTFMT_VARIABLE: return UPB_DESCRIPTOR_TYPE_INT64; case UPB_INTFMT_FIXED: return UPB_DESCRIPTOR_TYPE_SFIXED64; case UPB_INTFMT_ZIGZAG: return UPB_DESCRIPTOR_TYPE_SINT64; } case UPB_TYPE_UINT32: switch (upb_fielddef_intfmt(f)) { case UPB_INTFMT_VARIABLE: return UPB_DESCRIPTOR_TYPE_UINT32; case UPB_INTFMT_FIXED: return UPB_DESCRIPTOR_TYPE_FIXED32; case UPB_INTFMT_ZIGZAG: return -1; } case UPB_TYPE_UINT64: switch (upb_fielddef_intfmt(f)) { case UPB_INTFMT_VARIABLE: return UPB_DESCRIPTOR_TYPE_UINT64; case UPB_INTFMT_FIXED: return UPB_DESCRIPTOR_TYPE_FIXED64; case UPB_INTFMT_ZIGZAG: return -1; } case UPB_TYPE_MESSAGE: return upb_fielddef_istagdelim(f) ? UPB_DESCRIPTOR_TYPE_GROUP : UPB_DESCRIPTOR_TYPE_MESSAGE; } return 0; } void upb_fielddef_setisextension(upb_fielddef *f, bool is_extension) { UPB_ASSERT(!upb_fielddef_isfrozen(f)); f->is_extension_ = is_extension; } void upb_fielddef_setlazy(upb_fielddef *f, bool lazy) { UPB_ASSERT(!upb_fielddef_isfrozen(f)); f->lazy_ = lazy; } void upb_fielddef_setpacked(upb_fielddef *f, bool packed) { UPB_ASSERT(!upb_fielddef_isfrozen(f)); f->packed_ = packed; } void upb_fielddef_setlabel(upb_fielddef *f, upb_label_t label) { UPB_ASSERT(!upb_fielddef_isfrozen(f)); UPB_ASSERT(upb_fielddef_checklabel(label)); f->label_ = label; } void upb_fielddef_setintfmt(upb_fielddef *f, upb_intfmt_t fmt) { UPB_ASSERT(!upb_fielddef_isfrozen(f)); UPB_ASSERT(upb_fielddef_checkintfmt(fmt)); f->intfmt = fmt; } void upb_fielddef_settagdelim(upb_fielddef *f, bool tag_delim) { UPB_ASSERT(!upb_fielddef_isfrozen(f)); f->tagdelim = tag_delim; f->tagdelim = tag_delim; } static bool checksetdefault(upb_fielddef *f, upb_fieldtype_t type) { if (!f->type_is_set_ || upb_fielddef_isfrozen(f) || upb_fielddef_type(f) != type) { UPB_ASSERT(false); return false; } if (f->default_is_string) { str_t *s = f->defaultval.bytes; UPB_ASSERT(s || type == UPB_TYPE_ENUM); if (s) freestr(s); } f->default_is_string = false; return true; } void upb_fielddef_setdefaultint64(upb_fielddef *f, int64_t value) { if (checksetdefault(f, UPB_TYPE_INT64)) f->defaultval.sint = value; } void upb_fielddef_setdefaultint32(upb_fielddef *f, int32_t value) { if ((upb_fielddef_type(f) == UPB_TYPE_ENUM && checksetdefault(f, UPB_TYPE_ENUM)) || checksetdefault(f, UPB_TYPE_INT32)) { f->defaultval.sint = value; } } void upb_fielddef_setdefaultuint64(upb_fielddef *f, uint64_t value) { if (checksetdefault(f, UPB_TYPE_UINT64)) f->defaultval.uint = value; } void upb_fielddef_setdefaultuint32(upb_fielddef *f, uint32_t value) { if (checksetdefault(f, UPB_TYPE_UINT32)) f->defaultval.uint = value; } void upb_fielddef_setdefaultbool(upb_fielddef *f, bool value) { if (checksetdefault(f, UPB_TYPE_BOOL)) f->defaultval.uint = value; } void upb_fielddef_setdefaultfloat(upb_fielddef *f, float value) { if (checksetdefault(f, UPB_TYPE_FLOAT)) f->defaultval.flt = value; } void upb_fielddef_setdefaultdouble(upb_fielddef *f, double value) { if (checksetdefault(f, UPB_TYPE_DOUBLE)) f->defaultval.dbl = value; } bool upb_fielddef_setdefaultstr(upb_fielddef *f, const void *str, size_t len, upb_status *s) { str_t *str2; UPB_ASSERT(upb_fielddef_isstring(f) || f->type_ == UPB_TYPE_ENUM); if (f->type_ == UPB_TYPE_ENUM && !upb_isident(str, len, false, s)) return false; if (f->default_is_string) { str_t *s = f->defaultval.bytes; UPB_ASSERT(s || f->type_ == UPB_TYPE_ENUM); if (s) freestr(s); } else { UPB_ASSERT(f->type_ == UPB_TYPE_ENUM); } str2 = newstr(str, len); f->defaultval.bytes = str2; f->default_is_string = true; return true; } void upb_fielddef_setdefaultcstr(upb_fielddef *f, const char *str, upb_status *s) { UPB_ASSERT(f->type_is_set_); upb_fielddef_setdefaultstr(f, str, str ? strlen(str) : 0, s); } bool upb_fielddef_enumhasdefaultint32(const upb_fielddef *f) { int32_t val; UPB_ASSERT(f->type_is_set_ && f->type_ == UPB_TYPE_ENUM); return enumdefaultint32(f, &val); } bool upb_fielddef_enumhasdefaultstr(const upb_fielddef *f) { UPB_ASSERT(f->type_is_set_ && f->type_ == UPB_TYPE_ENUM); return enumdefaultstr(f) != NULL; } static bool upb_subdef_typecheck(upb_fielddef *f, const upb_def *subdef, upb_status *s) { if (f->type_ == UPB_TYPE_MESSAGE) { if (upb_dyncast_msgdef(subdef)) return true; upb_status_seterrmsg(s, "invalid subdef type for this submessage field"); return false; } else if (f->type_ == UPB_TYPE_ENUM) { if (upb_dyncast_enumdef(subdef)) return true; upb_status_seterrmsg(s, "invalid subdef type for this enum field"); return false; } else { upb_status_seterrmsg(s, "only message and enum fields can have a subdef"); return false; } } static void release_subdef(upb_fielddef *f) { if (f->subdef_is_symbolic) { upb_gfree(f->sub.name); } else if (f->sub.def) { upb_unref2(f->sub.def, f); } } bool upb_fielddef_setsubdef(upb_fielddef *f, const upb_def *subdef, upb_status *s) { UPB_ASSERT(!upb_fielddef_isfrozen(f)); UPB_ASSERT(upb_fielddef_hassubdef(f)); if (subdef && !upb_subdef_typecheck(f, subdef, s)) return false; release_subdef(f); f->sub.def = subdef; f->subdef_is_symbolic = false; if (f->sub.def) upb_ref2(f->sub.def, f); return true; } bool upb_fielddef_setmsgsubdef(upb_fielddef *f, const upb_msgdef *subdef, upb_status *s) { return upb_fielddef_setsubdef(f, upb_msgdef_upcast(subdef), s); } bool upb_fielddef_setenumsubdef(upb_fielddef *f, const upb_enumdef *subdef, upb_status *s) { return upb_fielddef_setsubdef(f, upb_enumdef_upcast(subdef), s); } bool upb_fielddef_setsubdefname(upb_fielddef *f, const char *name, upb_status *s) { char *name_copy; UPB_ASSERT(!upb_fielddef_isfrozen(f)); if (!upb_fielddef_hassubdef(f)) { upb_status_seterrmsg(s, "field type does not accept a subdef"); return false; } name_copy = upb_gstrdup(name); if (!name_copy) { upb_upberr_setoom(s); return false; } /* TODO: validate name (upb_isident() doesn't quite work atm because this name * may have a leading "."). */ release_subdef(f); f->sub.name = name_copy; f->subdef_is_symbolic = true; return true; } bool upb_fielddef_issubmsg(const upb_fielddef *f) { return upb_fielddef_type(f) == UPB_TYPE_MESSAGE; } bool upb_fielddef_isstring(const upb_fielddef *f) { return upb_fielddef_type(f) == UPB_TYPE_STRING || upb_fielddef_type(f) == UPB_TYPE_BYTES; } bool upb_fielddef_isseq(const upb_fielddef *f) { return upb_fielddef_label(f) == UPB_LABEL_REPEATED; } bool upb_fielddef_isprimitive(const upb_fielddef *f) { return !upb_fielddef_isstring(f) && !upb_fielddef_issubmsg(f); } bool upb_fielddef_ismap(const upb_fielddef *f) { return upb_fielddef_isseq(f) && upb_fielddef_issubmsg(f) && upb_msgdef_mapentry(upb_fielddef_msgsubdef(f)); } bool upb_fielddef_haspresence(const upb_fielddef *f) { if (upb_fielddef_isseq(f)) return false; if (upb_fielddef_issubmsg(f)) return true; /* Primitive field: return true unless there is a message that specifies * presence should not exist. */ if (f->msg_is_symbolic || !f->msg.def) return true; return f->msg.def->syntax == UPB_SYNTAX_PROTO2; } bool upb_fielddef_hassubdef(const upb_fielddef *f) { return upb_fielddef_issubmsg(f) || upb_fielddef_type(f) == UPB_TYPE_ENUM; } static bool between(int32_t x, int32_t low, int32_t high) { return x >= low && x <= high; } bool upb_fielddef_checklabel(int32_t label) { return between(label, 1, 3); } bool upb_fielddef_checktype(int32_t type) { return between(type, 1, 11); } bool upb_fielddef_checkintfmt(int32_t fmt) { return between(fmt, 1, 3); } bool upb_fielddef_checkdescriptortype(int32_t type) { return between(type, 1, 18); } /* upb_msgdef *****************************************************************/ static void visitmsg(const upb_refcounted *r, upb_refcounted_visit *visit, void *closure) { upb_msg_oneof_iter o; const upb_msgdef *m = (const upb_msgdef*)r; const upb_def *def = upb_msgdef_upcast(m); upb_msg_field_iter i; for(upb_msg_field_begin(&i, m); !upb_msg_field_done(&i); upb_msg_field_next(&i)) { upb_fielddef *f = upb_msg_iter_field(&i); visit(r, upb_fielddef_upcast2(f), closure); } for(upb_msg_oneof_begin(&o, m); !upb_msg_oneof_done(&o); upb_msg_oneof_next(&o)) { upb_oneofdef *f = upb_msg_iter_oneof(&o); visit(r, upb_oneofdef_upcast(f), closure); } if (upb_def_file(def)) { visit(r, upb_filedef_upcast(upb_def_file(def)), closure); } } static void freemsg(upb_refcounted *r) { upb_msgdef *m = (upb_msgdef*)r; upb_strtable_uninit(&m->ntof); upb_inttable_uninit(&m->itof); upb_def_uninit(upb_msgdef_upcast_mutable(m)); upb_gfree(m); } const struct upb_refcounted_vtbl upb_msgdef_vtbl = {visitmsg, freemsg}; upb_msgdef *upb_msgdef_new(const void *owner) { upb_msgdef *m = upb_gmalloc(sizeof(*m)); if (!m) return NULL; if (!upb_def_init(upb_msgdef_upcast_mutable(m), UPB_DEF_MSG, &upb_msgdef_vtbl, owner)) { goto err2; } if (!upb_inttable_init(&m->itof, UPB_CTYPE_PTR)) goto err2; if (!upb_strtable_init(&m->ntof, UPB_CTYPE_PTR)) goto err1; m->map_entry = false; m->syntax = UPB_SYNTAX_PROTO2; return m; err1: upb_inttable_uninit(&m->itof); err2: upb_gfree(m); return NULL; } static upb_oneofdef *upb_oneofdef_dup(const upb_oneofdef *o, const void *owner); static upb_msgdef *upb_msgdef_dup(const upb_msgdef *m, const void *owner) { bool ok; upb_msg_field_iter i; upb_msg_oneof_iter o; upb_msgdef *newm = upb_msgdef_new(owner); if (!newm) return NULL; ok = upb_def_setfullname(upb_msgdef_upcast_mutable(newm), upb_def_fullname(upb_msgdef_upcast(m)), NULL); newm->map_entry = m->map_entry; newm->syntax = m->syntax; UPB_ASSERT(ok); for(upb_msg_field_begin(&i, m); !upb_msg_field_done(&i); upb_msg_field_next(&i)) { upb_fielddef *f = upb_fielddef_dup(upb_msg_iter_field(&i), &f); /* Fields in oneofs are dup'd below. */ if (upb_fielddef_containingoneof(f)) continue; if (!f || !upb_msgdef_addfield(newm, f, &f, NULL)) { upb_msgdef_unref(newm, owner); return NULL; } } for(upb_msg_oneof_begin(&o, m); !upb_msg_oneof_done(&o); upb_msg_oneof_next(&o)) { upb_oneofdef *f = upb_oneofdef_dup(upb_msg_iter_oneof(&o), &f); if (!f || !upb_msgdef_addoneof(newm, f, &f, NULL)) { upb_msgdef_unref(newm, owner); return NULL; } } return newm; } bool upb_msgdef_freeze(upb_msgdef *m, upb_status *status) { upb_def *d = upb_msgdef_upcast_mutable(m); return upb_def_freeze(&d, 1, status); } const char *upb_msgdef_fullname(const upb_msgdef *m) { return upb_def_fullname(upb_msgdef_upcast(m)); } const char *upb_msgdef_name(const upb_msgdef *m) { return upb_def_name(upb_msgdef_upcast(m)); } bool upb_msgdef_setfullname(upb_msgdef *m, const char *fullname, upb_status *s) { return upb_def_setfullname(upb_msgdef_upcast_mutable(m), fullname, s); } bool upb_msgdef_setsyntax(upb_msgdef *m, upb_syntax_t syntax) { if (syntax != UPB_SYNTAX_PROTO2 && syntax != UPB_SYNTAX_PROTO3) { return false; } m->syntax = syntax; return true; } upb_syntax_t upb_msgdef_syntax(const upb_msgdef *m) { return m->syntax; } /* Helper: check that the field |f| is safe to add to msgdef |m|. Set an error * on status |s| and return false if not. */ static bool check_field_add(const upb_msgdef *m, const upb_fielddef *f, upb_status *s) { if (upb_fielddef_containingtype(f) != NULL) { upb_status_seterrmsg(s, "fielddef already belongs to a message"); return false; } else if (upb_fielddef_name(f) == NULL || upb_fielddef_number(f) == 0) { upb_status_seterrmsg(s, "field name or number were not set"); return false; } else if (upb_msgdef_itof(m, upb_fielddef_number(f))) { upb_status_seterrmsg(s, "duplicate field number"); return false; } else if (upb_strtable_lookup(&m->ntof, upb_fielddef_name(f), NULL)) { upb_status_seterrmsg(s, "name conflicts with existing field or oneof"); return false; } return true; } static void add_field(upb_msgdef *m, upb_fielddef *f, const void *ref_donor) { release_containingtype(f); f->msg.def = m; f->msg_is_symbolic = false; upb_inttable_insert(&m->itof, upb_fielddef_number(f), upb_value_ptr(f)); upb_strtable_insert(&m->ntof, upb_fielddef_name(f), upb_value_ptr(f)); upb_ref2(f, m); upb_ref2(m, f); if (ref_donor) upb_fielddef_unref(f, ref_donor); } bool upb_msgdef_addfield(upb_msgdef *m, upb_fielddef *f, const void *ref_donor, upb_status *s) { /* TODO: extensions need to have a separate namespace, because proto2 allows a * top-level extension (ie. one not in any package) to have the same name as a * field from the message. * * This also implies that there needs to be a separate lookup-by-name method * for extensions. It seems desirable for iteration to return both extensions * and non-extensions though. * * We also need to validate that the field number is in an extension range iff * it is an extension. * * This method is idempotent. Check if |f| is already part of this msgdef and * return immediately if so. */ if (upb_fielddef_containingtype(f) == m) { if (ref_donor) upb_fielddef_unref(f, ref_donor); return true; } /* Check constraints for all fields before performing any action. */ if (!check_field_add(m, f, s)) { return false; } else if (upb_fielddef_containingoneof(f) != NULL) { /* Fields in a oneof can only be added by adding the oneof to the msgdef. */ upb_status_seterrmsg(s, "fielddef is part of a oneof"); return false; } /* Constraint checks ok, perform the action. */ add_field(m, f, ref_donor); return true; } bool upb_msgdef_addoneof(upb_msgdef *m, upb_oneofdef *o, const void *ref_donor, upb_status *s) { upb_oneof_iter it; /* Check various conditions that would prevent this oneof from being added. */ if (upb_oneofdef_containingtype(o)) { upb_status_seterrmsg(s, "oneofdef already belongs to a message"); return false; } else if (upb_oneofdef_name(o) == NULL) { upb_status_seterrmsg(s, "oneofdef name was not set"); return false; } else if (upb_strtable_lookup(&m->ntof, upb_oneofdef_name(o), NULL)) { upb_status_seterrmsg(s, "name conflicts with existing field or oneof"); return false; } /* Check that all of the oneof's fields do not conflict with names or numbers * of fields already in the message. */ for (upb_oneof_begin(&it, o); !upb_oneof_done(&it); upb_oneof_next(&it)) { const upb_fielddef *f = upb_oneof_iter_field(&it); if (!check_field_add(m, f, s)) { return false; } } /* Everything checks out -- commit now. */ /* Add oneof itself first. */ o->parent = m; upb_strtable_insert(&m->ntof, upb_oneofdef_name(o), upb_value_ptr(o)); upb_ref2(o, m); upb_ref2(m, o); /* Add each field of the oneof directly to the msgdef. */ for (upb_oneof_begin(&it, o); !upb_oneof_done(&it); upb_oneof_next(&it)) { upb_fielddef *f = upb_oneof_iter_field(&it); add_field(m, f, NULL); } if (ref_donor) upb_oneofdef_unref(o, ref_donor); return true; } const upb_fielddef *upb_msgdef_itof(const upb_msgdef *m, uint32_t i) { upb_value val; return upb_inttable_lookup32(&m->itof, i, &val) ? upb_value_getptr(val) : NULL; } const upb_fielddef *upb_msgdef_ntof(const upb_msgdef *m, const char *name, size_t len) { upb_value val; if (!upb_strtable_lookup2(&m->ntof, name, len, &val)) { return NULL; } return upb_trygetfield(upb_value_getptr(val)); } const upb_oneofdef *upb_msgdef_ntoo(const upb_msgdef *m, const char *name, size_t len) { upb_value val; if (!upb_strtable_lookup2(&m->ntof, name, len, &val)) { return NULL; } return upb_trygetoneof(upb_value_getptr(val)); } bool upb_msgdef_lookupname(const upb_msgdef *m, const char *name, size_t len, const upb_fielddef **f, const upb_oneofdef **o) { upb_value val; if (!upb_strtable_lookup2(&m->ntof, name, len, &val)) { return false; } *o = upb_trygetoneof(upb_value_getptr(val)); *f = upb_trygetfield(upb_value_getptr(val)); UPB_ASSERT((*o != NULL) ^ (*f != NULL)); /* Exactly one of the two should be set. */ return true; } int upb_msgdef_numfields(const upb_msgdef *m) { /* The number table contains only fields. */ return upb_inttable_count(&m->itof); } int upb_msgdef_numoneofs(const upb_msgdef *m) { /* The name table includes oneofs, and the number table does not. */ return upb_strtable_count(&m->ntof) - upb_inttable_count(&m->itof); } void upb_msgdef_setmapentry(upb_msgdef *m, bool map_entry) { UPB_ASSERT(!upb_msgdef_isfrozen(m)); m->map_entry = map_entry; } bool upb_msgdef_mapentry(const upb_msgdef *m) { return m->map_entry; } void upb_msg_field_begin(upb_msg_field_iter *iter, const upb_msgdef *m) { upb_inttable_begin(iter, &m->itof); } void upb_msg_field_next(upb_msg_field_iter *iter) { upb_inttable_next(iter); } bool upb_msg_field_done(const upb_msg_field_iter *iter) { return upb_inttable_done(iter); } upb_fielddef *upb_msg_iter_field(const upb_msg_field_iter *iter) { return (upb_fielddef*)upb_value_getptr(upb_inttable_iter_value(iter)); } void upb_msg_field_iter_setdone(upb_msg_field_iter *iter) { upb_inttable_iter_setdone(iter); } void upb_msg_oneof_begin(upb_msg_oneof_iter *iter, const upb_msgdef *m) { upb_strtable_begin(iter, &m->ntof); /* We need to skip past any initial fields. */ while (!upb_strtable_done(iter) && !upb_isoneof(upb_value_getptr(upb_strtable_iter_value(iter)))) { upb_strtable_next(iter); } } void upb_msg_oneof_next(upb_msg_oneof_iter *iter) { /* We need to skip past fields to return only oneofs. */ do { upb_strtable_next(iter); } while (!upb_strtable_done(iter) && !upb_isoneof(upb_value_getptr(upb_strtable_iter_value(iter)))); } bool upb_msg_oneof_done(const upb_msg_oneof_iter *iter) { return upb_strtable_done(iter); } upb_oneofdef *upb_msg_iter_oneof(const upb_msg_oneof_iter *iter) { return (upb_oneofdef*)upb_value_getptr(upb_strtable_iter_value(iter)); } void upb_msg_oneof_iter_setdone(upb_msg_oneof_iter *iter) { upb_strtable_iter_setdone(iter); } /* upb_oneofdef ***************************************************************/ static void visitoneof(const upb_refcounted *r, upb_refcounted_visit *visit, void *closure) { const upb_oneofdef *o = (const upb_oneofdef*)r; upb_oneof_iter i; for (upb_oneof_begin(&i, o); !upb_oneof_done(&i); upb_oneof_next(&i)) { const upb_fielddef *f = upb_oneof_iter_field(&i); visit(r, upb_fielddef_upcast2(f), closure); } if (o->parent) { visit(r, upb_msgdef_upcast2(o->parent), closure); } } static void freeoneof(upb_refcounted *r) { upb_oneofdef *o = (upb_oneofdef*)r; upb_strtable_uninit(&o->ntof); upb_inttable_uninit(&o->itof); upb_gfree((void*)o->name); upb_gfree(o); } const struct upb_refcounted_vtbl upb_oneofdef_vtbl = {visitoneof, freeoneof}; upb_oneofdef *upb_oneofdef_new(const void *owner) { upb_oneofdef *o = upb_gmalloc(sizeof(*o)); if (!o) { return NULL; } o->parent = NULL; o->name = NULL; if (!upb_refcounted_init(upb_oneofdef_upcast_mutable(o), &upb_oneofdef_vtbl, owner)) { goto err2; } if (!upb_inttable_init(&o->itof, UPB_CTYPE_PTR)) goto err2; if (!upb_strtable_init(&o->ntof, UPB_CTYPE_PTR)) goto err1; return o; err1: upb_inttable_uninit(&o->itof); err2: upb_gfree(o); return NULL; } static upb_oneofdef *upb_oneofdef_dup(const upb_oneofdef *o, const void *owner) { bool ok; upb_oneof_iter i; upb_oneofdef *newo = upb_oneofdef_new(owner); if (!newo) return NULL; ok = upb_oneofdef_setname(newo, upb_oneofdef_name(o), NULL); UPB_ASSERT(ok); for (upb_oneof_begin(&i, o); !upb_oneof_done(&i); upb_oneof_next(&i)) { upb_fielddef *f = upb_fielddef_dup(upb_oneof_iter_field(&i), &f); if (!f || !upb_oneofdef_addfield(newo, f, &f, NULL)) { upb_oneofdef_unref(newo, owner); return NULL; } } return newo; } const char *upb_oneofdef_name(const upb_oneofdef *o) { return o->name; } bool upb_oneofdef_setname(upb_oneofdef *o, const char *name, upb_status *s) { UPB_ASSERT(!upb_oneofdef_isfrozen(o)); if (upb_oneofdef_containingtype(o)) { upb_status_seterrmsg(s, "oneof already added to a message"); return false; } if (!upb_isident(name, strlen(name), true, s)) { return false; } name = upb_gstrdup(name); if (!name) { upb_status_seterrmsg(s, "One of memory"); return false; } upb_gfree((void*)o->name); o->name = name; return true; } const upb_msgdef *upb_oneofdef_containingtype(const upb_oneofdef *o) { return o->parent; } int upb_oneofdef_numfields(const upb_oneofdef *o) { return upb_strtable_count(&o->ntof); } uint32_t upb_oneofdef_index(const upb_oneofdef *o) { return o->index; } bool upb_oneofdef_addfield(upb_oneofdef *o, upb_fielddef *f, const void *ref_donor, upb_status *s) { UPB_ASSERT(!upb_oneofdef_isfrozen(o)); UPB_ASSERT(!o->parent || !upb_msgdef_isfrozen(o->parent)); /* This method is idempotent. Check if |f| is already part of this oneofdef * and return immediately if so. */ if (upb_fielddef_containingoneof(f) == o) { return true; } /* The field must have an OPTIONAL label. */ if (upb_fielddef_label(f) != UPB_LABEL_OPTIONAL) { upb_status_seterrmsg(s, "fields in oneof must have OPTIONAL label"); return false; } /* Check that no field with this name or number exists already in the oneof. * Also check that the field is not already part of a oneof. */ if (upb_fielddef_name(f) == NULL || upb_fielddef_number(f) == 0) { upb_status_seterrmsg(s, "field name or number were not set"); return false; } else if (upb_oneofdef_itof(o, upb_fielddef_number(f)) || upb_oneofdef_ntofz(o, upb_fielddef_name(f))) { upb_status_seterrmsg(s, "duplicate field name or number"); return false; } else if (upb_fielddef_containingoneof(f) != NULL) { upb_status_seterrmsg(s, "fielddef already belongs to a oneof"); return false; } /* We allow adding a field to the oneof either if the field is not part of a * msgdef, or if it is and we are also part of the same msgdef. */ if (o->parent == NULL) { /* If we're not in a msgdef, the field cannot be either. Otherwise we would * need to magically add this oneof to a msgdef to remain consistent, which * is surprising behavior. */ if (upb_fielddef_containingtype(f) != NULL) { upb_status_seterrmsg(s, "fielddef already belongs to a message, but " "oneof does not"); return false; } } else { /* If we're in a msgdef, the user can add fields that either aren't in any * msgdef (in which case they're added to our msgdef) or already a part of * our msgdef. */ if (upb_fielddef_containingtype(f) != NULL && upb_fielddef_containingtype(f) != o->parent) { upb_status_seterrmsg(s, "fielddef belongs to a different message " "than oneof"); return false; } } /* Commit phase. First add the field to our parent msgdef, if any, because * that may fail; then add the field to our own tables. */ if (o->parent != NULL && upb_fielddef_containingtype(f) == NULL) { if (!upb_msgdef_addfield((upb_msgdef*)o->parent, f, NULL, s)) { return false; } } release_containingtype(f); f->oneof = o; upb_inttable_insert(&o->itof, upb_fielddef_number(f), upb_value_ptr(f)); upb_strtable_insert(&o->ntof, upb_fielddef_name(f), upb_value_ptr(f)); upb_ref2(f, o); upb_ref2(o, f); if (ref_donor) upb_fielddef_unref(f, ref_donor); return true; } const upb_fielddef *upb_oneofdef_ntof(const upb_oneofdef *o, const char *name, size_t length) { upb_value val; return upb_strtable_lookup2(&o->ntof, name, length, &val) ? upb_value_getptr(val) : NULL; } const upb_fielddef *upb_oneofdef_itof(const upb_oneofdef *o, uint32_t num) { upb_value val; return upb_inttable_lookup32(&o->itof, num, &val) ? upb_value_getptr(val) : NULL; } void upb_oneof_begin(upb_oneof_iter *iter, const upb_oneofdef *o) { upb_inttable_begin(iter, &o->itof); } void upb_oneof_next(upb_oneof_iter *iter) { upb_inttable_next(iter); } bool upb_oneof_done(upb_oneof_iter *iter) { return upb_inttable_done(iter); } upb_fielddef *upb_oneof_iter_field(const upb_oneof_iter *iter) { return (upb_fielddef*)upb_value_getptr(upb_inttable_iter_value(iter)); } void upb_oneof_iter_setdone(upb_oneof_iter *iter) { upb_inttable_iter_setdone(iter); } /* upb_filedef ****************************************************************/ static void visitfiledef(const upb_refcounted *r, upb_refcounted_visit *visit, void *closure) { const upb_filedef *f = (const upb_filedef*)r; size_t i; for(i = 0; i < upb_filedef_defcount(f); i++) { visit(r, upb_def_upcast(upb_filedef_def(f, i)), closure); } } static void freefiledef(upb_refcounted *r) { upb_filedef *f = (upb_filedef*)r; size_t i; for(i = 0; i < upb_filedef_depcount(f); i++) { upb_filedef_unref(upb_filedef_dep(f, i), f); } upb_inttable_uninit(&f->defs); upb_inttable_uninit(&f->deps); upb_gfree((void*)f->name); upb_gfree((void*)f->package); upb_gfree(f); } const struct upb_refcounted_vtbl upb_filedef_vtbl = {visitfiledef, freefiledef}; upb_filedef *upb_filedef_new(const void *owner) { upb_filedef *f = upb_gmalloc(sizeof(*f)); if (!f) { return NULL; } f->package = NULL; f->name = NULL; f->syntax = UPB_SYNTAX_PROTO2; if (!upb_refcounted_init(upb_filedef_upcast_mutable(f), &upb_filedef_vtbl, owner)) { goto err; } if (!upb_inttable_init(&f->defs, UPB_CTYPE_CONSTPTR)) { goto err; } if (!upb_inttable_init(&f->deps, UPB_CTYPE_CONSTPTR)) { goto err2; } return f; err2: upb_inttable_uninit(&f->defs); err: upb_gfree(f); return NULL; } const char *upb_filedef_name(const upb_filedef *f) { return f->name; } const char *upb_filedef_package(const upb_filedef *f) { return f->package; } upb_syntax_t upb_filedef_syntax(const upb_filedef *f) { return f->syntax; } size_t upb_filedef_defcount(const upb_filedef *f) { return upb_inttable_count(&f->defs); } size_t upb_filedef_depcount(const upb_filedef *f) { return upb_inttable_count(&f->deps); } const upb_def *upb_filedef_def(const upb_filedef *f, size_t i) { upb_value v; if (upb_inttable_lookup32(&f->defs, i, &v)) { return upb_value_getconstptr(v); } else { return NULL; } } const upb_filedef *upb_filedef_dep(const upb_filedef *f, size_t i) { upb_value v; if (upb_inttable_lookup32(&f->deps, i, &v)) { return upb_value_getconstptr(v); } else { return NULL; } } bool upb_filedef_setname(upb_filedef *f, const char *name, upb_status *s) { name = upb_gstrdup(name); if (!name) { upb_upberr_setoom(s); return false; } upb_gfree((void*)f->name); f->name = name; return true; } bool upb_filedef_setpackage(upb_filedef *f, const char *package, upb_status *s) { if (!upb_isident(package, strlen(package), true, s)) return false; package = upb_gstrdup(package); if (!package) { upb_upberr_setoom(s); return false; } upb_gfree((void*)f->package); f->package = package; return true; } bool upb_filedef_setsyntax(upb_filedef *f, upb_syntax_t syntax, upb_status *s) { UPB_UNUSED(s); if (syntax != UPB_SYNTAX_PROTO2 && syntax != UPB_SYNTAX_PROTO3) { upb_status_seterrmsg(s, "Unknown syntax value."); return false; } f->syntax = syntax; { /* Set all messages in this file to match. */ size_t i; for (i = 0; i < upb_filedef_defcount(f); i++) { /* Casting const away is safe since all defs in mutable filedef must * also be mutable. */ upb_def *def = (upb_def*)upb_filedef_def(f, i); upb_msgdef *m = upb_dyncast_msgdef_mutable(def); if (m) { m->syntax = syntax; } } } return true; } bool upb_filedef_adddef(upb_filedef *f, upb_def *def, const void *ref_donor, upb_status *s) { if (def->file) { upb_status_seterrmsg(s, "Def is already part of another filedef."); return false; } if (upb_inttable_push(&f->defs, upb_value_constptr(def))) { def->file = f; upb_ref2(def, f); upb_ref2(f, def); if (ref_donor) upb_def_unref(def, ref_donor); if (def->type == UPB_DEF_MSG) { upb_downcast_msgdef_mutable(def)->syntax = f->syntax; } return true; } else { upb_upberr_setoom(s); return false; } } bool upb_filedef_adddep(upb_filedef *f, const upb_filedef *dep) { if (upb_inttable_push(&f->deps, upb_value_constptr(dep))) { /* Regular ref instead of ref2 because files can't form cycles. */ upb_filedef_ref(dep, f); return true; } else { return false; } } void upb_symtab_free(upb_symtab *s) { upb_strtable_iter i; upb_strtable_begin(&i, &s->symtab); for (; !upb_strtable_done(&i); upb_strtable_next(&i)) { const upb_def *def = upb_value_getptr(upb_strtable_iter_value(&i)); upb_def_unref(def, s); } upb_strtable_uninit(&s->symtab); upb_gfree(s); } upb_symtab *upb_symtab_new() { upb_symtab *s = upb_gmalloc(sizeof(*s)); if (!s) { return NULL; } upb_strtable_init(&s->symtab, UPB_CTYPE_PTR); return s; } const upb_def *upb_symtab_lookup(const upb_symtab *s, const char *sym) { upb_value v; upb_def *ret = upb_strtable_lookup(&s->symtab, sym, &v) ? upb_value_getptr(v) : NULL; return ret; } const upb_msgdef *upb_symtab_lookupmsg(const upb_symtab *s, const char *sym) { upb_value v; upb_def *def = upb_strtable_lookup(&s->symtab, sym, &v) ? upb_value_getptr(v) : NULL; return def ? upb_dyncast_msgdef(def) : NULL; } const upb_enumdef *upb_symtab_lookupenum(const upb_symtab *s, const char *sym) { upb_value v; upb_def *def = upb_strtable_lookup(&s->symtab, sym, &v) ? upb_value_getptr(v) : NULL; return def ? upb_dyncast_enumdef(def) : NULL; } /* Given a symbol and the base symbol inside which it is defined, find the * symbol's definition in t. */ static upb_def *upb_resolvename(const upb_strtable *t, const char *base, const char *sym) { if(strlen(sym) == 0) return NULL; if(sym[0] == '.') { /* Symbols starting with '.' are absolute, so we do a single lookup. * Slice to omit the leading '.' */ upb_value v; return upb_strtable_lookup(t, sym + 1, &v) ? upb_value_getptr(v) : NULL; } else { /* Remove components from base until we find an entry or run out. * TODO: This branch is totally broken, but currently not used. */ (void)base; UPB_ASSERT(false); return NULL; } } const upb_def *upb_symtab_resolve(const upb_symtab *s, const char *base, const char *sym) { upb_def *ret = upb_resolvename(&s->symtab, base, sym); return ret; } /* TODO(haberman): we need a lot more testing of error conditions. */ static bool symtab_add(upb_symtab *s, upb_def *const*defs, size_t n, void *ref_donor, upb_refcounted *freeze_also, upb_status *status) { size_t i; size_t add_n; size_t freeze_n; upb_strtable_iter iter; upb_refcounted **add_objs = NULL; upb_def **add_defs = NULL; size_t add_objs_size; upb_strtable addtab; if (n == 0 && !freeze_also) { return true; } if (!upb_strtable_init(&addtab, UPB_CTYPE_PTR)) { upb_status_seterrmsg(status, "out of memory"); return false; } /* Add new defs to our "add" set. */ for (i = 0; i < n; i++) { upb_def *def = defs[i]; const char *fullname; upb_fielddef *f; if (upb_def_isfrozen(def)) { upb_status_seterrmsg(status, "added defs must be mutable"); goto err; } UPB_ASSERT(!upb_def_isfrozen(def)); fullname = upb_def_fullname(def); if (!fullname) { upb_status_seterrmsg( status, "Anonymous defs cannot be added to a symtab"); goto err; } f = upb_dyncast_fielddef_mutable(def); if (f) { if (!upb_fielddef_containingtypename(f)) { upb_status_seterrmsg(status, "Standalone fielddefs must have a containing type " "(extendee) name set"); goto err; } } else { if (upb_strtable_lookup(&addtab, fullname, NULL)) { upb_status_seterrf(status, "Conflicting defs named '%s'", fullname); goto err; } if (upb_strtable_lookup(&s->symtab, fullname, NULL)) { upb_status_seterrf(status, "Symtab already has a def named '%s'", fullname); goto err; } upb_def_donateref(def, ref_donor, s); if (!upb_strtable_insert(&addtab, fullname, upb_value_ptr(def))) goto oom_err; def->came_from_user = true; } } /* Add standalone fielddefs (ie. extensions) to the appropriate messages. * If the appropriate message only exists in the existing symtab, duplicate * it so we have a mutable copy we can add the fields to. */ for (i = 0; i < n; i++) { upb_def *def = defs[i]; upb_fielddef *f = upb_dyncast_fielddef_mutable(def); const char *msgname; upb_value v; upb_msgdef *m; if (!f) continue; msgname = upb_fielddef_containingtypename(f); /* We validated this earlier in this function. */ UPB_ASSERT(msgname); /* If the extendee name is absolutely qualified, move past the initial ".". * TODO(haberman): it is not obvious what it would mean if this was not * absolutely qualified. */ if (msgname[0] == '.') { msgname++; } if (upb_strtable_lookup(&addtab, msgname, &v)) { /* Extendee is in the set of defs the user asked us to add. */ m = upb_value_getptr(v); } else { /* Need to find and dup the extendee from the existing symtab. */ const upb_msgdef *frozen_m = upb_symtab_lookupmsg(s, msgname); if (!frozen_m) { upb_status_seterrf(status, "Tried to extend message %s that does not exist " "in this SymbolTable.", msgname); goto err; } m = upb_msgdef_dup(frozen_m, s); if (!m) goto oom_err; if (!upb_strtable_insert(&addtab, msgname, upb_value_ptr(m))) { upb_msgdef_unref(m, s); goto oom_err; } } if (!upb_msgdef_addfield(m, f, ref_donor, status)) { goto err; } } /* Now using the table, resolve symbolic references for subdefs. */ upb_strtable_begin(&iter, &addtab); for (; !upb_strtable_done(&iter); upb_strtable_next(&iter)) { const char *base; upb_def *def = upb_value_getptr(upb_strtable_iter_value(&iter)); upb_msgdef *m = upb_dyncast_msgdef_mutable(def); upb_msg_field_iter j; if (!m) continue; /* Type names are resolved relative to the message in which they appear. */ base = upb_msgdef_fullname(m); for(upb_msg_field_begin(&j, m); !upb_msg_field_done(&j); upb_msg_field_next(&j)) { upb_fielddef *f = upb_msg_iter_field(&j); const char *name = upb_fielddef_subdefname(f); if (name && !upb_fielddef_subdef(f)) { /* Try the lookup in the current set of to-be-added defs first. If not * there, try existing defs. */ upb_def *subdef = upb_resolvename(&addtab, base, name); if (subdef == NULL) { subdef = upb_resolvename(&s->symtab, base, name); } if (subdef == NULL) { upb_status_seterrf( status, "couldn't resolve name '%s' in message '%s'", name, base); goto err; } else if (!upb_fielddef_setsubdef(f, subdef, status)) { goto err; } } } } /* We need an array of the defs in addtab, for passing to * upb_refcounted_freeze(). */ add_objs_size = upb_strtable_count(&addtab); if (freeze_also) { add_objs_size++; } add_defs = upb_gmalloc(sizeof(void*) * add_objs_size); if (add_defs == NULL) goto oom_err; upb_strtable_begin(&iter, &addtab); for (add_n = 0; !upb_strtable_done(&iter); upb_strtable_next(&iter)) { add_defs[add_n++] = upb_value_getptr(upb_strtable_iter_value(&iter)); } /* Validate defs. */ if (!_upb_def_validate(add_defs, add_n, status)) { goto err; } /* Cheat a little and give the array a new type. * This is probably undefined behavior, but this code will be deleted soon. */ add_objs = (upb_refcounted**)add_defs; freeze_n = add_n; if (freeze_also) { add_objs[freeze_n++] = freeze_also; } if (!upb_refcounted_freeze(add_objs, freeze_n, status, UPB_MAX_MESSAGE_DEPTH * 2)) { goto err; } /* This must be delayed until all errors have been detected, since error * recovery code uses this table to cleanup defs. */ upb_strtable_uninit(&addtab); /* TODO(haberman) we don't properly handle errors after this point (like * OOM in upb_strtable_insert() below). */ for (i = 0; i < add_n; i++) { upb_def *def = (upb_def*)add_objs[i]; const char *name = upb_def_fullname(def); upb_value v; bool success; if (upb_strtable_remove(&s->symtab, name, &v)) { const upb_def *def = upb_value_getptr(v); upb_def_unref(def, s); } success = upb_strtable_insert(&s->symtab, name, upb_value_ptr(def)); UPB_ASSERT(success == true); } upb_gfree(add_defs); return true; oom_err: upb_status_seterrmsg(status, "out of memory"); err: { /* We need to donate the refs back. */ upb_strtable_begin(&iter, &addtab); for (; !upb_strtable_done(&iter); upb_strtable_next(&iter)) { upb_def *def = upb_value_getptr(upb_strtable_iter_value(&iter)); upb_def_donateref(def, s, ref_donor); } } upb_strtable_uninit(&addtab); upb_gfree(add_defs); UPB_ASSERT(!upb_ok(status)); return false; } bool upb_symtab_add(upb_symtab *s, upb_def *const*defs, size_t n, void *ref_donor, upb_status *status) { return symtab_add(s, defs, n, ref_donor, NULL, status); } bool upb_symtab_addfile(upb_symtab *s, upb_filedef *file, upb_status *status) { size_t n; size_t i; upb_def **defs; bool ret; n = upb_filedef_defcount(file); defs = upb_gmalloc(sizeof(*defs) * n); if (defs == NULL) { upb_status_seterrmsg(status, "Out of memory"); return false; } for (i = 0; i < n; i++) { defs[i] = upb_filedef_mutabledef(file, i); } ret = symtab_add(s, defs, n, NULL, upb_filedef_upcast_mutable(file), status); upb_gfree(defs); return ret; } /* Iteration. */ static void advance_to_matching(upb_symtab_iter *iter) { if (iter->type == UPB_DEF_ANY) return; while (!upb_strtable_done(&iter->iter) && iter->type != upb_symtab_iter_def(iter)->type) { upb_strtable_next(&iter->iter); } } void upb_symtab_begin(upb_symtab_iter *iter, const upb_symtab *s, upb_deftype_t type) { upb_strtable_begin(&iter->iter, &s->symtab); iter->type = type; advance_to_matching(iter); } void upb_symtab_next(upb_symtab_iter *iter) { upb_strtable_next(&iter->iter); advance_to_matching(iter); } bool upb_symtab_done(const upb_symtab_iter *iter) { return upb_strtable_done(&iter->iter); } const upb_def *upb_symtab_iter_def(const upb_symtab_iter *iter) { return upb_value_getptr(upb_strtable_iter_value(&iter->iter)); } /* ** TODO(haberman): it's unclear whether a lot of the consistency checks should ** UPB_ASSERT() or return false. */ #include static void *upb_calloc(size_t size) { void *mem = upb_gmalloc(size); if (mem) { memset(mem, 0, size); } return mem; } /* Defined for the sole purpose of having a unique pointer value for * UPB_NO_CLOSURE. */ char _upb_noclosure; static void freehandlers(upb_refcounted *r) { upb_handlers *h = (upb_handlers*)r; upb_inttable_iter i; upb_inttable_begin(&i, &h->cleanup_); for(; !upb_inttable_done(&i); upb_inttable_next(&i)) { void *val = (void*)upb_inttable_iter_key(&i); upb_value func_val = upb_inttable_iter_value(&i); upb_handlerfree *func = upb_value_getfptr(func_val); func(val); } upb_inttable_uninit(&h->cleanup_); upb_msgdef_unref(h->msg, h); upb_gfree(h->sub); upb_gfree(h); } static void visithandlers(const upb_refcounted *r, upb_refcounted_visit *visit, void *closure) { const upb_handlers *h = (const upb_handlers*)r; upb_msg_field_iter i; for(upb_msg_field_begin(&i, h->msg); !upb_msg_field_done(&i); upb_msg_field_next(&i)) { upb_fielddef *f = upb_msg_iter_field(&i); const upb_handlers *sub; if (!upb_fielddef_issubmsg(f)) continue; sub = upb_handlers_getsubhandlers(h, f); if (sub) visit(r, upb_handlers_upcast(sub), closure); } } static const struct upb_refcounted_vtbl vtbl = {visithandlers, freehandlers}; typedef struct { upb_inttable tab; /* maps upb_msgdef* -> upb_handlers*. */ upb_handlers_callback *callback; const void *closure; } dfs_state; /* TODO(haberman): discard upb_handlers* objects that do not actually have any * handlers set and cannot reach any upb_handlers* object that does. This is * slightly tricky to do correctly. */ static upb_handlers *newformsg(const upb_msgdef *m, const void *owner, dfs_state *s) { upb_msg_field_iter i; upb_handlers *h = upb_handlers_new(m, owner); if (!h) return NULL; if (!upb_inttable_insertptr(&s->tab, m, upb_value_ptr(h))) goto oom; s->callback(s->closure, h); /* For each submessage field, get or create a handlers object and set it as * the subhandlers. */ for(upb_msg_field_begin(&i, m); !upb_msg_field_done(&i); upb_msg_field_next(&i)) { upb_fielddef *f = upb_msg_iter_field(&i); const upb_msgdef *subdef; upb_value subm_ent; if (!upb_fielddef_issubmsg(f)) continue; subdef = upb_downcast_msgdef(upb_fielddef_subdef(f)); if (upb_inttable_lookupptr(&s->tab, subdef, &subm_ent)) { upb_handlers_setsubhandlers(h, f, upb_value_getptr(subm_ent)); } else { upb_handlers *sub_mh = newformsg(subdef, &sub_mh, s); if (!sub_mh) goto oom; upb_handlers_setsubhandlers(h, f, sub_mh); upb_handlers_unref(sub_mh, &sub_mh); } } return h; oom: upb_handlers_unref(h, owner); return NULL; } /* Given a selector for a STARTSUBMSG handler, resolves to a pointer to the * subhandlers for this submessage field. */ #define SUBH(h, selector) (h->sub[selector]) /* The selector for a submessage field is the field index. */ #define SUBH_F(h, f) SUBH(h, f->index_) static int32_t trygetsel(upb_handlers *h, const upb_fielddef *f, upb_handlertype_t type) { upb_selector_t sel; UPB_ASSERT(!upb_handlers_isfrozen(h)); if (upb_handlers_msgdef(h) != upb_fielddef_containingtype(f)) { upb_status_seterrf( &h->status_, "type mismatch: field %s does not belong to message %s", upb_fielddef_name(f), upb_msgdef_fullname(upb_handlers_msgdef(h))); return -1; } if (!upb_handlers_getselector(f, type, &sel)) { upb_status_seterrf( &h->status_, "type mismatch: cannot register handler type %d for field %s", type, upb_fielddef_name(f)); return -1; } return sel; } static upb_selector_t handlers_getsel(upb_handlers *h, const upb_fielddef *f, upb_handlertype_t type) { int32_t sel = trygetsel(h, f, type); UPB_ASSERT(sel >= 0); return sel; } static const void **returntype(upb_handlers *h, const upb_fielddef *f, upb_handlertype_t type) { return &h->table[handlers_getsel(h, f, type)].attr.return_closure_type_; } static bool doset(upb_handlers *h, int32_t sel, const upb_fielddef *f, upb_handlertype_t type, upb_func *func, upb_handlerattr *attr) { upb_handlerattr set_attr = UPB_HANDLERATTR_INITIALIZER; const void *closure_type; const void **context_closure_type; UPB_ASSERT(!upb_handlers_isfrozen(h)); if (sel < 0) { upb_status_seterrmsg(&h->status_, "incorrect handler type for this field."); return false; } if (h->table[sel].func) { upb_status_seterrmsg(&h->status_, "cannot change handler once it has been set."); return false; } if (attr) { set_attr = *attr; } /* Check that the given closure type matches the closure type that has been * established for this context (if any). */ closure_type = upb_handlerattr_closuretype(&set_attr); if (type == UPB_HANDLER_STRING) { context_closure_type = returntype(h, f, UPB_HANDLER_STARTSTR); } else if (f && upb_fielddef_isseq(f) && type != UPB_HANDLER_STARTSEQ && type != UPB_HANDLER_ENDSEQ) { context_closure_type = returntype(h, f, UPB_HANDLER_STARTSEQ); } else { context_closure_type = &h->top_closure_type; } if (closure_type && *context_closure_type && closure_type != *context_closure_type) { /* TODO(haberman): better message for debugging. */ if (f) { upb_status_seterrf(&h->status_, "closure type does not match for field %s", upb_fielddef_name(f)); } else { upb_status_seterrmsg( &h->status_, "closure type does not match for message-level handler"); } return false; } if (closure_type) *context_closure_type = closure_type; /* If this is a STARTSEQ or STARTSTR handler, check that the returned pointer * matches any pre-existing expectations about what type is expected. */ if (type == UPB_HANDLER_STARTSEQ || type == UPB_HANDLER_STARTSTR) { const void *return_type = upb_handlerattr_returnclosuretype(&set_attr); const void *table_return_type = upb_handlerattr_returnclosuretype(&h->table[sel].attr); if (return_type && table_return_type && return_type != table_return_type) { upb_status_seterrmsg(&h->status_, "closure return type does not match"); return false; } if (table_return_type && !return_type) upb_handlerattr_setreturnclosuretype(&set_attr, table_return_type); } h->table[sel].func = (upb_func*)func; h->table[sel].attr = set_attr; return true; } /* Returns the effective closure type for this handler (which will propagate * from outer frames if this frame has no START* handler). Not implemented for * UPB_HANDLER_STRING at the moment since this is not needed. Returns NULL is * the effective closure type is unspecified (either no handler was registered * to specify it or the handler that was registered did not specify the closure * type). */ const void *effective_closure_type(upb_handlers *h, const upb_fielddef *f, upb_handlertype_t type) { const void *ret; upb_selector_t sel; UPB_ASSERT(type != UPB_HANDLER_STRING); ret = h->top_closure_type; if (upb_fielddef_isseq(f) && type != UPB_HANDLER_STARTSEQ && type != UPB_HANDLER_ENDSEQ && h->table[sel = handlers_getsel(h, f, UPB_HANDLER_STARTSEQ)].func) { ret = upb_handlerattr_returnclosuretype(&h->table[sel].attr); } if (type == UPB_HANDLER_STRING && h->table[sel = handlers_getsel(h, f, UPB_HANDLER_STARTSTR)].func) { ret = upb_handlerattr_returnclosuretype(&h->table[sel].attr); } /* The effective type of the submessage; not used yet. * if (type == SUBMESSAGE && * h->table[sel = handlers_getsel(h, f, UPB_HANDLER_STARTSUBMSG)].func) { * ret = upb_handlerattr_returnclosuretype(&h->table[sel].attr); * } */ return ret; } /* Checks whether the START* handler specified by f & type is missing even * though it is required to convert the established type of an outer frame * ("closure_type") into the established type of an inner frame (represented in * the return closure type of this handler's attr. */ bool checkstart(upb_handlers *h, const upb_fielddef *f, upb_handlertype_t type, upb_status *status) { const void *closure_type; const upb_handlerattr *attr; const void *return_closure_type; upb_selector_t sel = handlers_getsel(h, f, type); if (h->table[sel].func) return true; closure_type = effective_closure_type(h, f, type); attr = &h->table[sel].attr; return_closure_type = upb_handlerattr_returnclosuretype(attr); if (closure_type && return_closure_type && closure_type != return_closure_type) { upb_status_seterrf(status, "expected start handler to return sub type for field %f", upb_fielddef_name(f)); return false; } return true; } /* Public interface ***********************************************************/ upb_handlers *upb_handlers_new(const upb_msgdef *md, const void *owner) { int extra; upb_handlers *h; UPB_ASSERT(upb_msgdef_isfrozen(md)); extra = sizeof(upb_handlers_tabent) * (md->selector_count - 1); h = upb_calloc(sizeof(*h) + extra); if (!h) return NULL; h->msg = md; upb_msgdef_ref(h->msg, h); upb_status_clear(&h->status_); if (md->submsg_field_count > 0) { h->sub = upb_calloc(md->submsg_field_count * sizeof(*h->sub)); if (!h->sub) goto oom; } else { h->sub = 0; } if (!upb_refcounted_init(upb_handlers_upcast_mutable(h), &vtbl, owner)) goto oom; if (!upb_inttable_init(&h->cleanup_, UPB_CTYPE_FPTR)) goto oom; /* calloc() above initialized all handlers to NULL. */ return h; oom: freehandlers(upb_handlers_upcast_mutable(h)); return NULL; } const upb_handlers *upb_handlers_newfrozen(const upb_msgdef *m, const void *owner, upb_handlers_callback *callback, const void *closure) { dfs_state state; upb_handlers *ret; bool ok; upb_refcounted *r; state.callback = callback; state.closure = closure; if (!upb_inttable_init(&state.tab, UPB_CTYPE_PTR)) return NULL; ret = newformsg(m, owner, &state); upb_inttable_uninit(&state.tab); if (!ret) return NULL; r = upb_handlers_upcast_mutable(ret); ok = upb_refcounted_freeze(&r, 1, NULL, UPB_MAX_HANDLER_DEPTH); UPB_ASSERT(ok); return ret; } const upb_status *upb_handlers_status(upb_handlers *h) { UPB_ASSERT(!upb_handlers_isfrozen(h)); return &h->status_; } void upb_handlers_clearerr(upb_handlers *h) { UPB_ASSERT(!upb_handlers_isfrozen(h)); upb_status_clear(&h->status_); } #define SETTER(name, handlerctype, handlertype) \ bool upb_handlers_set ## name(upb_handlers *h, const upb_fielddef *f, \ handlerctype func, upb_handlerattr *attr) { \ int32_t sel = trygetsel(h, f, handlertype); \ return doset(h, sel, f, handlertype, (upb_func*)func, attr); \ } SETTER(int32, upb_int32_handlerfunc*, UPB_HANDLER_INT32) SETTER(int64, upb_int64_handlerfunc*, UPB_HANDLER_INT64) SETTER(uint32, upb_uint32_handlerfunc*, UPB_HANDLER_UINT32) SETTER(uint64, upb_uint64_handlerfunc*, UPB_HANDLER_UINT64) SETTER(float, upb_float_handlerfunc*, UPB_HANDLER_FLOAT) SETTER(double, upb_double_handlerfunc*, UPB_HANDLER_DOUBLE) SETTER(bool, upb_bool_handlerfunc*, UPB_HANDLER_BOOL) SETTER(startstr, upb_startstr_handlerfunc*, UPB_HANDLER_STARTSTR) SETTER(string, upb_string_handlerfunc*, UPB_HANDLER_STRING) SETTER(endstr, upb_endfield_handlerfunc*, UPB_HANDLER_ENDSTR) SETTER(startseq, upb_startfield_handlerfunc*, UPB_HANDLER_STARTSEQ) SETTER(startsubmsg, upb_startfield_handlerfunc*, UPB_HANDLER_STARTSUBMSG) SETTER(endsubmsg, upb_endfield_handlerfunc*, UPB_HANDLER_ENDSUBMSG) SETTER(endseq, upb_endfield_handlerfunc*, UPB_HANDLER_ENDSEQ) #undef SETTER bool upb_handlers_setstartmsg(upb_handlers *h, upb_startmsg_handlerfunc *func, upb_handlerattr *attr) { return doset(h, UPB_STARTMSG_SELECTOR, NULL, UPB_HANDLER_INT32, (upb_func *)func, attr); } bool upb_handlers_setendmsg(upb_handlers *h, upb_endmsg_handlerfunc *func, upb_handlerattr *attr) { UPB_ASSERT(!upb_handlers_isfrozen(h)); return doset(h, UPB_ENDMSG_SELECTOR, NULL, UPB_HANDLER_INT32, (upb_func *)func, attr); } bool upb_handlers_setsubhandlers(upb_handlers *h, const upb_fielddef *f, const upb_handlers *sub) { UPB_ASSERT(sub); UPB_ASSERT(!upb_handlers_isfrozen(h)); UPB_ASSERT(upb_fielddef_issubmsg(f)); if (SUBH_F(h, f)) return false; /* Can't reset. */ if (upb_msgdef_upcast(upb_handlers_msgdef(sub)) != upb_fielddef_subdef(f)) { return false; } SUBH_F(h, f) = sub; upb_ref2(sub, h); return true; } const upb_handlers *upb_handlers_getsubhandlers(const upb_handlers *h, const upb_fielddef *f) { UPB_ASSERT(upb_fielddef_issubmsg(f)); return SUBH_F(h, f); } bool upb_handlers_getattr(const upb_handlers *h, upb_selector_t sel, upb_handlerattr *attr) { if (!upb_handlers_gethandler(h, sel)) return false; *attr = h->table[sel].attr; return true; } const upb_handlers *upb_handlers_getsubhandlers_sel(const upb_handlers *h, upb_selector_t sel) { /* STARTSUBMSG selector in sel is the field's selector base. */ return SUBH(h, sel - UPB_STATIC_SELECTOR_COUNT); } const upb_msgdef *upb_handlers_msgdef(const upb_handlers *h) { return h->msg; } bool upb_handlers_addcleanup(upb_handlers *h, void *p, upb_handlerfree *func) { bool ok; if (upb_inttable_lookupptr(&h->cleanup_, p, NULL)) { return false; } ok = upb_inttable_insertptr(&h->cleanup_, p, upb_value_fptr(func)); UPB_ASSERT(ok); return true; } /* "Static" methods ***********************************************************/ bool upb_handlers_freeze(upb_handlers *const*handlers, int n, upb_status *s) { /* TODO: verify we have a transitive closure. */ int i; for (i = 0; i < n; i++) { upb_msg_field_iter j; upb_handlers *h = handlers[i]; if (!upb_ok(&h->status_)) { upb_status_seterrf(s, "handlers for message %s had error status: %s", upb_msgdef_fullname(upb_handlers_msgdef(h)), upb_status_errmsg(&h->status_)); return false; } /* Check that there are no closure mismatches due to missing Start* handlers * or subhandlers with different type-level types. */ for(upb_msg_field_begin(&j, h->msg); !upb_msg_field_done(&j); upb_msg_field_next(&j)) { const upb_fielddef *f = upb_msg_iter_field(&j); if (upb_fielddef_isseq(f)) { if (!checkstart(h, f, UPB_HANDLER_STARTSEQ, s)) return false; } if (upb_fielddef_isstring(f)) { if (!checkstart(h, f, UPB_HANDLER_STARTSTR, s)) return false; } if (upb_fielddef_issubmsg(f)) { bool hashandler = false; if (upb_handlers_gethandler( h, handlers_getsel(h, f, UPB_HANDLER_STARTSUBMSG)) || upb_handlers_gethandler( h, handlers_getsel(h, f, UPB_HANDLER_ENDSUBMSG))) { hashandler = true; } if (upb_fielddef_isseq(f) && (upb_handlers_gethandler( h, handlers_getsel(h, f, UPB_HANDLER_STARTSEQ)) || upb_handlers_gethandler( h, handlers_getsel(h, f, UPB_HANDLER_ENDSEQ)))) { hashandler = true; } if (hashandler && !upb_handlers_getsubhandlers(h, f)) { /* For now we add an empty subhandlers in this case. It makes the * decoder code generator simpler, because it only has to handle two * cases (submessage has handlers or not) as opposed to three * (submessage has handlers in enclosing message but no subhandlers). * * This makes parsing less efficient in the case that we want to * notice a submessage but skip its contents (like if we're testing * for submessage presence or counting the number of repeated * submessages). In this case we will end up parsing the submessage * field by field and throwing away the results for each, instead of * skipping the whole delimited thing at once. If this is an issue we * can revisit it, but do remember that this only arises when you have * handlers (startseq/startsubmsg/endsubmsg/endseq) set for the * submessage but no subhandlers. The uses cases for this are * limited. */ upb_handlers *sub = upb_handlers_new(upb_fielddef_msgsubdef(f), &sub); upb_handlers_setsubhandlers(h, f, sub); upb_handlers_unref(sub, &sub); } /* TODO(haberman): check type of submessage. * This is slightly tricky; also consider whether we should check that * they match at setsubhandlers time. */ } } } if (!upb_refcounted_freeze((upb_refcounted*const*)handlers, n, s, UPB_MAX_HANDLER_DEPTH)) { return false; } return true; } upb_handlertype_t upb_handlers_getprimitivehandlertype(const upb_fielddef *f) { switch (upb_fielddef_type(f)) { case UPB_TYPE_INT32: case UPB_TYPE_ENUM: return UPB_HANDLER_INT32; case UPB_TYPE_INT64: return UPB_HANDLER_INT64; case UPB_TYPE_UINT32: return UPB_HANDLER_UINT32; case UPB_TYPE_UINT64: return UPB_HANDLER_UINT64; case UPB_TYPE_FLOAT: return UPB_HANDLER_FLOAT; case UPB_TYPE_DOUBLE: return UPB_HANDLER_DOUBLE; case UPB_TYPE_BOOL: return UPB_HANDLER_BOOL; default: UPB_ASSERT(false); return -1; /* Invalid input. */ } } bool upb_handlers_getselector(const upb_fielddef *f, upb_handlertype_t type, upb_selector_t *s) { switch (type) { case UPB_HANDLER_INT32: case UPB_HANDLER_INT64: case UPB_HANDLER_UINT32: case UPB_HANDLER_UINT64: case UPB_HANDLER_FLOAT: case UPB_HANDLER_DOUBLE: case UPB_HANDLER_BOOL: if (!upb_fielddef_isprimitive(f) || upb_handlers_getprimitivehandlertype(f) != type) return false; *s = f->selector_base; break; case UPB_HANDLER_STRING: if (upb_fielddef_isstring(f)) { *s = f->selector_base; } else if (upb_fielddef_lazy(f)) { *s = f->selector_base + 3; } else { return false; } break; case UPB_HANDLER_STARTSTR: if (upb_fielddef_isstring(f) || upb_fielddef_lazy(f)) { *s = f->selector_base + 1; } else { return false; } break; case UPB_HANDLER_ENDSTR: if (upb_fielddef_isstring(f) || upb_fielddef_lazy(f)) { *s = f->selector_base + 2; } else { return false; } break; case UPB_HANDLER_STARTSEQ: if (!upb_fielddef_isseq(f)) return false; *s = f->selector_base - 2; break; case UPB_HANDLER_ENDSEQ: if (!upb_fielddef_isseq(f)) return false; *s = f->selector_base - 1; break; case UPB_HANDLER_STARTSUBMSG: if (!upb_fielddef_issubmsg(f)) return false; /* Selectors for STARTSUBMSG are at the beginning of the table so that the * selector can also be used as an index into the "sub" array of * subhandlers. The indexes for the two into these two tables are the * same, except that in the handler table the static selectors come first. */ *s = f->index_ + UPB_STATIC_SELECTOR_COUNT; break; case UPB_HANDLER_ENDSUBMSG: if (!upb_fielddef_issubmsg(f)) return false; *s = f->selector_base; break; } UPB_ASSERT((size_t)*s < upb_fielddef_containingtype(f)->selector_count); return true; } uint32_t upb_handlers_selectorbaseoffset(const upb_fielddef *f) { return upb_fielddef_isseq(f) ? 2 : 0; } uint32_t upb_handlers_selectorcount(const upb_fielddef *f) { uint32_t ret = 1; if (upb_fielddef_isseq(f)) ret += 2; /* STARTSEQ/ENDSEQ */ if (upb_fielddef_isstring(f)) ret += 2; /* [STRING]/STARTSTR/ENDSTR */ if (upb_fielddef_issubmsg(f)) { /* ENDSUBMSG (STARTSUBMSG is at table beginning) */ ret += 0; if (upb_fielddef_lazy(f)) { /* STARTSTR/ENDSTR/STRING (for lazy) */ ret += 3; } } return ret; } /* upb_handlerattr ************************************************************/ void upb_handlerattr_init(upb_handlerattr *attr) { upb_handlerattr from = UPB_HANDLERATTR_INITIALIZER; memcpy(attr, &from, sizeof(*attr)); } void upb_handlerattr_uninit(upb_handlerattr *attr) { UPB_UNUSED(attr); } bool upb_handlerattr_sethandlerdata(upb_handlerattr *attr, const void *hd) { attr->handler_data_ = hd; return true; } bool upb_handlerattr_setclosuretype(upb_handlerattr *attr, const void *type) { attr->closure_type_ = type; return true; } const void *upb_handlerattr_closuretype(const upb_handlerattr *attr) { return attr->closure_type_; } bool upb_handlerattr_setreturnclosuretype(upb_handlerattr *attr, const void *type) { attr->return_closure_type_ = type; return true; } const void *upb_handlerattr_returnclosuretype(const upb_handlerattr *attr) { return attr->return_closure_type_; } bool upb_handlerattr_setalwaysok(upb_handlerattr *attr, bool alwaysok) { attr->alwaysok_ = alwaysok; return true; } bool upb_handlerattr_alwaysok(const upb_handlerattr *attr) { return attr->alwaysok_; } /* upb_bufhandle **************************************************************/ size_t upb_bufhandle_objofs(const upb_bufhandle *h) { return h->objofs_; } /* upb_byteshandler ***********************************************************/ void upb_byteshandler_init(upb_byteshandler* h) { memset(h, 0, sizeof(*h)); } /* For when we support handlerfree callbacks. */ void upb_byteshandler_uninit(upb_byteshandler* h) { UPB_UNUSED(h); } bool upb_byteshandler_setstartstr(upb_byteshandler *h, upb_startstr_handlerfunc *func, void *d) { h->table[UPB_STARTSTR_SELECTOR].func = (upb_func*)func; h->table[UPB_STARTSTR_SELECTOR].attr.handler_data_ = d; return true; } bool upb_byteshandler_setstring(upb_byteshandler *h, upb_string_handlerfunc *func, void *d) { h->table[UPB_STRING_SELECTOR].func = (upb_func*)func; h->table[UPB_STRING_SELECTOR].attr.handler_data_ = d; return true; } bool upb_byteshandler_setendstr(upb_byteshandler *h, upb_endfield_handlerfunc *func, void *d) { h->table[UPB_ENDSTR_SELECTOR].func = (upb_func*)func; h->table[UPB_ENDSTR_SELECTOR].attr.handler_data_ = d; return true; } static bool is_power_of_two(size_t val) { return (val & (val - 1)) == 0; } /* Align up to the given power of 2. */ static size_t align_up(size_t val, size_t align) { UPB_ASSERT(is_power_of_two(align)); return (val + align - 1) & ~(align - 1); } static size_t div_round_up(size_t n, size_t d) { return (n + d - 1) / d; } bool upb_fieldtype_mapkeyok(upb_fieldtype_t type) { return type == UPB_TYPE_BOOL || type == UPB_TYPE_INT32 || type == UPB_TYPE_UINT32 || type == UPB_TYPE_INT64 || type == UPB_TYPE_UINT64 || type == UPB_TYPE_STRING; } void *upb_array_pack(const upb_array *arr, void *p, size_t *ofs, size_t size); void *upb_map_pack(const upb_map *map, void *p, size_t *ofs, size_t size); #define CHARPTR_AT(msg, ofs) ((char*)msg + ofs) #define ENCODE_MAX_NESTING 64 #define CHECK_TRUE(x) if (!(x)) { return false; } /** upb_msgval ****************************************************************/ #define upb_alignof(t) offsetof(struct { char c; t x; }, x) /* These functions will generate real memcpy() calls on ARM sadly, because * the compiler assumes they might not be aligned. */ static upb_msgval upb_msgval_read(const void *p, size_t ofs, uint8_t size) { upb_msgval val; p = (char*)p + ofs; memcpy(&val, p, size); return val; } static void upb_msgval_write(void *p, size_t ofs, upb_msgval val, uint8_t size) { p = (char*)p + ofs; memcpy(p, &val, size); } static size_t upb_msgval_sizeof(upb_fieldtype_t type) { switch (type) { case UPB_TYPE_DOUBLE: case UPB_TYPE_INT64: case UPB_TYPE_UINT64: return 8; case UPB_TYPE_ENUM: case UPB_TYPE_INT32: case UPB_TYPE_UINT32: case UPB_TYPE_FLOAT: return 4; case UPB_TYPE_BOOL: return 1; case UPB_TYPE_BYTES: case UPB_TYPE_MESSAGE: return sizeof(void*); case UPB_TYPE_STRING: return sizeof(char*) + sizeof(size_t); } UPB_UNREACHABLE(); } static uint8_t upb_msg_fieldsize(const upb_fielddef *f) { if (upb_fielddef_isseq(f)) { return sizeof(void*); } else { return upb_msgval_sizeof(upb_fielddef_type(f)); } } /* TODO(haberman): this is broken right now because upb_msgval can contain * a char* / size_t pair, which is too big for a upb_value. To fix this * we'll probably need to dynamically allocate a upb_msgval and store a * pointer to that in the tables for extensions/maps. */ static upb_value upb_toval(upb_msgval val) { upb_value ret; UPB_UNUSED(val); memset(&ret, 0, sizeof(upb_value)); /* XXX */ return ret; } static upb_msgval upb_msgval_fromval(upb_value val) { upb_msgval ret; UPB_UNUSED(val); memset(&ret, 0, sizeof(upb_msgval)); /* XXX */ return ret; } static upb_ctype_t upb_fieldtotabtype(upb_fieldtype_t type) { switch (type) { case UPB_TYPE_FLOAT: return UPB_CTYPE_FLOAT; case UPB_TYPE_DOUBLE: return UPB_CTYPE_DOUBLE; case UPB_TYPE_BOOL: return UPB_CTYPE_BOOL; case UPB_TYPE_BYTES: case UPB_TYPE_MESSAGE: case UPB_TYPE_STRING: return UPB_CTYPE_CONSTPTR; case UPB_TYPE_ENUM: case UPB_TYPE_INT32: return UPB_CTYPE_INT32; case UPB_TYPE_UINT32: return UPB_CTYPE_UINT32; case UPB_TYPE_INT64: return UPB_CTYPE_INT64; case UPB_TYPE_UINT64: return UPB_CTYPE_UINT64; default: UPB_ASSERT(false); return 0; } } static upb_msgval upb_msgval_fromdefault(const upb_fielddef *f) { /* TODO(haberman): improve/optimize this (maybe use upb_msgval in fielddef) */ switch (upb_fielddef_type(f)) { case UPB_TYPE_FLOAT: return upb_msgval_float(upb_fielddef_defaultfloat(f)); case UPB_TYPE_DOUBLE: return upb_msgval_double(upb_fielddef_defaultdouble(f)); case UPB_TYPE_BOOL: return upb_msgval_bool(upb_fielddef_defaultbool(f)); case UPB_TYPE_STRING: case UPB_TYPE_BYTES: { size_t len; const char *ptr = upb_fielddef_defaultstr(f, &len); return upb_msgval_str(ptr, len); } case UPB_TYPE_MESSAGE: return upb_msgval_msg(NULL); case UPB_TYPE_ENUM: case UPB_TYPE_INT32: return upb_msgval_int32(upb_fielddef_defaultint32(f)); case UPB_TYPE_UINT32: return upb_msgval_uint32(upb_fielddef_defaultuint32(f)); case UPB_TYPE_INT64: return upb_msgval_int64(upb_fielddef_defaultint64(f)); case UPB_TYPE_UINT64: return upb_msgval_uint64(upb_fielddef_defaultuint64(f)); default: UPB_ASSERT(false); return upb_msgval_msg(NULL); } } /** upb_msglayout *************************************************************/ struct upb_msglayout { upb_msgfactory *factory; const upb_msgdef *msgdef; size_t size; size_t extdict_offset; void *default_msg; uint32_t *field_offsets; uint32_t *case_offsets; uint32_t *hasbits; bool has_extdict; uint8_t align; }; static void upb_msg_checkfield(const upb_msglayout *l, const upb_fielddef *f) { UPB_ASSERT(l->msgdef == upb_fielddef_containingtype(f)); } static void upb_msglayout_free(upb_msglayout *l) { upb_gfree(l->default_msg); upb_gfree(l); } const upb_msgdef *upb_msglayout_msgdef(const upb_msglayout *l) { return l->msgdef; } static size_t upb_msglayout_place(upb_msglayout *l, size_t size) { size_t ret; l->size = align_up(l->size, size); l->align = align_up(l->align, size); ret = l->size; l->size += size; return ret; } static uint32_t upb_msglayout_offset(const upb_msglayout *l, const upb_fielddef *f) { return l->field_offsets[upb_fielddef_index(f)]; } static uint32_t upb_msglayout_hasbit(const upb_msglayout *l, const upb_fielddef *f) { return l->hasbits[upb_fielddef_index(f)]; } static bool upb_msglayout_initdefault(upb_msglayout *l) { const upb_msgdef *m = l->msgdef; upb_msg_field_iter it; if (upb_msgdef_syntax(m) == UPB_SYNTAX_PROTO2 && l->size) { /* Allocate default message and set default values in it. */ l->default_msg = upb_gmalloc(l->size); if (!l->default_msg) { return false; } memset(l->default_msg, 0, l->size); for (upb_msg_field_begin(&it, m); !upb_msg_field_done(&it); upb_msg_field_next(&it)) { const upb_fielddef* f = upb_msg_iter_field(&it); if (upb_fielddef_containingoneof(f)) { continue; } if (!upb_fielddef_isstring(f) && !upb_fielddef_issubmsg(f) && !upb_fielddef_isseq(f)) { upb_msg_set(l->default_msg, f, upb_msgval_fromdefault(f), l); } } } return true; } static upb_msglayout *upb_msglayout_new(const upb_msgdef *m) { upb_msg_field_iter it; upb_msg_oneof_iter oit; upb_msglayout *l; size_t hasbit; size_t array_size = upb_msgdef_numfields(m) + upb_msgdef_numoneofs(m); if (upb_msgdef_syntax(m) == UPB_SYNTAX_PROTO2) { array_size += upb_msgdef_numfields(m); /* hasbits. */ } l = upb_gmalloc(sizeof(*l) + (sizeof(uint32_t) * array_size)); if (!l) return NULL; memset(l, 0, sizeof(*l)); l->msgdef = m; l->align = 1; l->field_offsets = (uint32_t*)CHARPTR_AT(l, sizeof(*l)); l->case_offsets = l->field_offsets + upb_msgdef_numfields(m); l->hasbits = l->case_offsets + upb_msgdef_numoneofs(m); /* Allocate data offsets in three stages: * * 1. hasbits. * 2. regular fields. * 3. oneof fields. * * OPT: There is a lot of room for optimization here to minimize the size. */ /* Allocate hasbits. Start at sizeof(void*) for upb_alloc*. */ for (upb_msg_field_begin(&it, m), hasbit = sizeof(void*) * 8; !upb_msg_field_done(&it); upb_msg_field_next(&it)) { const upb_fielddef* f = upb_msg_iter_field(&it); if (upb_fielddef_haspresence(f) && !upb_fielddef_containingoneof(f)) { l->hasbits[upb_fielddef_index(f)] = hasbit++; } } /* Account for space used by hasbits. */ l->size = div_round_up(hasbit, 8); /* Allocate non-oneof fields. */ for (upb_msg_field_begin(&it, m); !upb_msg_field_done(&it); upb_msg_field_next(&it)) { const upb_fielddef* f = upb_msg_iter_field(&it); size_t field_size = upb_msg_fieldsize(f); size_t index = upb_fielddef_index(f); if (upb_fielddef_containingoneof(f)) { /* Oneofs are handled separately below. */ continue; } l->field_offsets[index] = upb_msglayout_place(l, field_size); } /* Allocate oneof fields. Each oneof field consists of a uint32 for the case * and space for the actual data. */ for (upb_msg_oneof_begin(&oit, m); !upb_msg_oneof_done(&oit); upb_msg_oneof_next(&oit)) { const upb_oneofdef* oneof = upb_msg_iter_oneof(&oit); upb_oneof_iter fit; size_t case_size = sizeof(uint32_t); /* Could potentially optimize this. */ size_t field_size = 0; size_t case_offset; size_t val_offset; /* Calculate field size: the max of all field sizes. */ for (upb_oneof_begin(&fit, oneof); !upb_oneof_done(&fit); upb_oneof_next(&fit)) { const upb_fielddef* f = upb_oneof_iter_field(&fit); field_size = UPB_MAX(field_size, upb_msg_fieldsize(f)); } /* Align and allocate case offset. */ case_offset = upb_msglayout_place(l, case_size); val_offset = upb_msglayout_place(l, field_size); l->case_offsets[upb_oneofdef_index(oneof)] = case_offset; /* Assign all fields in the oneof this same offset. */ for (upb_oneof_begin(&fit, oneof); !upb_oneof_done(&fit); upb_oneof_next(&fit)) { const upb_fielddef* f = upb_oneof_iter_field(&fit); l->field_offsets[upb_fielddef_index(f)] = val_offset; } } /* Size of the entire structure should be a multiple of its greatest * alignment. */ l->size = align_up(l->size, l->align); if (upb_msglayout_initdefault(l)) { return l; } else { upb_msglayout_free(l); return NULL; } } upb_msgfactory *upb_msglayout_factory(const upb_msglayout *layout) { return layout->factory; } /** upb_msgfactory ************************************************************/ struct upb_msgfactory { const upb_symtab *symtab; /* We own a ref. */ upb_inttable layouts; upb_inttable mergehandlers; }; upb_msgfactory *upb_msgfactory_new(const upb_symtab *symtab) { upb_msgfactory *ret = upb_gmalloc(sizeof(*ret)); ret->symtab = symtab; upb_inttable_init(&ret->layouts, UPB_CTYPE_PTR); upb_inttable_init(&ret->mergehandlers, UPB_CTYPE_CONSTPTR); return ret; } void upb_msgfactory_free(upb_msgfactory *f) { upb_inttable_iter i; upb_inttable_begin(&i, &f->layouts); for(; !upb_inttable_done(&i); upb_inttable_next(&i)) { upb_msglayout *l = upb_value_getptr(upb_inttable_iter_value(&i)); upb_msglayout_free(l); } upb_inttable_begin(&i, &f->mergehandlers); for(; !upb_inttable_done(&i); upb_inttable_next(&i)) { const upb_handlers *h = upb_value_getconstptr(upb_inttable_iter_value(&i)); upb_handlers_unref(h, f); } upb_inttable_uninit(&f->layouts); upb_inttable_uninit(&f->mergehandlers); upb_gfree(f); } const upb_symtab *upb_msgfactory_symtab(const upb_msgfactory *f) { return f->symtab; } const upb_msglayout *upb_msgfactory_getlayout(upb_msgfactory *f, const upb_msgdef *m) { upb_value v; UPB_ASSERT(upb_symtab_lookupmsg(f->symtab, upb_msgdef_fullname(m)) == m); UPB_ASSERT(!upb_msgdef_mapentry(m)); if (upb_inttable_lookupptr(&f->layouts, m, &v)) { UPB_ASSERT(upb_value_getptr(v)); return upb_value_getptr(v); } else { upb_msgfactory *mutable_f = (void*)f; upb_msglayout *l = upb_msglayout_new(m); upb_inttable_insertptr(&mutable_f->layouts, m, upb_value_ptr(l)); UPB_ASSERT(l); l->factory = f; return l; } } /* Our handlers that we don't expose externally. */ void *upb_msg_startstr(void *msg, const void *hd, size_t size_hint) { uint32_t ofs = (uintptr_t)hd; /* We pass NULL here because we know we can get away with it. */ upb_alloc *alloc = upb_msg_alloc(msg, NULL); upb_msgval val; UPB_UNUSED(size_hint); val = upb_msgval_read(msg, ofs, upb_msgval_sizeof(UPB_TYPE_STRING)); upb_free(alloc, (void*)val.str.ptr); val.str.ptr = NULL; val.str.len = 0; upb_msgval_write(msg, ofs, val, upb_msgval_sizeof(UPB_TYPE_STRING)); return msg; } size_t upb_msg_str(void *msg, const void *hd, const char *ptr, size_t size, const upb_bufhandle *handle) { uint32_t ofs = (uintptr_t)hd; /* We pass NULL here because we know we can get away with it. */ upb_alloc *alloc = upb_msg_alloc(msg, NULL); upb_msgval val; size_t newsize; UPB_UNUSED(handle); val = upb_msgval_read(msg, ofs, upb_msgval_sizeof(UPB_TYPE_STRING)); newsize = val.str.len + size; val.str.ptr = upb_realloc(alloc, (void*)val.str.ptr, val.str.len, newsize); if (!val.str.ptr) { return false; } memcpy((char*)val.str.ptr + val.str.len, ptr, size); val.str.len = newsize; upb_msgval_write(msg, ofs, val, upb_msgval_sizeof(UPB_TYPE_STRING)); return size; } static void callback(const void *closure, upb_handlers *h) { upb_msgfactory *factory = (upb_msgfactory*)closure; const upb_msgdef *md = upb_handlers_msgdef(h); const upb_msglayout* layout = upb_msgfactory_getlayout(factory, md); upb_msg_field_iter i; UPB_UNUSED(factory); for(upb_msg_field_begin(&i, md); !upb_msg_field_done(&i); upb_msg_field_next(&i)) { const upb_fielddef *f = upb_msg_iter_field(&i); size_t offset = upb_msglayout_offset(layout, f); upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER; upb_handlerattr_sethandlerdata(&attr, (void*)offset); if (upb_fielddef_isseq(f)) { } else if (upb_fielddef_isstring(f)) { upb_handlers_setstartstr(h, f, upb_msg_startstr, &attr); upb_handlers_setstring(h, f, upb_msg_str, &attr); } else { upb_msg_setscalarhandler( h, f, offset, upb_msglayout_hasbit(layout, f)); } } } const upb_handlers *upb_msgfactory_getmergehandlers(upb_msgfactory *f, const upb_msgdef *m) { upb_msgfactory *mutable_f = (void*)f; /* TODO(haberman): properly cache these. */ const upb_handlers *ret = upb_handlers_newfrozen(m, f, callback, f); upb_inttable_push(&mutable_f->mergehandlers, upb_value_constptr(ret)); return ret; } const upb_visitorplan *upb_msgfactory_getvisitorplan(upb_msgfactory *f, const upb_handlers *h) { const upb_msgdef *md = upb_handlers_msgdef(h); return (const upb_visitorplan*)upb_msgfactory_getlayout(f, md); } /** upb_visitor ***************************************************************/ struct upb_visitor { const upb_msglayout *layout; upb_sink *sink; }; static upb_selector_t getsel2(const upb_fielddef *f, upb_handlertype_t type) { upb_selector_t ret; bool ok = upb_handlers_getselector(f, type, &ret); UPB_ASSERT(ok); return ret; } static bool upb_visitor_hasfield(const upb_msg *msg, const upb_fielddef *f, const upb_msglayout *layout) { if (upb_fielddef_isseq(f)) { return upb_msgval_getarr(upb_msg_get(msg, f, layout)) != NULL; } else if (upb_msgdef_syntax(upb_fielddef_containingtype(f)) == UPB_SYNTAX_PROTO2) { return upb_msg_has(msg, f, layout); } else { upb_msgval val = upb_msg_get(msg, f, layout); switch (upb_fielddef_type(f)) { case UPB_TYPE_FLOAT: return upb_msgval_getfloat(val) != 0; case UPB_TYPE_DOUBLE: return upb_msgval_getdouble(val) != 0; case UPB_TYPE_BOOL: return upb_msgval_getbool(val); case UPB_TYPE_ENUM: case UPB_TYPE_INT32: return upb_msgval_getint32(val) != 0; case UPB_TYPE_UINT32: return upb_msgval_getuint32(val) != 0; case UPB_TYPE_INT64: return upb_msgval_getint64(val) != 0; case UPB_TYPE_UINT64: return upb_msgval_getuint64(val) != 0; case UPB_TYPE_STRING: case UPB_TYPE_BYTES: return upb_msgval_getstr(val) && upb_msgval_getstrlen(val) > 0; case UPB_TYPE_MESSAGE: return upb_msgval_getmsg(val) != NULL; } UPB_UNREACHABLE(); } } static bool upb_visitor_visitmsg2(const upb_msg *msg, const upb_msglayout *layout, upb_sink *sink, int depth) { const upb_msgdef *md = upb_msglayout_msgdef(layout); upb_msg_field_iter i; upb_status status; upb_sink_startmsg(sink); /* Protect against cycles (possible because users may freely reassign message * and repeated fields) by imposing a maximum recursion depth. */ if (depth > ENCODE_MAX_NESTING) { return false; } for (upb_msg_field_begin(&i, md); !upb_msg_field_done(&i); upb_msg_field_next(&i)) { upb_fielddef *f = upb_msg_iter_field(&i); upb_msgval val; if (!upb_visitor_hasfield(msg, f, layout)) { continue; } val = upb_msg_get(msg, f, layout); if (upb_fielddef_isseq(f)) { const upb_array *arr = upb_msgval_getarr(val); UPB_ASSERT(arr); /* TODO: putary(ary, f, sink, depth);*/ } else if (upb_fielddef_issubmsg(f)) { const upb_map *map = upb_msgval_getmap(val); UPB_ASSERT(map); /* TODO: putmap(map, f, sink, depth);*/ } else if (upb_fielddef_isstring(f)) { /* TODO putstr(); */ } else { upb_selector_t sel = getsel2(f, upb_handlers_getprimitivehandlertype(f)); UPB_ASSERT(upb_fielddef_isprimitive(f)); switch (upb_fielddef_type(f)) { case UPB_TYPE_FLOAT: CHECK_TRUE(upb_sink_putfloat(sink, sel, upb_msgval_getfloat(val))); break; case UPB_TYPE_DOUBLE: CHECK_TRUE( upb_sink_putdouble(sink, sel, upb_msgval_getdouble(val))); break; case UPB_TYPE_BOOL: CHECK_TRUE(upb_sink_putbool(sink, sel, upb_msgval_getbool(val))); break; case UPB_TYPE_ENUM: case UPB_TYPE_INT32: CHECK_TRUE(upb_sink_putint32(sink, sel, upb_msgval_getint32(val))); break; case UPB_TYPE_UINT32: CHECK_TRUE( upb_sink_putuint32(sink, sel, upb_msgval_getuint32(val))); break; case UPB_TYPE_INT64: CHECK_TRUE(upb_sink_putint64(sink, sel, upb_msgval_getint64(val))); break; case UPB_TYPE_UINT64: CHECK_TRUE( upb_sink_putuint64(sink, sel, upb_msgval_getuint64(val))); break; case UPB_TYPE_STRING: case UPB_TYPE_BYTES: case UPB_TYPE_MESSAGE: UPB_UNREACHABLE(); } } } upb_sink_endmsg(sink, &status); return true; } upb_visitor *upb_visitor_create(upb_env *e, const upb_visitorplan *vp, upb_sink *output) { upb_visitor *visitor = upb_env_malloc(e, sizeof(*visitor)); visitor->layout = (const upb_msglayout*)vp; visitor->sink = output; return visitor; } bool upb_visitor_visitmsg(upb_visitor *visitor, const upb_msg *msg) { return upb_visitor_visitmsg2(msg, visitor->layout, visitor->sink, 0); } /** upb_msg *******************************************************************/ /* If we always read/write as a consistent type to each address, this shouldn't * violate aliasing. */ #define DEREF(msg, ofs, type) *(type*)CHARPTR_AT(msg, ofs) static upb_inttable *upb_msg_trygetextdict(const upb_msg *msg, const upb_msglayout *l) { return l->has_extdict ? DEREF(msg, l->extdict_offset, upb_inttable*) : NULL; } static upb_inttable *upb_msg_getextdict(upb_msg *msg, const upb_msglayout *l, upb_alloc *a) { upb_inttable *ext_dict; UPB_ASSERT(l->has_extdict); ext_dict = upb_msg_trygetextdict(msg, l); if (!ext_dict) { ext_dict = upb_malloc(a, sizeof(upb_inttable)); if (!ext_dict) { return NULL; } /* Use an 8-byte type to ensure all bytes are copied. */ if (!upb_inttable_init2(ext_dict, UPB_CTYPE_INT64, a)) { upb_free(a, ext_dict); return NULL; } DEREF(msg, l->extdict_offset, upb_inttable*) = ext_dict; } return ext_dict; } static uint32_t upb_msg_getoneofint(const upb_msg *msg, const upb_oneofdef *o, const upb_msglayout *l) { size_t oneof_ofs = l->case_offsets[upb_oneofdef_index(o)]; return DEREF(msg, oneof_ofs, uint8_t); } static void upb_msg_setoneofcase(const upb_msg *msg, const upb_oneofdef *o, const upb_msglayout *l, uint32_t val) { size_t oneof_ofs = l->case_offsets[upb_oneofdef_index(o)]; DEREF(msg, oneof_ofs, uint8_t) = val; } static bool upb_msg_oneofis(const upb_msg *msg, const upb_msglayout *l, const upb_oneofdef *o, const upb_fielddef *f) { return upb_msg_getoneofint(msg, o, l) == upb_fielddef_number(f); } size_t upb_msg_sizeof(const upb_msglayout *l) { return l->size; } void upb_msg_init(upb_msg *msg, const upb_msglayout *l, upb_alloc *a) { if (l->default_msg) { memcpy(msg, l->default_msg, l->size); } else { memset(msg, 0, l->size); } /* Set arena pointer. */ memcpy(msg, &a, sizeof(a)); } void upb_msg_uninit(upb_msg *msg, const upb_msglayout *l) { upb_inttable *ext_dict = upb_msg_trygetextdict(msg, l); if (ext_dict) { upb_inttable_uninit2(ext_dict, upb_msg_alloc(msg, l)); } } upb_msg *upb_msg_new(const upb_msglayout *l, upb_alloc *a) { upb_msg *msg = upb_malloc(a, upb_msg_sizeof(l)); if (msg) { upb_msg_init(msg, l, a); } return msg; } void upb_msg_free(upb_msg *msg, const upb_msglayout *l) { upb_msg_uninit(msg, l); upb_free(upb_msg_alloc(msg, l), msg); } upb_alloc *upb_msg_alloc(const upb_msg *msg, const upb_msglayout *l) { upb_alloc *alloc; UPB_UNUSED(l); memcpy(&alloc, msg, sizeof(alloc)); return alloc; } bool upb_msg_has(const upb_msg *msg, const upb_fielddef *f, const upb_msglayout *l) { const upb_oneofdef *o; upb_msg_checkfield(l, f); UPB_ASSERT(upb_fielddef_haspresence(f)); if (upb_fielddef_isextension(f)) { /* Extensions are set when they are present in the extension dict. */ upb_inttable *ext_dict = upb_msg_trygetextdict(msg, l); upb_value v; return ext_dict != NULL && upb_inttable_lookup32(ext_dict, upb_fielddef_number(f), &v); } else if ((o = upb_fielddef_containingoneof(f)) != NULL) { /* Oneofs are set when the oneof number is set to this field. */ return upb_msg_getoneofint(msg, o, l) == upb_fielddef_number(f); } else { /* Other fields are set when their hasbit is set. */ uint32_t hasbit = l->hasbits[upb_fielddef_index(f)]; return DEREF(msg, hasbit / 8, char) | (1 << (hasbit % 8)); } } upb_msgval upb_msg_get(const upb_msg *msg, const upb_fielddef *f, const upb_msglayout *l) { upb_msg_checkfield(l, f); if (upb_fielddef_isextension(f)) { upb_inttable *ext_dict = upb_msg_trygetextdict(msg, l); upb_value val; if (upb_inttable_lookup32(ext_dict, upb_fielddef_number(f), &val)) { return upb_msgval_fromval(val); } else { return upb_msgval_fromdefault(f); } } else { size_t ofs = l->field_offsets[upb_fielddef_index(f)]; const upb_oneofdef *o = upb_fielddef_containingoneof(f); upb_msgval ret; if (o && !upb_msg_oneofis(msg, l, o, f)) { /* Oneof defaults can't come from the message because the memory is reused * by all types in the oneof. */ return upb_msgval_fromdefault(f); } ret = upb_msgval_read(msg, ofs, upb_msg_fieldsize(f)); return ret; } } bool upb_msg_set(upb_msg *msg, const upb_fielddef *f, upb_msgval val, const upb_msglayout *l) { upb_alloc *a = upb_msg_alloc(msg, l); upb_msg_checkfield(l, f); if (upb_fielddef_isextension(f)) { /* TODO(haberman): introduce table API that can do this in one call. */ upb_inttable *ext = upb_msg_getextdict(msg, l, a); upb_value val2 = upb_toval(val); if (!upb_inttable_replace(ext, upb_fielddef_number(f), val2) && !upb_inttable_insert2(ext, upb_fielddef_number(f), val2, a)) { return false; } } else { size_t ofs = l->field_offsets[upb_fielddef_index(f)]; const upb_oneofdef *o = upb_fielddef_containingoneof(f); if (o) { upb_msg_setoneofcase(msg, o, l, upb_fielddef_number(f)); } upb_msgval_write(msg, ofs, val, upb_msg_fieldsize(f)); } return true; } /** upb_array *****************************************************************/ struct upb_array { upb_fieldtype_t type; uint8_t element_size; void *data; /* Each element is element_size. */ size_t len; /* Measured in elements. */ size_t size; /* Measured in elements. */ upb_alloc *alloc; }; #define DEREF_ARR(arr, i, type) ((type*)arr->data)[i] size_t upb_array_sizeof(upb_fieldtype_t type) { UPB_UNUSED(type); return sizeof(upb_array); } void upb_array_init(upb_array *arr, upb_fieldtype_t type, upb_alloc *alloc) { arr->type = type; arr->data = NULL; arr->len = 0; arr->size = 0; arr->element_size = upb_msgval_sizeof(type); arr->alloc = alloc; } void upb_array_uninit(upb_array *arr) { upb_free(arr->alloc, arr->data); } upb_array *upb_array_new(upb_fieldtype_t type, upb_alloc *a) { upb_array *ret = upb_malloc(a, upb_array_sizeof(type)); if (ret) { upb_array_init(ret, type, a); } return ret; } void upb_array_free(upb_array *arr) { upb_array_uninit(arr); upb_free(arr->alloc, arr); } size_t upb_array_size(const upb_array *arr) { return arr->len; } upb_fieldtype_t upb_array_type(const upb_array *arr) { return arr->type; } upb_msgval upb_array_get(const upb_array *arr, size_t i) { UPB_ASSERT(i < arr->len); return upb_msgval_read(arr->data, i * arr->element_size, arr->element_size); } bool upb_array_set(upb_array *arr, size_t i, upb_msgval val) { UPB_ASSERT(i <= arr->len); if (i == arr->len) { /* Extending the array. */ if (i == arr->size) { /* Need to reallocate. */ size_t new_size = UPB_MAX(arr->size * 2, 8); size_t new_bytes = new_size * arr->element_size; size_t old_bytes = arr->size * arr->element_size; upb_msgval *new_data = upb_realloc(arr->alloc, arr->data, old_bytes, new_bytes); if (!new_data) { return false; } arr->data = new_data; arr->size = new_size; } arr->len = i + 1; } upb_msgval_write(arr->data, i * arr->element_size, val, arr->element_size); return true; } /** upb_map *******************************************************************/ struct upb_map { upb_fieldtype_t key_type; upb_fieldtype_t val_type; /* We may want to optimize this to use inttable where possible, for greater * efficiency and lower memory footprint. */ upb_strtable strtab; upb_alloc *alloc; }; static void upb_map_tokey(upb_fieldtype_t type, upb_msgval *key, const char **out_key, size_t *out_len) { switch (type) { case UPB_TYPE_STRING: /* Point to string data of the input key. */ *out_key = key->str.ptr; *out_len = key->str.len; return; case UPB_TYPE_BOOL: case UPB_TYPE_INT32: case UPB_TYPE_UINT32: case UPB_TYPE_INT64: case UPB_TYPE_UINT64: /* Point to the key itself. XXX: big-endian. */ *out_key = (const char*)key; *out_len = upb_msgval_sizeof(type); return; case UPB_TYPE_BYTES: case UPB_TYPE_DOUBLE: case UPB_TYPE_ENUM: case UPB_TYPE_FLOAT: case UPB_TYPE_MESSAGE: break; /* Cannot be a map key. */ } UPB_UNREACHABLE(); } static upb_msgval upb_map_fromkey(upb_fieldtype_t type, const char *key, size_t len) { switch (type) { case UPB_TYPE_STRING: return upb_msgval_str(key, len); case UPB_TYPE_BOOL: case UPB_TYPE_INT32: case UPB_TYPE_UINT32: case UPB_TYPE_INT64: case UPB_TYPE_UINT64: return upb_msgval_read(key, 0, upb_msgval_sizeof(type)); case UPB_TYPE_BYTES: case UPB_TYPE_DOUBLE: case UPB_TYPE_ENUM: case UPB_TYPE_FLOAT: case UPB_TYPE_MESSAGE: break; /* Cannot be a map key. */ } UPB_UNREACHABLE(); } size_t upb_map_sizeof(upb_fieldtype_t ktype, upb_fieldtype_t vtype) { /* Size does not currently depend on key/value type. */ UPB_UNUSED(ktype); UPB_UNUSED(vtype); return sizeof(upb_map); } bool upb_map_init(upb_map *map, upb_fieldtype_t ktype, upb_fieldtype_t vtype, upb_alloc *a) { upb_ctype_t vtabtype = upb_fieldtotabtype(vtype); UPB_ASSERT(upb_fieldtype_mapkeyok(ktype)); map->key_type = ktype; map->val_type = vtype; map->alloc = a; if (!upb_strtable_init2(&map->strtab, vtabtype, a)) { return false; } return true; } void upb_map_uninit(upb_map *map) { upb_strtable_uninit2(&map->strtab, map->alloc); } upb_map *upb_map_new(upb_fieldtype_t ktype, upb_fieldtype_t vtype, upb_alloc *a) { upb_map *map = upb_malloc(a, upb_map_sizeof(ktype, vtype)); if (!map) { return NULL; } if (!upb_map_init(map, ktype, vtype, a)) { return NULL; } return map; } void upb_map_free(upb_map *map) { upb_map_uninit(map); upb_free(map->alloc, map); } size_t upb_map_size(const upb_map *map) { return upb_strtable_count(&map->strtab); } upb_fieldtype_t upb_map_keytype(const upb_map *map) { return map->key_type; } upb_fieldtype_t upb_map_valuetype(const upb_map *map) { return map->val_type; } bool upb_map_get(const upb_map *map, upb_msgval key, upb_msgval *val) { upb_value tabval; const char *key_str; size_t key_len; bool ret; upb_map_tokey(map->key_type, &key, &key_str, &key_len); ret = upb_strtable_lookup2(&map->strtab, key_str, key_len, &tabval); if (ret) { memcpy(val, &tabval, sizeof(tabval)); } return ret; } bool upb_map_set(upb_map *map, upb_msgval key, upb_msgval val, upb_msgval *removed) { const char *key_str; size_t key_len; upb_value tabval = upb_toval(val); upb_value removedtabval; upb_alloc *a = map->alloc; upb_map_tokey(map->key_type, &key, &key_str, &key_len); /* TODO(haberman): add overwrite operation to minimize number of lookups. */ if (upb_strtable_lookup2(&map->strtab, key_str, key_len, NULL)) { upb_strtable_remove3(&map->strtab, key_str, key_len, &removedtabval, a); memcpy(&removed, &removedtabval, sizeof(removed)); } return upb_strtable_insert3(&map->strtab, key_str, key_len, tabval, a); } bool upb_map_del(upb_map *map, upb_msgval key) { const char *key_str; size_t key_len; upb_alloc *a = map->alloc; upb_map_tokey(map->key_type, &key, &key_str, &key_len); return upb_strtable_remove3(&map->strtab, key_str, key_len, NULL, a); } /** upb_mapiter ***************************************************************/ struct upb_mapiter { upb_strtable_iter iter; upb_fieldtype_t key_type; }; size_t upb_mapiter_sizeof() { return sizeof(upb_mapiter); } void upb_mapiter_begin(upb_mapiter *i, const upb_map *map) { upb_strtable_begin(&i->iter, &map->strtab); i->key_type = map->key_type; } upb_mapiter *upb_mapiter_new(const upb_map *t, upb_alloc *a) { upb_mapiter *ret = upb_malloc(a, upb_mapiter_sizeof()); if (!ret) { return NULL; } upb_mapiter_begin(ret, t); return ret; } void upb_mapiter_free(upb_mapiter *i, upb_alloc *a) { upb_free(a, i); } void upb_mapiter_next(upb_mapiter *i) { upb_strtable_next(&i->iter); } bool upb_mapiter_done(const upb_mapiter *i) { return upb_strtable_done(&i->iter); } upb_msgval upb_mapiter_key(const upb_mapiter *i) { return upb_map_fromkey(i->key_type, upb_strtable_iter_key(&i->iter), upb_strtable_iter_keylength(&i->iter)); } upb_msgval upb_mapiter_value(const upb_mapiter *i) { return upb_msgval_fromval(upb_strtable_iter_value(&i->iter)); } void upb_mapiter_setdone(upb_mapiter *i) { upb_strtable_iter_setdone(&i->iter); } bool upb_mapiter_isequal(const upb_mapiter *i1, const upb_mapiter *i2) { return upb_strtable_iter_isequal(&i1->iter, &i2->iter); } /** Handlers for upb_msg ******************************************************/ typedef struct { size_t offset; int32_t hasbit; } upb_msg_handlerdata; /* Fallback implementation if the handler is not specialized by the producer. */ #define MSG_WRITER(type, ctype) \ bool upb_msg_set ## type (void *c, const void *hd, ctype val) { \ uint8_t *m = c; \ const upb_msg_handlerdata *d = hd; \ if (d->hasbit > 0) \ *(uint8_t*)&m[d->hasbit / 8] |= 1 << (d->hasbit % 8); \ *(ctype*)&m[d->offset] = val; \ return true; \ } \ MSG_WRITER(double, double) MSG_WRITER(float, float) MSG_WRITER(int32, int32_t) MSG_WRITER(int64, int64_t) MSG_WRITER(uint32, uint32_t) MSG_WRITER(uint64, uint64_t) MSG_WRITER(bool, bool) bool upb_msg_setscalarhandler(upb_handlers *h, const upb_fielddef *f, size_t offset, int32_t hasbit) { upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER; bool ok; upb_msg_handlerdata *d = upb_gmalloc(sizeof(*d)); if (!d) return false; d->offset = offset; d->hasbit = hasbit; upb_handlerattr_sethandlerdata(&attr, d); upb_handlerattr_setalwaysok(&attr, true); upb_handlers_addcleanup(h, d, upb_gfree); #define TYPE(u, l) \ case UPB_TYPE_##u: \ ok = upb_handlers_set##l(h, f, upb_msg_set##l, &attr); break; ok = false; switch (upb_fielddef_type(f)) { TYPE(INT64, int64); TYPE(INT32, int32); TYPE(ENUM, int32); TYPE(UINT64, uint64); TYPE(UINT32, uint32); TYPE(DOUBLE, double); TYPE(FLOAT, float); TYPE(BOOL, bool); default: UPB_ASSERT(false); break; } #undef TYPE upb_handlerattr_uninit(&attr); return ok; } bool upb_msg_getscalarhandlerdata(const upb_handlers *h, upb_selector_t s, upb_fieldtype_t *type, size_t *offset, int32_t *hasbit) { const upb_msg_handlerdata *d; upb_func *f = upb_handlers_gethandler(h, s); if ((upb_int64_handlerfunc*)f == upb_msg_setint64) { *type = UPB_TYPE_INT64; } else if ((upb_int32_handlerfunc*)f == upb_msg_setint32) { *type = UPB_TYPE_INT32; } else if ((upb_uint64_handlerfunc*)f == upb_msg_setuint64) { *type = UPB_TYPE_UINT64; } else if ((upb_uint32_handlerfunc*)f == upb_msg_setuint32) { *type = UPB_TYPE_UINT32; } else if ((upb_double_handlerfunc*)f == upb_msg_setdouble) { *type = UPB_TYPE_DOUBLE; } else if ((upb_float_handlerfunc*)f == upb_msg_setfloat) { *type = UPB_TYPE_FLOAT; } else if ((upb_bool_handlerfunc*)f == upb_msg_setbool) { *type = UPB_TYPE_BOOL; } else { return false; } d = upb_handlers_gethandlerdata(h, s); *offset = d->offset; *hasbit = d->hasbit; return true; } /* ** upb::RefCounted Implementation ** ** Our key invariants are: ** 1. reference cycles never span groups ** 2. for ref2(to, from), we increment to's count iff group(from) != group(to) ** ** The previous two are how we avoid leaking cycles. Other important ** invariants are: ** 3. for mutable objects "from" and "to", if there exists a ref2(to, from) ** this implies group(from) == group(to). (In practice, what we implement ** is even stronger; "from" and "to" will share a group if there has *ever* ** been a ref2(to, from), but all that is necessary for correctness is the ** weaker one). ** 4. mutable and immutable objects are never in the same group. */ #include static void freeobj(upb_refcounted *o); const char untracked_val; const void *UPB_UNTRACKED_REF = &untracked_val; /* arch-specific atomic primitives *******************************************/ #ifdef UPB_THREAD_UNSAFE /*---------------------------------------------------*/ static void atomic_inc(uint32_t *a) { (*a)++; } static bool atomic_dec(uint32_t *a) { return --(*a) == 0; } #elif defined(__GNUC__) || defined(__clang__) /*------------------------------*/ static void atomic_inc(uint32_t *a) { __sync_fetch_and_add(a, 1); } static bool atomic_dec(uint32_t *a) { return __sync_sub_and_fetch(a, 1) == 0; } #elif defined(WIN32) /*-------------------------------------------------------*/ #include static void atomic_inc(upb_atomic_t *a) { InterlockedIncrement(&a->val); } static bool atomic_dec(upb_atomic_t *a) { return InterlockedDecrement(&a->val) == 0; } #else #error Atomic primitives not defined for your platform/CPU. \ Implement them or compile with UPB_THREAD_UNSAFE. #endif /* All static objects point to this refcount. * It is special-cased in ref/unref below. */ uint32_t static_refcount = -1; /* We can avoid atomic ops for statically-declared objects. * This is a minor optimization but nice since we can avoid degrading under * contention in this case. */ static void refgroup(uint32_t *group) { if (group != &static_refcount) atomic_inc(group); } static bool unrefgroup(uint32_t *group) { if (group == &static_refcount) { return false; } else { return atomic_dec(group); } } /* Reference tracking (debug only) ********************************************/ #ifdef UPB_DEBUG_REFS #ifdef UPB_THREAD_UNSAFE static void upb_lock() {} static void upb_unlock() {} #else /* User must define functions that lock/unlock a global mutex and link this * file against them. */ void upb_lock(); void upb_unlock(); #endif /* UPB_DEBUG_REFS mode counts on being able to malloc() memory in some * code-paths that can normally never fail, like upb_refcounted_ref(). Since * we have no way to propagage out-of-memory errors back to the user, and since * these errors can only occur in UPB_DEBUG_REFS mode, we use an allocator that * immediately aborts on failure (avoiding the global allocator, which might * inject failures). */ #include static void *upb_debugrefs_allocfunc(upb_alloc *alloc, void *ptr, size_t oldsize, size_t size) { UPB_UNUSED(alloc); UPB_UNUSED(oldsize); if (size == 0) { free(ptr); return NULL; } else { void *ret = realloc(ptr, size); if (!ret) { abort(); } return ret; } } upb_alloc upb_alloc_debugrefs = {&upb_debugrefs_allocfunc}; typedef struct { int count; /* How many refs there are (duplicates only allowed for ref2). */ bool is_ref2; } trackedref; static trackedref *trackedref_new(bool is_ref2) { trackedref *ret = upb_malloc(&upb_alloc_debugrefs, sizeof(*ret)); ret->count = 1; ret->is_ref2 = is_ref2; return ret; } static void track(const upb_refcounted *r, const void *owner, bool ref2) { upb_value v; UPB_ASSERT(owner); if (owner == UPB_UNTRACKED_REF) return; upb_lock(); if (upb_inttable_lookupptr(r->refs, owner, &v)) { trackedref *ref = upb_value_getptr(v); /* Since we allow multiple ref2's for the same to/from pair without * allocating separate memory for each one, we lose the fine-grained * tracking behavior we get with regular refs. Since ref2s only happen * inside upb, we'll accept this limitation until/unless there is a really * difficult upb-internal bug that can't be figured out without it. */ UPB_ASSERT(ref2); UPB_ASSERT(ref->is_ref2); ref->count++; } else { trackedref *ref = trackedref_new(ref2); upb_inttable_insertptr2(r->refs, owner, upb_value_ptr(ref), &upb_alloc_debugrefs); if (ref2) { /* We know this cast is safe when it is a ref2, because it's coming from * another refcounted object. */ const upb_refcounted *from = owner; UPB_ASSERT(!upb_inttable_lookupptr(from->ref2s, r, NULL)); upb_inttable_insertptr2(from->ref2s, r, upb_value_ptr(NULL), &upb_alloc_debugrefs); } } upb_unlock(); } static void untrack(const upb_refcounted *r, const void *owner, bool ref2) { upb_value v; bool found; trackedref *ref; UPB_ASSERT(owner); if (owner == UPB_UNTRACKED_REF) return; upb_lock(); found = upb_inttable_lookupptr(r->refs, owner, &v); /* This assert will fail if an owner attempts to release a ref it didn't have. */ UPB_ASSERT(found); ref = upb_value_getptr(v); UPB_ASSERT(ref->is_ref2 == ref2); if (--ref->count == 0) { free(ref); upb_inttable_removeptr(r->refs, owner, NULL); if (ref2) { /* We know this cast is safe when it is a ref2, because it's coming from * another refcounted object. */ const upb_refcounted *from = owner; bool removed = upb_inttable_removeptr(from->ref2s, r, NULL); UPB_ASSERT(removed); } } upb_unlock(); } static void checkref(const upb_refcounted *r, const void *owner, bool ref2) { upb_value v; bool found; trackedref *ref; upb_lock(); found = upb_inttable_lookupptr(r->refs, owner, &v); UPB_ASSERT(found); ref = upb_value_getptr(v); UPB_ASSERT(ref->is_ref2 == ref2); upb_unlock(); } /* Populates the given UPB_CTYPE_INT32 inttable with counts of ref2's that * originate from the given owner. */ static void getref2s(const upb_refcounted *owner, upb_inttable *tab) { upb_inttable_iter i; upb_lock(); upb_inttable_begin(&i, owner->ref2s); for(; !upb_inttable_done(&i); upb_inttable_next(&i)) { upb_value v; upb_value count; trackedref *ref; bool found; upb_refcounted *to = (upb_refcounted*)upb_inttable_iter_key(&i); /* To get the count we need to look in the target's table. */ found = upb_inttable_lookupptr(to->refs, owner, &v); UPB_ASSERT(found); ref = upb_value_getptr(v); count = upb_value_int32(ref->count); upb_inttable_insertptr2(tab, to, count, &upb_alloc_debugrefs); } upb_unlock(); } typedef struct { upb_inttable ref2; const upb_refcounted *obj; } check_state; static void visit_check(const upb_refcounted *obj, const upb_refcounted *subobj, void *closure) { check_state *s = closure; upb_inttable *ref2 = &s->ref2; upb_value v; bool removed; int32_t newcount; UPB_ASSERT(obj == s->obj); UPB_ASSERT(subobj); removed = upb_inttable_removeptr(ref2, subobj, &v); /* The following assertion will fail if the visit() function visits a subobj * that it did not have a ref2 on, or visits the same subobj too many times. */ UPB_ASSERT(removed); newcount = upb_value_getint32(v) - 1; if (newcount > 0) { upb_inttable_insert2(ref2, (uintptr_t)subobj, upb_value_int32(newcount), &upb_alloc_debugrefs); } } static void visit(const upb_refcounted *r, upb_refcounted_visit *v, void *closure) { /* In DEBUG_REFS mode we know what existing ref2 refs there are, so we know * exactly the set of nodes that visit() should visit. So we verify visit()'s * correctness here. */ check_state state; state.obj = r; upb_inttable_init2(&state.ref2, UPB_CTYPE_INT32, &upb_alloc_debugrefs); getref2s(r, &state.ref2); /* This should visit any children in the ref2 table. */ if (r->vtbl->visit) r->vtbl->visit(r, visit_check, &state); /* This assertion will fail if the visit() function missed any children. */ UPB_ASSERT(upb_inttable_count(&state.ref2) == 0); upb_inttable_uninit2(&state.ref2, &upb_alloc_debugrefs); if (r->vtbl->visit) r->vtbl->visit(r, v, closure); } static void trackinit(upb_refcounted *r) { r->refs = upb_malloc(&upb_alloc_debugrefs, sizeof(*r->refs)); r->ref2s = upb_malloc(&upb_alloc_debugrefs, sizeof(*r->ref2s)); upb_inttable_init2(r->refs, UPB_CTYPE_PTR, &upb_alloc_debugrefs); upb_inttable_init2(r->ref2s, UPB_CTYPE_PTR, &upb_alloc_debugrefs); } static void trackfree(const upb_refcounted *r) { upb_inttable_uninit2(r->refs, &upb_alloc_debugrefs); upb_inttable_uninit2(r->ref2s, &upb_alloc_debugrefs); upb_free(&upb_alloc_debugrefs, r->refs); upb_free(&upb_alloc_debugrefs, r->ref2s); } #else static void track(const upb_refcounted *r, const void *owner, bool ref2) { UPB_UNUSED(r); UPB_UNUSED(owner); UPB_UNUSED(ref2); } static void untrack(const upb_refcounted *r, const void *owner, bool ref2) { UPB_UNUSED(r); UPB_UNUSED(owner); UPB_UNUSED(ref2); } static void checkref(const upb_refcounted *r, const void *owner, bool ref2) { UPB_UNUSED(r); UPB_UNUSED(owner); UPB_UNUSED(ref2); } static void trackinit(upb_refcounted *r) { UPB_UNUSED(r); } static void trackfree(const upb_refcounted *r) { UPB_UNUSED(r); } static void visit(const upb_refcounted *r, upb_refcounted_visit *v, void *closure) { if (r->vtbl->visit) r->vtbl->visit(r, v, closure); } #endif /* UPB_DEBUG_REFS */ /* freeze() *******************************************************************/ /* The freeze() operation is by far the most complicated part of this scheme. * We compute strongly-connected components and then mutate the graph such that * we preserve the invariants documented at the top of this file. And we must * handle out-of-memory errors gracefully (without leaving the graph * inconsistent), which adds to the fun. */ /* The state used by the freeze operation (shared across many functions). */ typedef struct { int depth; int maxdepth; uint64_t index; /* Maps upb_refcounted* -> attributes (color, etc). attr layout varies by * color. */ upb_inttable objattr; upb_inttable stack; /* stack of upb_refcounted* for Tarjan's algorithm. */ upb_inttable groups; /* array of uint32_t*, malloc'd refcounts for new groups */ upb_status *status; jmp_buf err; } tarjan; static void release_ref2(const upb_refcounted *obj, const upb_refcounted *subobj, void *closure); /* Node attributes -----------------------------------------------------------*/ /* After our analysis phase all nodes will be either GRAY or WHITE. */ typedef enum { BLACK = 0, /* Object has not been seen. */ GRAY, /* Object has been found via a refgroup but may not be reachable. */ GREEN, /* Object is reachable and is currently on the Tarjan stack. */ WHITE /* Object is reachable and has been assigned a group (SCC). */ } color_t; UPB_NORETURN static void err(tarjan *t) { longjmp(t->err, 1); } UPB_NORETURN static void oom(tarjan *t) { upb_status_seterrmsg(t->status, "out of memory"); err(t); } static uint64_t trygetattr(const tarjan *t, const upb_refcounted *r) { upb_value v; return upb_inttable_lookupptr(&t->objattr, r, &v) ? upb_value_getuint64(v) : 0; } static uint64_t getattr(const tarjan *t, const upb_refcounted *r) { upb_value v; bool found = upb_inttable_lookupptr(&t->objattr, r, &v); UPB_ASSERT(found); return upb_value_getuint64(v); } static void setattr(tarjan *t, const upb_refcounted *r, uint64_t attr) { upb_inttable_removeptr(&t->objattr, r, NULL); upb_inttable_insertptr(&t->objattr, r, upb_value_uint64(attr)); } static color_t color(tarjan *t, const upb_refcounted *r) { return trygetattr(t, r) & 0x3; /* Color is always stored in the low 2 bits. */ } static void set_gray(tarjan *t, const upb_refcounted *r) { UPB_ASSERT(color(t, r) == BLACK); setattr(t, r, GRAY); } /* Pushes an obj onto the Tarjan stack and sets it to GREEN. */ static void push(tarjan *t, const upb_refcounted *r) { UPB_ASSERT(color(t, r) == BLACK || color(t, r) == GRAY); /* This defines the attr layout for the GREEN state. "index" and "lowlink" * get 31 bits, which is plenty (limit of 2B objects frozen at a time). */ setattr(t, r, GREEN | (t->index << 2) | (t->index << 33)); if (++t->index == 0x80000000) { upb_status_seterrmsg(t->status, "too many objects to freeze"); err(t); } upb_inttable_push(&t->stack, upb_value_ptr((void*)r)); } /* Pops an obj from the Tarjan stack and sets it to WHITE, with a ptr to its * SCC group. */ static upb_refcounted *pop(tarjan *t) { upb_refcounted *r = upb_value_getptr(upb_inttable_pop(&t->stack)); UPB_ASSERT(color(t, r) == GREEN); /* This defines the attr layout for nodes in the WHITE state. * Top of group stack is [group, NULL]; we point at group. */ setattr(t, r, WHITE | (upb_inttable_count(&t->groups) - 2) << 8); return r; } static void tarjan_newgroup(tarjan *t) { uint32_t *group = upb_gmalloc(sizeof(*group)); if (!group) oom(t); /* Push group and empty group leader (we'll fill in leader later). */ if (!upb_inttable_push(&t->groups, upb_value_ptr(group)) || !upb_inttable_push(&t->groups, upb_value_ptr(NULL))) { upb_gfree(group); oom(t); } *group = 0; } static uint32_t idx(tarjan *t, const upb_refcounted *r) { UPB_ASSERT(color(t, r) == GREEN); return (getattr(t, r) >> 2) & 0x7FFFFFFF; } static uint32_t lowlink(tarjan *t, const upb_refcounted *r) { if (color(t, r) == GREEN) { return getattr(t, r) >> 33; } else { return UINT32_MAX; } } static void set_lowlink(tarjan *t, const upb_refcounted *r, uint32_t lowlink) { UPB_ASSERT(color(t, r) == GREEN); setattr(t, r, ((uint64_t)lowlink << 33) | (getattr(t, r) & 0x1FFFFFFFF)); } static uint32_t *group(tarjan *t, upb_refcounted *r) { uint64_t groupnum; upb_value v; bool found; UPB_ASSERT(color(t, r) == WHITE); groupnum = getattr(t, r) >> 8; found = upb_inttable_lookup(&t->groups, groupnum, &v); UPB_ASSERT(found); return upb_value_getptr(v); } /* If the group leader for this object's group has not previously been set, * the given object is assigned to be its leader. */ static upb_refcounted *groupleader(tarjan *t, upb_refcounted *r) { uint64_t leader_slot; upb_value v; bool found; UPB_ASSERT(color(t, r) == WHITE); leader_slot = (getattr(t, r) >> 8) + 1; found = upb_inttable_lookup(&t->groups, leader_slot, &v); UPB_ASSERT(found); if (upb_value_getptr(v)) { return upb_value_getptr(v); } else { upb_inttable_remove(&t->groups, leader_slot, NULL); upb_inttable_insert(&t->groups, leader_slot, upb_value_ptr(r)); return r; } } /* Tarjan's algorithm --------------------------------------------------------*/ /* See: * http://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm */ static void do_tarjan(const upb_refcounted *obj, tarjan *t); static void tarjan_visit(const upb_refcounted *obj, const upb_refcounted *subobj, void *closure) { tarjan *t = closure; if (++t->depth > t->maxdepth) { upb_status_seterrf(t->status, "graph too deep to freeze (%d)", t->maxdepth); err(t); } else if (subobj->is_frozen || color(t, subobj) == WHITE) { /* Do nothing: we don't want to visit or color already-frozen nodes, * and WHITE nodes have already been assigned a SCC. */ } else if (color(t, subobj) < GREEN) { /* Subdef has not yet been visited; recurse on it. */ do_tarjan(subobj, t); set_lowlink(t, obj, UPB_MIN(lowlink(t, obj), lowlink(t, subobj))); } else if (color(t, subobj) == GREEN) { /* Subdef is in the stack and hence in the current SCC. */ set_lowlink(t, obj, UPB_MIN(lowlink(t, obj), idx(t, subobj))); } --t->depth; } static void do_tarjan(const upb_refcounted *obj, tarjan *t) { if (color(t, obj) == BLACK) { /* We haven't seen this object's group; mark the whole group GRAY. */ const upb_refcounted *o = obj; do { set_gray(t, o); } while ((o = o->next) != obj); } push(t, obj); visit(obj, tarjan_visit, t); if (lowlink(t, obj) == idx(t, obj)) { tarjan_newgroup(t); while (pop(t) != obj) ; } } /* freeze() ------------------------------------------------------------------*/ static void crossref(const upb_refcounted *r, const upb_refcounted *subobj, void *_t) { tarjan *t = _t; UPB_ASSERT(color(t, r) > BLACK); if (color(t, subobj) > BLACK && r->group != subobj->group) { /* Previously this ref was not reflected in subobj->group because they * were in the same group; now that they are split a ref must be taken. */ refgroup(subobj->group); } } static bool freeze(upb_refcounted *const*roots, int n, upb_status *s, int maxdepth) { volatile bool ret = false; int i; upb_inttable_iter iter; /* We run in two passes so that we can allocate all memory before performing * any mutation of the input -- this allows us to leave the input unchanged * in the case of memory allocation failure. */ tarjan t; t.index = 0; t.depth = 0; t.maxdepth = maxdepth; t.status = s; if (!upb_inttable_init(&t.objattr, UPB_CTYPE_UINT64)) goto err1; if (!upb_inttable_init(&t.stack, UPB_CTYPE_PTR)) goto err2; if (!upb_inttable_init(&t.groups, UPB_CTYPE_PTR)) goto err3; if (setjmp(t.err) != 0) goto err4; for (i = 0; i < n; i++) { if (color(&t, roots[i]) < GREEN) { do_tarjan(roots[i], &t); } } /* If we've made it this far, no further errors are possible so it's safe to * mutate the objects without risk of leaving them in an inconsistent state. */ ret = true; /* The transformation that follows requires care. The preconditions are: * - all objects in attr map are WHITE or GRAY, and are in mutable groups * (groups of all mutable objs) * - no ref2(to, from) refs have incremented count(to) if both "to" and * "from" are in our attr map (this follows from invariants (2) and (3)) */ /* Pass 1: we remove WHITE objects from their mutable groups, and add them to * new groups according to the SCC's we computed. These new groups will * consist of only frozen objects. None will be immediately collectible, * because WHITE objects are by definition reachable from one of "roots", * which the caller must own refs on. */ upb_inttable_begin(&iter, &t.objattr); for(; !upb_inttable_done(&iter); upb_inttable_next(&iter)) { upb_refcounted *obj = (upb_refcounted*)upb_inttable_iter_key(&iter); /* Since removal from a singly-linked list requires access to the object's * predecessor, we consider obj->next instead of obj for moving. With the * while() loop we guarantee that we will visit every node's predecessor. * Proof: * 1. every node's predecessor is in our attr map. * 2. though the loop body may change a node's predecessor, it will only * change it to be the node we are currently operating on, so with a * while() loop we guarantee ourselves the chance to remove each node. */ while (color(&t, obj->next) == WHITE && group(&t, obj->next) != obj->next->group) { upb_refcounted *leader; /* Remove from old group. */ upb_refcounted *move = obj->next; if (obj == move) { /* Removing the last object from a group. */ UPB_ASSERT(*obj->group == obj->individual_count); upb_gfree(obj->group); } else { obj->next = move->next; /* This may decrease to zero; we'll collect GRAY objects (if any) that * remain in the group in the third pass. */ UPB_ASSERT(*move->group >= move->individual_count); *move->group -= move->individual_count; } /* Add to new group. */ leader = groupleader(&t, move); if (move == leader) { /* First object added to new group is its leader. */ move->group = group(&t, move); move->next = move; *move->group = move->individual_count; } else { /* Group already has at least one object in it. */ UPB_ASSERT(leader->group == group(&t, move)); move->group = group(&t, move); move->next = leader->next; leader->next = move; *move->group += move->individual_count; } move->is_frozen = true; } } /* Pass 2: GRAY and WHITE objects "obj" with ref2(to, obj) references must * increment count(to) if group(obj) != group(to) (which could now be the * case if "to" was just frozen). */ upb_inttable_begin(&iter, &t.objattr); for(; !upb_inttable_done(&iter); upb_inttable_next(&iter)) { upb_refcounted *obj = (upb_refcounted*)upb_inttable_iter_key(&iter); visit(obj, crossref, &t); } /* Pass 3: GRAY objects are collected if their group's refcount dropped to * zero when we removed its white nodes. This can happen if they had only * been kept alive by virtue of sharing a group with an object that was just * frozen. * * It is important that we do this last, since the GRAY object's free() * function could call unref2() on just-frozen objects, which will decrement * refs that were added in pass 2. */ upb_inttable_begin(&iter, &t.objattr); for(; !upb_inttable_done(&iter); upb_inttable_next(&iter)) { upb_refcounted *obj = (upb_refcounted*)upb_inttable_iter_key(&iter); if (obj->group == NULL || *obj->group == 0) { if (obj->group) { upb_refcounted *o; /* We eagerly free() the group's count (since we can't easily determine * the group's remaining size it's the easiest way to ensure it gets * done). */ upb_gfree(obj->group); /* Visit to release ref2's (done in a separate pass since release_ref2 * depends on o->group being unmodified so it can test merged()). */ o = obj; do { visit(o, release_ref2, NULL); } while ((o = o->next) != obj); /* Mark "group" fields as NULL so we know to free the objects later in * this loop, but also don't try to delete the group twice. */ o = obj; do { o->group = NULL; } while ((o = o->next) != obj); } freeobj(obj); } } err4: if (!ret) { upb_inttable_begin(&iter, &t.groups); for(; !upb_inttable_done(&iter); upb_inttable_next(&iter)) upb_gfree(upb_value_getptr(upb_inttable_iter_value(&iter))); } upb_inttable_uninit(&t.groups); err3: upb_inttable_uninit(&t.stack); err2: upb_inttable_uninit(&t.objattr); err1: return ret; } /* Misc internal functions ***************************************************/ static bool merged(const upb_refcounted *r, const upb_refcounted *r2) { return r->group == r2->group; } static void merge(upb_refcounted *r, upb_refcounted *from) { upb_refcounted *base; upb_refcounted *tmp; if (merged(r, from)) return; *r->group += *from->group; upb_gfree(from->group); base = from; /* Set all refcount pointers in the "from" chain to the merged refcount. * * TODO(haberman): this linear algorithm can result in an overall O(n^2) bound * if the user continuously extends a group by one object. Prevent this by * using one of the techniques in this paper: * http://bioinfo.ict.ac.cn/~dbu/AlgorithmCourses/Lectures/Union-Find-Tarjan.pdf */ do { from->group = r->group; } while ((from = from->next) != base); /* Merge the two circularly linked lists by swapping their next pointers. */ tmp = r->next; r->next = base->next; base->next = tmp; } static void unref(const upb_refcounted *r); static void release_ref2(const upb_refcounted *obj, const upb_refcounted *subobj, void *closure) { UPB_UNUSED(closure); untrack(subobj, obj, true); if (!merged(obj, subobj)) { UPB_ASSERT(subobj->is_frozen); unref(subobj); } } static void unref(const upb_refcounted *r) { if (unrefgroup(r->group)) { const upb_refcounted *o; upb_gfree(r->group); /* In two passes, since release_ref2 needs a guarantee that any subobjs * are alive. */ o = r; do { visit(o, release_ref2, NULL); } while((o = o->next) != r); o = r; do { const upb_refcounted *next = o->next; UPB_ASSERT(o->is_frozen || o->individual_count == 0); freeobj((upb_refcounted*)o); o = next; } while(o != r); } } static void freeobj(upb_refcounted *o) { trackfree(o); o->vtbl->free((upb_refcounted*)o); } /* Public interface ***********************************************************/ bool upb_refcounted_init(upb_refcounted *r, const struct upb_refcounted_vtbl *vtbl, const void *owner) { #ifndef NDEBUG /* Endianness check. This is unrelated to upb_refcounted, it's just a * convenient place to put the check that we can be assured will run for * basically every program using upb. */ const int x = 1; #ifdef UPB_BIG_ENDIAN UPB_ASSERT(*(char*)&x != 1); #else UPB_ASSERT(*(char*)&x == 1); #endif #endif r->next = r; r->vtbl = vtbl; r->individual_count = 0; r->is_frozen = false; r->group = upb_gmalloc(sizeof(*r->group)); if (!r->group) return false; *r->group = 0; trackinit(r); upb_refcounted_ref(r, owner); return true; } bool upb_refcounted_isfrozen(const upb_refcounted *r) { return r->is_frozen; } void upb_refcounted_ref(const upb_refcounted *r, const void *owner) { track(r, owner, false); if (!r->is_frozen) ((upb_refcounted*)r)->individual_count++; refgroup(r->group); } void upb_refcounted_unref(const upb_refcounted *r, const void *owner) { untrack(r, owner, false); if (!r->is_frozen) ((upb_refcounted*)r)->individual_count--; unref(r); } void upb_refcounted_ref2(const upb_refcounted *r, upb_refcounted *from) { UPB_ASSERT(!from->is_frozen); /* Non-const pointer implies this. */ track(r, from, true); if (r->is_frozen) { refgroup(r->group); } else { merge((upb_refcounted*)r, from); } } void upb_refcounted_unref2(const upb_refcounted *r, upb_refcounted *from) { UPB_ASSERT(!from->is_frozen); /* Non-const pointer implies this. */ untrack(r, from, true); if (r->is_frozen) { unref(r); } else { UPB_ASSERT(merged(r, from)); } } void upb_refcounted_donateref( const upb_refcounted *r, const void *from, const void *to) { UPB_ASSERT(from != to); if (to != NULL) upb_refcounted_ref(r, to); if (from != NULL) upb_refcounted_unref(r, from); } void upb_refcounted_checkref(const upb_refcounted *r, const void *owner) { checkref(r, owner, false); } bool upb_refcounted_freeze(upb_refcounted *const*roots, int n, upb_status *s, int maxdepth) { int i; bool ret; for (i = 0; i < n; i++) { UPB_ASSERT(!roots[i]->is_frozen); } ret = freeze(roots, n, s, maxdepth); UPB_ASSERT(!s || ret == upb_ok(s)); return ret; } bool upb_bufsrc_putbuf(const char *buf, size_t len, upb_bytessink *sink) { void *subc; bool ret; upb_bufhandle handle; upb_bufhandle_init(&handle); upb_bufhandle_setbuf(&handle, buf, 0); ret = upb_bytessink_start(sink, len, &subc); if (ret && len != 0) { ret = (upb_bytessink_putbuf(sink, subc, buf, len, &handle) >= len); } if (ret) { ret = upb_bytessink_end(sink); } upb_bufhandle_uninit(&handle); return ret; } struct upb_bufsink { upb_byteshandler handler; upb_bytessink sink; upb_env *env; char *ptr; size_t len, size; }; static void *upb_bufsink_start(void *_sink, const void *hd, size_t size_hint) { upb_bufsink *sink = _sink; UPB_UNUSED(hd); UPB_UNUSED(size_hint); sink->len = 0; return sink; } static size_t upb_bufsink_string(void *_sink, const void *hd, const char *ptr, size_t len, const upb_bufhandle *handle) { upb_bufsink *sink = _sink; size_t new_size = sink->size; UPB_ASSERT(new_size > 0); UPB_UNUSED(hd); UPB_UNUSED(handle); while (sink->len + len > new_size) { new_size *= 2; } if (new_size != sink->size) { sink->ptr = upb_env_realloc(sink->env, sink->ptr, sink->size, new_size); sink->size = new_size; } memcpy(sink->ptr + sink->len, ptr, len); sink->len += len; return len; } upb_bufsink *upb_bufsink_new(upb_env *env) { upb_bufsink *sink = upb_env_malloc(env, sizeof(upb_bufsink)); upb_byteshandler_init(&sink->handler); upb_byteshandler_setstartstr(&sink->handler, upb_bufsink_start, NULL); upb_byteshandler_setstring(&sink->handler, upb_bufsink_string, NULL); upb_bytessink_reset(&sink->sink, &sink->handler, sink); sink->env = env; sink->size = 32; sink->ptr = upb_env_malloc(env, sink->size); sink->len = 0; return sink; } void upb_bufsink_free(upb_bufsink *sink) { upb_env_free(sink->env, sink->ptr); upb_env_free(sink->env, sink); } upb_bytessink *upb_bufsink_sink(upb_bufsink *sink) { return &sink->sink; } const char *upb_bufsink_getdata(const upb_bufsink *sink, size_t *len) { *len = sink->len; return sink->ptr; } /* ** upb_table Implementation ** ** Implementation is heavily inspired by Lua's ltable.c. */ #include #define UPB_MAXARRSIZE 16 /* 64k. */ /* From Chromium. */ #define ARRAY_SIZE(x) \ ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x]))))) static void upb_check_alloc(upb_table *t, upb_alloc *a) { UPB_UNUSED(t); UPB_UNUSED(a); UPB_ASSERT_DEBUGVAR(t->alloc == a); } static const double MAX_LOAD = 0.85; /* The minimum utilization of the array part of a mixed hash/array table. This * is a speed/memory-usage tradeoff (though it's not straightforward because of * cache effects). The lower this is, the more memory we'll use. */ static const double MIN_DENSITY = 0.1; bool is_pow2(uint64_t v) { return v == 0 || (v & (v - 1)) == 0; } int log2ceil(uint64_t v) { int ret = 0; bool pow2 = is_pow2(v); while (v >>= 1) ret++; ret = pow2 ? ret : ret + 1; /* Ceiling. */ return UPB_MIN(UPB_MAXARRSIZE, ret); } char *upb_strdup(const char *s, upb_alloc *a) { return upb_strdup2(s, strlen(s), a); } char *upb_strdup2(const char *s, size_t len, upb_alloc *a) { size_t n; char *p; /* Prevent overflow errors. */ if (len == SIZE_MAX) return NULL; /* Always null-terminate, even if binary data; but don't rely on the input to * have a null-terminating byte since it may be a raw binary buffer. */ n = len + 1; p = upb_malloc(a, n); if (p) { memcpy(p, s, len); p[len] = 0; } return p; } /* A type to represent the lookup key of either a strtable or an inttable. */ typedef union { uintptr_t num; struct { const char *str; size_t len; } str; } lookupkey_t; static lookupkey_t strkey2(const char *str, size_t len) { lookupkey_t k; k.str.str = str; k.str.len = len; return k; } static lookupkey_t intkey(uintptr_t key) { lookupkey_t k; k.num = key; return k; } typedef uint32_t hashfunc_t(upb_tabkey key); typedef bool eqlfunc_t(upb_tabkey k1, lookupkey_t k2); /* Base table (shared code) ***************************************************/ /* For when we need to cast away const. */ static upb_tabent *mutable_entries(upb_table *t) { return (upb_tabent*)t->entries; } static bool isfull(upb_table *t) { if (upb_table_size(t) == 0) { return true; } else { return ((double)(t->count + 1) / upb_table_size(t)) > MAX_LOAD; } } static bool init(upb_table *t, upb_ctype_t ctype, uint8_t size_lg2, upb_alloc *a) { size_t bytes; t->count = 0; t->ctype = ctype; t->size_lg2 = size_lg2; t->mask = upb_table_size(t) ? upb_table_size(t) - 1 : 0; #ifndef NDEBUG t->alloc = a; #endif bytes = upb_table_size(t) * sizeof(upb_tabent); if (bytes > 0) { t->entries = upb_malloc(a, bytes); if (!t->entries) return false; memset(mutable_entries(t), 0, bytes); } else { t->entries = NULL; } return true; } static void uninit(upb_table *t, upb_alloc *a) { upb_check_alloc(t, a); upb_free(a, mutable_entries(t)); } static upb_tabent *emptyent(upb_table *t) { upb_tabent *e = mutable_entries(t) + upb_table_size(t); while (1) { if (upb_tabent_isempty(--e)) return e; UPB_ASSERT(e > t->entries); } } static upb_tabent *getentry_mutable(upb_table *t, uint32_t hash) { return (upb_tabent*)upb_getentry(t, hash); } static const upb_tabent *findentry(const upb_table *t, lookupkey_t key, uint32_t hash, eqlfunc_t *eql) { const upb_tabent *e; if (t->size_lg2 == 0) return NULL; e = upb_getentry(t, hash); if (upb_tabent_isempty(e)) return NULL; while (1) { if (eql(e->key, key)) return e; if ((e = e->next) == NULL) return NULL; } } static upb_tabent *findentry_mutable(upb_table *t, lookupkey_t key, uint32_t hash, eqlfunc_t *eql) { return (upb_tabent*)findentry(t, key, hash, eql); } static bool lookup(const upb_table *t, lookupkey_t key, upb_value *v, uint32_t hash, eqlfunc_t *eql) { const upb_tabent *e = findentry(t, key, hash, eql); if (e) { if (v) { _upb_value_setval(v, e->val.val, t->ctype); } return true; } else { return false; } } /* The given key must not already exist in the table. */ static void insert(upb_table *t, lookupkey_t key, upb_tabkey tabkey, upb_value val, uint32_t hash, hashfunc_t *hashfunc, eqlfunc_t *eql) { upb_tabent *mainpos_e; upb_tabent *our_e; UPB_ASSERT(findentry(t, key, hash, eql) == NULL); UPB_ASSERT_DEBUGVAR(val.ctype == t->ctype); t->count++; mainpos_e = getentry_mutable(t, hash); our_e = mainpos_e; if (upb_tabent_isempty(mainpos_e)) { /* Our main position is empty; use it. */ our_e->next = NULL; } else { /* Collision. */ upb_tabent *new_e = emptyent(t); /* Head of collider's chain. */ upb_tabent *chain = getentry_mutable(t, hashfunc(mainpos_e->key)); if (chain == mainpos_e) { /* Existing ent is in its main posisiton (it has the same hash as us, and * is the head of our chain). Insert to new ent and append to this chain. */ new_e->next = mainpos_e->next; mainpos_e->next = new_e; our_e = new_e; } else { /* Existing ent is not in its main position (it is a node in some other * chain). This implies that no existing ent in the table has our hash. * Evict it (updating its chain) and use its ent for head of our chain. */ *new_e = *mainpos_e; /* copies next. */ while (chain->next != mainpos_e) { chain = (upb_tabent*)chain->next; UPB_ASSERT(chain); } chain->next = new_e; our_e = mainpos_e; our_e->next = NULL; } } our_e->key = tabkey; our_e->val.val = val.val; UPB_ASSERT(findentry(t, key, hash, eql) == our_e); } static bool rm(upb_table *t, lookupkey_t key, upb_value *val, upb_tabkey *removed, uint32_t hash, eqlfunc_t *eql) { upb_tabent *chain = getentry_mutable(t, hash); if (upb_tabent_isempty(chain)) return false; if (eql(chain->key, key)) { /* Element to remove is at the head of its chain. */ t->count--; if (val) _upb_value_setval(val, chain->val.val, t->ctype); if (removed) *removed = chain->key; if (chain->next) { upb_tabent *move = (upb_tabent*)chain->next; *chain = *move; move->key = 0; /* Make the slot empty. */ } else { chain->key = 0; /* Make the slot empty. */ } return true; } else { /* Element to remove is either in a non-head position or not in the * table. */ while (chain->next && !eql(chain->next->key, key)) { chain = (upb_tabent*)chain->next; } if (chain->next) { /* Found element to remove. */ upb_tabent *rm = (upb_tabent*)chain->next; t->count--; if (val) _upb_value_setval(val, chain->next->val.val, t->ctype); if (removed) *removed = rm->key; rm->key = 0; /* Make the slot empty. */ chain->next = rm->next; return true; } else { /* Element to remove is not in the table. */ return false; } } } static size_t next(const upb_table *t, size_t i) { do { if (++i >= upb_table_size(t)) return SIZE_MAX; } while(upb_tabent_isempty(&t->entries[i])); return i; } static size_t begin(const upb_table *t) { return next(t, -1); } /* upb_strtable ***************************************************************/ /* A simple "subclass" of upb_table that only adds a hash function for strings. */ static upb_tabkey strcopy(lookupkey_t k2, upb_alloc *a) { char *str = upb_malloc(a, k2.str.len + sizeof(uint32_t) + 1); if (str == NULL) return 0; memcpy(str, &k2.str.len, sizeof(uint32_t)); memcpy(str + sizeof(uint32_t), k2.str.str, k2.str.len + 1); return (uintptr_t)str; } static uint32_t strhash(upb_tabkey key) { uint32_t len; char *str = upb_tabstr(key, &len); return MurmurHash2(str, len, 0); } static bool streql(upb_tabkey k1, lookupkey_t k2) { uint32_t len; char *str = upb_tabstr(k1, &len); return len == k2.str.len && memcmp(str, k2.str.str, len) == 0; } bool upb_strtable_init2(upb_strtable *t, upb_ctype_t ctype, upb_alloc *a) { return init(&t->t, ctype, 2, a); } void upb_strtable_uninit2(upb_strtable *t, upb_alloc *a) { size_t i; for (i = 0; i < upb_table_size(&t->t); i++) upb_free(a, (void*)t->t.entries[i].key); uninit(&t->t, a); } bool upb_strtable_resize(upb_strtable *t, size_t size_lg2, upb_alloc *a) { upb_strtable new_table; upb_strtable_iter i; upb_check_alloc(&t->t, a); if (!init(&new_table.t, t->t.ctype, size_lg2, a)) return false; upb_strtable_begin(&i, t); for ( ; !upb_strtable_done(&i); upb_strtable_next(&i)) { upb_strtable_insert3( &new_table, upb_strtable_iter_key(&i), upb_strtable_iter_keylength(&i), upb_strtable_iter_value(&i), a); } upb_strtable_uninit2(t, a); *t = new_table; return true; } bool upb_strtable_insert3(upb_strtable *t, const char *k, size_t len, upb_value v, upb_alloc *a) { lookupkey_t key; upb_tabkey tabkey; uint32_t hash; upb_check_alloc(&t->t, a); if (isfull(&t->t)) { /* Need to resize. New table of double the size, add old elements to it. */ if (!upb_strtable_resize(t, t->t.size_lg2 + 1, a)) { return false; } } key = strkey2(k, len); tabkey = strcopy(key, a); if (tabkey == 0) return false; hash = MurmurHash2(key.str.str, key.str.len, 0); insert(&t->t, key, tabkey, v, hash, &strhash, &streql); return true; } bool upb_strtable_lookup2(const upb_strtable *t, const char *key, size_t len, upb_value *v) { uint32_t hash = MurmurHash2(key, len, 0); return lookup(&t->t, strkey2(key, len), v, hash, &streql); } bool upb_strtable_remove3(upb_strtable *t, const char *key, size_t len, upb_value *val, upb_alloc *alloc) { uint32_t hash = MurmurHash2(key, len, 0); upb_tabkey tabkey; if (rm(&t->t, strkey2(key, len), val, &tabkey, hash, &streql)) { upb_free(alloc, (void*)tabkey); return true; } else { return false; } } /* Iteration */ static const upb_tabent *str_tabent(const upb_strtable_iter *i) { return &i->t->t.entries[i->index]; } void upb_strtable_begin(upb_strtable_iter *i, const upb_strtable *t) { i->t = t; i->index = begin(&t->t); } void upb_strtable_next(upb_strtable_iter *i) { i->index = next(&i->t->t, i->index); } bool upb_strtable_done(const upb_strtable_iter *i) { return i->index >= upb_table_size(&i->t->t) || upb_tabent_isempty(str_tabent(i)); } const char *upb_strtable_iter_key(const upb_strtable_iter *i) { UPB_ASSERT(!upb_strtable_done(i)); return upb_tabstr(str_tabent(i)->key, NULL); } size_t upb_strtable_iter_keylength(const upb_strtable_iter *i) { uint32_t len; UPB_ASSERT(!upb_strtable_done(i)); upb_tabstr(str_tabent(i)->key, &len); return len; } upb_value upb_strtable_iter_value(const upb_strtable_iter *i) { UPB_ASSERT(!upb_strtable_done(i)); return _upb_value_val(str_tabent(i)->val.val, i->t->t.ctype); } void upb_strtable_iter_setdone(upb_strtable_iter *i) { i->index = SIZE_MAX; } bool upb_strtable_iter_isequal(const upb_strtable_iter *i1, const upb_strtable_iter *i2) { if (upb_strtable_done(i1) && upb_strtable_done(i2)) return true; return i1->t == i2->t && i1->index == i2->index; } /* upb_inttable ***************************************************************/ /* For inttables we use a hybrid structure where small keys are kept in an * array and large keys are put in the hash table. */ static uint32_t inthash(upb_tabkey key) { return upb_inthash(key); } static bool inteql(upb_tabkey k1, lookupkey_t k2) { return k1 == k2.num; } static upb_tabval *mutable_array(upb_inttable *t) { return (upb_tabval*)t->array; } static upb_tabval *inttable_val(upb_inttable *t, uintptr_t key) { if (key < t->array_size) { return upb_arrhas(t->array[key]) ? &(mutable_array(t)[key]) : NULL; } else { upb_tabent *e = findentry_mutable(&t->t, intkey(key), upb_inthash(key), &inteql); return e ? &e->val : NULL; } } static const upb_tabval *inttable_val_const(const upb_inttable *t, uintptr_t key) { return inttable_val((upb_inttable*)t, key); } size_t upb_inttable_count(const upb_inttable *t) { return t->t.count + t->array_count; } static void check(upb_inttable *t) { UPB_UNUSED(t); #if defined(UPB_DEBUG_TABLE) && !defined(NDEBUG) { /* This check is very expensive (makes inserts/deletes O(N)). */ size_t count = 0; upb_inttable_iter i; upb_inttable_begin(&i, t); for(; !upb_inttable_done(&i); upb_inttable_next(&i), count++) { UPB_ASSERT(upb_inttable_lookup(t, upb_inttable_iter_key(&i), NULL)); } UPB_ASSERT(count == upb_inttable_count(t)); } #endif } bool upb_inttable_sizedinit(upb_inttable *t, upb_ctype_t ctype, size_t asize, int hsize_lg2, upb_alloc *a) { size_t array_bytes; if (!init(&t->t, ctype, hsize_lg2, a)) return false; /* Always make the array part at least 1 long, so that we know key 0 * won't be in the hash part, which simplifies things. */ t->array_size = UPB_MAX(1, asize); t->array_count = 0; array_bytes = t->array_size * sizeof(upb_value); t->array = upb_malloc(a, array_bytes); if (!t->array) { uninit(&t->t, a); return false; } memset(mutable_array(t), 0xff, array_bytes); check(t); return true; } bool upb_inttable_init2(upb_inttable *t, upb_ctype_t ctype, upb_alloc *a) { return upb_inttable_sizedinit(t, ctype, 0, 4, a); } void upb_inttable_uninit2(upb_inttable *t, upb_alloc *a) { uninit(&t->t, a); upb_free(a, mutable_array(t)); } bool upb_inttable_insert2(upb_inttable *t, uintptr_t key, upb_value val, upb_alloc *a) { upb_tabval tabval; tabval.val = val.val; UPB_ASSERT(upb_arrhas(tabval)); /* This will reject (uint64_t)-1. Fix this. */ upb_check_alloc(&t->t, a); if (key < t->array_size) { UPB_ASSERT(!upb_arrhas(t->array[key])); t->array_count++; mutable_array(t)[key].val = val.val; } else { if (isfull(&t->t)) { /* Need to resize the hash part, but we re-use the array part. */ size_t i; upb_table new_table; if (!init(&new_table, t->t.ctype, t->t.size_lg2 + 1, a)) { return false; } for (i = begin(&t->t); i < upb_table_size(&t->t); i = next(&t->t, i)) { const upb_tabent *e = &t->t.entries[i]; uint32_t hash; upb_value v; _upb_value_setval(&v, e->val.val, t->t.ctype); hash = upb_inthash(e->key); insert(&new_table, intkey(e->key), e->key, v, hash, &inthash, &inteql); } UPB_ASSERT(t->t.count == new_table.count); uninit(&t->t, a); t->t = new_table; } insert(&t->t, intkey(key), key, val, upb_inthash(key), &inthash, &inteql); } check(t); return true; } bool upb_inttable_lookup(const upb_inttable *t, uintptr_t key, upb_value *v) { const upb_tabval *table_v = inttable_val_const(t, key); if (!table_v) return false; if (v) _upb_value_setval(v, table_v->val, t->t.ctype); return true; } bool upb_inttable_replace(upb_inttable *t, uintptr_t key, upb_value val) { upb_tabval *table_v = inttable_val(t, key); if (!table_v) return false; table_v->val = val.val; return true; } bool upb_inttable_remove(upb_inttable *t, uintptr_t key, upb_value *val) { bool success; if (key < t->array_size) { if (upb_arrhas(t->array[key])) { upb_tabval empty = UPB_TABVALUE_EMPTY_INIT; t->array_count--; if (val) { _upb_value_setval(val, t->array[key].val, t->t.ctype); } mutable_array(t)[key] = empty; success = true; } else { success = false; } } else { success = rm(&t->t, intkey(key), val, NULL, upb_inthash(key), &inteql); } check(t); return success; } bool upb_inttable_push2(upb_inttable *t, upb_value val, upb_alloc *a) { upb_check_alloc(&t->t, a); return upb_inttable_insert2(t, upb_inttable_count(t), val, a); } upb_value upb_inttable_pop(upb_inttable *t) { upb_value val; bool ok = upb_inttable_remove(t, upb_inttable_count(t) - 1, &val); UPB_ASSERT(ok); return val; } bool upb_inttable_insertptr2(upb_inttable *t, const void *key, upb_value val, upb_alloc *a) { upb_check_alloc(&t->t, a); return upb_inttable_insert2(t, (uintptr_t)key, val, a); } bool upb_inttable_lookupptr(const upb_inttable *t, const void *key, upb_value *v) { return upb_inttable_lookup(t, (uintptr_t)key, v); } bool upb_inttable_removeptr(upb_inttable *t, const void *key, upb_value *val) { return upb_inttable_remove(t, (uintptr_t)key, val); } void upb_inttable_compact2(upb_inttable *t, upb_alloc *a) { /* A power-of-two histogram of the table keys. */ size_t counts[UPB_MAXARRSIZE + 1] = {0}; /* The max key in each bucket. */ uintptr_t max[UPB_MAXARRSIZE + 1] = {0}; upb_inttable_iter i; size_t arr_count; int size_lg2; upb_inttable new_t; upb_check_alloc(&t->t, a); upb_inttable_begin(&i, t); for (; !upb_inttable_done(&i); upb_inttable_next(&i)) { uintptr_t key = upb_inttable_iter_key(&i); int bucket = log2ceil(key); max[bucket] = UPB_MAX(max[bucket], key); counts[bucket]++; } /* Find the largest power of two that satisfies the MIN_DENSITY * definition (while actually having some keys). */ arr_count = upb_inttable_count(t); for (size_lg2 = ARRAY_SIZE(counts) - 1; size_lg2 > 0; size_lg2--) { if (counts[size_lg2] == 0) { /* We can halve again without losing any entries. */ continue; } else if (arr_count >= (1 << size_lg2) * MIN_DENSITY) { break; } arr_count -= counts[size_lg2]; } UPB_ASSERT(arr_count <= upb_inttable_count(t)); { /* Insert all elements into new, perfectly-sized table. */ size_t arr_size = max[size_lg2] + 1; /* +1 so arr[max] will fit. */ size_t hash_count = upb_inttable_count(t) - arr_count; size_t hash_size = hash_count ? (hash_count / MAX_LOAD) + 1 : 0; size_t hashsize_lg2 = log2ceil(hash_size); upb_inttable_sizedinit(&new_t, t->t.ctype, arr_size, hashsize_lg2, a); upb_inttable_begin(&i, t); for (; !upb_inttable_done(&i); upb_inttable_next(&i)) { uintptr_t k = upb_inttable_iter_key(&i); upb_inttable_insert2(&new_t, k, upb_inttable_iter_value(&i), a); } UPB_ASSERT(new_t.array_size == arr_size); UPB_ASSERT(new_t.t.size_lg2 == hashsize_lg2); } upb_inttable_uninit2(t, a); *t = new_t; } /* Iteration. */ static const upb_tabent *int_tabent(const upb_inttable_iter *i) { UPB_ASSERT(!i->array_part); return &i->t->t.entries[i->index]; } static upb_tabval int_arrent(const upb_inttable_iter *i) { UPB_ASSERT(i->array_part); return i->t->array[i->index]; } void upb_inttable_begin(upb_inttable_iter *i, const upb_inttable *t) { i->t = t; i->index = -1; i->array_part = true; upb_inttable_next(i); } void upb_inttable_next(upb_inttable_iter *iter) { const upb_inttable *t = iter->t; if (iter->array_part) { while (++iter->index < t->array_size) { if (upb_arrhas(int_arrent(iter))) { return; } } iter->array_part = false; iter->index = begin(&t->t); } else { iter->index = next(&t->t, iter->index); } } bool upb_inttable_done(const upb_inttable_iter *i) { if (i->array_part) { return i->index >= i->t->array_size || !upb_arrhas(int_arrent(i)); } else { return i->index >= upb_table_size(&i->t->t) || upb_tabent_isempty(int_tabent(i)); } } uintptr_t upb_inttable_iter_key(const upb_inttable_iter *i) { UPB_ASSERT(!upb_inttable_done(i)); return i->array_part ? i->index : int_tabent(i)->key; } upb_value upb_inttable_iter_value(const upb_inttable_iter *i) { UPB_ASSERT(!upb_inttable_done(i)); return _upb_value_val( i->array_part ? i->t->array[i->index].val : int_tabent(i)->val.val, i->t->t.ctype); } void upb_inttable_iter_setdone(upb_inttable_iter *i) { i->index = SIZE_MAX; i->array_part = false; } bool upb_inttable_iter_isequal(const upb_inttable_iter *i1, const upb_inttable_iter *i2) { if (upb_inttable_done(i1) && upb_inttable_done(i2)) return true; return i1->t == i2->t && i1->index == i2->index && i1->array_part == i2->array_part; } #ifdef UPB_UNALIGNED_READS_OK /* ----------------------------------------------------------------------------- * MurmurHash2, by Austin Appleby (released as public domain). * Reformatted and C99-ified by Joshua Haberman. * Note - This code makes a few assumptions about how your machine behaves - * 1. We can read a 4-byte value from any address without crashing * 2. sizeof(int) == 4 (in upb this limitation is removed by using uint32_t * And it has a few limitations - * 1. It will not work incrementally. * 2. It will not produce the same results on little-endian and big-endian * machines. */ uint32_t MurmurHash2(const void *key, size_t len, uint32_t seed) { /* 'm' and 'r' are mixing constants generated offline. * They're not really 'magic', they just happen to work well. */ const uint32_t m = 0x5bd1e995; const int32_t r = 24; /* Initialize the hash to a 'random' value */ uint32_t h = seed ^ len; /* Mix 4 bytes at a time into the hash */ const uint8_t * data = (const uint8_t *)key; while(len >= 4) { uint32_t k = *(uint32_t *)data; k *= m; k ^= k >> r; k *= m; h *= m; h ^= k; data += 4; len -= 4; } /* Handle the last few bytes of the input array */ switch(len) { case 3: h ^= data[2] << 16; case 2: h ^= data[1] << 8; case 1: h ^= data[0]; h *= m; }; /* Do a few final mixes of the hash to ensure the last few * bytes are well-incorporated. */ h ^= h >> 13; h *= m; h ^= h >> 15; return h; } #else /* !UPB_UNALIGNED_READS_OK */ /* ----------------------------------------------------------------------------- * MurmurHashAligned2, by Austin Appleby * Same algorithm as MurmurHash2, but only does aligned reads - should be safer * on certain platforms. * Performance will be lower than MurmurHash2 */ #define MIX(h,k,m) { k *= m; k ^= k >> r; k *= m; h *= m; h ^= k; } uint32_t MurmurHash2(const void * key, size_t len, uint32_t seed) { const uint32_t m = 0x5bd1e995; const int32_t r = 24; const uint8_t * data = (const uint8_t *)key; uint32_t h = seed ^ len; uint8_t align = (uintptr_t)data & 3; if(align && (len >= 4)) { /* Pre-load the temp registers */ uint32_t t = 0, d = 0; int32_t sl; int32_t sr; switch(align) { case 1: t |= data[2] << 16; case 2: t |= data[1] << 8; case 3: t |= data[0]; } t <<= (8 * align); data += 4-align; len -= 4-align; sl = 8 * (4-align); sr = 8 * align; /* Mix */ while(len >= 4) { uint32_t k; d = *(uint32_t *)data; t = (t >> sr) | (d << sl); k = t; MIX(h,k,m); t = d; data += 4; len -= 4; } /* Handle leftover data in temp registers */ d = 0; if(len >= align) { uint32_t k; switch(align) { case 3: d |= data[2] << 16; case 2: d |= data[1] << 8; case 1: d |= data[0]; } k = (t >> sr) | (d << sl); MIX(h,k,m); data += align; len -= align; /* ---------- * Handle tail bytes */ switch(len) { case 3: h ^= data[2] << 16; case 2: h ^= data[1] << 8; case 1: h ^= data[0]; h *= m; }; } else { switch(len) { case 3: d |= data[2] << 16; case 2: d |= data[1] << 8; case 1: d |= data[0]; case 0: h ^= (t >> sr) | (d << sl); h *= m; } } h ^= h >> 13; h *= m; h ^= h >> 15; return h; } else { while(len >= 4) { uint32_t k = *(uint32_t *)data; MIX(h,k,m); data += 4; len -= 4; } /* ---------- * Handle tail bytes */ switch(len) { case 3: h ^= data[2] << 16; case 2: h ^= data[1] << 8; case 1: h ^= data[0]; h *= m; }; h ^= h >> 13; h *= m; h ^= h >> 15; return h; } } #undef MIX #endif /* UPB_UNALIGNED_READS_OK */ #include #include #include #include #include #include #include bool upb_dumptostderr(void *closure, const upb_status* status) { UPB_UNUSED(closure); fprintf(stderr, "%s\n", upb_status_errmsg(status)); return false; } /* Guarantee null-termination and provide ellipsis truncation. * It may be tempting to "optimize" this by initializing these final * four bytes up-front and then being careful never to overwrite them, * this is safer and simpler. */ static void nullz(upb_status *status) { const char *ellipsis = "..."; size_t len = strlen(ellipsis); UPB_ASSERT(sizeof(status->msg) > len); memcpy(status->msg + sizeof(status->msg) - len, ellipsis, len); } /* upb_upberr *****************************************************************/ upb_errorspace upb_upberr = {"upb error"}; void upb_upberr_setoom(upb_status *status) { status->error_space_ = &upb_upberr; upb_status_seterrmsg(status, "Out of memory"); } /* upb_status *****************************************************************/ void upb_status_clear(upb_status *status) { if (!status) return; status->ok_ = true; status->code_ = 0; status->msg[0] = '\0'; } bool upb_ok(const upb_status *status) { return status->ok_; } upb_errorspace *upb_status_errspace(const upb_status *status) { return status->error_space_; } int upb_status_errcode(const upb_status *status) { return status->code_; } const char *upb_status_errmsg(const upb_status *status) { return status->msg; } void upb_status_seterrmsg(upb_status *status, const char *msg) { if (!status) return; status->ok_ = false; strncpy(status->msg, msg, sizeof(status->msg)); nullz(status); } void upb_status_seterrf(upb_status *status, const char *fmt, ...) { va_list args; va_start(args, fmt); upb_status_vseterrf(status, fmt, args); va_end(args); } void upb_status_vseterrf(upb_status *status, const char *fmt, va_list args) { if (!status) return; status->ok_ = false; _upb_vsnprintf(status->msg, sizeof(status->msg), fmt, args); nullz(status); } void upb_status_copy(upb_status *to, const upb_status *from) { if (!to) return; *to = *from; } /* upb_alloc ******************************************************************/ static void *upb_global_allocfunc(upb_alloc *alloc, void *ptr, size_t oldsize, size_t size) { UPB_UNUSED(alloc); UPB_UNUSED(oldsize); if (size == 0) { free(ptr); return NULL; } else { return realloc(ptr, size); } } upb_alloc upb_alloc_global = {&upb_global_allocfunc}; /* upb_arena ******************************************************************/ /* Be conservative and choose 16 in case anyone is using SSE. */ static const size_t maxalign = 16; static size_t align_up_max(size_t size) { return ((size + maxalign - 1) / maxalign) * maxalign; } typedef struct mem_block { struct mem_block *next; size_t size; size_t used; bool owned; /* Data follows. */ } mem_block; typedef struct cleanup_ent { struct cleanup_ent *next; upb_cleanup_func *cleanup; void *ud; } cleanup_ent; static void upb_arena_addblock(upb_arena *a, void *ptr, size_t size, bool owned) { mem_block *block = ptr; block->next = a->block_head; block->size = size; block->used = align_up_max(sizeof(mem_block)); block->owned = owned; a->block_head = block; /* TODO(haberman): ASAN poison. */ } static mem_block *upb_arena_allocblock(upb_arena *a, size_t size) { size_t block_size = UPB_MAX(size, a->next_block_size) + sizeof(mem_block); mem_block *block = upb_malloc(a->block_alloc, block_size); if (!block) { return NULL; } upb_arena_addblock(a, block, block_size, true); a->next_block_size = UPB_MIN(block_size * 2, a->max_block_size); return block; } static void *upb_arena_doalloc(upb_alloc *alloc, void *ptr, size_t oldsize, size_t size) { upb_arena *a = (upb_arena*)alloc; /* upb_alloc is initial member. */ mem_block *block = a->block_head; void *ret; if (size == 0) { return NULL; /* We are an arena, don't need individual frees. */ } size = align_up_max(size); /* TODO(haberman): special-case if this is a realloc of the last alloc? */ if (!block || block->size - block->used < size) { /* Slow path: have to allocate a new block. */ block = upb_arena_allocblock(a, size); if (!block) { return NULL; /* Out of memory. */ } } ret = (char*)block + block->used; block->used += size; if (oldsize > 0) { memcpy(ret, ptr, oldsize); /* Preserve existing data. */ } /* TODO(haberman): ASAN unpoison. */ a->bytes_allocated += size; return ret; } /* Public Arena API ***********************************************************/ void upb_arena_init(upb_arena *a) { a->alloc.func = &upb_arena_doalloc; a->block_alloc = &upb_alloc_global; a->bytes_allocated = 0; a->next_block_size = 256; a->max_block_size = 16384; a->cleanup_head = NULL; a->block_head = NULL; } void upb_arena_init2(upb_arena *a, void *mem, size_t size, upb_alloc *alloc) { upb_arena_init(a); if (size > sizeof(mem_block)) { upb_arena_addblock(a, mem, size, false); } if (alloc) { a->block_alloc = alloc; } } void upb_arena_uninit(upb_arena *a) { cleanup_ent *ent = a->cleanup_head; mem_block *block = a->block_head; while (ent) { ent->cleanup(ent->ud); ent = ent->next; } /* Must do this after running cleanup functions, because this will delete * the memory we store our cleanup entries in! */ while (block) { mem_block *next = block->next; if (block->owned) { upb_free(a->block_alloc, block); } block = next; } /* Protect against multiple-uninit. */ a->cleanup_head = NULL; a->block_head = NULL; } bool upb_arena_addcleanup(upb_arena *a, upb_cleanup_func *func, void *ud) { cleanup_ent *ent = upb_malloc(&a->alloc, sizeof(cleanup_ent)); if (!ent) { return false; /* Out of memory. */ } ent->cleanup = func; ent->ud = ud; ent->next = a->cleanup_head; a->cleanup_head = ent; return true; } size_t upb_arena_bytesallocated(const upb_arena *a) { return a->bytes_allocated; } /* Standard error functions ***************************************************/ static bool default_err(void *ud, const upb_status *status) { UPB_UNUSED(ud); UPB_UNUSED(status); return false; } static bool write_err_to(void *ud, const upb_status *status) { upb_status *copy_to = ud; upb_status_copy(copy_to, status); return false; } /* upb_env ********************************************************************/ void upb_env_initonly(upb_env *e) { e->ok_ = true; e->error_func_ = &default_err; e->error_ud_ = NULL; } void upb_env_init(upb_env *e) { upb_arena_init(&e->arena_); upb_env_initonly(e); } void upb_env_init2(upb_env *e, void *mem, size_t n, upb_alloc *alloc) { upb_arena_init2(&e->arena_, mem, n, alloc); upb_env_initonly(e); } void upb_env_uninit(upb_env *e) { upb_arena_uninit(&e->arena_); } void upb_env_seterrorfunc(upb_env *e, upb_error_func *func, void *ud) { e->error_func_ = func; e->error_ud_ = ud; } void upb_env_reporterrorsto(upb_env *e, upb_status *s) { e->error_func_ = &write_err_to; e->error_ud_ = s; } bool upb_env_reporterror(upb_env *e, const upb_status *status) { e->ok_ = false; return e->error_func_(e->error_ud_, status); } void *upb_env_malloc(upb_env *e, size_t size) { return upb_malloc(&e->arena_.alloc, size); } void *upb_env_realloc(upb_env *e, void *ptr, size_t oldsize, size_t size) { return upb_realloc(&e->arena_.alloc, ptr, oldsize, size); } void upb_env_free(upb_env *e, void *ptr) { upb_free(&e->arena_.alloc, ptr); } bool upb_env_addcleanup(upb_env *e, upb_cleanup_func *func, void *ud) { return upb_arena_addcleanup(&e->arena_, func, ud); } size_t upb_env_bytesallocated(const upb_env *e) { return upb_arena_bytesallocated(&e->arena_); } /* This file was generated by upbc (the upb compiler) from the input * file: * * upb/descriptor/descriptor.proto * * Do not edit -- your changes will be discarded when the file is * regenerated. */ static const upb_msgdef msgs[22]; static const upb_fielddef fields[105]; static const upb_enumdef enums[5]; static const upb_tabent strentries[236]; static const upb_tabent intentries[18]; static const upb_tabval arrays[184]; #ifdef UPB_DEBUG_REFS static upb_inttable reftables[264]; #endif static const upb_msgdef msgs[22] = { UPB_MSGDEF_INIT("google.protobuf.DescriptorProto", 40, 8, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[0], 11, 10), UPB_STRTABLE_INIT(10, 15, UPB_CTYPE_PTR, 4, &strentries[0]), false, UPB_SYNTAX_PROTO2, &reftables[0], &reftables[1]), UPB_MSGDEF_INIT("google.protobuf.DescriptorProto.ExtensionRange", 4, 0, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[11], 3, 2), UPB_STRTABLE_INIT(2, 3, UPB_CTYPE_PTR, 2, &strentries[16]), false, UPB_SYNTAX_PROTO2, &reftables[2], &reftables[3]), UPB_MSGDEF_INIT("google.protobuf.DescriptorProto.ReservedRange", 4, 0, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[14], 3, 2), UPB_STRTABLE_INIT(2, 3, UPB_CTYPE_PTR, 2, &strentries[20]), false, UPB_SYNTAX_PROTO2, &reftables[4], &reftables[5]), UPB_MSGDEF_INIT("google.protobuf.EnumDescriptorProto", 11, 2, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[17], 4, 3), UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_PTR, 2, &strentries[24]), false, UPB_SYNTAX_PROTO2, &reftables[6], &reftables[7]), UPB_MSGDEF_INIT("google.protobuf.EnumOptions", 8, 1, UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &intentries[0], &arrays[21], 4, 2), UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_PTR, 2, &strentries[28]), false, UPB_SYNTAX_PROTO2, &reftables[8], &reftables[9]), UPB_MSGDEF_INIT("google.protobuf.EnumValueDescriptorProto", 8, 1, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[25], 4, 3), UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_PTR, 2, &strentries[32]), false, UPB_SYNTAX_PROTO2, &reftables[10], &reftables[11]), UPB_MSGDEF_INIT("google.protobuf.EnumValueOptions", 7, 1, UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &intentries[2], &arrays[29], 2, 1), UPB_STRTABLE_INIT(2, 3, UPB_CTYPE_PTR, 2, &strentries[36]), false, UPB_SYNTAX_PROTO2, &reftables[12], &reftables[13]), UPB_MSGDEF_INIT("google.protobuf.FieldDescriptorProto", 23, 1, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[31], 11, 10), UPB_STRTABLE_INIT(10, 15, UPB_CTYPE_PTR, 4, &strentries[40]), false, UPB_SYNTAX_PROTO2, &reftables[14], &reftables[15]), UPB_MSGDEF_INIT("google.protobuf.FieldOptions", 12, 1, UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &intentries[4], &arrays[42], 11, 6), UPB_STRTABLE_INIT(7, 15, UPB_CTYPE_PTR, 4, &strentries[56]), false, UPB_SYNTAX_PROTO2, &reftables[16], &reftables[17]), UPB_MSGDEF_INIT("google.protobuf.FileDescriptorProto", 42, 6, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[53], 13, 12), UPB_STRTABLE_INIT(12, 15, UPB_CTYPE_PTR, 4, &strentries[72]), false, UPB_SYNTAX_PROTO2, &reftables[18], &reftables[19]), UPB_MSGDEF_INIT("google.protobuf.FileDescriptorSet", 6, 1, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[66], 2, 1), UPB_STRTABLE_INIT(1, 3, UPB_CTYPE_PTR, 2, &strentries[88]), false, UPB_SYNTAX_PROTO2, &reftables[20], &reftables[21]), UPB_MSGDEF_INIT("google.protobuf.FileOptions", 31, 1, UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &intentries[6], &arrays[68], 39, 15), UPB_STRTABLE_INIT(16, 31, UPB_CTYPE_PTR, 5, &strentries[92]), false, UPB_SYNTAX_PROTO2, &reftables[22], &reftables[23]), UPB_MSGDEF_INIT("google.protobuf.MessageOptions", 10, 1, UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &intentries[8], &arrays[107], 8, 4), UPB_STRTABLE_INIT(5, 7, UPB_CTYPE_PTR, 3, &strentries[124]), false, UPB_SYNTAX_PROTO2, &reftables[24], &reftables[25]), UPB_MSGDEF_INIT("google.protobuf.MethodDescriptorProto", 15, 1, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[115], 7, 6), UPB_STRTABLE_INIT(6, 7, UPB_CTYPE_PTR, 3, &strentries[132]), false, UPB_SYNTAX_PROTO2, &reftables[26], &reftables[27]), UPB_MSGDEF_INIT("google.protobuf.MethodOptions", 7, 1, UPB_INTTABLE_INIT(2, 3, UPB_CTYPE_PTR, 2, &intentries[10], &arrays[122], 1, 0), UPB_STRTABLE_INIT(2, 3, UPB_CTYPE_PTR, 2, &strentries[140]), false, UPB_SYNTAX_PROTO2, &reftables[28], &reftables[29]), UPB_MSGDEF_INIT("google.protobuf.OneofDescriptorProto", 5, 0, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[123], 2, 1), UPB_STRTABLE_INIT(1, 3, UPB_CTYPE_PTR, 2, &strentries[144]), false, UPB_SYNTAX_PROTO2, &reftables[30], &reftables[31]), UPB_MSGDEF_INIT("google.protobuf.ServiceDescriptorProto", 11, 2, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[125], 4, 3), UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_PTR, 2, &strentries[148]), false, UPB_SYNTAX_PROTO2, &reftables[32], &reftables[33]), UPB_MSGDEF_INIT("google.protobuf.ServiceOptions", 7, 1, UPB_INTTABLE_INIT(2, 3, UPB_CTYPE_PTR, 2, &intentries[14], &arrays[129], 1, 0), UPB_STRTABLE_INIT(2, 3, UPB_CTYPE_PTR, 2, &strentries[152]), false, UPB_SYNTAX_PROTO2, &reftables[34], &reftables[35]), UPB_MSGDEF_INIT("google.protobuf.SourceCodeInfo", 6, 1, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[130], 2, 1), UPB_STRTABLE_INIT(1, 3, UPB_CTYPE_PTR, 2, &strentries[156]), false, UPB_SYNTAX_PROTO2, &reftables[36], &reftables[37]), UPB_MSGDEF_INIT("google.protobuf.SourceCodeInfo.Location", 19, 0, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[132], 7, 5), UPB_STRTABLE_INIT(5, 7, UPB_CTYPE_PTR, 3, &strentries[160]), false, UPB_SYNTAX_PROTO2, &reftables[38], &reftables[39]), UPB_MSGDEF_INIT("google.protobuf.UninterpretedOption", 18, 1, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[139], 9, 7), UPB_STRTABLE_INIT(7, 15, UPB_CTYPE_PTR, 4, &strentries[168]), false, UPB_SYNTAX_PROTO2, &reftables[40], &reftables[41]), UPB_MSGDEF_INIT("google.protobuf.UninterpretedOption.NamePart", 6, 0, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[148], 3, 2), UPB_STRTABLE_INIT(2, 3, UPB_CTYPE_PTR, 2, &strentries[184]), false, UPB_SYNTAX_PROTO2, &reftables[42], &reftables[43]), }; static const upb_fielddef fields[105] = { UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "aggregate_value", 8, &msgs[20], NULL, 15, 6, {0},&reftables[44], &reftables[45]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "allow_alias", 2, &msgs[4], NULL, 6, 1, {0},&reftables[46], &reftables[47]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "cc_enable_arenas", 31, &msgs[11], NULL, 23, 12, {0},&reftables[48], &reftables[49]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "cc_generic_services", 16, &msgs[11], NULL, 17, 6, {0},&reftables[50], &reftables[51]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "client_streaming", 5, &msgs[13], NULL, 13, 4, {0},&reftables[52], &reftables[53]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "csharp_namespace", 37, &msgs[11], NULL, 27, 14, {0},&reftables[54], &reftables[55]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, 0, false, false, false, false, "ctype", 1, &msgs[8], (const upb_def*)(&enums[2]), 6, 1, {0},&reftables[56], &reftables[57]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "default_value", 7, &msgs[7], NULL, 16, 7, {0},&reftables[58], &reftables[59]), UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_STRING, 0, false, false, false, false, "dependency", 3, &msgs[9], NULL, 30, 8, {0},&reftables[60], &reftables[61]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "deprecated", 3, &msgs[12], NULL, 8, 3, {0},&reftables[62], &reftables[63]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "deprecated", 3, &msgs[8], NULL, 8, 3, {0},&reftables[64], &reftables[65]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "deprecated", 33, &msgs[14], NULL, 6, 1, {0},&reftables[66], &reftables[67]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "deprecated", 23, &msgs[11], NULL, 21, 10, {0},&reftables[68], &reftables[69]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "deprecated", 3, &msgs[4], NULL, 7, 2, {0},&reftables[70], &reftables[71]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "deprecated", 33, &msgs[17], NULL, 6, 1, {0},&reftables[72], &reftables[73]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "deprecated", 1, &msgs[6], NULL, 6, 1, {0},&reftables[74], &reftables[75]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_DOUBLE, 0, false, false, false, false, "double_value", 6, &msgs[20], NULL, 11, 4, {0},&reftables[76], &reftables[77]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, false, false, false, "end", 2, &msgs[2], NULL, 3, 1, {0},&reftables[78], &reftables[79]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, false, false, false, "end", 2, &msgs[1], NULL, 3, 1, {0},&reftables[80], &reftables[81]), UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "enum_type", 4, &msgs[0], (const upb_def*)(&msgs[3]), 18, 2, {0},&reftables[82], &reftables[83]), UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "enum_type", 5, &msgs[9], (const upb_def*)(&msgs[3]), 13, 1, {0},&reftables[84], &reftables[85]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "extendee", 2, &msgs[7], NULL, 7, 2, {0},&reftables[86], &reftables[87]), UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "extension", 6, &msgs[0], (const upb_def*)(&msgs[7]), 24, 4, {0},&reftables[88], &reftables[89]), UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "extension", 7, &msgs[9], (const upb_def*)(&msgs[7]), 19, 3, {0},&reftables[90], &reftables[91]), UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "extension_range", 5, &msgs[0], (const upb_def*)(&msgs[1]), 21, 3, {0},&reftables[92], &reftables[93]), UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "field", 2, &msgs[0], (const upb_def*)(&msgs[7]), 12, 0, {0},&reftables[94], &reftables[95]), UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "file", 1, &msgs[10], (const upb_def*)(&msgs[9]), 5, 0, {0},&reftables[96], &reftables[97]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "go_package", 11, &msgs[11], NULL, 14, 5, {0},&reftables[98], &reftables[99]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "identifier_value", 3, &msgs[20], NULL, 6, 1, {0},&reftables[100], &reftables[101]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "input_type", 2, &msgs[13], NULL, 7, 2, {0},&reftables[102], &reftables[103]), UPB_FIELDDEF_INIT(UPB_LABEL_REQUIRED, UPB_TYPE_BOOL, 0, false, false, false, false, "is_extension", 2, &msgs[21], NULL, 5, 1, {0},&reftables[104], &reftables[105]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "java_generate_equals_and_hash", 20, &msgs[11], NULL, 20, 9, {0},&reftables[106], &reftables[107]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "java_generic_services", 17, &msgs[11], NULL, 18, 7, {0},&reftables[108], &reftables[109]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "java_multiple_files", 10, &msgs[11], NULL, 13, 4, {0},&reftables[110], &reftables[111]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "java_outer_classname", 8, &msgs[11], NULL, 9, 2, {0},&reftables[112], &reftables[113]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "java_package", 1, &msgs[11], NULL, 6, 1, {0},&reftables[114], &reftables[115]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "java_string_check_utf8", 27, &msgs[11], NULL, 22, 11, {0},&reftables[116], &reftables[117]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "javanano_use_deprecated_package", 38, &msgs[11], NULL, 30, 15, {0},&reftables[118], &reftables[119]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "json_name", 10, &msgs[7], NULL, 20, 9, {0},&reftables[120], &reftables[121]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, 0, false, false, false, false, "jstype", 6, &msgs[8], (const upb_def*)(&enums[3]), 10, 5, {0},&reftables[122], &reftables[123]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, 0, false, false, false, false, "label", 4, &msgs[7], (const upb_def*)(&enums[0]), 11, 4, {0},&reftables[124], &reftables[125]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "lazy", 5, &msgs[8], NULL, 9, 4, {0},&reftables[126], &reftables[127]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "leading_comments", 3, &msgs[19], NULL, 8, 2, {0},&reftables[128], &reftables[129]), UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_STRING, 0, false, false, false, false, "leading_detached_comments", 6, &msgs[19], NULL, 16, 4, {0},&reftables[130], &reftables[131]), UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "location", 1, &msgs[18], (const upb_def*)(&msgs[19]), 5, 0, {0},&reftables[132], &reftables[133]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "map_entry", 7, &msgs[12], NULL, 9, 4, {0},&reftables[134], &reftables[135]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "message_set_wire_format", 1, &msgs[12], NULL, 6, 1, {0},&reftables[136], &reftables[137]), UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "message_type", 4, &msgs[9], (const upb_def*)(&msgs[0]), 10, 0, {0},&reftables[138], &reftables[139]), UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "method", 2, &msgs[16], (const upb_def*)(&msgs[13]), 6, 0, {0},&reftables[140], &reftables[141]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "name", 1, &msgs[3], NULL, 8, 2, {0},&reftables[142], &reftables[143]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "name", 1, &msgs[15], NULL, 2, 0, {0},&reftables[144], &reftables[145]), UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "name", 2, &msgs[20], (const upb_def*)(&msgs[21]), 5, 0, {0},&reftables[146], &reftables[147]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "name", 1, &msgs[0], NULL, 32, 8, {0},&reftables[148], &reftables[149]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "name", 1, &msgs[5], NULL, 4, 1, {0},&reftables[150], &reftables[151]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "name", 1, &msgs[9], NULL, 22, 6, {0},&reftables[152], &reftables[153]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "name", 1, &msgs[7], NULL, 4, 1, {0},&reftables[154], &reftables[155]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "name", 1, &msgs[13], NULL, 4, 1, {0},&reftables[156], &reftables[157]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "name", 1, &msgs[16], NULL, 8, 2, {0},&reftables[158], &reftables[159]), UPB_FIELDDEF_INIT(UPB_LABEL_REQUIRED, UPB_TYPE_STRING, 0, false, false, false, false, "name_part", 1, &msgs[21], NULL, 2, 0, {0},&reftables[160], &reftables[161]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT64, UPB_INTFMT_VARIABLE, false, false, false, false, "negative_int_value", 5, &msgs[20], NULL, 10, 3, {0},&reftables[162], &reftables[163]), UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "nested_type", 3, &msgs[0], (const upb_def*)(&msgs[0]), 15, 1, {0},&reftables[164], &reftables[165]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "no_standard_descriptor_accessor", 2, &msgs[12], NULL, 7, 2, {0},&reftables[166], &reftables[167]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, false, false, false, "number", 2, &msgs[5], NULL, 7, 2, {0},&reftables[168], &reftables[169]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, false, false, false, "number", 3, &msgs[7], NULL, 10, 3, {0},&reftables[170], &reftables[171]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "objc_class_prefix", 36, &msgs[11], NULL, 24, 13, {0},&reftables[172], &reftables[173]), UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "oneof_decl", 8, &msgs[0], (const upb_def*)(&msgs[15]), 28, 6, {0},&reftables[174], &reftables[175]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, false, false, false, "oneof_index", 9, &msgs[7], NULL, 19, 8, {0},&reftables[176], &reftables[177]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, 0, false, false, false, false, "optimize_for", 9, &msgs[11], (const upb_def*)(&enums[4]), 12, 3, {0},&reftables[178], &reftables[179]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, false, false, false, "options", 7, &msgs[0], (const upb_def*)(&msgs[12]), 25, 5, {0},&reftables[180], &reftables[181]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, false, false, false, "options", 8, &msgs[9], (const upb_def*)(&msgs[11]), 20, 4, {0},&reftables[182], &reftables[183]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, false, false, false, "options", 4, &msgs[13], (const upb_def*)(&msgs[14]), 3, 0, {0},&reftables[184], &reftables[185]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, false, false, false, "options", 8, &msgs[7], (const upb_def*)(&msgs[8]), 3, 0, {0},&reftables[186], &reftables[187]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, false, false, false, "options", 3, &msgs[16], (const upb_def*)(&msgs[17]), 7, 1, {0},&reftables[188], &reftables[189]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, false, false, false, "options", 3, &msgs[5], (const upb_def*)(&msgs[6]), 3, 0, {0},&reftables[190], &reftables[191]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, false, false, false, "options", 3, &msgs[3], (const upb_def*)(&msgs[4]), 7, 1, {0},&reftables[192], &reftables[193]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "output_type", 3, &msgs[13], NULL, 10, 3, {0},&reftables[194], &reftables[195]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "package", 2, &msgs[9], NULL, 25, 7, {0},&reftables[196], &reftables[197]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "packed", 2, &msgs[8], NULL, 7, 2, {0},&reftables[198], &reftables[199]), UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, false, false, true, "path", 1, &msgs[19], NULL, 4, 0, {0},&reftables[200], &reftables[201]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_UINT64, UPB_INTFMT_VARIABLE, false, false, false, false, "positive_int_value", 4, &msgs[20], NULL, 9, 2, {0},&reftables[202], &reftables[203]), UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, false, false, false, "public_dependency", 10, &msgs[9], NULL, 35, 9, {0},&reftables[204], &reftables[205]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "py_generic_services", 18, &msgs[11], NULL, 19, 8, {0},&reftables[206], &reftables[207]), UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_STRING, 0, false, false, false, false, "reserved_name", 10, &msgs[0], NULL, 37, 9, {0},&reftables[208], &reftables[209]), UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "reserved_range", 9, &msgs[0], (const upb_def*)(&msgs[2]), 31, 7, {0},&reftables[210], &reftables[211]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "server_streaming", 6, &msgs[13], NULL, 14, 5, {0},&reftables[212], &reftables[213]), UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "service", 6, &msgs[9], (const upb_def*)(&msgs[16]), 16, 2, {0},&reftables[214], &reftables[215]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, false, false, false, "source_code_info", 9, &msgs[9], (const upb_def*)(&msgs[18]), 21, 5, {0},&reftables[216], &reftables[217]), UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, false, false, true, "span", 2, &msgs[19], NULL, 7, 1, {0},&reftables[218], &reftables[219]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, false, false, false, "start", 1, &msgs[2], NULL, 2, 0, {0},&reftables[220], &reftables[221]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, false, false, false, "start", 1, &msgs[1], NULL, 2, 0, {0},&reftables[222], &reftables[223]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BYTES, 0, false, false, false, false, "string_value", 7, &msgs[20], NULL, 12, 5, {0},&reftables[224], &reftables[225]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "syntax", 12, &msgs[9], NULL, 39, 11, {0},&reftables[226], &reftables[227]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "trailing_comments", 4, &msgs[19], NULL, 11, 3, {0},&reftables[228], &reftables[229]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, 0, false, false, false, false, "type", 5, &msgs[7], (const upb_def*)(&enums[1]), 12, 5, {0},&reftables[230], &reftables[231]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "type_name", 6, &msgs[7], NULL, 13, 6, {0},&reftables[232], &reftables[233]), UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "uninterpreted_option", 999, &msgs[11], (const upb_def*)(&msgs[20]), 5, 0, {0},&reftables[234], &reftables[235]), UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "uninterpreted_option", 999, &msgs[12], (const upb_def*)(&msgs[20]), 5, 0, {0},&reftables[236], &reftables[237]), UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "uninterpreted_option", 999, &msgs[6], (const upb_def*)(&msgs[20]), 5, 0, {0},&reftables[238], &reftables[239]), UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "uninterpreted_option", 999, &msgs[4], (const upb_def*)(&msgs[20]), 5, 0, {0},&reftables[240], &reftables[241]), UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "uninterpreted_option", 999, &msgs[8], (const upb_def*)(&msgs[20]), 5, 0, {0},&reftables[242], &reftables[243]), UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "uninterpreted_option", 999, &msgs[14], (const upb_def*)(&msgs[20]), 5, 0, {0},&reftables[244], &reftables[245]), UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "uninterpreted_option", 999, &msgs[17], (const upb_def*)(&msgs[20]), 5, 0, {0},&reftables[246], &reftables[247]), UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "value", 2, &msgs[3], (const upb_def*)(&msgs[5]), 6, 0, {0},&reftables[248], &reftables[249]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "weak", 10, &msgs[8], NULL, 11, 6, {0},&reftables[250], &reftables[251]), UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, false, false, false, "weak_dependency", 11, &msgs[9], NULL, 38, 10, {0},&reftables[252], &reftables[253]), }; static const upb_enumdef enums[5] = { UPB_ENUMDEF_INIT("google.protobuf.FieldDescriptorProto.Label", UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_INT32, 2, &strentries[188]), UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_CSTR, 0, NULL, &arrays[151], 4, 3), 0, &reftables[254], &reftables[255]), UPB_ENUMDEF_INIT("google.protobuf.FieldDescriptorProto.Type", UPB_STRTABLE_INIT(18, 31, UPB_CTYPE_INT32, 5, &strentries[192]), UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_CSTR, 0, NULL, &arrays[155], 19, 18), 0, &reftables[256], &reftables[257]), UPB_ENUMDEF_INIT("google.protobuf.FieldOptions.CType", UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_INT32, 2, &strentries[224]), UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_CSTR, 0, NULL, &arrays[174], 3, 3), 0, &reftables[258], &reftables[259]), UPB_ENUMDEF_INIT("google.protobuf.FieldOptions.JSType", UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_INT32, 2, &strentries[228]), UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_CSTR, 0, NULL, &arrays[177], 3, 3), 0, &reftables[260], &reftables[261]), UPB_ENUMDEF_INIT("google.protobuf.FileOptions.OptimizeMode", UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_INT32, 2, &strentries[232]), UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_CSTR, 0, NULL, &arrays[180], 4, 3), 0, &reftables[262], &reftables[263]), }; static const upb_tabent strentries[236] = { {UPB_TABKEY_STR("\011", "\000", "\000", "\000", "extension"), UPB_TABVALUE_PTR_INIT(&fields[22]), NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_STR("\015", "\000", "\000", "\000", "reserved_name"), UPB_TABVALUE_PTR_INIT(&fields[82]), NULL}, {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "name"), UPB_TABVALUE_PTR_INIT(&fields[52]), NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_STR("\005", "\000", "\000", "\000", "field"), UPB_TABVALUE_PTR_INIT(&fields[25]), &strentries[12]}, {UPB_TABKEY_STR("\017", "\000", "\000", "\000", "extension_range"), UPB_TABVALUE_PTR_INIT(&fields[24]), &strentries[14]}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_STR("\013", "\000", "\000", "\000", "nested_type"), UPB_TABVALUE_PTR_INIT(&fields[60]), NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_STR("\016", "\000", "\000", "\000", "reserved_range"), UPB_TABVALUE_PTR_INIT(&fields[83]), NULL}, {UPB_TABKEY_STR("\007", "\000", "\000", "\000", "options"), UPB_TABVALUE_PTR_INIT(&fields[68]), NULL}, {UPB_TABKEY_STR("\012", "\000", "\000", "\000", "oneof_decl"), UPB_TABVALUE_PTR_INIT(&fields[65]), NULL}, {UPB_TABKEY_STR("\011", "\000", "\000", "\000", "enum_type"), UPB_TABVALUE_PTR_INIT(&fields[19]), &strentries[13]}, {UPB_TABKEY_STR("\005", "\000", "\000", "\000", "start"), UPB_TABVALUE_PTR_INIT(&fields[89]), NULL}, {UPB_TABKEY_STR("\003", "\000", "\000", "\000", "end"), UPB_TABVALUE_PTR_INIT(&fields[18]), NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_STR("\005", "\000", "\000", "\000", "start"), UPB_TABVALUE_PTR_INIT(&fields[88]), NULL}, {UPB_TABKEY_STR("\003", "\000", "\000", "\000", "end"), UPB_TABVALUE_PTR_INIT(&fields[17]), NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_STR("\005", "\000", "\000", "\000", "value"), UPB_TABVALUE_PTR_INIT(&fields[102]), NULL}, {UPB_TABKEY_STR("\007", "\000", "\000", "\000", "options"), UPB_TABVALUE_PTR_INIT(&fields[74]), NULL}, {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "name"), UPB_TABVALUE_PTR_INIT(&fields[49]), &strentries[26]}, {UPB_TABKEY_STR("\024", "\000", "\000", "\000", "uninterpreted_option"), UPB_TABVALUE_PTR_INIT(&fields[98]), NULL}, {UPB_TABKEY_STR("\012", "\000", "\000", "\000", "deprecated"), UPB_TABVALUE_PTR_INIT(&fields[13]), NULL}, {UPB_TABKEY_STR("\013", "\000", "\000", "\000", "allow_alias"), UPB_TABVALUE_PTR_INIT(&fields[1]), NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_STR("\006", "\000", "\000", "\000", "number"), UPB_TABVALUE_PTR_INIT(&fields[62]), NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_STR("\007", "\000", "\000", "\000", "options"), UPB_TABVALUE_PTR_INIT(&fields[73]), NULL}, {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "name"), UPB_TABVALUE_PTR_INIT(&fields[53]), &strentries[34]}, {UPB_TABKEY_STR("\024", "\000", "\000", "\000", "uninterpreted_option"), UPB_TABVALUE_PTR_INIT(&fields[97]), NULL}, {UPB_TABKEY_STR("\012", "\000", "\000", "\000", "deprecated"), UPB_TABVALUE_PTR_INIT(&fields[15]), NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_STR("\013", "\000", "\000", "\000", "oneof_index"), UPB_TABVALUE_PTR_INIT(&fields[66]), NULL}, {UPB_TABKEY_STR("\005", "\000", "\000", "\000", "label"), UPB_TABVALUE_PTR_INIT(&fields[40]), NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "name"), UPB_TABVALUE_PTR_INIT(&fields[55]), NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_STR("\006", "\000", "\000", "\000", "number"), UPB_TABVALUE_PTR_INIT(&fields[63]), &strentries[53]}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_STR("\010", "\000", "\000", "\000", "extendee"), UPB_TABVALUE_PTR_INIT(&fields[21]), NULL}, {UPB_TABKEY_STR("\011", "\000", "\000", "\000", "type_name"), UPB_TABVALUE_PTR_INIT(&fields[94]), NULL}, {UPB_TABKEY_STR("\011", "\000", "\000", "\000", "json_name"), UPB_TABVALUE_PTR_INIT(&fields[38]), NULL}, {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "type"), UPB_TABVALUE_PTR_INIT(&fields[93]), &strentries[50]}, {UPB_TABKEY_STR("\015", "\000", "\000", "\000", "default_value"), UPB_TABVALUE_PTR_INIT(&fields[7]), NULL}, {UPB_TABKEY_STR("\007", "\000", "\000", "\000", "options"), UPB_TABVALUE_PTR_INIT(&fields[71]), NULL}, {UPB_TABKEY_STR("\024", "\000", "\000", "\000", "uninterpreted_option"), UPB_TABVALUE_PTR_INIT(&fields[99]), NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "weak"), UPB_TABVALUE_PTR_INIT(&fields[103]), NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_STR("\006", "\000", "\000", "\000", "packed"), UPB_TABVALUE_PTR_INIT(&fields[77]), NULL}, {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "lazy"), UPB_TABVALUE_PTR_INIT(&fields[41]), NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_STR("\005", "\000", "\000", "\000", "ctype"), UPB_TABVALUE_PTR_INIT(&fields[6]), NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_STR("\006", "\000", "\000", "\000", "jstype"), UPB_TABVALUE_PTR_INIT(&fields[39]), NULL}, {UPB_TABKEY_STR("\012", "\000", "\000", "\000", "deprecated"), UPB_TABVALUE_PTR_INIT(&fields[10]), NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_STR("\011", "\000", "\000", "\000", "extension"), UPB_TABVALUE_PTR_INIT(&fields[23]), NULL}, {UPB_TABKEY_STR("\017", "\000", "\000", "\000", "weak_dependency"), UPB_TABVALUE_PTR_INIT(&fields[104]), NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "name"), UPB_TABVALUE_PTR_INIT(&fields[54]), NULL}, {UPB_TABKEY_STR("\007", "\000", "\000", "\000", "service"), UPB_TABVALUE_PTR_INIT(&fields[85]), NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_STR("\020", "\000", "\000", "\000", "source_code_info"), UPB_TABVALUE_PTR_INIT(&fields[86]), NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_STR("\006", "\000", "\000", "\000", "syntax"), UPB_TABVALUE_PTR_INIT(&fields[91]), NULL}, {UPB_TABKEY_STR("\012", "\000", "\000", "\000", "dependency"), UPB_TABVALUE_PTR_INIT(&fields[8]), NULL}, {UPB_TABKEY_STR("\014", "\000", "\000", "\000", "message_type"), UPB_TABVALUE_PTR_INIT(&fields[47]), NULL}, {UPB_TABKEY_STR("\007", "\000", "\000", "\000", "package"), UPB_TABVALUE_PTR_INIT(&fields[76]), NULL}, {UPB_TABKEY_STR("\007", "\000", "\000", "\000", "options"), UPB_TABVALUE_PTR_INIT(&fields[69]), &strentries[86]}, {UPB_TABKEY_STR("\011", "\000", "\000", "\000", "enum_type"), UPB_TABVALUE_PTR_INIT(&fields[20]), NULL}, {UPB_TABKEY_STR("\021", "\000", "\000", "\000", "public_dependency"), UPB_TABVALUE_PTR_INIT(&fields[80]), &strentries[85]}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "file"), UPB_TABVALUE_PTR_INIT(&fields[26]), NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_STR("\023", "\000", "\000", "\000", "cc_generic_services"), UPB_TABVALUE_PTR_INIT(&fields[3]), NULL}, {UPB_TABKEY_STR("\020", "\000", "\000", "\000", "csharp_namespace"), UPB_TABVALUE_PTR_INIT(&fields[5]), NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_STR("\012", "\000", "\000", "\000", "go_package"), UPB_TABVALUE_PTR_INIT(&fields[27]), NULL}, {UPB_TABKEY_STR("\014", "\000", "\000", "\000", "java_package"), UPB_TABVALUE_PTR_INIT(&fields[35]), &strentries[120]}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_STR("\024", "\000", "\000", "\000", "java_outer_classname"), UPB_TABVALUE_PTR_INIT(&fields[34]), NULL}, {UPB_TABKEY_STR("\024", "\000", "\000", "\000", "uninterpreted_option"), UPB_TABVALUE_PTR_INIT(&fields[95]), NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_STR("\023", "\000", "\000", "\000", "java_multiple_files"), UPB_TABVALUE_PTR_INIT(&fields[33]), &strentries[117]}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_STR("\025", "\000", "\000", "\000", "java_generic_services"), UPB_TABVALUE_PTR_INIT(&fields[32]), &strentries[118]}, {UPB_TABKEY_STR("\035", "\000", "\000", "\000", "java_generate_equals_and_hash"), UPB_TABVALUE_PTR_INIT(&fields[31]), NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_STR("\037", "\000", "\000", "\000", "javanano_use_deprecated_package"), UPB_TABVALUE_PTR_INIT(&fields[37]), &strentries[123]}, {UPB_TABKEY_STR("\023", "\000", "\000", "\000", "py_generic_services"), UPB_TABVALUE_PTR_INIT(&fields[81]), NULL}, {UPB_TABKEY_STR("\014", "\000", "\000", "\000", "optimize_for"), UPB_TABVALUE_PTR_INIT(&fields[67]), NULL}, {UPB_TABKEY_STR("\026", "\000", "\000", "\000", "java_string_check_utf8"), UPB_TABVALUE_PTR_INIT(&fields[36]), NULL}, {UPB_TABKEY_STR("\012", "\000", "\000", "\000", "deprecated"), UPB_TABVALUE_PTR_INIT(&fields[12]), &strentries[119]}, {UPB_TABKEY_STR("\021", "\000", "\000", "\000", "objc_class_prefix"), UPB_TABVALUE_PTR_INIT(&fields[64]), NULL}, {UPB_TABKEY_STR("\020", "\000", "\000", "\000", "cc_enable_arenas"), UPB_TABVALUE_PTR_INIT(&fields[2]), NULL}, {UPB_TABKEY_STR("\027", "\000", "\000", "\000", "message_set_wire_format"), UPB_TABVALUE_PTR_INIT(&fields[46]), &strentries[128]}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_STR("\024", "\000", "\000", "\000", "uninterpreted_option"), UPB_TABVALUE_PTR_INIT(&fields[96]), NULL}, {UPB_TABKEY_STR("\012", "\000", "\000", "\000", "deprecated"), UPB_TABVALUE_PTR_INIT(&fields[9]), NULL}, {UPB_TABKEY_STR("\011", "\000", "\000", "\000", "map_entry"), UPB_TABVALUE_PTR_INIT(&fields[45]), NULL}, {UPB_TABKEY_STR("\037", "\000", "\000", "\000", "no_standard_descriptor_accessor"), UPB_TABVALUE_PTR_INIT(&fields[61]), NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_STR("\020", "\000", "\000", "\000", "client_streaming"), UPB_TABVALUE_PTR_INIT(&fields[4]), NULL}, {UPB_TABKEY_STR("\020", "\000", "\000", "\000", "server_streaming"), UPB_TABVALUE_PTR_INIT(&fields[84]), NULL}, {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "name"), UPB_TABVALUE_PTR_INIT(&fields[56]), NULL}, {UPB_TABKEY_STR("\012", "\000", "\000", "\000", "input_type"), UPB_TABVALUE_PTR_INIT(&fields[29]), NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_STR("\013", "\000", "\000", "\000", "output_type"), UPB_TABVALUE_PTR_INIT(&fields[75]), NULL}, {UPB_TABKEY_STR("\007", "\000", "\000", "\000", "options"), UPB_TABVALUE_PTR_INIT(&fields[70]), NULL}, {UPB_TABKEY_STR("\024", "\000", "\000", "\000", "uninterpreted_option"), UPB_TABVALUE_PTR_INIT(&fields[100]), NULL}, {UPB_TABKEY_STR("\012", "\000", "\000", "\000", "deprecated"), UPB_TABVALUE_PTR_INIT(&fields[11]), NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "name"), UPB_TABVALUE_PTR_INIT(&fields[50]), NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_STR("\007", "\000", "\000", "\000", "options"), UPB_TABVALUE_PTR_INIT(&fields[72]), &strentries[150]}, {UPB_TABKEY_STR("\006", "\000", "\000", "\000", "method"), UPB_TABVALUE_PTR_INIT(&fields[48]), NULL}, {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "name"), UPB_TABVALUE_PTR_INIT(&fields[57]), &strentries[149]}, {UPB_TABKEY_STR("\024", "\000", "\000", "\000", "uninterpreted_option"), UPB_TABVALUE_PTR_INIT(&fields[101]), NULL}, {UPB_TABKEY_STR("\012", "\000", "\000", "\000", "deprecated"), UPB_TABVALUE_PTR_INIT(&fields[14]), NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_STR("\010", "\000", "\000", "\000", "location"), UPB_TABVALUE_PTR_INIT(&fields[44]), NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "span"), UPB_TABVALUE_PTR_INIT(&fields[87]), &strentries[167]}, {UPB_TABKEY_STR("\031", "\000", "\000", "\000", "leading_detached_comments"), UPB_TABVALUE_PTR_INIT(&fields[43]), &strentries[165]}, {UPB_TABKEY_STR("\021", "\000", "\000", "\000", "trailing_comments"), UPB_TABVALUE_PTR_INIT(&fields[92]), NULL}, {UPB_TABKEY_STR("\020", "\000", "\000", "\000", "leading_comments"), UPB_TABVALUE_PTR_INIT(&fields[42]), &strentries[164]}, {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "path"), UPB_TABVALUE_PTR_INIT(&fields[78]), NULL}, {UPB_TABKEY_STR("\014", "\000", "\000", "\000", "double_value"), UPB_TABVALUE_PTR_INIT(&fields[16]), NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "name"), UPB_TABVALUE_PTR_INIT(&fields[51]), NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_STR("\022", "\000", "\000", "\000", "negative_int_value"), UPB_TABVALUE_PTR_INIT(&fields[59]), NULL}, {UPB_TABKEY_STR("\017", "\000", "\000", "\000", "aggregate_value"), UPB_TABVALUE_PTR_INIT(&fields[0]), NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_STR("\022", "\000", "\000", "\000", "positive_int_value"), UPB_TABVALUE_PTR_INIT(&fields[79]), NULL}, {UPB_TABKEY_STR("\020", "\000", "\000", "\000", "identifier_value"), UPB_TABVALUE_PTR_INIT(&fields[28]), NULL}, {UPB_TABKEY_STR("\014", "\000", "\000", "\000", "string_value"), UPB_TABVALUE_PTR_INIT(&fields[90]), &strentries[182]}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_STR("\014", "\000", "\000", "\000", "is_extension"), UPB_TABVALUE_PTR_INIT(&fields[30]), NULL}, {UPB_TABKEY_STR("\011", "\000", "\000", "\000", "name_part"), UPB_TABVALUE_PTR_INIT(&fields[58]), NULL}, {UPB_TABKEY_STR("\016", "\000", "\000", "\000", "LABEL_REQUIRED"), UPB_TABVALUE_INT_INIT(2), &strentries[190]}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_STR("\016", "\000", "\000", "\000", "LABEL_REPEATED"), UPB_TABVALUE_INT_INIT(3), NULL}, {UPB_TABKEY_STR("\016", "\000", "\000", "\000", "LABEL_OPTIONAL"), UPB_TABVALUE_INT_INIT(1), NULL}, {UPB_TABKEY_STR("\014", "\000", "\000", "\000", "TYPE_FIXED64"), UPB_TABVALUE_INT_INIT(6), NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_STR("\013", "\000", "\000", "\000", "TYPE_STRING"), UPB_TABVALUE_INT_INIT(9), NULL}, {UPB_TABKEY_STR("\012", "\000", "\000", "\000", "TYPE_FLOAT"), UPB_TABVALUE_INT_INIT(2), &strentries[221]}, {UPB_TABKEY_STR("\013", "\000", "\000", "\000", "TYPE_DOUBLE"), UPB_TABVALUE_INT_INIT(1), NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_STR("\012", "\000", "\000", "\000", "TYPE_INT32"), UPB_TABVALUE_INT_INIT(5), NULL}, {UPB_TABKEY_STR("\015", "\000", "\000", "\000", "TYPE_SFIXED32"), UPB_TABVALUE_INT_INIT(15), NULL}, {UPB_TABKEY_STR("\014", "\000", "\000", "\000", "TYPE_FIXED32"), UPB_TABVALUE_INT_INIT(7), NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_STR("\014", "\000", "\000", "\000", "TYPE_MESSAGE"), UPB_TABVALUE_INT_INIT(11), &strentries[222]}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_STR("\012", "\000", "\000", "\000", "TYPE_INT64"), UPB_TABVALUE_INT_INIT(3), &strentries[219]}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_STR("\011", "\000", "\000", "\000", "TYPE_ENUM"), UPB_TABVALUE_INT_INIT(14), NULL}, {UPB_TABKEY_STR("\013", "\000", "\000", "\000", "TYPE_UINT32"), UPB_TABVALUE_INT_INIT(13), NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_STR("\013", "\000", "\000", "\000", "TYPE_UINT64"), UPB_TABVALUE_INT_INIT(4), &strentries[218]}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_STR("\015", "\000", "\000", "\000", "TYPE_SFIXED64"), UPB_TABVALUE_INT_INIT(16), NULL}, {UPB_TABKEY_STR("\012", "\000", "\000", "\000", "TYPE_BYTES"), UPB_TABVALUE_INT_INIT(12), NULL}, {UPB_TABKEY_STR("\013", "\000", "\000", "\000", "TYPE_SINT64"), UPB_TABVALUE_INT_INIT(18), NULL}, {UPB_TABKEY_STR("\011", "\000", "\000", "\000", "TYPE_BOOL"), UPB_TABVALUE_INT_INIT(8), NULL}, {UPB_TABKEY_STR("\012", "\000", "\000", "\000", "TYPE_GROUP"), UPB_TABVALUE_INT_INIT(10), NULL}, {UPB_TABKEY_STR("\013", "\000", "\000", "\000", "TYPE_SINT32"), UPB_TABVALUE_INT_INIT(17), NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "CORD"), UPB_TABVALUE_INT_INIT(1), NULL}, {UPB_TABKEY_STR("\006", "\000", "\000", "\000", "STRING"), UPB_TABVALUE_INT_INIT(0), &strentries[225]}, {UPB_TABKEY_STR("\014", "\000", "\000", "\000", "STRING_PIECE"), UPB_TABVALUE_INT_INIT(2), NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_STR("\011", "\000", "\000", "\000", "JS_NORMAL"), UPB_TABVALUE_INT_INIT(0), NULL}, {UPB_TABKEY_STR("\011", "\000", "\000", "\000", "JS_NUMBER"), UPB_TABVALUE_INT_INIT(2), NULL}, {UPB_TABKEY_STR("\011", "\000", "\000", "\000", "JS_STRING"), UPB_TABVALUE_INT_INIT(1), NULL}, {UPB_TABKEY_STR("\011", "\000", "\000", "\000", "CODE_SIZE"), UPB_TABVALUE_INT_INIT(2), NULL}, {UPB_TABKEY_STR("\005", "\000", "\000", "\000", "SPEED"), UPB_TABVALUE_INT_INIT(1), &strentries[235]}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_STR("\014", "\000", "\000", "\000", "LITE_RUNTIME"), UPB_TABVALUE_INT_INIT(3), NULL}, }; static const upb_tabent intentries[18] = { {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_NUM(999), UPB_TABVALUE_PTR_INIT(&fields[98]), NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_NUM(999), UPB_TABVALUE_PTR_INIT(&fields[97]), NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_NUM(999), UPB_TABVALUE_PTR_INIT(&fields[99]), NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_NUM(999), UPB_TABVALUE_PTR_INIT(&fields[95]), NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_NUM(999), UPB_TABVALUE_PTR_INIT(&fields[96]), NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_NUM(33), UPB_TABVALUE_PTR_INIT(&fields[11]), NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_NUM(999), UPB_TABVALUE_PTR_INIT(&fields[100]), NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_NUM(33), UPB_TABVALUE_PTR_INIT(&fields[14]), NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_NUM(999), UPB_TABVALUE_PTR_INIT(&fields[101]), NULL}, }; static const upb_tabval arrays[184] = { UPB_TABVALUE_EMPTY_INIT, UPB_TABVALUE_PTR_INIT(&fields[52]), UPB_TABVALUE_PTR_INIT(&fields[25]), UPB_TABVALUE_PTR_INIT(&fields[60]), UPB_TABVALUE_PTR_INIT(&fields[19]), UPB_TABVALUE_PTR_INIT(&fields[24]), UPB_TABVALUE_PTR_INIT(&fields[22]), UPB_TABVALUE_PTR_INIT(&fields[68]), UPB_TABVALUE_PTR_INIT(&fields[65]), UPB_TABVALUE_PTR_INIT(&fields[83]), UPB_TABVALUE_PTR_INIT(&fields[82]), UPB_TABVALUE_EMPTY_INIT, UPB_TABVALUE_PTR_INIT(&fields[89]), UPB_TABVALUE_PTR_INIT(&fields[18]), UPB_TABVALUE_EMPTY_INIT, UPB_TABVALUE_PTR_INIT(&fields[88]), UPB_TABVALUE_PTR_INIT(&fields[17]), UPB_TABVALUE_EMPTY_INIT, UPB_TABVALUE_PTR_INIT(&fields[49]), UPB_TABVALUE_PTR_INIT(&fields[102]), UPB_TABVALUE_PTR_INIT(&fields[74]), UPB_TABVALUE_EMPTY_INIT, UPB_TABVALUE_EMPTY_INIT, UPB_TABVALUE_PTR_INIT(&fields[1]), UPB_TABVALUE_PTR_INIT(&fields[13]), UPB_TABVALUE_EMPTY_INIT, UPB_TABVALUE_PTR_INIT(&fields[53]), UPB_TABVALUE_PTR_INIT(&fields[62]), UPB_TABVALUE_PTR_INIT(&fields[73]), UPB_TABVALUE_EMPTY_INIT, UPB_TABVALUE_PTR_INIT(&fields[15]), UPB_TABVALUE_EMPTY_INIT, UPB_TABVALUE_PTR_INIT(&fields[55]), UPB_TABVALUE_PTR_INIT(&fields[21]), UPB_TABVALUE_PTR_INIT(&fields[63]), UPB_TABVALUE_PTR_INIT(&fields[40]), UPB_TABVALUE_PTR_INIT(&fields[93]), UPB_TABVALUE_PTR_INIT(&fields[94]), UPB_TABVALUE_PTR_INIT(&fields[7]), UPB_TABVALUE_PTR_INIT(&fields[71]), UPB_TABVALUE_PTR_INIT(&fields[66]), UPB_TABVALUE_PTR_INIT(&fields[38]), UPB_TABVALUE_EMPTY_INIT, UPB_TABVALUE_PTR_INIT(&fields[6]), UPB_TABVALUE_PTR_INIT(&fields[77]), UPB_TABVALUE_PTR_INIT(&fields[10]), UPB_TABVALUE_EMPTY_INIT, UPB_TABVALUE_PTR_INIT(&fields[41]), UPB_TABVALUE_PTR_INIT(&fields[39]), UPB_TABVALUE_EMPTY_INIT, UPB_TABVALUE_EMPTY_INIT, UPB_TABVALUE_EMPTY_INIT, UPB_TABVALUE_PTR_INIT(&fields[103]), UPB_TABVALUE_EMPTY_INIT, UPB_TABVALUE_PTR_INIT(&fields[54]), UPB_TABVALUE_PTR_INIT(&fields[76]), UPB_TABVALUE_PTR_INIT(&fields[8]), UPB_TABVALUE_PTR_INIT(&fields[47]), UPB_TABVALUE_PTR_INIT(&fields[20]), UPB_TABVALUE_PTR_INIT(&fields[85]), UPB_TABVALUE_PTR_INIT(&fields[23]), UPB_TABVALUE_PTR_INIT(&fields[69]), UPB_TABVALUE_PTR_INIT(&fields[86]), UPB_TABVALUE_PTR_INIT(&fields[80]), UPB_TABVALUE_PTR_INIT(&fields[104]), UPB_TABVALUE_PTR_INIT(&fields[91]), UPB_TABVALUE_EMPTY_INIT, UPB_TABVALUE_PTR_INIT(&fields[26]), UPB_TABVALUE_EMPTY_INIT, UPB_TABVALUE_PTR_INIT(&fields[35]), UPB_TABVALUE_EMPTY_INIT, UPB_TABVALUE_EMPTY_INIT, UPB_TABVALUE_EMPTY_INIT, UPB_TABVALUE_EMPTY_INIT, UPB_TABVALUE_EMPTY_INIT, UPB_TABVALUE_EMPTY_INIT, UPB_TABVALUE_PTR_INIT(&fields[34]), UPB_TABVALUE_PTR_INIT(&fields[67]), UPB_TABVALUE_PTR_INIT(&fields[33]), UPB_TABVALUE_PTR_INIT(&fields[27]), UPB_TABVALUE_EMPTY_INIT, UPB_TABVALUE_EMPTY_INIT, UPB_TABVALUE_EMPTY_INIT, UPB_TABVALUE_EMPTY_INIT, UPB_TABVALUE_PTR_INIT(&fields[3]), UPB_TABVALUE_PTR_INIT(&fields[32]), UPB_TABVALUE_PTR_INIT(&fields[81]), UPB_TABVALUE_EMPTY_INIT, UPB_TABVALUE_PTR_INIT(&fields[31]), UPB_TABVALUE_EMPTY_INIT, UPB_TABVALUE_EMPTY_INIT, UPB_TABVALUE_PTR_INIT(&fields[12]), UPB_TABVALUE_EMPTY_INIT, UPB_TABVALUE_EMPTY_INIT, UPB_TABVALUE_EMPTY_INIT, UPB_TABVALUE_PTR_INIT(&fields[36]), UPB_TABVALUE_EMPTY_INIT, UPB_TABVALUE_EMPTY_INIT, UPB_TABVALUE_EMPTY_INIT, UPB_TABVALUE_PTR_INIT(&fields[2]), UPB_TABVALUE_EMPTY_INIT, UPB_TABVALUE_EMPTY_INIT, UPB_TABVALUE_EMPTY_INIT, UPB_TABVALUE_EMPTY_INIT, UPB_TABVALUE_PTR_INIT(&fields[64]), UPB_TABVALUE_PTR_INIT(&fields[5]), UPB_TABVALUE_PTR_INIT(&fields[37]), UPB_TABVALUE_EMPTY_INIT, UPB_TABVALUE_PTR_INIT(&fields[46]), UPB_TABVALUE_PTR_INIT(&fields[61]), UPB_TABVALUE_PTR_INIT(&fields[9]), UPB_TABVALUE_EMPTY_INIT, UPB_TABVALUE_EMPTY_INIT, UPB_TABVALUE_EMPTY_INIT, UPB_TABVALUE_PTR_INIT(&fields[45]), UPB_TABVALUE_EMPTY_INIT, UPB_TABVALUE_PTR_INIT(&fields[56]), UPB_TABVALUE_PTR_INIT(&fields[29]), UPB_TABVALUE_PTR_INIT(&fields[75]), UPB_TABVALUE_PTR_INIT(&fields[70]), UPB_TABVALUE_PTR_INIT(&fields[4]), UPB_TABVALUE_PTR_INIT(&fields[84]), UPB_TABVALUE_EMPTY_INIT, UPB_TABVALUE_EMPTY_INIT, UPB_TABVALUE_PTR_INIT(&fields[50]), UPB_TABVALUE_EMPTY_INIT, UPB_TABVALUE_PTR_INIT(&fields[57]), UPB_TABVALUE_PTR_INIT(&fields[48]), UPB_TABVALUE_PTR_INIT(&fields[72]), UPB_TABVALUE_EMPTY_INIT, UPB_TABVALUE_EMPTY_INIT, UPB_TABVALUE_PTR_INIT(&fields[44]), UPB_TABVALUE_EMPTY_INIT, UPB_TABVALUE_PTR_INIT(&fields[78]), UPB_TABVALUE_PTR_INIT(&fields[87]), UPB_TABVALUE_PTR_INIT(&fields[42]), UPB_TABVALUE_PTR_INIT(&fields[92]), UPB_TABVALUE_EMPTY_INIT, UPB_TABVALUE_PTR_INIT(&fields[43]), UPB_TABVALUE_EMPTY_INIT, UPB_TABVALUE_EMPTY_INIT, UPB_TABVALUE_PTR_INIT(&fields[51]), UPB_TABVALUE_PTR_INIT(&fields[28]), UPB_TABVALUE_PTR_INIT(&fields[79]), UPB_TABVALUE_PTR_INIT(&fields[59]), UPB_TABVALUE_PTR_INIT(&fields[16]), UPB_TABVALUE_PTR_INIT(&fields[90]), UPB_TABVALUE_PTR_INIT(&fields[0]), UPB_TABVALUE_EMPTY_INIT, UPB_TABVALUE_PTR_INIT(&fields[58]), UPB_TABVALUE_PTR_INIT(&fields[30]), UPB_TABVALUE_EMPTY_INIT, UPB_TABVALUE_PTR_INIT("LABEL_OPTIONAL"), UPB_TABVALUE_PTR_INIT("LABEL_REQUIRED"), UPB_TABVALUE_PTR_INIT("LABEL_REPEATED"), UPB_TABVALUE_EMPTY_INIT, UPB_TABVALUE_PTR_INIT("TYPE_DOUBLE"), UPB_TABVALUE_PTR_INIT("TYPE_FLOAT"), UPB_TABVALUE_PTR_INIT("TYPE_INT64"), UPB_TABVALUE_PTR_INIT("TYPE_UINT64"), UPB_TABVALUE_PTR_INIT("TYPE_INT32"), UPB_TABVALUE_PTR_INIT("TYPE_FIXED64"), UPB_TABVALUE_PTR_INIT("TYPE_FIXED32"), UPB_TABVALUE_PTR_INIT("TYPE_BOOL"), UPB_TABVALUE_PTR_INIT("TYPE_STRING"), UPB_TABVALUE_PTR_INIT("TYPE_GROUP"), UPB_TABVALUE_PTR_INIT("TYPE_MESSAGE"), UPB_TABVALUE_PTR_INIT("TYPE_BYTES"), UPB_TABVALUE_PTR_INIT("TYPE_UINT32"), UPB_TABVALUE_PTR_INIT("TYPE_ENUM"), UPB_TABVALUE_PTR_INIT("TYPE_SFIXED32"), UPB_TABVALUE_PTR_INIT("TYPE_SFIXED64"), UPB_TABVALUE_PTR_INIT("TYPE_SINT32"), UPB_TABVALUE_PTR_INIT("TYPE_SINT64"), UPB_TABVALUE_PTR_INIT("STRING"), UPB_TABVALUE_PTR_INIT("CORD"), UPB_TABVALUE_PTR_INIT("STRING_PIECE"), UPB_TABVALUE_PTR_INIT("JS_NORMAL"), UPB_TABVALUE_PTR_INIT("JS_STRING"), UPB_TABVALUE_PTR_INIT("JS_NUMBER"), UPB_TABVALUE_EMPTY_INIT, UPB_TABVALUE_PTR_INIT("SPEED"), UPB_TABVALUE_PTR_INIT("CODE_SIZE"), UPB_TABVALUE_PTR_INIT("LITE_RUNTIME"), }; #ifdef UPB_DEBUG_REFS static upb_inttable reftables[264] = { UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), }; #endif static const upb_msgdef *refm(const upb_msgdef *m, const void *owner) { upb_msgdef_ref(m, owner); return m; } static const upb_enumdef *refe(const upb_enumdef *e, const void *owner) { upb_enumdef_ref(e, owner); return e; } /* Public API. */ const upb_msgdef *upbdefs_google_protobuf_DescriptorProto_get(const void *owner) { return refm(&msgs[0], owner); } const upb_msgdef *upbdefs_google_protobuf_DescriptorProto_ExtensionRange_get(const void *owner) { return refm(&msgs[1], owner); } const upb_msgdef *upbdefs_google_protobuf_DescriptorProto_ReservedRange_get(const void *owner) { return refm(&msgs[2], owner); } const upb_msgdef *upbdefs_google_protobuf_EnumDescriptorProto_get(const void *owner) { return refm(&msgs[3], owner); } const upb_msgdef *upbdefs_google_protobuf_EnumOptions_get(const void *owner) { return refm(&msgs[4], owner); } const upb_msgdef *upbdefs_google_protobuf_EnumValueDescriptorProto_get(const void *owner) { return refm(&msgs[5], owner); } const upb_msgdef *upbdefs_google_protobuf_EnumValueOptions_get(const void *owner) { return refm(&msgs[6], owner); } const upb_msgdef *upbdefs_google_protobuf_FieldDescriptorProto_get(const void *owner) { return refm(&msgs[7], owner); } const upb_msgdef *upbdefs_google_protobuf_FieldOptions_get(const void *owner) { return refm(&msgs[8], owner); } const upb_msgdef *upbdefs_google_protobuf_FileDescriptorProto_get(const void *owner) { return refm(&msgs[9], owner); } const upb_msgdef *upbdefs_google_protobuf_FileDescriptorSet_get(const void *owner) { return refm(&msgs[10], owner); } const upb_msgdef *upbdefs_google_protobuf_FileOptions_get(const void *owner) { return refm(&msgs[11], owner); } const upb_msgdef *upbdefs_google_protobuf_MessageOptions_get(const void *owner) { return refm(&msgs[12], owner); } const upb_msgdef *upbdefs_google_protobuf_MethodDescriptorProto_get(const void *owner) { return refm(&msgs[13], owner); } const upb_msgdef *upbdefs_google_protobuf_MethodOptions_get(const void *owner) { return refm(&msgs[14], owner); } const upb_msgdef *upbdefs_google_protobuf_OneofDescriptorProto_get(const void *owner) { return refm(&msgs[15], owner); } const upb_msgdef *upbdefs_google_protobuf_ServiceDescriptorProto_get(const void *owner) { return refm(&msgs[16], owner); } const upb_msgdef *upbdefs_google_protobuf_ServiceOptions_get(const void *owner) { return refm(&msgs[17], owner); } const upb_msgdef *upbdefs_google_protobuf_SourceCodeInfo_get(const void *owner) { return refm(&msgs[18], owner); } const upb_msgdef *upbdefs_google_protobuf_SourceCodeInfo_Location_get(const void *owner) { return refm(&msgs[19], owner); } const upb_msgdef *upbdefs_google_protobuf_UninterpretedOption_get(const void *owner) { return refm(&msgs[20], owner); } const upb_msgdef *upbdefs_google_protobuf_UninterpretedOption_NamePart_get(const void *owner) { return refm(&msgs[21], owner); } const upb_enumdef *upbdefs_google_protobuf_FieldDescriptorProto_Label_get(const void *owner) { return refe(&enums[0], owner); } const upb_enumdef *upbdefs_google_protobuf_FieldDescriptorProto_Type_get(const void *owner) { return refe(&enums[1], owner); } const upb_enumdef *upbdefs_google_protobuf_FieldOptions_CType_get(const void *owner) { return refe(&enums[2], owner); } const upb_enumdef *upbdefs_google_protobuf_FieldOptions_JSType_get(const void *owner) { return refe(&enums[3], owner); } const upb_enumdef *upbdefs_google_protobuf_FileOptions_OptimizeMode_get(const void *owner) { return refe(&enums[4], owner); } /* ** XXX: The routines in this file that consume a string do not currently ** support having the string span buffers. In the future, as upb_sink and ** its buffering/sharing functionality evolve there should be an easy and ** idiomatic way of correctly handling this case. For now, we accept this ** limitation since we currently only parse descriptors from single strings. */ #include #include #include /* Compares a NULL-terminated string with a non-NULL-terminated string. */ static bool upb_streq(const char *str, const char *buf, size_t n) { return strlen(str) == n && memcmp(str, buf, n) == 0; } /* We keep a stack of all the messages scopes we are currently in, as well as * the top-level file scope. This is necessary to correctly qualify the * definitions that are contained inside. "name" tracks the name of the * message or package (a bare name -- not qualified by any enclosing scopes). */ typedef struct { char *name; /* Index of the first def that is under this scope. For msgdefs, the * msgdef itself is at start-1. */ int start; uint32_t oneof_start; uint32_t oneof_index; } upb_descreader_frame; /* The maximum number of nested declarations that are allowed, ie. * message Foo { * message Bar { * message Baz { * } * } * } * * This is a resource limit that affects how big our runtime stack can grow. * TODO: make this a runtime-settable property of the Reader instance. */ #define UPB_MAX_MESSAGE_NESTING 64 struct upb_descreader { upb_sink sink; upb_inttable files; upb_filedef *file; /* The last file in files. */ upb_descreader_frame stack[UPB_MAX_MESSAGE_NESTING]; int stack_len; upb_inttable oneofs; uint32_t number; char *name; bool saw_number; bool saw_name; char *default_string; upb_fielddef *f; }; static char *upb_gstrndup(const char *buf, size_t n) { char *ret = upb_gmalloc(n + 1); if (!ret) return NULL; memcpy(ret, buf, n); ret[n] = '\0'; return ret; } /* Returns a newly allocated string that joins input strings together, for * example: * join("Foo.Bar", "Baz") -> "Foo.Bar.Baz" * join("", "Baz") -> "Baz" * Caller owns a ref on the returned string. */ static char *upb_join(const char *base, const char *name) { if (!base || strlen(base) == 0) { return upb_gstrdup(name); } else { char *ret = upb_gmalloc(strlen(base) + strlen(name) + 2); if (!ret) { return NULL; } ret[0] = '\0'; strcat(ret, base); strcat(ret, "."); strcat(ret, name); return ret; } } /* Qualify the defname for all defs starting with offset "start" with "str". */ static bool upb_descreader_qualify(upb_filedef *f, char *str, int32_t start) { size_t i; for (i = start; i < upb_filedef_defcount(f); i++) { upb_def *def = upb_filedef_mutabledef(f, i); char *name = upb_join(str, upb_def_fullname(def)); if (!name) { /* Need better logic here; at this point we've qualified some names but * not others. */ return false; } upb_def_setfullname(def, name, NULL); upb_gfree(name); } return true; } /* upb_descreader ************************************************************/ static upb_msgdef *upb_descreader_top(upb_descreader *r) { int index; UPB_ASSERT(r->stack_len > 1); index = r->stack[r->stack_len-1].start - 1; UPB_ASSERT(index >= 0); return upb_downcast_msgdef_mutable(upb_filedef_mutabledef(r->file, index)); } static upb_def *upb_descreader_last(upb_descreader *r) { return upb_filedef_mutabledef(r->file, upb_filedef_defcount(r->file) - 1); } /* Start/end handlers for FileDescriptorProto and DescriptorProto (the two * entities that have names and can contain sub-definitions. */ void upb_descreader_startcontainer(upb_descreader *r) { upb_descreader_frame *f = &r->stack[r->stack_len++]; f->start = upb_filedef_defcount(r->file); f->oneof_start = upb_inttable_count(&r->oneofs); f->oneof_index = 0; f->name = NULL; } bool upb_descreader_endcontainer(upb_descreader *r) { upb_descreader_frame *f = &r->stack[r->stack_len - 1]; while (upb_inttable_count(&r->oneofs) > f->oneof_start) { upb_oneofdef *o = upb_value_getptr(upb_inttable_pop(&r->oneofs)); bool ok = upb_msgdef_addoneof(upb_descreader_top(r), o, &r->oneofs, NULL); UPB_ASSERT(ok); } if (!upb_descreader_qualify(r->file, f->name, f->start)) { return false; } upb_gfree(f->name); f->name = NULL; r->stack_len--; return true; } void upb_descreader_setscopename(upb_descreader *r, char *str) { upb_descreader_frame *f = &r->stack[r->stack_len-1]; upb_gfree(f->name); f->name = str; } static upb_oneofdef *upb_descreader_getoneof(upb_descreader *r, uint32_t index) { bool found; upb_value val; upb_descreader_frame *f = &r->stack[r->stack_len-1]; /* DescriptorProto messages can be nested, so we will see the nested messages * between when we see the FieldDescriptorProto and the OneofDescriptorProto. * We need to preserve the oneofs in between these two things. */ index += f->oneof_start; while (upb_inttable_count(&r->oneofs) <= index) { upb_inttable_push(&r->oneofs, upb_value_ptr(upb_oneofdef_new(&r->oneofs))); } found = upb_inttable_lookup(&r->oneofs, index, &val); UPB_ASSERT(found); return upb_value_getptr(val); } /** Handlers for google.protobuf.FileDescriptorSet. ***************************/ static void *fileset_startfile(void *closure, const void *hd) { upb_descreader *r = closure; UPB_UNUSED(hd); r->file = upb_filedef_new(&r->files); upb_inttable_push(&r->files, upb_value_ptr(r->file)); return r; } /** Handlers for google.protobuf.FileDescriptorProto. *************************/ static bool file_start(void *closure, const void *hd) { upb_descreader *r = closure; UPB_UNUSED(hd); upb_descreader_startcontainer(r); return true; } static bool file_end(void *closure, const void *hd, upb_status *status) { upb_descreader *r = closure; UPB_UNUSED(hd); UPB_UNUSED(status); return upb_descreader_endcontainer(r); } static size_t file_onname(void *closure, const void *hd, const char *buf, size_t n, const upb_bufhandle *handle) { upb_descreader *r = closure; char *name; bool ok; UPB_UNUSED(hd); UPB_UNUSED(handle); name = upb_gstrndup(buf, n); /* XXX: see comment at the top of the file. */ ok = upb_filedef_setname(r->file, name, NULL); upb_gfree(name); UPB_ASSERT(ok); return n; } static size_t file_onpackage(void *closure, const void *hd, const char *buf, size_t n, const upb_bufhandle *handle) { upb_descreader *r = closure; char *package; bool ok; UPB_UNUSED(hd); UPB_UNUSED(handle); package = upb_gstrndup(buf, n); /* XXX: see comment at the top of the file. */ upb_descreader_setscopename(r, package); ok = upb_filedef_setpackage(r->file, package, NULL); UPB_ASSERT(ok); return n; } static size_t file_onsyntax(void *closure, const void *hd, const char *buf, size_t n, const upb_bufhandle *handle) { upb_descreader *r = closure; bool ok; UPB_UNUSED(hd); UPB_UNUSED(handle); /* XXX: see comment at the top of the file. */ if (upb_streq("proto2", buf, n)) { ok = upb_filedef_setsyntax(r->file, UPB_SYNTAX_PROTO2, NULL); } else if (upb_streq("proto3", buf, n)) { ok = upb_filedef_setsyntax(r->file, UPB_SYNTAX_PROTO3, NULL); } else { ok = false; } UPB_ASSERT(ok); return n; } static void *file_startmsg(void *closure, const void *hd) { upb_descreader *r = closure; upb_msgdef *m = upb_msgdef_new(&m); bool ok = upb_filedef_addmsg(r->file, m, &m, NULL); UPB_UNUSED(hd); UPB_ASSERT(ok); return r; } static void *file_startenum(void *closure, const void *hd) { upb_descreader *r = closure; upb_enumdef *e = upb_enumdef_new(&e); bool ok = upb_filedef_addenum(r->file, e, &e, NULL); UPB_UNUSED(hd); UPB_ASSERT(ok); return r; } static void *file_startext(void *closure, const void *hd) { upb_descreader *r = closure; bool ok; r->f = upb_fielddef_new(r); ok = upb_filedef_addext(r->file, r->f, r, NULL); UPB_UNUSED(hd); UPB_ASSERT(ok); return r; } /** Handlers for google.protobuf.EnumValueDescriptorProto. *********************/ static bool enumval_startmsg(void *closure, const void *hd) { upb_descreader *r = closure; UPB_UNUSED(hd); r->saw_number = false; r->saw_name = false; return true; } static size_t enumval_onname(void *closure, const void *hd, const char *buf, size_t n, const upb_bufhandle *handle) { upb_descreader *r = closure; UPB_UNUSED(hd); UPB_UNUSED(handle); /* XXX: see comment at the top of the file. */ upb_gfree(r->name); r->name = upb_gstrndup(buf, n); r->saw_name = true; return n; } static bool enumval_onnumber(void *closure, const void *hd, int32_t val) { upb_descreader *r = closure; UPB_UNUSED(hd); r->number = val; r->saw_number = true; return true; } static bool enumval_endmsg(void *closure, const void *hd, upb_status *status) { upb_descreader *r = closure; upb_enumdef *e; UPB_UNUSED(hd); if(!r->saw_number || !r->saw_name) { upb_status_seterrmsg(status, "Enum value missing name or number."); return false; } e = upb_downcast_enumdef_mutable(upb_descreader_last(r)); upb_enumdef_addval(e, r->name, r->number, status); upb_gfree(r->name); r->name = NULL; return true; } /** Handlers for google.protobuf.EnumDescriptorProto. *************************/ static bool enum_endmsg(void *closure, const void *hd, upb_status *status) { upb_descreader *r = closure; upb_enumdef *e; UPB_UNUSED(hd); e = upb_downcast_enumdef_mutable(upb_descreader_last(r)); if (upb_def_fullname(upb_descreader_last(r)) == NULL) { upb_status_seterrmsg(status, "Enum had no name."); return false; } if (upb_enumdef_numvals(e) == 0) { upb_status_seterrmsg(status, "Enum had no values."); return false; } return true; } static size_t enum_onname(void *closure, const void *hd, const char *buf, size_t n, const upb_bufhandle *handle) { upb_descreader *r = closure; char *fullname = upb_gstrndup(buf, n); UPB_UNUSED(hd); UPB_UNUSED(handle); /* XXX: see comment at the top of the file. */ upb_def_setfullname(upb_descreader_last(r), fullname, NULL); upb_gfree(fullname); return n; } /** Handlers for google.protobuf.FieldDescriptorProto *************************/ static bool field_startmsg(void *closure, const void *hd) { upb_descreader *r = closure; UPB_UNUSED(hd); UPB_ASSERT(r->f); upb_gfree(r->default_string); r->default_string = NULL; /* fielddefs default to packed, but descriptors default to non-packed. */ upb_fielddef_setpacked(r->f, false); return true; } /* Converts the default value in string "str" into "d". Passes a ref on str. * Returns true on success. */ static bool parse_default(char *str, upb_fielddef *f) { bool success = true; char *end; switch (upb_fielddef_type(f)) { case UPB_TYPE_INT32: { long val = strtol(str, &end, 0); if (val > INT32_MAX || val < INT32_MIN || errno == ERANGE || *end) success = false; else upb_fielddef_setdefaultint32(f, val); break; } case UPB_TYPE_INT64: { /* XXX: Need to write our own strtoll, since it's not available in c89. */ long long val = strtol(str, &end, 0); if (val > INT64_MAX || val < INT64_MIN || errno == ERANGE || *end) success = false; else upb_fielddef_setdefaultint64(f, val); break; } case UPB_TYPE_UINT32: { unsigned long val = strtoul(str, &end, 0); if (val > UINT32_MAX || errno == ERANGE || *end) success = false; else upb_fielddef_setdefaultuint32(f, val); break; } case UPB_TYPE_UINT64: { /* XXX: Need to write our own strtoull, since it's not available in c89. */ unsigned long long val = strtoul(str, &end, 0); if (val > UINT64_MAX || errno == ERANGE || *end) success = false; else upb_fielddef_setdefaultuint64(f, val); break; } case UPB_TYPE_DOUBLE: { double val = strtod(str, &end); if (errno == ERANGE || *end) success = false; else upb_fielddef_setdefaultdouble(f, val); break; } case UPB_TYPE_FLOAT: { /* XXX: Need to write our own strtof, since it's not available in c89. */ float val = strtod(str, &end); if (errno == ERANGE || *end) success = false; else upb_fielddef_setdefaultfloat(f, val); break; } case UPB_TYPE_BOOL: { if (strcmp(str, "false") == 0) upb_fielddef_setdefaultbool(f, false); else if (strcmp(str, "true") == 0) upb_fielddef_setdefaultbool(f, true); else success = false; break; } default: abort(); } return success; } static bool field_endmsg(void *closure, const void *hd, upb_status *status) { upb_descreader *r = closure; upb_fielddef *f = r->f; UPB_UNUSED(hd); /* TODO: verify that all required fields were present. */ UPB_ASSERT(upb_fielddef_number(f) != 0); UPB_ASSERT(upb_fielddef_name(f) != NULL); UPB_ASSERT((upb_fielddef_subdefname(f) != NULL) == upb_fielddef_hassubdef(f)); if (r->default_string) { if (upb_fielddef_issubmsg(f)) { upb_status_seterrmsg(status, "Submessages cannot have defaults."); return false; } if (upb_fielddef_isstring(f) || upb_fielddef_type(f) == UPB_TYPE_ENUM) { upb_fielddef_setdefaultcstr(f, r->default_string, NULL); } else { if (r->default_string && !parse_default(r->default_string, f)) { /* We don't worry too much about giving a great error message since the * compiler should have ensured this was correct. */ upb_status_seterrmsg(status, "Error converting default value."); return false; } } } return true; } static bool field_onlazy(void *closure, const void *hd, bool val) { upb_descreader *r = closure; UPB_UNUSED(hd); upb_fielddef_setlazy(r->f, val); return true; } static bool field_onpacked(void *closure, const void *hd, bool val) { upb_descreader *r = closure; UPB_UNUSED(hd); upb_fielddef_setpacked(r->f, val); return true; } static bool field_ontype(void *closure, const void *hd, int32_t val) { upb_descreader *r = closure; UPB_UNUSED(hd); upb_fielddef_setdescriptortype(r->f, val); return true; } static bool field_onlabel(void *closure, const void *hd, int32_t val) { upb_descreader *r = closure; UPB_UNUSED(hd); upb_fielddef_setlabel(r->f, val); return true; } static bool field_onnumber(void *closure, const void *hd, int32_t val) { upb_descreader *r = closure; bool ok; UPB_UNUSED(hd); ok = upb_fielddef_setnumber(r->f, val, NULL); UPB_ASSERT(ok); return true; } static size_t field_onname(void *closure, const void *hd, const char *buf, size_t n, const upb_bufhandle *handle) { upb_descreader *r = closure; char *name = upb_gstrndup(buf, n); UPB_UNUSED(hd); UPB_UNUSED(handle); /* XXX: see comment at the top of the file. */ upb_fielddef_setname(r->f, name, NULL); upb_gfree(name); return n; } static size_t field_ontypename(void *closure, const void *hd, const char *buf, size_t n, const upb_bufhandle *handle) { upb_descreader *r = closure; char *name = upb_gstrndup(buf, n); UPB_UNUSED(hd); UPB_UNUSED(handle); /* XXX: see comment at the top of the file. */ upb_fielddef_setsubdefname(r->f, name, NULL); upb_gfree(name); return n; } static size_t field_onextendee(void *closure, const void *hd, const char *buf, size_t n, const upb_bufhandle *handle) { upb_descreader *r = closure; char *name = upb_gstrndup(buf, n); UPB_UNUSED(hd); UPB_UNUSED(handle); /* XXX: see comment at the top of the file. */ upb_fielddef_setcontainingtypename(r->f, name, NULL); upb_gfree(name); return n; } static size_t field_ondefaultval(void *closure, const void *hd, const char *buf, size_t n, const upb_bufhandle *handle) { upb_descreader *r = closure; UPB_UNUSED(hd); UPB_UNUSED(handle); /* Have to convert from string to the correct type, but we might not know the * type yet, so we save it as a string until the end of the field. * XXX: see comment at the top of the file. */ upb_gfree(r->default_string); r->default_string = upb_gstrndup(buf, n); return n; } static bool field_ononeofindex(void *closure, const void *hd, int32_t index) { upb_descreader *r = closure; upb_oneofdef *o = upb_descreader_getoneof(r, index); bool ok = upb_oneofdef_addfield(o, r->f, &r->f, NULL); UPB_UNUSED(hd); UPB_ASSERT(ok); return true; } /** Handlers for google.protobuf.OneofDescriptorProto. ************************/ static size_t oneof_name(void *closure, const void *hd, const char *buf, size_t n, const upb_bufhandle *handle) { upb_descreader *r = closure; upb_descreader_frame *f = &r->stack[r->stack_len-1]; upb_oneofdef *o = upb_descreader_getoneof(r, f->oneof_index++); char *name_null_terminated = upb_gstrndup(buf, n); bool ok = upb_oneofdef_setname(o, name_null_terminated, NULL); UPB_UNUSED(hd); UPB_UNUSED(handle); UPB_ASSERT(ok); free(name_null_terminated); return n; } /** Handlers for google.protobuf.DescriptorProto ******************************/ static bool msg_start(void *closure, const void *hd) { upb_descreader *r = closure; UPB_UNUSED(hd); upb_descreader_startcontainer(r); return true; } static bool msg_end(void *closure, const void *hd, upb_status *status) { upb_descreader *r = closure; upb_msgdef *m = upb_descreader_top(r); UPB_UNUSED(hd); if(!upb_def_fullname(upb_msgdef_upcast_mutable(m))) { upb_status_seterrmsg(status, "Encountered message with no name."); return false; } return upb_descreader_endcontainer(r); } static size_t msg_name(void *closure, const void *hd, const char *buf, size_t n, const upb_bufhandle *handle) { upb_descreader *r = closure; upb_msgdef *m = upb_descreader_top(r); /* XXX: see comment at the top of the file. */ char *name = upb_gstrndup(buf, n); UPB_UNUSED(hd); UPB_UNUSED(handle); upb_def_setfullname(upb_msgdef_upcast_mutable(m), name, NULL); upb_descreader_setscopename(r, name); /* Passes ownership of name. */ return n; } static void *msg_startmsg(void *closure, const void *hd) { upb_descreader *r = closure; upb_msgdef *m = upb_msgdef_new(&m); bool ok = upb_filedef_addmsg(r->file, m, &m, NULL); UPB_UNUSED(hd); UPB_ASSERT(ok); return r; } static void *msg_startext(void *closure, const void *hd) { upb_descreader *r = closure; upb_fielddef *f = upb_fielddef_new(&f); bool ok = upb_filedef_addext(r->file, f, &f, NULL); UPB_UNUSED(hd); UPB_ASSERT(ok); return r; } static void *msg_startfield(void *closure, const void *hd) { upb_descreader *r = closure; r->f = upb_fielddef_new(&r->f); /* We can't add the new field to the message until its name/number are * filled in. */ UPB_UNUSED(hd); return r; } static bool msg_endfield(void *closure, const void *hd) { upb_descreader *r = closure; upb_msgdef *m = upb_descreader_top(r); bool ok; UPB_UNUSED(hd); /* Oneof fields are added to the msgdef through their oneof, so don't need to * be added here. */ if (upb_fielddef_containingoneof(r->f) == NULL) { ok = upb_msgdef_addfield(m, r->f, &r->f, NULL); UPB_ASSERT(ok); } r->f = NULL; return true; } static bool msg_onmapentry(void *closure, const void *hd, bool mapentry) { upb_descreader *r = closure; upb_msgdef *m = upb_descreader_top(r); UPB_UNUSED(hd); upb_msgdef_setmapentry(m, mapentry); r->f = NULL; return true; } /** Code to register handlers *************************************************/ #define F(msg, field) upbdefs_google_protobuf_ ## msg ## _f_ ## field(m) static void reghandlers(const void *closure, upb_handlers *h) { const upb_msgdef *m = upb_handlers_msgdef(h); UPB_UNUSED(closure); if (upbdefs_google_protobuf_FileDescriptorSet_is(m)) { upb_handlers_setstartsubmsg(h, F(FileDescriptorSet, file), &fileset_startfile, NULL); } else if (upbdefs_google_protobuf_DescriptorProto_is(m)) { upb_handlers_setstartmsg(h, &msg_start, NULL); upb_handlers_setendmsg(h, &msg_end, NULL); upb_handlers_setstring(h, F(DescriptorProto, name), &msg_name, NULL); upb_handlers_setstartsubmsg(h, F(DescriptorProto, extension), &msg_startext, NULL); upb_handlers_setstartsubmsg(h, F(DescriptorProto, nested_type), &msg_startmsg, NULL); upb_handlers_setstartsubmsg(h, F(DescriptorProto, field), &msg_startfield, NULL); upb_handlers_setendsubmsg(h, F(DescriptorProto, field), &msg_endfield, NULL); upb_handlers_setstartsubmsg(h, F(DescriptorProto, enum_type), &file_startenum, NULL); } else if (upbdefs_google_protobuf_FileDescriptorProto_is(m)) { upb_handlers_setstartmsg(h, &file_start, NULL); upb_handlers_setendmsg(h, &file_end, NULL); upb_handlers_setstring(h, F(FileDescriptorProto, name), &file_onname, NULL); upb_handlers_setstring(h, F(FileDescriptorProto, package), &file_onpackage, NULL); upb_handlers_setstring(h, F(FileDescriptorProto, syntax), &file_onsyntax, NULL); upb_handlers_setstartsubmsg(h, F(FileDescriptorProto, message_type), &file_startmsg, NULL); upb_handlers_setstartsubmsg(h, F(FileDescriptorProto, enum_type), &file_startenum, NULL); upb_handlers_setstartsubmsg(h, F(FileDescriptorProto, extension), &file_startext, NULL); } else if (upbdefs_google_protobuf_EnumValueDescriptorProto_is(m)) { upb_handlers_setstartmsg(h, &enumval_startmsg, NULL); upb_handlers_setendmsg(h, &enumval_endmsg, NULL); upb_handlers_setstring(h, F(EnumValueDescriptorProto, name), &enumval_onname, NULL); upb_handlers_setint32(h, F(EnumValueDescriptorProto, number), &enumval_onnumber, NULL); } else if (upbdefs_google_protobuf_EnumDescriptorProto_is(m)) { upb_handlers_setendmsg(h, &enum_endmsg, NULL); upb_handlers_setstring(h, F(EnumDescriptorProto, name), &enum_onname, NULL); } else if (upbdefs_google_protobuf_FieldDescriptorProto_is(m)) { upb_handlers_setstartmsg(h, &field_startmsg, NULL); upb_handlers_setendmsg(h, &field_endmsg, NULL); upb_handlers_setint32(h, F(FieldDescriptorProto, type), &field_ontype, NULL); upb_handlers_setint32(h, F(FieldDescriptorProto, label), &field_onlabel, NULL); upb_handlers_setint32(h, F(FieldDescriptorProto, number), &field_onnumber, NULL); upb_handlers_setstring(h, F(FieldDescriptorProto, name), &field_onname, NULL); upb_handlers_setstring(h, F(FieldDescriptorProto, type_name), &field_ontypename, NULL); upb_handlers_setstring(h, F(FieldDescriptorProto, extendee), &field_onextendee, NULL); upb_handlers_setstring(h, F(FieldDescriptorProto, default_value), &field_ondefaultval, NULL); upb_handlers_setint32(h, F(FieldDescriptorProto, oneof_index), &field_ononeofindex, NULL); } else if (upbdefs_google_protobuf_OneofDescriptorProto_is(m)) { upb_handlers_setstring(h, F(OneofDescriptorProto, name), &oneof_name, NULL); } else if (upbdefs_google_protobuf_FieldOptions_is(m)) { upb_handlers_setbool(h, F(FieldOptions, lazy), &field_onlazy, NULL); upb_handlers_setbool(h, F(FieldOptions, packed), &field_onpacked, NULL); } else if (upbdefs_google_protobuf_MessageOptions_is(m)) { upb_handlers_setbool(h, F(MessageOptions, map_entry), &msg_onmapentry, NULL); } UPB_ASSERT(upb_ok(upb_handlers_status(h))); } #undef F void descreader_cleanup(void *_r) { upb_descreader *r = _r; size_t i; for (i = 0; i < upb_descreader_filecount(r); i++) { upb_filedef_unref(upb_descreader_file(r, i), &r->files); } upb_gfree(r->name); upb_inttable_uninit(&r->files); upb_inttable_uninit(&r->oneofs); upb_gfree(r->default_string); while (r->stack_len > 0) { upb_descreader_frame *f = &r->stack[--r->stack_len]; upb_gfree(f->name); } } /* Public API ****************************************************************/ upb_descreader *upb_descreader_create(upb_env *e, const upb_handlers *h) { upb_descreader *r = upb_env_malloc(e, sizeof(upb_descreader)); if (!r || !upb_env_addcleanup(e, descreader_cleanup, r)) { return NULL; } upb_inttable_init(&r->files, UPB_CTYPE_PTR); upb_inttable_init(&r->oneofs, UPB_CTYPE_PTR); upb_sink_reset(upb_descreader_input(r), h, r); r->stack_len = 0; r->name = NULL; r->default_string = NULL; return r; } size_t upb_descreader_filecount(const upb_descreader *r) { return upb_inttable_count(&r->files); } upb_filedef *upb_descreader_file(const upb_descreader *r, size_t i) { upb_value v; if (upb_inttable_lookup(&r->files, i, &v)) { return upb_value_getptr(v); } else { return NULL; } } upb_sink *upb_descreader_input(upb_descreader *r) { return &r->sink; } const upb_handlers *upb_descreader_newhandlers(const void *owner) { const upb_msgdef *m = upbdefs_google_protobuf_FileDescriptorSet_get(&m); const upb_handlers *h = upb_handlers_newfrozen(m, owner, reghandlers, NULL); upb_msgdef_unref(m, &m); return h; } /* ** protobuf decoder bytecode compiler ** ** Code to compile a upb::Handlers into bytecode for decoding a protobuf ** according to that specific schema and destination handlers. ** ** Compiling to bytecode is always the first step. If we are using the ** interpreted decoder we leave it as bytecode and interpret that. If we are ** using a JIT decoder we use a code generator to turn the bytecode into native ** code, LLVM IR, etc. ** ** Bytecode definition is in decoder.int.h. */ #include #ifdef UPB_DUMP_BYTECODE #include #endif #define MAXLABEL 5 #define EMPTYLABEL -1 /* mgroup *********************************************************************/ static void freegroup(upb_refcounted *r) { mgroup *g = (mgroup*)r; upb_inttable_uninit(&g->methods); #ifdef UPB_USE_JIT_X64 upb_pbdecoder_freejit(g); #endif upb_gfree(g->bytecode); upb_gfree(g); } static void visitgroup(const upb_refcounted *r, upb_refcounted_visit *visit, void *closure) { const mgroup *g = (const mgroup*)r; upb_inttable_iter i; upb_inttable_begin(&i, &g->methods); for(; !upb_inttable_done(&i); upb_inttable_next(&i)) { upb_pbdecodermethod *method = upb_value_getptr(upb_inttable_iter_value(&i)); visit(r, upb_pbdecodermethod_upcast(method), closure); } } mgroup *newgroup(const void *owner) { mgroup *g = upb_gmalloc(sizeof(*g)); static const struct upb_refcounted_vtbl vtbl = {visitgroup, freegroup}; upb_refcounted_init(mgroup_upcast_mutable(g), &vtbl, owner); upb_inttable_init(&g->methods, UPB_CTYPE_PTR); g->bytecode = NULL; g->bytecode_end = NULL; return g; } /* upb_pbdecodermethod ********************************************************/ static void freemethod(upb_refcounted *r) { upb_pbdecodermethod *method = (upb_pbdecodermethod*)r; if (method->dest_handlers_) { upb_handlers_unref(method->dest_handlers_, method); } upb_inttable_uninit(&method->dispatch); upb_gfree(method); } static void visitmethod(const upb_refcounted *r, upb_refcounted_visit *visit, void *closure) { const upb_pbdecodermethod *m = (const upb_pbdecodermethod*)r; visit(r, m->group, closure); } static upb_pbdecodermethod *newmethod(const upb_handlers *dest_handlers, mgroup *group) { static const struct upb_refcounted_vtbl vtbl = {visitmethod, freemethod}; upb_pbdecodermethod *ret = upb_gmalloc(sizeof(*ret)); upb_refcounted_init(upb_pbdecodermethod_upcast_mutable(ret), &vtbl, &ret); upb_byteshandler_init(&ret->input_handler_); /* The method references the group and vice-versa, in a circular reference. */ upb_ref2(ret, group); upb_ref2(group, ret); upb_inttable_insertptr(&group->methods, dest_handlers, upb_value_ptr(ret)); upb_pbdecodermethod_unref(ret, &ret); ret->group = mgroup_upcast_mutable(group); ret->dest_handlers_ = dest_handlers; ret->is_native_ = false; /* If we JIT, it will update this later. */ upb_inttable_init(&ret->dispatch, UPB_CTYPE_UINT64); if (ret->dest_handlers_) { upb_handlers_ref(ret->dest_handlers_, ret); } return ret; } const upb_handlers *upb_pbdecodermethod_desthandlers( const upb_pbdecodermethod *m) { return m->dest_handlers_; } const upb_byteshandler *upb_pbdecodermethod_inputhandler( const upb_pbdecodermethod *m) { return &m->input_handler_; } bool upb_pbdecodermethod_isnative(const upb_pbdecodermethod *m) { return m->is_native_; } const upb_pbdecodermethod *upb_pbdecodermethod_new( const upb_pbdecodermethodopts *opts, const void *owner) { const upb_pbdecodermethod *ret; upb_pbcodecache cache; upb_pbcodecache_init(&cache); ret = upb_pbcodecache_getdecodermethod(&cache, opts); upb_pbdecodermethod_ref(ret, owner); upb_pbcodecache_uninit(&cache); return ret; } /* bytecode compiler **********************************************************/ /* Data used only at compilation time. */ typedef struct { mgroup *group; uint32_t *pc; int fwd_labels[MAXLABEL]; int back_labels[MAXLABEL]; /* For fields marked "lazy", parse them lazily or eagerly? */ bool lazy; } compiler; static compiler *newcompiler(mgroup *group, bool lazy) { compiler *ret = upb_gmalloc(sizeof(*ret)); int i; ret->group = group; ret->lazy = lazy; for (i = 0; i < MAXLABEL; i++) { ret->fwd_labels[i] = EMPTYLABEL; ret->back_labels[i] = EMPTYLABEL; } return ret; } static void freecompiler(compiler *c) { upb_gfree(c); } const size_t ptr_words = sizeof(void*) / sizeof(uint32_t); /* How many words an instruction is. */ static int instruction_len(uint32_t instr) { switch (getop(instr)) { case OP_SETDISPATCH: return 1 + ptr_words; case OP_TAGN: return 3; case OP_SETBIGGROUPNUM: return 2; default: return 1; } } bool op_has_longofs(int32_t instruction) { switch (getop(instruction)) { case OP_CALL: case OP_BRANCH: case OP_CHECKDELIM: return true; /* The "tag" instructions only have 8 bytes available for the jump target, * but that is ok because these opcodes only require short jumps. */ case OP_TAG1: case OP_TAG2: case OP_TAGN: return false; default: UPB_ASSERT(false); return false; } } static int32_t getofs(uint32_t instruction) { if (op_has_longofs(instruction)) { return (int32_t)instruction >> 8; } else { return (int8_t)(instruction >> 8); } } static void setofs(uint32_t *instruction, int32_t ofs) { if (op_has_longofs(*instruction)) { *instruction = getop(*instruction) | ofs << 8; } else { *instruction = (*instruction & ~0xff00) | ((ofs & 0xff) << 8); } UPB_ASSERT(getofs(*instruction) == ofs); /* Would fail in cases of overflow. */ } static uint32_t pcofs(compiler *c) { return c->pc - c->group->bytecode; } /* Defines a local label at the current PC location. All previous forward * references are updated to point to this location. The location is noted * for any future backward references. */ static void label(compiler *c, unsigned int label) { int val; uint32_t *codep; UPB_ASSERT(label < MAXLABEL); val = c->fwd_labels[label]; codep = (val == EMPTYLABEL) ? NULL : c->group->bytecode + val; while (codep) { int ofs = getofs(*codep); setofs(codep, c->pc - codep - instruction_len(*codep)); codep = ofs ? codep + ofs : NULL; } c->fwd_labels[label] = EMPTYLABEL; c->back_labels[label] = pcofs(c); } /* Creates a reference to a numbered label; either a forward reference * (positive arg) or backward reference (negative arg). For forward references * the value returned now is actually a "next" pointer into a linked list of all * instructions that use this label and will be patched later when the label is * defined with label(). * * The returned value is the offset that should be written into the instruction. */ static int32_t labelref(compiler *c, int label) { UPB_ASSERT(label < MAXLABEL); if (label == LABEL_DISPATCH) { /* No resolving required. */ return 0; } else if (label < 0) { /* Backward local label. Relative to the next instruction. */ uint32_t from = (c->pc + 1) - c->group->bytecode; return c->back_labels[-label] - from; } else { /* Forward local label: prepend to (possibly-empty) linked list. */ int *lptr = &c->fwd_labels[label]; int32_t ret = (*lptr == EMPTYLABEL) ? 0 : *lptr - pcofs(c); *lptr = pcofs(c); return ret; } } static void put32(compiler *c, uint32_t v) { mgroup *g = c->group; if (c->pc == g->bytecode_end) { int ofs = pcofs(c); size_t oldsize = g->bytecode_end - g->bytecode; size_t newsize = UPB_MAX(oldsize * 2, 64); /* TODO(haberman): handle OOM. */ g->bytecode = upb_grealloc(g->bytecode, oldsize * sizeof(uint32_t), newsize * sizeof(uint32_t)); g->bytecode_end = g->bytecode + newsize; c->pc = g->bytecode + ofs; } *c->pc++ = v; } static void putop(compiler *c, opcode op, ...) { va_list ap; va_start(ap, op); switch (op) { case OP_SETDISPATCH: { uintptr_t ptr = (uintptr_t)va_arg(ap, void*); put32(c, OP_SETDISPATCH); put32(c, ptr); if (sizeof(uintptr_t) > sizeof(uint32_t)) put32(c, (uint64_t)ptr >> 32); break; } case OP_STARTMSG: case OP_ENDMSG: case OP_PUSHLENDELIM: case OP_POP: case OP_SETDELIM: case OP_HALT: case OP_RET: case OP_DISPATCH: put32(c, op); break; case OP_PARSE_DOUBLE: case OP_PARSE_FLOAT: case OP_PARSE_INT64: case OP_PARSE_UINT64: case OP_PARSE_INT32: case OP_PARSE_FIXED64: case OP_PARSE_FIXED32: case OP_PARSE_BOOL: case OP_PARSE_UINT32: case OP_PARSE_SFIXED32: case OP_PARSE_SFIXED64: case OP_PARSE_SINT32: case OP_PARSE_SINT64: case OP_STARTSEQ: case OP_ENDSEQ: case OP_STARTSUBMSG: case OP_ENDSUBMSG: case OP_STARTSTR: case OP_STRING: case OP_ENDSTR: case OP_PUSHTAGDELIM: put32(c, op | va_arg(ap, upb_selector_t) << 8); break; case OP_SETBIGGROUPNUM: put32(c, op); put32(c, va_arg(ap, int)); break; case OP_CALL: { const upb_pbdecodermethod *method = va_arg(ap, upb_pbdecodermethod *); put32(c, op | (method->code_base.ofs - (pcofs(c) + 1)) << 8); break; } case OP_CHECKDELIM: case OP_BRANCH: { uint32_t instruction = op; int label = va_arg(ap, int); setofs(&instruction, labelref(c, label)); put32(c, instruction); break; } case OP_TAG1: case OP_TAG2: { int label = va_arg(ap, int); uint64_t tag = va_arg(ap, uint64_t); uint32_t instruction = op | (tag << 16); UPB_ASSERT(tag <= 0xffff); setofs(&instruction, labelref(c, label)); put32(c, instruction); break; } case OP_TAGN: { int label = va_arg(ap, int); uint64_t tag = va_arg(ap, uint64_t); uint32_t instruction = op | (upb_value_size(tag) << 16); setofs(&instruction, labelref(c, label)); put32(c, instruction); put32(c, tag); put32(c, tag >> 32); break; } } va_end(ap); } #if defined(UPB_USE_JIT_X64) || defined(UPB_DUMP_BYTECODE) const char *upb_pbdecoder_getopname(unsigned int op) { #define QUOTE(x) #x #define EXPAND_AND_QUOTE(x) QUOTE(x) #define OPNAME(x) OP_##x #define OP(x) case OPNAME(x): return EXPAND_AND_QUOTE(OPNAME(x)); #define T(x) OP(PARSE_##x) /* Keep in sync with list in decoder.int.h. */ switch ((opcode)op) { T(DOUBLE) T(FLOAT) T(INT64) T(UINT64) T(INT32) T(FIXED64) T(FIXED32) T(BOOL) T(UINT32) T(SFIXED32) T(SFIXED64) T(SINT32) T(SINT64) OP(STARTMSG) OP(ENDMSG) OP(STARTSEQ) OP(ENDSEQ) OP(STARTSUBMSG) OP(ENDSUBMSG) OP(STARTSTR) OP(STRING) OP(ENDSTR) OP(CALL) OP(RET) OP(PUSHLENDELIM) OP(PUSHTAGDELIM) OP(SETDELIM) OP(CHECKDELIM) OP(BRANCH) OP(TAG1) OP(TAG2) OP(TAGN) OP(SETDISPATCH) OP(POP) OP(SETBIGGROUPNUM) OP(DISPATCH) OP(HALT) } return ""; #undef OP #undef T } #endif #ifdef UPB_DUMP_BYTECODE static void dumpbc(uint32_t *p, uint32_t *end, FILE *f) { uint32_t *begin = p; while (p < end) { fprintf(f, "%p %8tx", p, p - begin); uint32_t instr = *p++; uint8_t op = getop(instr); fprintf(f, " %s", upb_pbdecoder_getopname(op)); switch ((opcode)op) { case OP_SETDISPATCH: { const upb_inttable *dispatch; memcpy(&dispatch, p, sizeof(void*)); p += ptr_words; const upb_pbdecodermethod *method = (void *)((char *)dispatch - offsetof(upb_pbdecodermethod, dispatch)); fprintf(f, " %s", upb_msgdef_fullname( upb_handlers_msgdef(method->dest_handlers_))); break; } case OP_DISPATCH: case OP_STARTMSG: case OP_ENDMSG: case OP_PUSHLENDELIM: case OP_POP: case OP_SETDELIM: case OP_HALT: case OP_RET: break; case OP_PARSE_DOUBLE: case OP_PARSE_FLOAT: case OP_PARSE_INT64: case OP_PARSE_UINT64: case OP_PARSE_INT32: case OP_PARSE_FIXED64: case OP_PARSE_FIXED32: case OP_PARSE_BOOL: case OP_PARSE_UINT32: case OP_PARSE_SFIXED32: case OP_PARSE_SFIXED64: case OP_PARSE_SINT32: case OP_PARSE_SINT64: case OP_STARTSEQ: case OP_ENDSEQ: case OP_STARTSUBMSG: case OP_ENDSUBMSG: case OP_STARTSTR: case OP_STRING: case OP_ENDSTR: case OP_PUSHTAGDELIM: fprintf(f, " %d", instr >> 8); break; case OP_SETBIGGROUPNUM: fprintf(f, " %d", *p++); break; case OP_CHECKDELIM: case OP_CALL: case OP_BRANCH: fprintf(f, " =>0x%tx", p + getofs(instr) - begin); break; case OP_TAG1: case OP_TAG2: { fprintf(f, " tag:0x%x", instr >> 16); if (getofs(instr)) { fprintf(f, " =>0x%tx", p + getofs(instr) - begin); } break; } case OP_TAGN: { uint64_t tag = *p++; tag |= (uint64_t)*p++ << 32; fprintf(f, " tag:0x%llx", (long long)tag); fprintf(f, " n:%d", instr >> 16); if (getofs(instr)) { fprintf(f, " =>0x%tx", p + getofs(instr) - begin); } break; } } fputs("\n", f); } } #endif static uint64_t get_encoded_tag(const upb_fielddef *f, int wire_type) { uint32_t tag = (upb_fielddef_number(f) << 3) | wire_type; uint64_t encoded_tag = upb_vencode32(tag); /* No tag should be greater than 5 bytes. */ UPB_ASSERT(encoded_tag <= 0xffffffffff); return encoded_tag; } static void putchecktag(compiler *c, const upb_fielddef *f, int wire_type, int dest) { uint64_t tag = get_encoded_tag(f, wire_type); switch (upb_value_size(tag)) { case 1: putop(c, OP_TAG1, dest, tag); break; case 2: putop(c, OP_TAG2, dest, tag); break; default: putop(c, OP_TAGN, dest, tag); break; } } static upb_selector_t getsel(const upb_fielddef *f, upb_handlertype_t type) { upb_selector_t selector; bool ok = upb_handlers_getselector(f, type, &selector); UPB_ASSERT(ok); return selector; } /* Takes an existing, primary dispatch table entry and repacks it with a * different alternate wire type. Called when we are inserting a secondary * dispatch table entry for an alternate wire type. */ static uint64_t repack(uint64_t dispatch, int new_wt2) { uint64_t ofs; uint8_t wt1; uint8_t old_wt2; upb_pbdecoder_unpackdispatch(dispatch, &ofs, &wt1, &old_wt2); UPB_ASSERT(old_wt2 == NO_WIRE_TYPE); /* wt2 should not be set yet. */ return upb_pbdecoder_packdispatch(ofs, wt1, new_wt2); } /* Marks the current bytecode position as the dispatch target for this message, * field, and wire type. */ static void dispatchtarget(compiler *c, upb_pbdecodermethod *method, const upb_fielddef *f, int wire_type) { /* Offset is relative to msg base. */ uint64_t ofs = pcofs(c) - method->code_base.ofs; uint32_t fn = upb_fielddef_number(f); upb_inttable *d = &method->dispatch; upb_value v; if (upb_inttable_remove(d, fn, &v)) { /* TODO: prioritize based on packed setting in .proto file. */ uint64_t repacked = repack(upb_value_getuint64(v), wire_type); upb_inttable_insert(d, fn, upb_value_uint64(repacked)); upb_inttable_insert(d, fn + UPB_MAX_FIELDNUMBER, upb_value_uint64(ofs)); } else { uint64_t val = upb_pbdecoder_packdispatch(ofs, wire_type, NO_WIRE_TYPE); upb_inttable_insert(d, fn, upb_value_uint64(val)); } } static void putpush(compiler *c, const upb_fielddef *f) { if (upb_fielddef_descriptortype(f) == UPB_DESCRIPTOR_TYPE_MESSAGE) { putop(c, OP_PUSHLENDELIM); } else { uint32_t fn = upb_fielddef_number(f); if (fn >= 1 << 24) { putop(c, OP_PUSHTAGDELIM, 0); putop(c, OP_SETBIGGROUPNUM, fn); } else { putop(c, OP_PUSHTAGDELIM, fn); } } } static upb_pbdecodermethod *find_submethod(const compiler *c, const upb_pbdecodermethod *method, const upb_fielddef *f) { const upb_handlers *sub = upb_handlers_getsubhandlers(method->dest_handlers_, f); upb_value v; return upb_inttable_lookupptr(&c->group->methods, sub, &v) ? upb_value_getptr(v) : NULL; } static void putsel(compiler *c, opcode op, upb_selector_t sel, const upb_handlers *h) { if (upb_handlers_gethandler(h, sel)) { putop(c, op, sel); } } /* Puts an opcode to call a callback, but only if a callback actually exists for * this field and handler type. */ static void maybeput(compiler *c, opcode op, const upb_handlers *h, const upb_fielddef *f, upb_handlertype_t type) { putsel(c, op, getsel(f, type), h); } static bool haslazyhandlers(const upb_handlers *h, const upb_fielddef *f) { if (!upb_fielddef_lazy(f)) return false; return upb_handlers_gethandler(h, getsel(f, UPB_HANDLER_STARTSTR)) || upb_handlers_gethandler(h, getsel(f, UPB_HANDLER_STRING)) || upb_handlers_gethandler(h, getsel(f, UPB_HANDLER_ENDSTR)); } /* bytecode compiler code generation ******************************************/ /* Symbolic names for our local labels. */ #define LABEL_LOOPSTART 1 /* Top of a repeated field loop. */ #define LABEL_LOOPBREAK 2 /* To jump out of a repeated loop */ #define LABEL_FIELD 3 /* Jump backward to find the most recent field. */ #define LABEL_ENDMSG 4 /* To reach the OP_ENDMSG instr for this msg. */ /* Generates bytecode to parse a single non-lazy message field. */ static void generate_msgfield(compiler *c, const upb_fielddef *f, upb_pbdecodermethod *method) { const upb_handlers *h = upb_pbdecodermethod_desthandlers(method); const upb_pbdecodermethod *sub_m = find_submethod(c, method, f); int wire_type; if (!sub_m) { /* Don't emit any code for this field at all; it will be parsed as an * unknown field. * * TODO(haberman): we should change this to parse it as a string field * instead. It will probably be faster, but more importantly, once we * start vending unknown fields, a field shouldn't be treated as unknown * just because it doesn't have subhandlers registered. */ return; } label(c, LABEL_FIELD); wire_type = (upb_fielddef_descriptortype(f) == UPB_DESCRIPTOR_TYPE_MESSAGE) ? UPB_WIRE_TYPE_DELIMITED : UPB_WIRE_TYPE_START_GROUP; if (upb_fielddef_isseq(f)) { putop(c, OP_CHECKDELIM, LABEL_ENDMSG); putchecktag(c, f, wire_type, LABEL_DISPATCH); dispatchtarget(c, method, f, wire_type); putop(c, OP_PUSHTAGDELIM, 0); putop(c, OP_STARTSEQ, getsel(f, UPB_HANDLER_STARTSEQ)); label(c, LABEL_LOOPSTART); putpush(c, f); putop(c, OP_STARTSUBMSG, getsel(f, UPB_HANDLER_STARTSUBMSG)); putop(c, OP_CALL, sub_m); putop(c, OP_POP); maybeput(c, OP_ENDSUBMSG, h, f, UPB_HANDLER_ENDSUBMSG); if (wire_type == UPB_WIRE_TYPE_DELIMITED) { putop(c, OP_SETDELIM); } putop(c, OP_CHECKDELIM, LABEL_LOOPBREAK); putchecktag(c, f, wire_type, LABEL_LOOPBREAK); putop(c, OP_BRANCH, -LABEL_LOOPSTART); label(c, LABEL_LOOPBREAK); putop(c, OP_POP); maybeput(c, OP_ENDSEQ, h, f, UPB_HANDLER_ENDSEQ); } else { putop(c, OP_CHECKDELIM, LABEL_ENDMSG); putchecktag(c, f, wire_type, LABEL_DISPATCH); dispatchtarget(c, method, f, wire_type); putpush(c, f); putop(c, OP_STARTSUBMSG, getsel(f, UPB_HANDLER_STARTSUBMSG)); putop(c, OP_CALL, sub_m); putop(c, OP_POP); maybeput(c, OP_ENDSUBMSG, h, f, UPB_HANDLER_ENDSUBMSG); if (wire_type == UPB_WIRE_TYPE_DELIMITED) { putop(c, OP_SETDELIM); } } } /* Generates bytecode to parse a single string or lazy submessage field. */ static void generate_delimfield(compiler *c, const upb_fielddef *f, upb_pbdecodermethod *method) { const upb_handlers *h = upb_pbdecodermethod_desthandlers(method); label(c, LABEL_FIELD); if (upb_fielddef_isseq(f)) { putop(c, OP_CHECKDELIM, LABEL_ENDMSG); putchecktag(c, f, UPB_WIRE_TYPE_DELIMITED, LABEL_DISPATCH); dispatchtarget(c, method, f, UPB_WIRE_TYPE_DELIMITED); putop(c, OP_PUSHTAGDELIM, 0); putop(c, OP_STARTSEQ, getsel(f, UPB_HANDLER_STARTSEQ)); label(c, LABEL_LOOPSTART); putop(c, OP_PUSHLENDELIM); putop(c, OP_STARTSTR, getsel(f, UPB_HANDLER_STARTSTR)); /* Need to emit even if no handler to skip past the string. */ putop(c, OP_STRING, getsel(f, UPB_HANDLER_STRING)); putop(c, OP_POP); maybeput(c, OP_ENDSTR, h, f, UPB_HANDLER_ENDSTR); putop(c, OP_SETDELIM); putop(c, OP_CHECKDELIM, LABEL_LOOPBREAK); putchecktag(c, f, UPB_WIRE_TYPE_DELIMITED, LABEL_LOOPBREAK); putop(c, OP_BRANCH, -LABEL_LOOPSTART); label(c, LABEL_LOOPBREAK); putop(c, OP_POP); maybeput(c, OP_ENDSEQ, h, f, UPB_HANDLER_ENDSEQ); } else { putop(c, OP_CHECKDELIM, LABEL_ENDMSG); putchecktag(c, f, UPB_WIRE_TYPE_DELIMITED, LABEL_DISPATCH); dispatchtarget(c, method, f, UPB_WIRE_TYPE_DELIMITED); putop(c, OP_PUSHLENDELIM); putop(c, OP_STARTSTR, getsel(f, UPB_HANDLER_STARTSTR)); putop(c, OP_STRING, getsel(f, UPB_HANDLER_STRING)); putop(c, OP_POP); maybeput(c, OP_ENDSTR, h, f, UPB_HANDLER_ENDSTR); putop(c, OP_SETDELIM); } } /* Generates bytecode to parse a single primitive field. */ static void generate_primitivefield(compiler *c, const upb_fielddef *f, upb_pbdecodermethod *method) { const upb_handlers *h = upb_pbdecodermethod_desthandlers(method); upb_descriptortype_t descriptor_type = upb_fielddef_descriptortype(f); opcode parse_type; upb_selector_t sel; int wire_type; label(c, LABEL_FIELD); /* From a decoding perspective, ENUM is the same as INT32. */ if (descriptor_type == UPB_DESCRIPTOR_TYPE_ENUM) descriptor_type = UPB_DESCRIPTOR_TYPE_INT32; parse_type = (opcode)descriptor_type; /* TODO(haberman): generate packed or non-packed first depending on "packed" * setting in the fielddef. This will favor (in speed) whichever was * specified. */ UPB_ASSERT((int)parse_type >= 0 && parse_type <= OP_MAX); sel = getsel(f, upb_handlers_getprimitivehandlertype(f)); wire_type = upb_pb_native_wire_types[upb_fielddef_descriptortype(f)]; if (upb_fielddef_isseq(f)) { putop(c, OP_CHECKDELIM, LABEL_ENDMSG); putchecktag(c, f, UPB_WIRE_TYPE_DELIMITED, LABEL_DISPATCH); dispatchtarget(c, method, f, UPB_WIRE_TYPE_DELIMITED); putop(c, OP_PUSHLENDELIM); putop(c, OP_STARTSEQ, getsel(f, UPB_HANDLER_STARTSEQ)); /* Packed */ label(c, LABEL_LOOPSTART); putop(c, parse_type, sel); putop(c, OP_CHECKDELIM, LABEL_LOOPBREAK); putop(c, OP_BRANCH, -LABEL_LOOPSTART); dispatchtarget(c, method, f, wire_type); putop(c, OP_PUSHTAGDELIM, 0); putop(c, OP_STARTSEQ, getsel(f, UPB_HANDLER_STARTSEQ)); /* Non-packed */ label(c, LABEL_LOOPSTART); putop(c, parse_type, sel); putop(c, OP_CHECKDELIM, LABEL_LOOPBREAK); putchecktag(c, f, wire_type, LABEL_LOOPBREAK); putop(c, OP_BRANCH, -LABEL_LOOPSTART); label(c, LABEL_LOOPBREAK); putop(c, OP_POP); /* Packed and non-packed join. */ maybeput(c, OP_ENDSEQ, h, f, UPB_HANDLER_ENDSEQ); putop(c, OP_SETDELIM); /* Could remove for non-packed by dup ENDSEQ. */ } else { putop(c, OP_CHECKDELIM, LABEL_ENDMSG); putchecktag(c, f, wire_type, LABEL_DISPATCH); dispatchtarget(c, method, f, wire_type); putop(c, parse_type, sel); } } /* Adds bytecode for parsing the given message to the given decoderplan, * while adding all dispatch targets to this message's dispatch table. */ static void compile_method(compiler *c, upb_pbdecodermethod *method) { const upb_handlers *h; const upb_msgdef *md; uint32_t* start_pc; upb_msg_field_iter i; upb_value val; UPB_ASSERT(method); /* Clear all entries in the dispatch table. */ upb_inttable_uninit(&method->dispatch); upb_inttable_init(&method->dispatch, UPB_CTYPE_UINT64); h = upb_pbdecodermethod_desthandlers(method); md = upb_handlers_msgdef(h); method->code_base.ofs = pcofs(c); putop(c, OP_SETDISPATCH, &method->dispatch); putsel(c, OP_STARTMSG, UPB_STARTMSG_SELECTOR, h); label(c, LABEL_FIELD); start_pc = c->pc; for(upb_msg_field_begin(&i, md); !upb_msg_field_done(&i); upb_msg_field_next(&i)) { const upb_fielddef *f = upb_msg_iter_field(&i); upb_fieldtype_t type = upb_fielddef_type(f); if (type == UPB_TYPE_MESSAGE && !(haslazyhandlers(h, f) && c->lazy)) { generate_msgfield(c, f, method); } else if (type == UPB_TYPE_STRING || type == UPB_TYPE_BYTES || type == UPB_TYPE_MESSAGE) { generate_delimfield(c, f, method); } else { generate_primitivefield(c, f, method); } } /* If there were no fields, or if no handlers were defined, we need to * generate a non-empty loop body so that we can at least dispatch for unknown * fields and check for the end of the message. */ if (c->pc == start_pc) { /* Check for end-of-message. */ putop(c, OP_CHECKDELIM, LABEL_ENDMSG); /* Unconditionally dispatch. */ putop(c, OP_DISPATCH, 0); } /* For now we just loop back to the last field of the message (or if none, * the DISPATCH opcode for the message). */ putop(c, OP_BRANCH, -LABEL_FIELD); /* Insert both a label and a dispatch table entry for this end-of-msg. */ label(c, LABEL_ENDMSG); val = upb_value_uint64(pcofs(c) - method->code_base.ofs); upb_inttable_insert(&method->dispatch, DISPATCH_ENDMSG, val); putsel(c, OP_ENDMSG, UPB_ENDMSG_SELECTOR, h); putop(c, OP_RET); upb_inttable_compact(&method->dispatch); } /* Populate "methods" with new upb_pbdecodermethod objects reachable from "h". * Returns the method for these handlers. * * Generates a new method for every destination handlers reachable from "h". */ static void find_methods(compiler *c, const upb_handlers *h) { upb_value v; upb_msg_field_iter i; const upb_msgdef *md; if (upb_inttable_lookupptr(&c->group->methods, h, &v)) return; newmethod(h, c->group); /* Find submethods. */ md = upb_handlers_msgdef(h); for(upb_msg_field_begin(&i, md); !upb_msg_field_done(&i); upb_msg_field_next(&i)) { const upb_fielddef *f = upb_msg_iter_field(&i); const upb_handlers *sub_h; if (upb_fielddef_type(f) == UPB_TYPE_MESSAGE && (sub_h = upb_handlers_getsubhandlers(h, f)) != NULL) { /* We only generate a decoder method for submessages with handlers. * Others will be parsed as unknown fields. */ find_methods(c, sub_h); } } } /* (Re-)compile bytecode for all messages in "msgs." * Overwrites any existing bytecode in "c". */ static void compile_methods(compiler *c) { upb_inttable_iter i; /* Start over at the beginning of the bytecode. */ c->pc = c->group->bytecode; upb_inttable_begin(&i, &c->group->methods); for(; !upb_inttable_done(&i); upb_inttable_next(&i)) { upb_pbdecodermethod *method = upb_value_getptr(upb_inttable_iter_value(&i)); compile_method(c, method); } } static void set_bytecode_handlers(mgroup *g) { upb_inttable_iter i; upb_inttable_begin(&i, &g->methods); for(; !upb_inttable_done(&i); upb_inttable_next(&i)) { upb_pbdecodermethod *m = upb_value_getptr(upb_inttable_iter_value(&i)); upb_byteshandler *h = &m->input_handler_; m->code_base.ptr = g->bytecode + m->code_base.ofs; upb_byteshandler_setstartstr(h, upb_pbdecoder_startbc, m->code_base.ptr); upb_byteshandler_setstring(h, upb_pbdecoder_decode, g); upb_byteshandler_setendstr(h, upb_pbdecoder_end, m); } } /* JIT setup. *****************************************************************/ #ifdef UPB_USE_JIT_X64 static void sethandlers(mgroup *g, bool allowjit) { g->jit_code = NULL; if (allowjit) { /* Compile byte-code into machine code, create handlers. */ upb_pbdecoder_jit(g); } else { set_bytecode_handlers(g); } } #else /* UPB_USE_JIT_X64 */ static void sethandlers(mgroup *g, bool allowjit) { /* No JIT compiled in; use bytecode handlers unconditionally. */ UPB_UNUSED(allowjit); set_bytecode_handlers(g); } #endif /* UPB_USE_JIT_X64 */ /* TODO(haberman): allow this to be constructed for an arbitrary set of dest * handlers and other mgroups (but verify we have a transitive closure). */ const mgroup *mgroup_new(const upb_handlers *dest, bool allowjit, bool lazy, const void *owner) { mgroup *g; compiler *c; UPB_UNUSED(allowjit); UPB_ASSERT(upb_handlers_isfrozen(dest)); g = newgroup(owner); c = newcompiler(g, lazy); find_methods(c, dest); /* We compile in two passes: * 1. all messages are assigned relative offsets from the beginning of the * bytecode (saved in method->code_base). * 2. forwards OP_CALL instructions can be correctly linked since message * offsets have been previously assigned. * * Could avoid the second pass by linking OP_CALL instructions somehow. */ compile_methods(c); compile_methods(c); g->bytecode_end = c->pc; freecompiler(c); #ifdef UPB_DUMP_BYTECODE { FILE *f = fopen("/tmp/upb-bytecode", "w"); UPB_ASSERT(f); dumpbc(g->bytecode, g->bytecode_end, stderr); dumpbc(g->bytecode, g->bytecode_end, f); fclose(f); f = fopen("/tmp/upb-bytecode.bin", "wb"); UPB_ASSERT(f); fwrite(g->bytecode, 1, g->bytecode_end - g->bytecode, f); fclose(f); } #endif sethandlers(g, allowjit); return g; } /* upb_pbcodecache ************************************************************/ void upb_pbcodecache_init(upb_pbcodecache *c) { upb_inttable_init(&c->groups, UPB_CTYPE_CONSTPTR); c->allow_jit_ = true; } void upb_pbcodecache_uninit(upb_pbcodecache *c) { upb_inttable_iter i; upb_inttable_begin(&i, &c->groups); for(; !upb_inttable_done(&i); upb_inttable_next(&i)) { const mgroup *group = upb_value_getconstptr(upb_inttable_iter_value(&i)); mgroup_unref(group, c); } upb_inttable_uninit(&c->groups); } bool upb_pbcodecache_allowjit(const upb_pbcodecache *c) { return c->allow_jit_; } bool upb_pbcodecache_setallowjit(upb_pbcodecache *c, bool allow) { if (upb_inttable_count(&c->groups) > 0) return false; c->allow_jit_ = allow; return true; } const upb_pbdecodermethod *upb_pbcodecache_getdecodermethod( upb_pbcodecache *c, const upb_pbdecodermethodopts *opts) { upb_value v; bool ok; /* Right now we build a new DecoderMethod every time. * TODO(haberman): properly cache methods by their true key. */ const mgroup *g = mgroup_new(opts->handlers, c->allow_jit_, opts->lazy, c); upb_inttable_push(&c->groups, upb_value_constptr(g)); ok = upb_inttable_lookupptr(&g->methods, opts->handlers, &v); UPB_ASSERT(ok); return upb_value_getptr(v); } /* upb_pbdecodermethodopts ****************************************************/ void upb_pbdecodermethodopts_init(upb_pbdecodermethodopts *opts, const upb_handlers *h) { opts->handlers = h; opts->lazy = false; } void upb_pbdecodermethodopts_setlazy(upb_pbdecodermethodopts *opts, bool lazy) { opts->lazy = lazy; } /* ** upb::Decoder (Bytecode Decoder VM) ** ** Bytecode must previously have been generated using the bytecode compiler in ** compile_decoder.c. This decoder then walks through the bytecode op-by-op to ** parse the input. ** ** Decoding is fully resumable; we just keep a pointer to the current bytecode ** instruction and resume from there. A fair amount of the logic here is to ** handle the fact that values can span buffer seams and we have to be able to ** be capable of suspending/resuming from any byte in the stream. This ** sometimes requires keeping a few trailing bytes from the last buffer around ** in the "residual" buffer. */ #include #include #ifdef UPB_DUMP_BYTECODE #include #endif #define CHECK_SUSPEND(x) if (!(x)) return upb_pbdecoder_suspend(d); /* Error messages that are shared between the bytecode and JIT decoders. */ const char *kPbDecoderStackOverflow = "Nesting too deep."; const char *kPbDecoderSubmessageTooLong = "Submessage end extends past enclosing submessage."; /* Error messages shared within this file. */ static const char *kUnterminatedVarint = "Unterminated varint."; /* upb_pbdecoder **************************************************************/ static opcode halt = OP_HALT; /* A dummy character we can point to when the user passes us a NULL buffer. * We need this because in C (NULL + 0) and (NULL - NULL) are undefined * behavior, which would invalidate functions like curbufleft(). */ static const char dummy_char; /* Whether an op consumes any of the input buffer. */ static bool consumes_input(opcode op) { switch (op) { case OP_SETDISPATCH: case OP_STARTMSG: case OP_ENDMSG: case OP_STARTSEQ: case OP_ENDSEQ: case OP_STARTSUBMSG: case OP_ENDSUBMSG: case OP_STARTSTR: case OP_ENDSTR: case OP_PUSHTAGDELIM: case OP_POP: case OP_SETDELIM: case OP_SETBIGGROUPNUM: case OP_CHECKDELIM: case OP_CALL: case OP_RET: case OP_BRANCH: return false; default: return true; } } static size_t stacksize(upb_pbdecoder *d, size_t entries) { UPB_UNUSED(d); return entries * sizeof(upb_pbdecoder_frame); } static size_t callstacksize(upb_pbdecoder *d, size_t entries) { UPB_UNUSED(d); #ifdef UPB_USE_JIT_X64 if (d->method_->is_native_) { /* Each native stack frame needs two pointers, plus we need a few frames for * the enter/exit trampolines. */ size_t ret = entries * sizeof(void*) * 2; ret += sizeof(void*) * 10; return ret; } #endif return entries * sizeof(uint32_t*); } static bool in_residual_buf(const upb_pbdecoder *d, const char *p); /* It's unfortunate that we have to micro-manage the compiler with * UPB_FORCEINLINE and UPB_NOINLINE, especially since this tuning is necessarily * specific to one hardware configuration. But empirically on a Core i7, * performance increases 30-50% with these annotations. Every instance where * these appear, gcc 4.2.1 made the wrong decision and degraded performance in * benchmarks. */ static void seterr(upb_pbdecoder *d, const char *msg) { upb_status status = UPB_STATUS_INIT; upb_status_seterrmsg(&status, msg); upb_env_reporterror(d->env, &status); } void upb_pbdecoder_seterr(upb_pbdecoder *d, const char *msg) { seterr(d, msg); } /* Buffering ******************************************************************/ /* We operate on one buffer at a time, which is either the user's buffer passed * to our "decode" callback or some residual bytes from the previous buffer. */ /* How many bytes can be safely read from d->ptr without reading past end-of-buf * or past the current delimited end. */ static size_t curbufleft(const upb_pbdecoder *d) { UPB_ASSERT(d->data_end >= d->ptr); return d->data_end - d->ptr; } /* How many bytes are available before end-of-buffer. */ static size_t bufleft(const upb_pbdecoder *d) { return d->end - d->ptr; } /* Overall stream offset of d->ptr. */ uint64_t offset(const upb_pbdecoder *d) { return d->bufstart_ofs + (d->ptr - d->buf); } /* How many bytes are available before the end of this delimited region. */ size_t delim_remaining(const upb_pbdecoder *d) { return d->top->end_ofs - offset(d); } /* Advances d->ptr. */ static void advance(upb_pbdecoder *d, size_t len) { UPB_ASSERT(curbufleft(d) >= len); d->ptr += len; } static bool in_buf(const char *p, const char *buf, const char *end) { return p >= buf && p <= end; } static bool in_residual_buf(const upb_pbdecoder *d, const char *p) { return in_buf(p, d->residual, d->residual_end); } /* Calculates the delim_end value, which is affected by both the current buffer * and the parsing stack, so must be called whenever either is updated. */ static void set_delim_end(upb_pbdecoder *d) { size_t delim_ofs = d->top->end_ofs - d->bufstart_ofs; if (delim_ofs <= (size_t)(d->end - d->buf)) { d->delim_end = d->buf + delim_ofs; d->data_end = d->delim_end; } else { d->data_end = d->end; d->delim_end = NULL; } } static void switchtobuf(upb_pbdecoder *d, const char *buf, const char *end) { d->ptr = buf; d->buf = buf; d->end = end; set_delim_end(d); } static void advancetobuf(upb_pbdecoder *d, const char *buf, size_t len) { UPB_ASSERT(curbufleft(d) == 0); d->bufstart_ofs += (d->end - d->buf); switchtobuf(d, buf, buf + len); } static void checkpoint(upb_pbdecoder *d) { /* The assertion here is in the interests of efficiency, not correctness. * We are trying to ensure that we don't checkpoint() more often than * necessary. */ UPB_ASSERT(d->checkpoint != d->ptr); d->checkpoint = d->ptr; } /* Skips "bytes" bytes in the stream, which may be more than available. If we * skip more bytes than are available, we return a long read count to the caller * indicating how many bytes can be skipped over before passing actual data * again. Skipped bytes can pass a NULL buffer and the decoder guarantees they * won't actually be read. */ static int32_t skip(upb_pbdecoder *d, size_t bytes) { UPB_ASSERT(!in_residual_buf(d, d->ptr) || d->size_param == 0); UPB_ASSERT(d->skip == 0); if (bytes > delim_remaining(d)) { seterr(d, "Skipped value extended beyond enclosing submessage."); return upb_pbdecoder_suspend(d); } else if (bufleft(d) >= bytes) { /* Skipped data is all in current buffer, and more is still available. */ advance(d, bytes); d->skip = 0; return DECODE_OK; } else { /* Skipped data extends beyond currently available buffers. */ d->pc = d->last; d->skip = bytes - curbufleft(d); d->bufstart_ofs += (d->end - d->buf); d->residual_end = d->residual; switchtobuf(d, d->residual, d->residual_end); return d->size_param + d->skip; } } /* Resumes the decoder from an initial state or from a previous suspend. */ int32_t upb_pbdecoder_resume(upb_pbdecoder *d, void *p, const char *buf, size_t size, const upb_bufhandle *handle) { UPB_UNUSED(p); /* Useless; just for the benefit of the JIT. */ /* d->skip and d->residual_end could probably elegantly be represented * as a single variable, to more easily represent this invariant. */ UPB_ASSERT(!(d->skip && d->residual_end > d->residual)); /* We need to remember the original size_param, so that the value we return * is relative to it, even if we do some skipping first. */ d->size_param = size; d->handle = handle; /* Have to handle this case specially (ie. not with skip()) because the user * is allowed to pass a NULL buffer here, which won't allow us to safely * calculate a d->end or use our normal functions like curbufleft(). */ if (d->skip && d->skip >= size) { d->skip -= size; d->bufstart_ofs += size; buf = &dummy_char; size = 0; /* We can't just return now, because we might need to execute some ops * like CHECKDELIM, which could call some callbacks and pop the stack. */ } /* We need to pretend that this was the actual buffer param, since some of the * calculations assume that d->ptr/d->buf is relative to this. */ d->buf_param = buf; if (!buf) { /* NULL buf is ok if its entire span is covered by the "skip" above, but * by this point we know that "skip" doesn't cover the buffer. */ seterr(d, "Passed NULL buffer over non-skippable region."); return upb_pbdecoder_suspend(d); } if (d->residual_end > d->residual) { /* We have residual bytes from the last buffer. */ UPB_ASSERT(d->ptr == d->residual); } else { switchtobuf(d, buf, buf + size); } d->checkpoint = d->ptr; /* Handle skips that don't cover the whole buffer (as above). */ if (d->skip) { size_t skip_bytes = d->skip; d->skip = 0; CHECK_RETURN(skip(d, skip_bytes)); checkpoint(d); } /* If we're inside an unknown group, continue to parse unknown values. */ if (d->top->groupnum < 0) { CHECK_RETURN(upb_pbdecoder_skipunknown(d, -1, 0)); checkpoint(d); } return DECODE_OK; } /* Suspends the decoder at the last checkpoint, without saving any residual * bytes. If there are any unconsumed bytes, returns a short byte count. */ size_t upb_pbdecoder_suspend(upb_pbdecoder *d) { d->pc = d->last; if (d->checkpoint == d->residual) { /* Checkpoint was in residual buf; no user bytes were consumed. */ d->ptr = d->residual; return 0; } else { size_t ret = d->size_param - (d->end - d->checkpoint); UPB_ASSERT(!in_residual_buf(d, d->checkpoint)); UPB_ASSERT(d->buf == d->buf_param || d->buf == &dummy_char); d->bufstart_ofs += (d->checkpoint - d->buf); d->residual_end = d->residual; switchtobuf(d, d->residual, d->residual_end); return ret; } } /* Suspends the decoder at the last checkpoint, and saves any unconsumed * bytes in our residual buffer. This is necessary if we need more user * bytes to form a complete value, which might not be contiguous in the * user's buffers. Always consumes all user bytes. */ static size_t suspend_save(upb_pbdecoder *d) { /* We hit end-of-buffer before we could parse a full value. * Save any unconsumed bytes (if any) to the residual buffer. */ d->pc = d->last; if (d->checkpoint == d->residual) { /* Checkpoint was in residual buf; append user byte(s) to residual buf. */ UPB_ASSERT((d->residual_end - d->residual) + d->size_param <= sizeof(d->residual)); if (!in_residual_buf(d, d->ptr)) { d->bufstart_ofs -= (d->residual_end - d->residual); } memcpy(d->residual_end, d->buf_param, d->size_param); d->residual_end += d->size_param; } else { /* Checkpoint was in user buf; old residual bytes not needed. */ size_t save; UPB_ASSERT(!in_residual_buf(d, d->checkpoint)); d->ptr = d->checkpoint; save = curbufleft(d); UPB_ASSERT(save <= sizeof(d->residual)); memcpy(d->residual, d->ptr, save); d->residual_end = d->residual + save; d->bufstart_ofs = offset(d); } switchtobuf(d, d->residual, d->residual_end); return d->size_param; } /* Copies the next "bytes" bytes into "buf" and advances the stream. * Requires that this many bytes are available in the current buffer. */ UPB_FORCEINLINE static void consumebytes(upb_pbdecoder *d, void *buf, size_t bytes) { UPB_ASSERT(bytes <= curbufleft(d)); memcpy(buf, d->ptr, bytes); advance(d, bytes); } /* Slow path for getting the next "bytes" bytes, regardless of whether they are * available in the current buffer or not. Returns a status code as described * in decoder.int.h. */ UPB_NOINLINE static int32_t getbytes_slow(upb_pbdecoder *d, void *buf, size_t bytes) { const size_t avail = curbufleft(d); consumebytes(d, buf, avail); bytes -= avail; UPB_ASSERT(bytes > 0); if (in_residual_buf(d, d->ptr)) { advancetobuf(d, d->buf_param, d->size_param); } if (curbufleft(d) >= bytes) { consumebytes(d, (char *)buf + avail, bytes); return DECODE_OK; } else if (d->data_end == d->delim_end) { seterr(d, "Submessage ended in the middle of a value or group"); return upb_pbdecoder_suspend(d); } else { return suspend_save(d); } } /* Gets the next "bytes" bytes, regardless of whether they are available in the * current buffer or not. Returns a status code as described in decoder.int.h. */ UPB_FORCEINLINE static int32_t getbytes(upb_pbdecoder *d, void *buf, size_t bytes) { if (curbufleft(d) >= bytes) { /* Buffer has enough data to satisfy. */ consumebytes(d, buf, bytes); return DECODE_OK; } else { return getbytes_slow(d, buf, bytes); } } UPB_NOINLINE static size_t peekbytes_slow(upb_pbdecoder *d, void *buf, size_t bytes) { size_t ret = curbufleft(d); memcpy(buf, d->ptr, ret); if (in_residual_buf(d, d->ptr)) { size_t copy = UPB_MIN(bytes - ret, d->size_param); memcpy((char *)buf + ret, d->buf_param, copy); ret += copy; } return ret; } UPB_FORCEINLINE static size_t peekbytes(upb_pbdecoder *d, void *buf, size_t bytes) { if (curbufleft(d) >= bytes) { memcpy(buf, d->ptr, bytes); return bytes; } else { return peekbytes_slow(d, buf, bytes); } } /* Decoding of wire types *****************************************************/ /* Slow path for decoding a varint from the current buffer position. * Returns a status code as described in decoder.int.h. */ UPB_NOINLINE int32_t upb_pbdecoder_decode_varint_slow(upb_pbdecoder *d, uint64_t *u64) { uint8_t byte = 0x80; int bitpos; *u64 = 0; for(bitpos = 0; bitpos < 70 && (byte & 0x80); bitpos += 7) { CHECK_RETURN(getbytes(d, &byte, 1)); *u64 |= (uint64_t)(byte & 0x7F) << bitpos; } if(bitpos == 70 && (byte & 0x80)) { seterr(d, kUnterminatedVarint); return upb_pbdecoder_suspend(d); } return DECODE_OK; } /* Decodes a varint from the current buffer position. * Returns a status code as described in decoder.int.h. */ UPB_FORCEINLINE static int32_t decode_varint(upb_pbdecoder *d, uint64_t *u64) { if (curbufleft(d) > 0 && !(*d->ptr & 0x80)) { *u64 = *d->ptr; advance(d, 1); return DECODE_OK; } else if (curbufleft(d) >= 10) { /* Fast case. */ upb_decoderet r = upb_vdecode_fast(d->ptr); if (r.p == NULL) { seterr(d, kUnterminatedVarint); return upb_pbdecoder_suspend(d); } advance(d, r.p - d->ptr); *u64 = r.val; return DECODE_OK; } else { /* Slow case -- varint spans buffer seam. */ return upb_pbdecoder_decode_varint_slow(d, u64); } } /* Decodes a 32-bit varint from the current buffer position. * Returns a status code as described in decoder.int.h. */ UPB_FORCEINLINE static int32_t decode_v32(upb_pbdecoder *d, uint32_t *u32) { uint64_t u64; int32_t ret = decode_varint(d, &u64); if (ret >= 0) return ret; if (u64 > UINT32_MAX) { seterr(d, "Unterminated 32-bit varint"); /* TODO(haberman) guarantee that this function return is >= 0 somehow, * so we know this path will always be treated as error by our caller. * Right now the size_t -> int32_t can overflow and produce negative values. */ *u32 = 0; return upb_pbdecoder_suspend(d); } *u32 = u64; return DECODE_OK; } /* Decodes a fixed32 from the current buffer position. * Returns a status code as described in decoder.int.h. * TODO: proper byte swapping for big-endian machines. */ UPB_FORCEINLINE static int32_t decode_fixed32(upb_pbdecoder *d, uint32_t *u32) { return getbytes(d, u32, 4); } /* Decodes a fixed64 from the current buffer position. * Returns a status code as described in decoder.int.h. * TODO: proper byte swapping for big-endian machines. */ UPB_FORCEINLINE static int32_t decode_fixed64(upb_pbdecoder *d, uint64_t *u64) { return getbytes(d, u64, 8); } /* Non-static versions of the above functions. * These are called by the JIT for fallback paths. */ int32_t upb_pbdecoder_decode_f32(upb_pbdecoder *d, uint32_t *u32) { return decode_fixed32(d, u32); } int32_t upb_pbdecoder_decode_f64(upb_pbdecoder *d, uint64_t *u64) { return decode_fixed64(d, u64); } static double as_double(uint64_t n) { double d; memcpy(&d, &n, 8); return d; } static float as_float(uint32_t n) { float f; memcpy(&f, &n, 4); return f; } /* Pushes a frame onto the decoder stack. */ static bool decoder_push(upb_pbdecoder *d, uint64_t end) { upb_pbdecoder_frame *fr = d->top; if (end > fr->end_ofs) { seterr(d, kPbDecoderSubmessageTooLong); return false; } else if (fr == d->limit) { seterr(d, kPbDecoderStackOverflow); return false; } fr++; fr->end_ofs = end; fr->dispatch = NULL; fr->groupnum = 0; d->top = fr; return true; } static bool pushtagdelim(upb_pbdecoder *d, uint32_t arg) { /* While we expect to see an "end" tag (either ENDGROUP or a non-sequence * field number) prior to hitting any enclosing submessage end, pushing our * existing delim end prevents us from continuing to parse values from a * corrupt proto that doesn't give us an END tag in time. */ if (!decoder_push(d, d->top->end_ofs)) return false; d->top->groupnum = arg; return true; } /* Pops a frame from the decoder stack. */ static void decoder_pop(upb_pbdecoder *d) { d->top--; } UPB_NOINLINE int32_t upb_pbdecoder_checktag_slow(upb_pbdecoder *d, uint64_t expected) { uint64_t data = 0; size_t bytes = upb_value_size(expected); size_t read = peekbytes(d, &data, bytes); if (read == bytes && data == expected) { /* Advance past matched bytes. */ int32_t ok = getbytes(d, &data, read); UPB_ASSERT(ok < 0); return DECODE_OK; } else if (read < bytes && memcmp(&data, &expected, read) == 0) { return suspend_save(d); } else { return DECODE_MISMATCH; } } int32_t upb_pbdecoder_skipunknown(upb_pbdecoder *d, int32_t fieldnum, uint8_t wire_type) { if (fieldnum >= 0) goto have_tag; while (true) { uint32_t tag; CHECK_RETURN(decode_v32(d, &tag)); wire_type = tag & 0x7; fieldnum = tag >> 3; have_tag: if (fieldnum == 0) { seterr(d, "Saw invalid field number (0)"); return upb_pbdecoder_suspend(d); } /* TODO: deliver to unknown field callback. */ switch (wire_type) { case UPB_WIRE_TYPE_32BIT: CHECK_RETURN(skip(d, 4)); break; case UPB_WIRE_TYPE_64BIT: CHECK_RETURN(skip(d, 8)); break; case UPB_WIRE_TYPE_VARINT: { uint64_t u64; CHECK_RETURN(decode_varint(d, &u64)); break; } case UPB_WIRE_TYPE_DELIMITED: { uint32_t len; CHECK_RETURN(decode_v32(d, &len)); CHECK_RETURN(skip(d, len)); break; } case UPB_WIRE_TYPE_START_GROUP: CHECK_SUSPEND(pushtagdelim(d, -fieldnum)); break; case UPB_WIRE_TYPE_END_GROUP: if (fieldnum == -d->top->groupnum) { decoder_pop(d); } else if (fieldnum == d->top->groupnum) { return DECODE_ENDGROUP; } else { seterr(d, "Unmatched ENDGROUP tag."); return upb_pbdecoder_suspend(d); } break; default: seterr(d, "Invalid wire type"); return upb_pbdecoder_suspend(d); } if (d->top->groupnum >= 0) { return DECODE_OK; } /* Unknown group -- continue looping over unknown fields. */ checkpoint(d); } } static void goto_endmsg(upb_pbdecoder *d) { upb_value v; bool found = upb_inttable_lookup32(d->top->dispatch, DISPATCH_ENDMSG, &v); UPB_ASSERT(found); d->pc = d->top->base + upb_value_getuint64(v); } /* Parses a tag and jumps to the corresponding bytecode instruction for this * field. * * If the tag is unknown (or the wire type doesn't match), parses the field as * unknown. If the tag is a valid ENDGROUP tag, jumps to the bytecode * instruction for the end of message. */ static int32_t dispatch(upb_pbdecoder *d) { upb_inttable *dispatch = d->top->dispatch; uint32_t tag; uint8_t wire_type; uint32_t fieldnum; upb_value val; int32_t retval; /* Decode tag. */ CHECK_RETURN(decode_v32(d, &tag)); wire_type = tag & 0x7; fieldnum = tag >> 3; /* Lookup tag. Because of packed/non-packed compatibility, we have to * check the wire type against two possibilities. */ if (fieldnum != DISPATCH_ENDMSG && upb_inttable_lookup32(dispatch, fieldnum, &val)) { uint64_t v = upb_value_getuint64(val); if (wire_type == (v & 0xff)) { d->pc = d->top->base + (v >> 16); return DECODE_OK; } else if (wire_type == ((v >> 8) & 0xff)) { bool found = upb_inttable_lookup(dispatch, fieldnum + UPB_MAX_FIELDNUMBER, &val); UPB_ASSERT(found); d->pc = d->top->base + upb_value_getuint64(val); return DECODE_OK; } } /* We have some unknown fields (or ENDGROUP) to parse. The DISPATCH or TAG * bytecode that triggered this is preceded by a CHECKDELIM bytecode which * we need to back up to, so that when we're done skipping unknown data we * can re-check the delimited end. */ d->last--; /* Necessary if we get suspended */ d->pc = d->last; UPB_ASSERT(getop(*d->last) == OP_CHECKDELIM); /* Unknown field or ENDGROUP. */ retval = upb_pbdecoder_skipunknown(d, fieldnum, wire_type); CHECK_RETURN(retval); if (retval == DECODE_ENDGROUP) { goto_endmsg(d); return DECODE_OK; } return DECODE_OK; } /* Callers know that the stack is more than one deep because the opcodes that * call this only occur after PUSH operations. */ upb_pbdecoder_frame *outer_frame(upb_pbdecoder *d) { UPB_ASSERT(d->top != d->stack); return d->top - 1; } /* The main decoding loop *****************************************************/ /* The main decoder VM function. Uses traditional bytecode dispatch loop with a * switch() statement. */ size_t run_decoder_vm(upb_pbdecoder *d, const mgroup *group, const upb_bufhandle* handle) { #define VMCASE(op, code) \ case op: { code; if (consumes_input(op)) checkpoint(d); break; } #define PRIMITIVE_OP(type, wt, name, convfunc, ctype) \ VMCASE(OP_PARSE_ ## type, { \ ctype val; \ CHECK_RETURN(decode_ ## wt(d, &val)); \ upb_sink_put ## name(&d->top->sink, arg, (convfunc)(val)); \ }) while(1) { int32_t instruction; opcode op; uint32_t arg; int32_t longofs; d->last = d->pc; instruction = *d->pc++; op = getop(instruction); arg = instruction >> 8; longofs = arg; UPB_ASSERT(d->ptr != d->residual_end); UPB_UNUSED(group); #ifdef UPB_DUMP_BYTECODE fprintf(stderr, "s_ofs=%d buf_ofs=%d data_rem=%d buf_rem=%d delim_rem=%d " "%x %s (%d)\n", (int)offset(d), (int)(d->ptr - d->buf), (int)(d->data_end - d->ptr), (int)(d->end - d->ptr), (int)((d->top->end_ofs - d->bufstart_ofs) - (d->ptr - d->buf)), (int)(d->pc - 1 - group->bytecode), upb_pbdecoder_getopname(op), arg); #endif switch (op) { /* Technically, we are losing data if we see a 32-bit varint that is not * properly sign-extended. We could detect this and error about the data * loss, but proto2 does not do this, so we pass. */ PRIMITIVE_OP(INT32, varint, int32, int32_t, uint64_t) PRIMITIVE_OP(INT64, varint, int64, int64_t, uint64_t) PRIMITIVE_OP(UINT32, varint, uint32, uint32_t, uint64_t) PRIMITIVE_OP(UINT64, varint, uint64, uint64_t, uint64_t) PRIMITIVE_OP(FIXED32, fixed32, uint32, uint32_t, uint32_t) PRIMITIVE_OP(FIXED64, fixed64, uint64, uint64_t, uint64_t) PRIMITIVE_OP(SFIXED32, fixed32, int32, int32_t, uint32_t) PRIMITIVE_OP(SFIXED64, fixed64, int64, int64_t, uint64_t) PRIMITIVE_OP(BOOL, varint, bool, bool, uint64_t) PRIMITIVE_OP(DOUBLE, fixed64, double, as_double, uint64_t) PRIMITIVE_OP(FLOAT, fixed32, float, as_float, uint32_t) PRIMITIVE_OP(SINT32, varint, int32, upb_zzdec_32, uint64_t) PRIMITIVE_OP(SINT64, varint, int64, upb_zzdec_64, uint64_t) VMCASE(OP_SETDISPATCH, d->top->base = d->pc - 1; memcpy(&d->top->dispatch, d->pc, sizeof(void*)); d->pc += sizeof(void*) / sizeof(uint32_t); ) VMCASE(OP_STARTMSG, CHECK_SUSPEND(upb_sink_startmsg(&d->top->sink)); ) VMCASE(OP_ENDMSG, CHECK_SUSPEND(upb_sink_endmsg(&d->top->sink, d->status)); ) VMCASE(OP_STARTSEQ, upb_pbdecoder_frame *outer = outer_frame(d); CHECK_SUSPEND(upb_sink_startseq(&outer->sink, arg, &d->top->sink)); ) VMCASE(OP_ENDSEQ, CHECK_SUSPEND(upb_sink_endseq(&d->top->sink, arg)); ) VMCASE(OP_STARTSUBMSG, upb_pbdecoder_frame *outer = outer_frame(d); CHECK_SUSPEND(upb_sink_startsubmsg(&outer->sink, arg, &d->top->sink)); ) VMCASE(OP_ENDSUBMSG, CHECK_SUSPEND(upb_sink_endsubmsg(&d->top->sink, arg)); ) VMCASE(OP_STARTSTR, uint32_t len = delim_remaining(d); upb_pbdecoder_frame *outer = outer_frame(d); CHECK_SUSPEND(upb_sink_startstr(&outer->sink, arg, len, &d->top->sink)); if (len == 0) { d->pc++; /* Skip OP_STRING. */ } ) VMCASE(OP_STRING, uint32_t len = curbufleft(d); size_t n = upb_sink_putstring(&d->top->sink, arg, d->ptr, len, handle); if (n > len) { if (n > delim_remaining(d)) { seterr(d, "Tried to skip past end of string."); return upb_pbdecoder_suspend(d); } else { int32_t ret = skip(d, n); /* This shouldn't return DECODE_OK, because n > len. */ UPB_ASSERT(ret >= 0); return ret; } } advance(d, n); if (n < len || d->delim_end == NULL) { /* We aren't finished with this string yet. */ d->pc--; /* Repeat OP_STRING. */ if (n > 0) checkpoint(d); return upb_pbdecoder_suspend(d); } ) VMCASE(OP_ENDSTR, CHECK_SUSPEND(upb_sink_endstr(&d->top->sink, arg)); ) VMCASE(OP_PUSHTAGDELIM, CHECK_SUSPEND(pushtagdelim(d, arg)); ) VMCASE(OP_SETBIGGROUPNUM, d->top->groupnum = *d->pc++; ) VMCASE(OP_POP, UPB_ASSERT(d->top > d->stack); decoder_pop(d); ) VMCASE(OP_PUSHLENDELIM, uint32_t len; CHECK_RETURN(decode_v32(d, &len)); CHECK_SUSPEND(decoder_push(d, offset(d) + len)); set_delim_end(d); ) VMCASE(OP_SETDELIM, set_delim_end(d); ) VMCASE(OP_CHECKDELIM, /* We are guaranteed of this assert because we never allow ourselves to * consume bytes beyond data_end, which covers delim_end when non-NULL. */ UPB_ASSERT(!(d->delim_end && d->ptr > d->delim_end)); if (d->ptr == d->delim_end) d->pc += longofs; ) VMCASE(OP_CALL, d->callstack[d->call_len++] = d->pc; d->pc += longofs; ) VMCASE(OP_RET, UPB_ASSERT(d->call_len > 0); d->pc = d->callstack[--d->call_len]; ) VMCASE(OP_BRANCH, d->pc += longofs; ) VMCASE(OP_TAG1, uint8_t expected; CHECK_SUSPEND(curbufleft(d) > 0); expected = (arg >> 8) & 0xff; if (*d->ptr == expected) { advance(d, 1); } else { int8_t shortofs; badtag: shortofs = arg; if (shortofs == LABEL_DISPATCH) { CHECK_RETURN(dispatch(d)); } else { d->pc += shortofs; break; /* Avoid checkpoint(). */ } } ) VMCASE(OP_TAG2, uint16_t expected; CHECK_SUSPEND(curbufleft(d) > 0); expected = (arg >> 8) & 0xffff; if (curbufleft(d) >= 2) { uint16_t actual; memcpy(&actual, d->ptr, 2); if (expected == actual) { advance(d, 2); } else { goto badtag; } } else { int32_t result = upb_pbdecoder_checktag_slow(d, expected); if (result == DECODE_MISMATCH) goto badtag; if (result >= 0) return result; } ) VMCASE(OP_TAGN, { uint64_t expected; int32_t result; memcpy(&expected, d->pc, 8); d->pc += 2; result = upb_pbdecoder_checktag_slow(d, expected); if (result == DECODE_MISMATCH) goto badtag; if (result >= 0) return result; }) VMCASE(OP_DISPATCH, { CHECK_RETURN(dispatch(d)); }) VMCASE(OP_HALT, { return d->size_param; }) } } } /* BytesHandler handlers ******************************************************/ void *upb_pbdecoder_startbc(void *closure, const void *pc, size_t size_hint) { upb_pbdecoder *d = closure; UPB_UNUSED(size_hint); d->top->end_ofs = UINT64_MAX; d->bufstart_ofs = 0; d->call_len = 1; d->callstack[0] = &halt; d->pc = pc; d->skip = 0; return d; } void *upb_pbdecoder_startjit(void *closure, const void *hd, size_t size_hint) { upb_pbdecoder *d = closure; UPB_UNUSED(hd); UPB_UNUSED(size_hint); d->top->end_ofs = UINT64_MAX; d->bufstart_ofs = 0; d->call_len = 0; d->skip = 0; return d; } bool upb_pbdecoder_end(void *closure, const void *handler_data) { upb_pbdecoder *d = closure; const upb_pbdecodermethod *method = handler_data; uint64_t end; char dummy; if (d->residual_end > d->residual) { seterr(d, "Unexpected EOF: decoder still has buffered unparsed data"); return false; } if (d->skip) { seterr(d, "Unexpected EOF inside skipped data"); return false; } if (d->top->end_ofs != UINT64_MAX) { seterr(d, "Unexpected EOF inside delimited string"); return false; } /* The user's end() call indicates that the message ends here. */ end = offset(d); d->top->end_ofs = end; #ifdef UPB_USE_JIT_X64 if (method->is_native_) { const mgroup *group = (const mgroup*)method->group; if (d->top != d->stack) d->stack->end_ofs = 0; group->jit_code(closure, method->code_base.ptr, &dummy, 0, NULL); } else #endif { const uint32_t *p = d->pc; d->stack->end_ofs = end; /* Check the previous bytecode, but guard against beginning. */ if (p != method->code_base.ptr) p--; if (getop(*p) == OP_CHECKDELIM) { /* Rewind from OP_TAG* to OP_CHECKDELIM. */ UPB_ASSERT(getop(*d->pc) == OP_TAG1 || getop(*d->pc) == OP_TAG2 || getop(*d->pc) == OP_TAGN || getop(*d->pc) == OP_DISPATCH); d->pc = p; } upb_pbdecoder_decode(closure, handler_data, &dummy, 0, NULL); } if (d->call_len != 0) { seterr(d, "Unexpected EOF inside submessage or group"); return false; } return true; } size_t upb_pbdecoder_decode(void *decoder, const void *group, const char *buf, size_t size, const upb_bufhandle *handle) { int32_t result = upb_pbdecoder_resume(decoder, NULL, buf, size, handle); if (result == DECODE_ENDGROUP) goto_endmsg(decoder); CHECK_RETURN(result); return run_decoder_vm(decoder, group, handle); } /* Public API *****************************************************************/ void upb_pbdecoder_reset(upb_pbdecoder *d) { d->top = d->stack; d->top->groupnum = 0; d->ptr = d->residual; d->buf = d->residual; d->end = d->residual; d->residual_end = d->residual; } upb_pbdecoder *upb_pbdecoder_create(upb_env *e, const upb_pbdecodermethod *m, upb_sink *sink) { const size_t default_max_nesting = 64; #ifndef NDEBUG size_t size_before = upb_env_bytesallocated(e); #endif upb_pbdecoder *d = upb_env_malloc(e, sizeof(upb_pbdecoder)); if (!d) return NULL; d->method_ = m; d->callstack = upb_env_malloc(e, callstacksize(d, default_max_nesting)); d->stack = upb_env_malloc(e, stacksize(d, default_max_nesting)); if (!d->stack || !d->callstack) { return NULL; } d->env = e; d->limit = d->stack + default_max_nesting - 1; d->stack_size = default_max_nesting; d->status = NULL; upb_pbdecoder_reset(d); upb_bytessink_reset(&d->input_, &m->input_handler_, d); UPB_ASSERT(sink); if (d->method_->dest_handlers_) { if (sink->handlers != d->method_->dest_handlers_) return NULL; } upb_sink_reset(&d->top->sink, sink->handlers, sink->closure); /* If this fails, increase the value in decoder.h. */ UPB_ASSERT_DEBUGVAR(upb_env_bytesallocated(e) - size_before <= UPB_PB_DECODER_SIZE); return d; } uint64_t upb_pbdecoder_bytesparsed(const upb_pbdecoder *d) { return offset(d); } const upb_pbdecodermethod *upb_pbdecoder_method(const upb_pbdecoder *d) { return d->method_; } upb_bytessink *upb_pbdecoder_input(upb_pbdecoder *d) { return &d->input_; } size_t upb_pbdecoder_maxnesting(const upb_pbdecoder *d) { return d->stack_size; } bool upb_pbdecoder_setmaxnesting(upb_pbdecoder *d, size_t max) { UPB_ASSERT(d->top >= d->stack); if (max < (size_t)(d->top - d->stack)) { /* Can't set a limit smaller than what we are currently at. */ return false; } if (max > d->stack_size) { /* Need to reallocate stack and callstack to accommodate. */ size_t old_size = stacksize(d, d->stack_size); size_t new_size = stacksize(d, max); void *p = upb_env_realloc(d->env, d->stack, old_size, new_size); if (!p) { return false; } d->stack = p; old_size = callstacksize(d, d->stack_size); new_size = callstacksize(d, max); p = upb_env_realloc(d->env, d->callstack, old_size, new_size); if (!p) { return false; } d->callstack = p; d->stack_size = max; } d->limit = d->stack + max - 1; return true; } /* ** upb::Encoder ** ** Since we are implementing pure handlers (ie. without any out-of-band access ** to pre-computed lengths), we have to buffer all submessages before we can ** emit even their first byte. ** ** Not knowing the size of submessages also means we can't write a perfect ** zero-copy implementation, even with buffering. Lengths are stored as ** varints, which means that we don't know how many bytes to reserve for the ** length until we know what the length is. ** ** This leaves us with three main choices: ** ** 1. buffer all submessage data in a temporary buffer, then copy it exactly ** once into the output buffer. ** ** 2. attempt to buffer data directly into the output buffer, estimating how ** many bytes each length will take. When our guesses are wrong, use ** memmove() to grow or shrink the allotted space. ** ** 3. buffer directly into the output buffer, allocating a max length ** ahead-of-time for each submessage length. If we overallocated, we waste ** space, but no memcpy() or memmove() is required. This approach requires ** defining a maximum size for submessages and rejecting submessages that ** exceed that size. ** ** (2) and (3) have the potential to have better performance, but they are more ** complicated and subtle to implement: ** ** (3) requires making an arbitrary choice of the maximum message size; it ** wastes space when submessages are shorter than this and fails ** completely when they are longer. This makes it more finicky and ** requires configuration based on the input. It also makes it impossible ** to perfectly match the output of reference encoders that always use the ** optimal amount of space for each length. ** ** (2) requires guessing the the size upfront, and if multiple lengths are ** guessed wrong the minimum required number of memmove() operations may ** be complicated to compute correctly. Implemented properly, it may have ** a useful amortized or average cost, but more investigation is required ** to determine this and what the optimal algorithm is to achieve it. ** ** (1) makes you always pay for exactly one copy, but its implementation is ** the simplest and its performance is predictable. ** ** So for now, we implement (1) only. If we wish to optimize later, we should ** be able to do it without affecting users. ** ** The strategy is to buffer the segments of data that do *not* depend on ** unknown lengths in one buffer, and keep a separate buffer of segment pointers ** and lengths. When the top-level submessage ends, we can go beginning to end, ** alternating the writing of lengths with memcpy() of the rest of the data. ** At the top level though, no buffering is required. */ /* The output buffer is divided into segments; a segment is a string of data * that is "ready to go" -- it does not need any varint lengths inserted into * the middle. The seams between segments are where varints will be inserted * once they are known. * * We also use the concept of a "run", which is a range of encoded bytes that * occur at a single submessage level. Every segment contains one or more runs. * * A segment can span messages. Consider: * * .--Submessage lengths---------. * | | | * | V V * V | |--------------- | |----------------- * Submessages: | |----------------------------------------------- * Top-level msg: ------------------------------------------------------------ * * Segments: ----- ------------------- ----------------- * Runs: *---- *--------------*--- *---------------- * (* marks the start) * * Note that the top-level menssage is not in any segment because it does not * have any length preceding it. * * A segment is only interrupted when another length needs to be inserted. So * observe how the second segment spans both the inner submessage and part of * the next enclosing message. */ typedef struct { uint32_t msglen; /* The length to varint-encode before this segment. */ uint32_t seglen; /* Length of the segment. */ } upb_pb_encoder_segment; struct upb_pb_encoder { upb_env *env; /* Our input and output. */ upb_sink input_; upb_bytessink *output_; /* The "subclosure" -- used as the inner closure as part of the bytessink * protocol. */ void *subc; /* The output buffer and limit, and our current write position. "buf" * initially points to "initbuf", but is dynamically allocated if we need to * grow beyond the initial size. */ char *buf, *ptr, *limit; /* The beginning of the current run, or undefined if we are at the top * level. */ char *runbegin; /* The list of segments we are accumulating. */ upb_pb_encoder_segment *segbuf, *segptr, *seglimit; /* The stack of enclosing submessages. Each entry in the stack points to the * segment where this submessage's length is being accumulated. */ int *stack, *top, *stacklimit; /* Depth of startmsg/endmsg calls. */ int depth; }; /* low-level buffering ********************************************************/ /* Low-level functions for interacting with the output buffer. */ /* TODO(haberman): handle pushback */ static void putbuf(upb_pb_encoder *e, const char *buf, size_t len) { size_t n = upb_bytessink_putbuf(e->output_, e->subc, buf, len, NULL); UPB_ASSERT(n == len); } static upb_pb_encoder_segment *top(upb_pb_encoder *e) { return &e->segbuf[*e->top]; } /* Call to ensure that at least "bytes" bytes are available for writing at * e->ptr. Returns false if the bytes could not be allocated. */ static bool reserve(upb_pb_encoder *e, size_t bytes) { if ((size_t)(e->limit - e->ptr) < bytes) { /* Grow buffer. */ char *new_buf; size_t needed = bytes + (e->ptr - e->buf); size_t old_size = e->limit - e->buf; size_t new_size = old_size; while (new_size < needed) { new_size *= 2; } new_buf = upb_env_realloc(e->env, e->buf, old_size, new_size); if (new_buf == NULL) { return false; } e->ptr = new_buf + (e->ptr - e->buf); e->runbegin = new_buf + (e->runbegin - e->buf); e->limit = new_buf + new_size; e->buf = new_buf; } return true; } /* Call when "bytes" bytes have been writte at e->ptr. The caller *must* have * previously called reserve() with at least this many bytes. */ static void encoder_advance(upb_pb_encoder *e, size_t bytes) { UPB_ASSERT((size_t)(e->limit - e->ptr) >= bytes); e->ptr += bytes; } /* Call when all of the bytes for a handler have been written. Flushes the * bytes if possible and necessary, returning false if this failed. */ static bool commit(upb_pb_encoder *e) { if (!e->top) { /* We aren't inside a delimited region. Flush our accumulated bytes to * the output. * * TODO(haberman): in the future we may want to delay flushing for * efficiency reasons. */ putbuf(e, e->buf, e->ptr - e->buf); e->ptr = e->buf; } return true; } /* Writes the given bytes to the buffer, handling reserve/advance. */ static bool encode_bytes(upb_pb_encoder *e, const void *data, size_t len) { if (!reserve(e, len)) { return false; } memcpy(e->ptr, data, len); encoder_advance(e, len); return true; } /* Finish the current run by adding the run totals to the segment and message * length. */ static void accumulate(upb_pb_encoder *e) { size_t run_len; UPB_ASSERT(e->ptr >= e->runbegin); run_len = e->ptr - e->runbegin; e->segptr->seglen += run_len; top(e)->msglen += run_len; e->runbegin = e->ptr; } /* Call to indicate the start of delimited region for which the full length is * not yet known. All data will be buffered until the length is known. * Delimited regions may be nested; their lengths will all be tracked properly. */ static bool start_delim(upb_pb_encoder *e) { if (e->top) { /* We are already buffering, advance to the next segment and push it on the * stack. */ accumulate(e); if (++e->top == e->stacklimit) { /* TODO(haberman): grow stack? */ return false; } if (++e->segptr == e->seglimit) { /* Grow segment buffer. */ size_t old_size = (e->seglimit - e->segbuf) * sizeof(upb_pb_encoder_segment); size_t new_size = old_size * 2; upb_pb_encoder_segment *new_buf = upb_env_realloc(e->env, e->segbuf, old_size, new_size); if (new_buf == NULL) { return false; } e->segptr = new_buf + (e->segptr - e->segbuf); e->seglimit = new_buf + (new_size / sizeof(upb_pb_encoder_segment)); e->segbuf = new_buf; } } else { /* We were previously at the top level, start buffering. */ e->segptr = e->segbuf; e->top = e->stack; e->runbegin = e->ptr; } *e->top = e->segptr - e->segbuf; e->segptr->seglen = 0; e->segptr->msglen = 0; return true; } /* Call to indicate the end of a delimited region. We now know the length of * the delimited region. If we are not nested inside any other delimited * regions, we can now emit all of the buffered data we accumulated. */ static bool end_delim(upb_pb_encoder *e) { size_t msglen; accumulate(e); msglen = top(e)->msglen; if (e->top == e->stack) { /* All lengths are now available, emit all buffered data. */ char buf[UPB_PB_VARINT_MAX_LEN]; upb_pb_encoder_segment *s; const char *ptr = e->buf; for (s = e->segbuf; s <= e->segptr; s++) { size_t lenbytes = upb_vencode64(s->msglen, buf); putbuf(e, buf, lenbytes); putbuf(e, ptr, s->seglen); ptr += s->seglen; } e->ptr = e->buf; e->top = NULL; } else { /* Need to keep buffering; propagate length info into enclosing * submessages. */ --e->top; top(e)->msglen += msglen + upb_varint_size(msglen); } return true; } /* tag_t **********************************************************************/ /* A precomputed (pre-encoded) tag and length. */ typedef struct { uint8_t bytes; char tag[7]; } tag_t; /* Allocates a new tag for this field, and sets it in these handlerattr. */ static void new_tag(upb_handlers *h, const upb_fielddef *f, upb_wiretype_t wt, upb_handlerattr *attr) { uint32_t n = upb_fielddef_number(f); tag_t *tag = upb_gmalloc(sizeof(tag_t)); tag->bytes = upb_vencode64((n << 3) | wt, tag->tag); upb_handlerattr_init(attr); upb_handlerattr_sethandlerdata(attr, tag); upb_handlers_addcleanup(h, tag, upb_gfree); } static bool encode_tag(upb_pb_encoder *e, const tag_t *tag) { return encode_bytes(e, tag->tag, tag->bytes); } /* encoding of wire types *****************************************************/ static bool encode_fixed64(upb_pb_encoder *e, uint64_t val) { /* TODO(haberman): byte-swap for big endian. */ return encode_bytes(e, &val, sizeof(uint64_t)); } static bool encode_fixed32(upb_pb_encoder *e, uint32_t val) { /* TODO(haberman): byte-swap for big endian. */ return encode_bytes(e, &val, sizeof(uint32_t)); } static bool encode_varint(upb_pb_encoder *e, uint64_t val) { if (!reserve(e, UPB_PB_VARINT_MAX_LEN)) { return false; } encoder_advance(e, upb_vencode64(val, e->ptr)); return true; } static uint64_t dbl2uint64(double d) { uint64_t ret; memcpy(&ret, &d, sizeof(uint64_t)); return ret; } static uint32_t flt2uint32(float d) { uint32_t ret; memcpy(&ret, &d, sizeof(uint32_t)); return ret; } /* encoding of proto types ****************************************************/ static bool startmsg(void *c, const void *hd) { upb_pb_encoder *e = c; UPB_UNUSED(hd); if (e->depth++ == 0) { upb_bytessink_start(e->output_, 0, &e->subc); } return true; } static bool endmsg(void *c, const void *hd, upb_status *status) { upb_pb_encoder *e = c; UPB_UNUSED(hd); UPB_UNUSED(status); if (--e->depth == 0) { upb_bytessink_end(e->output_); } return true; } static void *encode_startdelimfield(void *c, const void *hd) { bool ok = encode_tag(c, hd) && commit(c) && start_delim(c); return ok ? c : UPB_BREAK; } static bool encode_enddelimfield(void *c, const void *hd) { UPB_UNUSED(hd); return end_delim(c); } static void *encode_startgroup(void *c, const void *hd) { return (encode_tag(c, hd) && commit(c)) ? c : UPB_BREAK; } static bool encode_endgroup(void *c, const void *hd) { return encode_tag(c, hd) && commit(c); } static void *encode_startstr(void *c, const void *hd, size_t size_hint) { UPB_UNUSED(size_hint); return encode_startdelimfield(c, hd); } static size_t encode_strbuf(void *c, const void *hd, const char *buf, size_t len, const upb_bufhandle *h) { UPB_UNUSED(hd); UPB_UNUSED(h); return encode_bytes(c, buf, len) ? len : 0; } #define T(type, ctype, convert, encode) \ static bool encode_scalar_##type(void *e, const void *hd, ctype val) { \ return encode_tag(e, hd) && encode(e, (convert)(val)) && commit(e); \ } \ static bool encode_packed_##type(void *e, const void *hd, ctype val) { \ UPB_UNUSED(hd); \ return encode(e, (convert)(val)); \ } T(double, double, dbl2uint64, encode_fixed64) T(float, float, flt2uint32, encode_fixed32) T(int64, int64_t, uint64_t, encode_varint) T(int32, int32_t, uint32_t, encode_varint) T(fixed64, uint64_t, uint64_t, encode_fixed64) T(fixed32, uint32_t, uint32_t, encode_fixed32) T(bool, bool, bool, encode_varint) T(uint32, uint32_t, uint32_t, encode_varint) T(uint64, uint64_t, uint64_t, encode_varint) T(enum, int32_t, uint32_t, encode_varint) T(sfixed32, int32_t, uint32_t, encode_fixed32) T(sfixed64, int64_t, uint64_t, encode_fixed64) T(sint32, int32_t, upb_zzenc_32, encode_varint) T(sint64, int64_t, upb_zzenc_64, encode_varint) #undef T /* code to build the handlers *************************************************/ static void newhandlers_callback(const void *closure, upb_handlers *h) { const upb_msgdef *m; upb_msg_field_iter i; UPB_UNUSED(closure); upb_handlers_setstartmsg(h, startmsg, NULL); upb_handlers_setendmsg(h, endmsg, NULL); m = upb_handlers_msgdef(h); for(upb_msg_field_begin(&i, m); !upb_msg_field_done(&i); upb_msg_field_next(&i)) { const upb_fielddef *f = upb_msg_iter_field(&i); bool packed = upb_fielddef_isseq(f) && upb_fielddef_isprimitive(f) && upb_fielddef_packed(f); upb_handlerattr attr; upb_wiretype_t wt = packed ? UPB_WIRE_TYPE_DELIMITED : upb_pb_native_wire_types[upb_fielddef_descriptortype(f)]; /* Pre-encode the tag for this field. */ new_tag(h, f, wt, &attr); if (packed) { upb_handlers_setstartseq(h, f, encode_startdelimfield, &attr); upb_handlers_setendseq(h, f, encode_enddelimfield, &attr); } #define T(upper, lower, upbtype) \ case UPB_DESCRIPTOR_TYPE_##upper: \ if (packed) { \ upb_handlers_set##upbtype(h, f, encode_packed_##lower, &attr); \ } else { \ upb_handlers_set##upbtype(h, f, encode_scalar_##lower, &attr); \ } \ break; switch (upb_fielddef_descriptortype(f)) { T(DOUBLE, double, double); T(FLOAT, float, float); T(INT64, int64, int64); T(INT32, int32, int32); T(FIXED64, fixed64, uint64); T(FIXED32, fixed32, uint32); T(BOOL, bool, bool); T(UINT32, uint32, uint32); T(UINT64, uint64, uint64); T(ENUM, enum, int32); T(SFIXED32, sfixed32, int32); T(SFIXED64, sfixed64, int64); T(SINT32, sint32, int32); T(SINT64, sint64, int64); case UPB_DESCRIPTOR_TYPE_STRING: case UPB_DESCRIPTOR_TYPE_BYTES: upb_handlers_setstartstr(h, f, encode_startstr, &attr); upb_handlers_setendstr(h, f, encode_enddelimfield, &attr); upb_handlers_setstring(h, f, encode_strbuf, &attr); break; case UPB_DESCRIPTOR_TYPE_MESSAGE: upb_handlers_setstartsubmsg(h, f, encode_startdelimfield, &attr); upb_handlers_setendsubmsg(h, f, encode_enddelimfield, &attr); break; case UPB_DESCRIPTOR_TYPE_GROUP: { /* Endgroup takes a different tag (wire_type = END_GROUP). */ upb_handlerattr attr2; new_tag(h, f, UPB_WIRE_TYPE_END_GROUP, &attr2); upb_handlers_setstartsubmsg(h, f, encode_startgroup, &attr); upb_handlers_setendsubmsg(h, f, encode_endgroup, &attr2); upb_handlerattr_uninit(&attr2); break; } } #undef T upb_handlerattr_uninit(&attr); } } void upb_pb_encoder_reset(upb_pb_encoder *e) { e->segptr = NULL; e->top = NULL; e->depth = 0; } /* public API *****************************************************************/ const upb_handlers *upb_pb_encoder_newhandlers(const upb_msgdef *m, const void *owner) { return upb_handlers_newfrozen(m, owner, newhandlers_callback, NULL); } upb_pb_encoder *upb_pb_encoder_create(upb_env *env, const upb_handlers *h, upb_bytessink *output) { const size_t initial_bufsize = 256; const size_t initial_segbufsize = 16; /* TODO(haberman): make this configurable. */ const size_t stack_size = 64; #ifndef NDEBUG const size_t size_before = upb_env_bytesallocated(env); #endif upb_pb_encoder *e = upb_env_malloc(env, sizeof(upb_pb_encoder)); if (!e) return NULL; e->buf = upb_env_malloc(env, initial_bufsize); e->segbuf = upb_env_malloc(env, initial_segbufsize * sizeof(*e->segbuf)); e->stack = upb_env_malloc(env, stack_size * sizeof(*e->stack)); if (!e->buf || !e->segbuf || !e->stack) { return NULL; } e->limit = e->buf + initial_bufsize; e->seglimit = e->segbuf + initial_segbufsize; e->stacklimit = e->stack + stack_size; upb_pb_encoder_reset(e); upb_sink_reset(&e->input_, h, e); e->env = env; e->output_ = output; e->subc = output->closure; e->ptr = e->buf; /* If this fails, increase the value in encoder.h. */ UPB_ASSERT_DEBUGVAR(upb_env_bytesallocated(env) - size_before <= UPB_PB_ENCODER_SIZE); return e; } upb_sink *upb_pb_encoder_input(upb_pb_encoder *e) { return &e->input_; } upb_filedef **upb_loaddescriptor(const char *buf, size_t n, const void *owner, upb_status *status) { /* Create handlers. */ const upb_pbdecodermethod *decoder_m; const upb_handlers *reader_h = upb_descreader_newhandlers(&reader_h); upb_env env; upb_pbdecodermethodopts opts; upb_pbdecoder *decoder; upb_descreader *reader; bool ok; size_t i; upb_filedef **ret = NULL; upb_pbdecodermethodopts_init(&opts, reader_h); decoder_m = upb_pbdecodermethod_new(&opts, &decoder_m); upb_env_init(&env); upb_env_reporterrorsto(&env, status); reader = upb_descreader_create(&env, reader_h); decoder = upb_pbdecoder_create(&env, decoder_m, upb_descreader_input(reader)); /* Push input data. */ ok = upb_bufsrc_putbuf(buf, n, upb_pbdecoder_input(decoder)); if (!ok) { goto cleanup; } ret = upb_gmalloc(sizeof (*ret) * (upb_descreader_filecount(reader) + 1)); if (!ret) { goto cleanup; } for (i = 0; i < upb_descreader_filecount(reader); i++) { ret[i] = upb_descreader_file(reader, i); upb_filedef_ref(ret[i], owner); } ret[i] = NULL; cleanup: upb_env_uninit(&env); upb_handlers_unref(reader_h, &reader_h); upb_pbdecodermethod_unref(decoder_m, &decoder_m); return ret; } /* * upb::pb::TextPrinter * * OPT: This is not optimized at all. It uses printf() which parses the format * string every time, and it allocates memory for every put. */ #include #include #include #include #include #include struct upb_textprinter { upb_sink input_; upb_bytessink *output_; int indent_depth_; bool single_line_; void *subc; }; #define CHECK(x) if ((x) < 0) goto err; static const char *shortname(const char *longname) { const char *last = strrchr(longname, '.'); return last ? last + 1 : longname; } static int indent(upb_textprinter *p) { int i; if (!p->single_line_) for (i = 0; i < p->indent_depth_; i++) upb_bytessink_putbuf(p->output_, p->subc, " ", 2, NULL); return 0; } static int endfield(upb_textprinter *p) { const char ch = (p->single_line_ ? ' ' : '\n'); upb_bytessink_putbuf(p->output_, p->subc, &ch, 1, NULL); return 0; } static int putescaped(upb_textprinter *p, const char *buf, size_t len, bool preserve_utf8) { /* Based on CEscapeInternal() from Google's protobuf release. */ char dstbuf[4096], *dst = dstbuf, *dstend = dstbuf + sizeof(dstbuf); const char *end = buf + len; /* I think hex is prettier and more useful, but proto2 uses octal; should * investigate whether it can parse hex also. */ const bool use_hex = false; bool last_hex_escape = false; /* true if last output char was \xNN */ for (; buf < end; buf++) { bool is_hex_escape; if (dstend - dst < 4) { upb_bytessink_putbuf(p->output_, p->subc, dstbuf, dst - dstbuf, NULL); dst = dstbuf; } is_hex_escape = false; switch (*buf) { case '\n': *(dst++) = '\\'; *(dst++) = 'n'; break; case '\r': *(dst++) = '\\'; *(dst++) = 'r'; break; case '\t': *(dst++) = '\\'; *(dst++) = 't'; break; case '\"': *(dst++) = '\\'; *(dst++) = '\"'; break; case '\'': *(dst++) = '\\'; *(dst++) = '\''; break; case '\\': *(dst++) = '\\'; *(dst++) = '\\'; break; default: /* Note that if we emit \xNN and the buf character after that is a hex * digit then that digit must be escaped too to prevent it being * interpreted as part of the character code by C. */ if ((!preserve_utf8 || (uint8_t)*buf < 0x80) && (!isprint(*buf) || (last_hex_escape && isxdigit(*buf)))) { sprintf(dst, (use_hex ? "\\x%02x" : "\\%03o"), (uint8_t)*buf); is_hex_escape = use_hex; dst += 4; } else { *(dst++) = *buf; break; } } last_hex_escape = is_hex_escape; } /* Flush remaining data. */ upb_bytessink_putbuf(p->output_, p->subc, dstbuf, dst - dstbuf, NULL); return 0; } bool putf(upb_textprinter *p, const char *fmt, ...) { va_list args; va_list args_copy; char *str; int written; int len; bool ok; va_start(args, fmt); /* Run once to get the length of the string. */ _upb_va_copy(args_copy, args); len = _upb_vsnprintf(NULL, 0, fmt, args_copy); va_end(args_copy); /* + 1 for NULL terminator (vsprintf() requires it even if we don't). */ str = upb_gmalloc(len + 1); if (!str) return false; written = vsprintf(str, fmt, args); va_end(args); UPB_ASSERT(written == len); ok = upb_bytessink_putbuf(p->output_, p->subc, str, len, NULL); upb_gfree(str); return ok; } /* handlers *******************************************************************/ static bool textprinter_startmsg(void *c, const void *hd) { upb_textprinter *p = c; UPB_UNUSED(hd); if (p->indent_depth_ == 0) { upb_bytessink_start(p->output_, 0, &p->subc); } return true; } static bool textprinter_endmsg(void *c, const void *hd, upb_status *s) { upb_textprinter *p = c; UPB_UNUSED(hd); UPB_UNUSED(s); if (p->indent_depth_ == 0) { upb_bytessink_end(p->output_); } return true; } #define TYPE(name, ctype, fmt) \ static bool textprinter_put ## name(void *closure, const void *handler_data, \ ctype val) { \ upb_textprinter *p = closure; \ const upb_fielddef *f = handler_data; \ CHECK(indent(p)); \ putf(p, "%s: " fmt, upb_fielddef_name(f), val); \ CHECK(endfield(p)); \ return true; \ err: \ return false; \ } static bool textprinter_putbool(void *closure, const void *handler_data, bool val) { upb_textprinter *p = closure; const upb_fielddef *f = handler_data; CHECK(indent(p)); putf(p, "%s: %s", upb_fielddef_name(f), val ? "true" : "false"); CHECK(endfield(p)); return true; err: return false; } #define STRINGIFY_HELPER(x) #x #define STRINGIFY_MACROVAL(x) STRINGIFY_HELPER(x) TYPE(int32, int32_t, "%" PRId32) TYPE(int64, int64_t, "%" PRId64) TYPE(uint32, uint32_t, "%" PRIu32) TYPE(uint64, uint64_t, "%" PRIu64) TYPE(float, float, "%." STRINGIFY_MACROVAL(FLT_DIG) "g") TYPE(double, double, "%." STRINGIFY_MACROVAL(DBL_DIG) "g") #undef TYPE /* Output a symbolic value from the enum if found, else just print as int32. */ static bool textprinter_putenum(void *closure, const void *handler_data, int32_t val) { upb_textprinter *p = closure; const upb_fielddef *f = handler_data; const upb_enumdef *enum_def = upb_downcast_enumdef(upb_fielddef_subdef(f)); const char *label = upb_enumdef_iton(enum_def, val); if (label) { indent(p); putf(p, "%s: %s", upb_fielddef_name(f), label); endfield(p); } else { if (!textprinter_putint32(closure, handler_data, val)) return false; } return true; } static void *textprinter_startstr(void *closure, const void *handler_data, size_t size_hint) { upb_textprinter *p = closure; const upb_fielddef *f = handler_data; UPB_UNUSED(size_hint); indent(p); putf(p, "%s: \"", upb_fielddef_name(f)); return p; } static bool textprinter_endstr(void *closure, const void *handler_data) { upb_textprinter *p = closure; UPB_UNUSED(handler_data); putf(p, "\""); endfield(p); return true; } static size_t textprinter_putstr(void *closure, const void *hd, const char *buf, size_t len, const upb_bufhandle *handle) { upb_textprinter *p = closure; const upb_fielddef *f = hd; UPB_UNUSED(handle); CHECK(putescaped(p, buf, len, upb_fielddef_type(f) == UPB_TYPE_STRING)); return len; err: return 0; } static void *textprinter_startsubmsg(void *closure, const void *handler_data) { upb_textprinter *p = closure; const char *name = handler_data; CHECK(indent(p)); putf(p, "%s {%c", name, p->single_line_ ? ' ' : '\n'); p->indent_depth_++; return p; err: return UPB_BREAK; } static bool textprinter_endsubmsg(void *closure, const void *handler_data) { upb_textprinter *p = closure; UPB_UNUSED(handler_data); p->indent_depth_--; CHECK(indent(p)); upb_bytessink_putbuf(p->output_, p->subc, "}", 1, NULL); CHECK(endfield(p)); return true; err: return false; } static void onmreg(const void *c, upb_handlers *h) { const upb_msgdef *m = upb_handlers_msgdef(h); upb_msg_field_iter i; UPB_UNUSED(c); upb_handlers_setstartmsg(h, textprinter_startmsg, NULL); upb_handlers_setendmsg(h, textprinter_endmsg, NULL); for(upb_msg_field_begin(&i, m); !upb_msg_field_done(&i); upb_msg_field_next(&i)) { upb_fielddef *f = upb_msg_iter_field(&i); upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER; upb_handlerattr_sethandlerdata(&attr, f); switch (upb_fielddef_type(f)) { case UPB_TYPE_INT32: upb_handlers_setint32(h, f, textprinter_putint32, &attr); break; case UPB_TYPE_INT64: upb_handlers_setint64(h, f, textprinter_putint64, &attr); break; case UPB_TYPE_UINT32: upb_handlers_setuint32(h, f, textprinter_putuint32, &attr); break; case UPB_TYPE_UINT64: upb_handlers_setuint64(h, f, textprinter_putuint64, &attr); break; case UPB_TYPE_FLOAT: upb_handlers_setfloat(h, f, textprinter_putfloat, &attr); break; case UPB_TYPE_DOUBLE: upb_handlers_setdouble(h, f, textprinter_putdouble, &attr); break; case UPB_TYPE_BOOL: upb_handlers_setbool(h, f, textprinter_putbool, &attr); break; case UPB_TYPE_STRING: case UPB_TYPE_BYTES: upb_handlers_setstartstr(h, f, textprinter_startstr, &attr); upb_handlers_setstring(h, f, textprinter_putstr, &attr); upb_handlers_setendstr(h, f, textprinter_endstr, &attr); break; case UPB_TYPE_MESSAGE: { const char *name = upb_fielddef_istagdelim(f) ? shortname(upb_msgdef_fullname(upb_fielddef_msgsubdef(f))) : upb_fielddef_name(f); upb_handlerattr_sethandlerdata(&attr, name); upb_handlers_setstartsubmsg(h, f, textprinter_startsubmsg, &attr); upb_handlers_setendsubmsg(h, f, textprinter_endsubmsg, &attr); break; } case UPB_TYPE_ENUM: upb_handlers_setint32(h, f, textprinter_putenum, &attr); break; } } } static void textprinter_reset(upb_textprinter *p, bool single_line) { p->single_line_ = single_line; p->indent_depth_ = 0; } /* Public API *****************************************************************/ upb_textprinter *upb_textprinter_create(upb_env *env, const upb_handlers *h, upb_bytessink *output) { upb_textprinter *p = upb_env_malloc(env, sizeof(upb_textprinter)); if (!p) return NULL; p->output_ = output; upb_sink_reset(&p->input_, h, p); textprinter_reset(p, false); return p; } const upb_handlers *upb_textprinter_newhandlers(const upb_msgdef *m, const void *owner) { return upb_handlers_newfrozen(m, owner, &onmreg, NULL); } upb_sink *upb_textprinter_input(upb_textprinter *p) { return &p->input_; } void upb_textprinter_setsingleline(upb_textprinter *p, bool single_line) { p->single_line_ = single_line; } /* Index is descriptor type. */ const uint8_t upb_pb_native_wire_types[] = { UPB_WIRE_TYPE_END_GROUP, /* ENDGROUP */ UPB_WIRE_TYPE_64BIT, /* DOUBLE */ UPB_WIRE_TYPE_32BIT, /* FLOAT */ UPB_WIRE_TYPE_VARINT, /* INT64 */ UPB_WIRE_TYPE_VARINT, /* UINT64 */ UPB_WIRE_TYPE_VARINT, /* INT32 */ UPB_WIRE_TYPE_64BIT, /* FIXED64 */ UPB_WIRE_TYPE_32BIT, /* FIXED32 */ UPB_WIRE_TYPE_VARINT, /* BOOL */ UPB_WIRE_TYPE_DELIMITED, /* STRING */ UPB_WIRE_TYPE_START_GROUP, /* GROUP */ UPB_WIRE_TYPE_DELIMITED, /* MESSAGE */ UPB_WIRE_TYPE_DELIMITED, /* BYTES */ UPB_WIRE_TYPE_VARINT, /* UINT32 */ UPB_WIRE_TYPE_VARINT, /* ENUM */ UPB_WIRE_TYPE_32BIT, /* SFIXED32 */ UPB_WIRE_TYPE_64BIT, /* SFIXED64 */ UPB_WIRE_TYPE_VARINT, /* SINT32 */ UPB_WIRE_TYPE_VARINT, /* SINT64 */ }; /* A basic branch-based decoder, uses 32-bit values to get good performance * on 32-bit architectures (but performs well on 64-bits also). * This scheme comes from the original Google Protobuf implementation * (proto2). */ upb_decoderet upb_vdecode_max8_branch32(upb_decoderet r) { upb_decoderet err = {NULL, 0}; const char *p = r.p; uint32_t low = (uint32_t)r.val; uint32_t high = 0; uint32_t b; b = *(p++); low |= (b & 0x7fU) << 14; if (!(b & 0x80)) goto done; b = *(p++); low |= (b & 0x7fU) << 21; if (!(b & 0x80)) goto done; b = *(p++); low |= (b & 0x7fU) << 28; high = (b & 0x7fU) >> 4; if (!(b & 0x80)) goto done; b = *(p++); high |= (b & 0x7fU) << 3; if (!(b & 0x80)) goto done; b = *(p++); high |= (b & 0x7fU) << 10; if (!(b & 0x80)) goto done; b = *(p++); high |= (b & 0x7fU) << 17; if (!(b & 0x80)) goto done; b = *(p++); high |= (b & 0x7fU) << 24; if (!(b & 0x80)) goto done; b = *(p++); high |= (b & 0x7fU) << 31; if (!(b & 0x80)) goto done; return err; done: r.val = ((uint64_t)high << 32) | low; r.p = p; return r; } /* Like the previous, but uses 64-bit values. */ upb_decoderet upb_vdecode_max8_branch64(upb_decoderet r) { const char *p = r.p; uint64_t val = r.val; uint64_t b; upb_decoderet err = {NULL, 0}; b = *(p++); val |= (b & 0x7fU) << 14; if (!(b & 0x80)) goto done; b = *(p++); val |= (b & 0x7fU) << 21; if (!(b & 0x80)) goto done; b = *(p++); val |= (b & 0x7fU) << 28; if (!(b & 0x80)) goto done; b = *(p++); val |= (b & 0x7fU) << 35; if (!(b & 0x80)) goto done; b = *(p++); val |= (b & 0x7fU) << 42; if (!(b & 0x80)) goto done; b = *(p++); val |= (b & 0x7fU) << 49; if (!(b & 0x80)) goto done; b = *(p++); val |= (b & 0x7fU) << 56; if (!(b & 0x80)) goto done; b = *(p++); val |= (b & 0x7fU) << 63; if (!(b & 0x80)) goto done; return err; done: r.val = val; r.p = p; return r; } /* Given an encoded varint v, returns an integer with a single bit set that * indicates the end of the varint. Subtracting one from this value will * yield a mask that leaves only bits that are part of the varint. Returns * 0 if the varint is unterminated. */ static uint64_t upb_get_vstopbit(uint64_t v) { uint64_t cbits = v | 0x7f7f7f7f7f7f7f7fULL; return ~cbits & (cbits+1); } /* A branchless decoder. Credit to Pascal Massimino for the bit-twiddling. */ upb_decoderet upb_vdecode_max8_massimino(upb_decoderet r) { uint64_t b; uint64_t stop_bit; upb_decoderet my_r; memcpy(&b, r.p, sizeof(b)); stop_bit = upb_get_vstopbit(b); b = (b & 0x7f7f7f7f7f7f7f7fULL) & (stop_bit - 1); b += b & 0x007f007f007f007fULL; b += 3 * (b & 0x0000ffff0000ffffULL); b += 15 * (b & 0x00000000ffffffffULL); if (stop_bit == 0) { /* Error: unterminated varint. */ upb_decoderet err_r = {(void*)0, 0}; return err_r; } my_r = upb_decoderet_make(r.p + ((__builtin_ctzll(stop_bit) + 1) / 8), r.val | (b << 7)); return my_r; } /* A branchless decoder. Credit to Daniel Wright for the bit-twiddling. */ upb_decoderet upb_vdecode_max8_wright(upb_decoderet r) { uint64_t b; uint64_t stop_bit; upb_decoderet my_r; memcpy(&b, r.p, sizeof(b)); stop_bit = upb_get_vstopbit(b); b &= (stop_bit - 1); b = ((b & 0x7f007f007f007f00ULL) >> 1) | (b & 0x007f007f007f007fULL); b = ((b & 0xffff0000ffff0000ULL) >> 2) | (b & 0x0000ffff0000ffffULL); b = ((b & 0xffffffff00000000ULL) >> 4) | (b & 0x00000000ffffffffULL); if (stop_bit == 0) { /* Error: unterminated varint. */ upb_decoderet err_r = {(void*)0, 0}; return err_r; } my_r = upb_decoderet_make(r.p + ((__builtin_ctzll(stop_bit) + 1) / 8), r.val | (b << 14)); return my_r; } #line 1 "upb/json/parser.rl" /* ** upb::json::Parser (upb_json_parser) ** ** A parser that uses the Ragel State Machine Compiler to generate ** the finite automata. ** ** Ragel only natively handles regular languages, but we can manually ** program it a bit to handle context-free languages like JSON, by using ** the "fcall" and "fret" constructs. ** ** This parser can handle the basics, but needs several things to be fleshed ** out: ** ** - handling of unicode escape sequences (including high surrogate pairs). ** - properly check and report errors for unknown fields, stack overflow, ** improper array nesting (or lack of nesting). ** - handling of base64 sequences with padding characters. ** - handling of push-back (non-success returns from sink functions). ** - handling of keys/escape-sequences/etc that span input buffers. */ #include #include #include #include #include #define UPB_JSON_MAX_DEPTH 64 typedef struct { upb_sink sink; /* The current message in which we're parsing, and the field whose value we're * expecting next. */ const upb_msgdef *m; const upb_fielddef *f; /* The table mapping json name to fielddef for this message. */ upb_strtable *name_table; /* We are in a repeated-field context, ready to emit mapentries as * submessages. This flag alters the start-of-object (open-brace) behavior to * begin a sequence of mapentry messages rather than a single submessage. */ bool is_map; /* We are in a map-entry message context. This flag is set when parsing the * value field of a single map entry and indicates to all value-field parsers * (subobjects, strings, numbers, and bools) that the map-entry submessage * should end as soon as the value is parsed. */ bool is_mapentry; /* If |is_map| or |is_mapentry| is true, |mapfield| refers to the parent * message's map field that we're currently parsing. This differs from |f| * because |f| is the field in the *current* message (i.e., the map-entry * message itself), not the parent's field that leads to this map. */ const upb_fielddef *mapfield; } upb_jsonparser_frame; struct upb_json_parser { upb_env *env; const upb_json_parsermethod *method; upb_bytessink input_; /* Stack to track the JSON scopes we are in. */ upb_jsonparser_frame stack[UPB_JSON_MAX_DEPTH]; upb_jsonparser_frame *top; upb_jsonparser_frame *limit; upb_status status; /* Ragel's internal parsing stack for the parsing state machine. */ int current_state; int parser_stack[UPB_JSON_MAX_DEPTH]; int parser_top; /* The handle for the current buffer. */ const upb_bufhandle *handle; /* Accumulate buffer. See details in parser.rl. */ const char *accumulated; size_t accumulated_len; char *accumulate_buf; size_t accumulate_buf_size; /* Multi-part text data. See details in parser.rl. */ int multipart_state; upb_selector_t string_selector; /* Input capture. See details in parser.rl. */ const char *capture; /* Intermediate result of parsing a unicode escape sequence. */ uint32_t digit; }; struct upb_json_parsermethod { upb_refcounted base; upb_byteshandler input_handler_; /* Mainly for the purposes of refcounting, so all the fielddefs we point * to stay alive. */ const upb_msgdef *msg; /* Keys are upb_msgdef*, values are upb_strtable (json_name -> fielddef) */ upb_inttable name_tables; }; #define PARSER_CHECK_RETURN(x) if (!(x)) return false /* Used to signal that a capture has been suspended. */ static char suspend_capture; static upb_selector_t getsel_for_handlertype(upb_json_parser *p, upb_handlertype_t type) { upb_selector_t sel; bool ok = upb_handlers_getselector(p->top->f, type, &sel); UPB_ASSERT(ok); return sel; } static upb_selector_t parser_getsel(upb_json_parser *p) { return getsel_for_handlertype( p, upb_handlers_getprimitivehandlertype(p->top->f)); } static bool check_stack(upb_json_parser *p) { if ((p->top + 1) == p->limit) { upb_status_seterrmsg(&p->status, "Nesting too deep"); upb_env_reporterror(p->env, &p->status); return false; } return true; } static void set_name_table(upb_json_parser *p, upb_jsonparser_frame *frame) { upb_value v; bool ok = upb_inttable_lookupptr(&p->method->name_tables, frame->m, &v); UPB_ASSERT(ok); frame->name_table = upb_value_getptr(v); } /* There are GCC/Clang built-ins for overflow checking which we could start * using if there was any performance benefit to it. */ static bool checked_add(size_t a, size_t b, size_t *c) { if (SIZE_MAX - a < b) return false; *c = a + b; return true; } static size_t saturating_multiply(size_t a, size_t b) { /* size_t is unsigned, so this is defined behavior even on overflow. */ size_t ret = a * b; if (b != 0 && ret / b != a) { ret = SIZE_MAX; } return ret; } /* Base64 decoding ************************************************************/ /* TODO(haberman): make this streaming. */ static const signed char b64table[] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62/*+*/, -1, -1, -1, 63/*/ */, 52/*0*/, 53/*1*/, 54/*2*/, 55/*3*/, 56/*4*/, 57/*5*/, 58/*6*/, 59/*7*/, 60/*8*/, 61/*9*/, -1, -1, -1, -1, -1, -1, -1, 0/*A*/, 1/*B*/, 2/*C*/, 3/*D*/, 4/*E*/, 5/*F*/, 6/*G*/, 07/*H*/, 8/*I*/, 9/*J*/, 10/*K*/, 11/*L*/, 12/*M*/, 13/*N*/, 14/*O*/, 15/*P*/, 16/*Q*/, 17/*R*/, 18/*S*/, 19/*T*/, 20/*U*/, 21/*V*/, 22/*W*/, 23/*X*/, 24/*Y*/, 25/*Z*/, -1, -1, -1, -1, -1, -1, 26/*a*/, 27/*b*/, 28/*c*/, 29/*d*/, 30/*e*/, 31/*f*/, 32/*g*/, 33/*h*/, 34/*i*/, 35/*j*/, 36/*k*/, 37/*l*/, 38/*m*/, 39/*n*/, 40/*o*/, 41/*p*/, 42/*q*/, 43/*r*/, 44/*s*/, 45/*t*/, 46/*u*/, 47/*v*/, 48/*w*/, 49/*x*/, 50/*y*/, 51/*z*/, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; /* Returns the table value sign-extended to 32 bits. Knowing that the upper * bits will be 1 for unrecognized characters makes it easier to check for * this error condition later (see below). */ int32_t b64lookup(unsigned char ch) { return b64table[ch]; } /* Returns true if the given character is not a valid base64 character or * padding. */ bool nonbase64(unsigned char ch) { return b64lookup(ch) == -1 && ch != '='; } static bool base64_push(upb_json_parser *p, upb_selector_t sel, const char *ptr, size_t len) { const char *limit = ptr + len; for (; ptr < limit; ptr += 4) { uint32_t val; char output[3]; if (limit - ptr < 4) { upb_status_seterrf(&p->status, "Base64 input for bytes field not a multiple of 4: %s", upb_fielddef_name(p->top->f)); upb_env_reporterror(p->env, &p->status); return false; } val = b64lookup(ptr[0]) << 18 | b64lookup(ptr[1]) << 12 | b64lookup(ptr[2]) << 6 | b64lookup(ptr[3]); /* Test the upper bit; returns true if any of the characters returned -1. */ if (val & 0x80000000) { goto otherchar; } output[0] = val >> 16; output[1] = (val >> 8) & 0xff; output[2] = val & 0xff; upb_sink_putstring(&p->top->sink, sel, output, 3, NULL); } return true; otherchar: if (nonbase64(ptr[0]) || nonbase64(ptr[1]) || nonbase64(ptr[2]) || nonbase64(ptr[3]) ) { upb_status_seterrf(&p->status, "Non-base64 characters in bytes field: %s", upb_fielddef_name(p->top->f)); upb_env_reporterror(p->env, &p->status); return false; } if (ptr[2] == '=') { uint32_t val; char output; /* Last group contains only two input bytes, one output byte. */ if (ptr[0] == '=' || ptr[1] == '=' || ptr[3] != '=') { goto badpadding; } val = b64lookup(ptr[0]) << 18 | b64lookup(ptr[1]) << 12; UPB_ASSERT(!(val & 0x80000000)); output = val >> 16; upb_sink_putstring(&p->top->sink, sel, &output, 1, NULL); return true; } else { uint32_t val; char output[2]; /* Last group contains only three input bytes, two output bytes. */ if (ptr[0] == '=' || ptr[1] == '=' || ptr[2] == '=') { goto badpadding; } val = b64lookup(ptr[0]) << 18 | b64lookup(ptr[1]) << 12 | b64lookup(ptr[2]) << 6; output[0] = val >> 16; output[1] = (val >> 8) & 0xff; upb_sink_putstring(&p->top->sink, sel, output, 2, NULL); return true; } badpadding: upb_status_seterrf(&p->status, "Incorrect base64 padding for field: %s (%.*s)", upb_fielddef_name(p->top->f), 4, ptr); upb_env_reporterror(p->env, &p->status); return false; } /* Accumulate buffer **********************************************************/ /* Functionality for accumulating a buffer. * * Some parts of the parser need an entire value as a contiguous string. For * example, to look up a member name in a hash table, or to turn a string into * a number, the relevant library routines need the input string to be in * contiguous memory, even if the value spanned two or more buffers in the * input. These routines handle that. * * In the common case we can just point to the input buffer to get this * contiguous string and avoid any actual copy. So we optimistically begin * this way. But there are a few cases where we must instead copy into a * separate buffer: * * 1. The string was not contiguous in the input (it spanned buffers). * * 2. The string included escape sequences that need to be interpreted to get * the true value in a contiguous buffer. */ static void assert_accumulate_empty(upb_json_parser *p) { UPB_ASSERT(p->accumulated == NULL); UPB_ASSERT(p->accumulated_len == 0); } static void accumulate_clear(upb_json_parser *p) { p->accumulated = NULL; p->accumulated_len = 0; } /* Used internally by accumulate_append(). */ static bool accumulate_realloc(upb_json_parser *p, size_t need) { void *mem; size_t old_size = p->accumulate_buf_size; size_t new_size = UPB_MAX(old_size, 128); while (new_size < need) { new_size = saturating_multiply(new_size, 2); } mem = upb_env_realloc(p->env, p->accumulate_buf, old_size, new_size); if (!mem) { upb_status_seterrmsg(&p->status, "Out of memory allocating buffer."); upb_env_reporterror(p->env, &p->status); return false; } p->accumulate_buf = mem; p->accumulate_buf_size = new_size; return true; } /* Logically appends the given data to the append buffer. * If "can_alias" is true, we will try to avoid actually copying, but the buffer * must be valid until the next accumulate_append() call (if any). */ static bool accumulate_append(upb_json_parser *p, const char *buf, size_t len, bool can_alias) { size_t need; if (!p->accumulated && can_alias) { p->accumulated = buf; p->accumulated_len = len; return true; } if (!checked_add(p->accumulated_len, len, &need)) { upb_status_seterrmsg(&p->status, "Integer overflow."); upb_env_reporterror(p->env, &p->status); return false; } if (need > p->accumulate_buf_size && !accumulate_realloc(p, need)) { return false; } if (p->accumulated != p->accumulate_buf) { memcpy(p->accumulate_buf, p->accumulated, p->accumulated_len); p->accumulated = p->accumulate_buf; } memcpy(p->accumulate_buf + p->accumulated_len, buf, len); p->accumulated_len += len; return true; } /* Returns a pointer to the data accumulated since the last accumulate_clear() * call, and writes the length to *len. This with point either to the input * buffer or a temporary accumulate buffer. */ static const char *accumulate_getptr(upb_json_parser *p, size_t *len) { UPB_ASSERT(p->accumulated); *len = p->accumulated_len; return p->accumulated; } /* Mult-part text data ********************************************************/ /* When we have text data in the input, it can often come in multiple segments. * For example, there may be some raw string data followed by an escape * sequence. The two segments are processed with different logic. Also buffer * seams in the input can cause multiple segments. * * As we see segments, there are two main cases for how we want to process them: * * 1. we want to push the captured input directly to string handlers. * * 2. we need to accumulate all the parts into a contiguous buffer for further * processing (field name lookup, string->number conversion, etc). */ /* This is the set of states for p->multipart_state. */ enum { /* We are not currently processing multipart data. */ MULTIPART_INACTIVE = 0, /* We are processing multipart data by accumulating it into a contiguous * buffer. */ MULTIPART_ACCUMULATE = 1, /* We are processing multipart data by pushing each part directly to the * current string handlers. */ MULTIPART_PUSHEAGERLY = 2 }; /* Start a multi-part text value where we accumulate the data for processing at * the end. */ static void multipart_startaccum(upb_json_parser *p) { assert_accumulate_empty(p); UPB_ASSERT(p->multipart_state == MULTIPART_INACTIVE); p->multipart_state = MULTIPART_ACCUMULATE; } /* Start a multi-part text value where we immediately push text data to a string * value with the given selector. */ static void multipart_start(upb_json_parser *p, upb_selector_t sel) { assert_accumulate_empty(p); UPB_ASSERT(p->multipart_state == MULTIPART_INACTIVE); p->multipart_state = MULTIPART_PUSHEAGERLY; p->string_selector = sel; } static bool multipart_text(upb_json_parser *p, const char *buf, size_t len, bool can_alias) { switch (p->multipart_state) { case MULTIPART_INACTIVE: upb_status_seterrmsg( &p->status, "Internal error: unexpected state MULTIPART_INACTIVE"); upb_env_reporterror(p->env, &p->status); return false; case MULTIPART_ACCUMULATE: if (!accumulate_append(p, buf, len, can_alias)) { return false; } break; case MULTIPART_PUSHEAGERLY: { const upb_bufhandle *handle = can_alias ? p->handle : NULL; upb_sink_putstring(&p->top->sink, p->string_selector, buf, len, handle); break; } } return true; } /* Note: this invalidates the accumulate buffer! Call only after reading its * contents. */ static void multipart_end(upb_json_parser *p) { UPB_ASSERT(p->multipart_state != MULTIPART_INACTIVE); p->multipart_state = MULTIPART_INACTIVE; accumulate_clear(p); } /* Input capture **************************************************************/ /* Functionality for capturing a region of the input as text. Gracefully * handles the case where a buffer seam occurs in the middle of the captured * region. */ static void capture_begin(upb_json_parser *p, const char *ptr) { UPB_ASSERT(p->multipart_state != MULTIPART_INACTIVE); UPB_ASSERT(p->capture == NULL); p->capture = ptr; } static bool capture_end(upb_json_parser *p, const char *ptr) { UPB_ASSERT(p->capture); if (multipart_text(p, p->capture, ptr - p->capture, true)) { p->capture = NULL; return true; } else { return false; } } /* This is called at the end of each input buffer (ie. when we have hit a * buffer seam). If we are in the middle of capturing the input, this * processes the unprocessed capture region. */ static void capture_suspend(upb_json_parser *p, const char **ptr) { if (!p->capture) return; if (multipart_text(p, p->capture, *ptr - p->capture, false)) { /* We use this as a signal that we were in the middle of capturing, and * that capturing should resume at the beginning of the next buffer. * * We can't use *ptr here, because we have no guarantee that this pointer * will be valid when we resume (if the underlying memory is freed, then * using the pointer at all, even to compare to NULL, is likely undefined * behavior). */ p->capture = &suspend_capture; } else { /* Need to back up the pointer to the beginning of the capture, since * we were not able to actually preserve it. */ *ptr = p->capture; } } static void capture_resume(upb_json_parser *p, const char *ptr) { if (p->capture) { UPB_ASSERT(p->capture == &suspend_capture); p->capture = ptr; } } /* Callbacks from the parser **************************************************/ /* These are the functions called directly from the parser itself. * We define these in the same order as their declarations in the parser. */ static char escape_char(char in) { switch (in) { case 'r': return '\r'; case 't': return '\t'; case 'n': return '\n'; case 'f': return '\f'; case 'b': return '\b'; case '/': return '/'; case '"': return '"'; case '\\': return '\\'; default: UPB_ASSERT(0); return 'x'; } } static bool escape(upb_json_parser *p, const char *ptr) { char ch = escape_char(*ptr); return multipart_text(p, &ch, 1, false); } static void start_hex(upb_json_parser *p) { p->digit = 0; } static void hexdigit(upb_json_parser *p, const char *ptr) { char ch = *ptr; p->digit <<= 4; if (ch >= '0' && ch <= '9') { p->digit += (ch - '0'); } else if (ch >= 'a' && ch <= 'f') { p->digit += ((ch - 'a') + 10); } else { UPB_ASSERT(ch >= 'A' && ch <= 'F'); p->digit += ((ch - 'A') + 10); } } static bool end_hex(upb_json_parser *p) { uint32_t codepoint = p->digit; /* emit the codepoint as UTF-8. */ char utf8[3]; /* support \u0000 -- \uFFFF -- need only three bytes. */ int length = 0; if (codepoint <= 0x7F) { utf8[0] = codepoint; length = 1; } else if (codepoint <= 0x07FF) { utf8[1] = (codepoint & 0x3F) | 0x80; codepoint >>= 6; utf8[0] = (codepoint & 0x1F) | 0xC0; length = 2; } else /* codepoint <= 0xFFFF */ { utf8[2] = (codepoint & 0x3F) | 0x80; codepoint >>= 6; utf8[1] = (codepoint & 0x3F) | 0x80; codepoint >>= 6; utf8[0] = (codepoint & 0x0F) | 0xE0; length = 3; } /* TODO(haberman): Handle high surrogates: if codepoint is a high surrogate * we have to wait for the next escape to get the full code point). */ return multipart_text(p, utf8, length, false); } static void start_text(upb_json_parser *p, const char *ptr) { capture_begin(p, ptr); } static bool end_text(upb_json_parser *p, const char *ptr) { return capture_end(p, ptr); } static void start_number(upb_json_parser *p, const char *ptr) { multipart_startaccum(p); capture_begin(p, ptr); } static bool parse_number(upb_json_parser *p); static bool end_number(upb_json_parser *p, const char *ptr) { if (!capture_end(p, ptr)) { return false; } return parse_number(p); } static bool parse_number(upb_json_parser *p) { size_t len; const char *buf; const char *myend; char *end; /* strtol() and friends unfortunately do not support specifying the length of * the input string, so we need to force a copy into a NULL-terminated buffer. */ if (!multipart_text(p, "\0", 1, false)) { return false; } buf = accumulate_getptr(p, &len); myend = buf + len - 1; /* One for NULL. */ /* XXX: We are using strtol to parse integers, but this is wrong as even * integers can be represented as 1e6 (for example), which strtol can't * handle correctly. * * XXX: Also, we can't handle large integers properly because strto[u]ll * isn't in C89. * * XXX: Also, we don't properly check floats for overflow, since strtof * isn't in C89. */ switch (upb_fielddef_type(p->top->f)) { case UPB_TYPE_ENUM: case UPB_TYPE_INT32: { long val = strtol(p->accumulated, &end, 0); if (val > INT32_MAX || val < INT32_MIN || errno == ERANGE || end != myend) goto err; else upb_sink_putint32(&p->top->sink, parser_getsel(p), val); break; } case UPB_TYPE_INT64: { long long val = strtol(p->accumulated, &end, 0); if (val > INT64_MAX || val < INT64_MIN || errno == ERANGE || end != myend) goto err; else upb_sink_putint64(&p->top->sink, parser_getsel(p), val); break; } case UPB_TYPE_UINT32: { unsigned long val = strtoul(p->accumulated, &end, 0); if (val > UINT32_MAX || errno == ERANGE || end != myend) goto err; else upb_sink_putuint32(&p->top->sink, parser_getsel(p), val); break; } case UPB_TYPE_UINT64: { unsigned long long val = strtoul(p->accumulated, &end, 0); if (val > UINT64_MAX || errno == ERANGE || end != myend) goto err; else upb_sink_putuint64(&p->top->sink, parser_getsel(p), val); break; } case UPB_TYPE_DOUBLE: { double val = strtod(p->accumulated, &end); if (errno == ERANGE || end != myend) goto err; else upb_sink_putdouble(&p->top->sink, parser_getsel(p), val); break; } case UPB_TYPE_FLOAT: { float val = strtod(p->accumulated, &end); if (errno == ERANGE || end != myend) goto err; else upb_sink_putfloat(&p->top->sink, parser_getsel(p), val); break; } default: UPB_ASSERT(false); } multipart_end(p); return true; err: upb_status_seterrf(&p->status, "error parsing number: %s", buf); upb_env_reporterror(p->env, &p->status); multipart_end(p); return false; } static bool parser_putbool(upb_json_parser *p, bool val) { bool ok; if (upb_fielddef_type(p->top->f) != UPB_TYPE_BOOL) { upb_status_seterrf(&p->status, "Boolean value specified for non-bool field: %s", upb_fielddef_name(p->top->f)); upb_env_reporterror(p->env, &p->status); return false; } ok = upb_sink_putbool(&p->top->sink, parser_getsel(p), val); UPB_ASSERT(ok); return true; } static bool start_stringval(upb_json_parser *p) { UPB_ASSERT(p->top->f); if (upb_fielddef_isstring(p->top->f)) { upb_jsonparser_frame *inner; upb_selector_t sel; if (!check_stack(p)) return false; /* Start a new parser frame: parser frames correspond one-to-one with * handler frames, and string events occur in a sub-frame. */ inner = p->top + 1; sel = getsel_for_handlertype(p, UPB_HANDLER_STARTSTR); upb_sink_startstr(&p->top->sink, sel, 0, &inner->sink); inner->m = p->top->m; inner->f = p->top->f; inner->name_table = NULL; inner->is_map = false; inner->is_mapentry = false; p->top = inner; if (upb_fielddef_type(p->top->f) == UPB_TYPE_STRING) { /* For STRING fields we push data directly to the handlers as it is * parsed. We don't do this yet for BYTES fields, because our base64 * decoder is not streaming. * * TODO(haberman): make base64 decoding streaming also. */ multipart_start(p, getsel_for_handlertype(p, UPB_HANDLER_STRING)); return true; } else { multipart_startaccum(p); return true; } } else if (upb_fielddef_type(p->top->f) == UPB_TYPE_ENUM) { /* No need to push a frame -- symbolic enum names in quotes remain in the * current parser frame. * * Enum string values must accumulate so we can look up the value in a table * once it is complete. */ multipart_startaccum(p); return true; } else { upb_status_seterrf(&p->status, "String specified for non-string/non-enum field: %s", upb_fielddef_name(p->top->f)); upb_env_reporterror(p->env, &p->status); return false; } } static bool end_stringval(upb_json_parser *p) { bool ok = true; switch (upb_fielddef_type(p->top->f)) { case UPB_TYPE_BYTES: if (!base64_push(p, getsel_for_handlertype(p, UPB_HANDLER_STRING), p->accumulated, p->accumulated_len)) { return false; } /* Fall through. */ case UPB_TYPE_STRING: { upb_selector_t sel = getsel_for_handlertype(p, UPB_HANDLER_ENDSTR); p->top--; upb_sink_endstr(&p->top->sink, sel); break; } case UPB_TYPE_ENUM: { /* Resolve enum symbolic name to integer value. */ const upb_enumdef *enumdef = (const upb_enumdef*)upb_fielddef_subdef(p->top->f); size_t len; const char *buf = accumulate_getptr(p, &len); int32_t int_val = 0; ok = upb_enumdef_ntoi(enumdef, buf, len, &int_val); if (ok) { upb_selector_t sel = parser_getsel(p); upb_sink_putint32(&p->top->sink, sel, int_val); } else { upb_status_seterrf(&p->status, "Enum value unknown: '%.*s'", len, buf); upb_env_reporterror(p->env, &p->status); } break; } default: UPB_ASSERT(false); upb_status_seterrmsg(&p->status, "Internal error in JSON decoder"); upb_env_reporterror(p->env, &p->status); ok = false; break; } multipart_end(p); return ok; } static void start_member(upb_json_parser *p) { UPB_ASSERT(!p->top->f); multipart_startaccum(p); } /* Helper: invoked during parse_mapentry() to emit the mapentry message's key * field based on the current contents of the accumulate buffer. */ static bool parse_mapentry_key(upb_json_parser *p) { size_t len; const char *buf = accumulate_getptr(p, &len); /* Emit the key field. We do a bit of ad-hoc parsing here because the * parser state machine has already decided that this is a string field * name, and we are reinterpreting it as some arbitrary key type. In * particular, integer and bool keys are quoted, so we need to parse the * quoted string contents here. */ p->top->f = upb_msgdef_itof(p->top->m, UPB_MAPENTRY_KEY); if (p->top->f == NULL) { upb_status_seterrmsg(&p->status, "mapentry message has no key"); upb_env_reporterror(p->env, &p->status); return false; } switch (upb_fielddef_type(p->top->f)) { case UPB_TYPE_INT32: case UPB_TYPE_INT64: case UPB_TYPE_UINT32: case UPB_TYPE_UINT64: /* Invoke end_number. The accum buffer has the number's text already. */ if (!parse_number(p)) { return false; } break; case UPB_TYPE_BOOL: if (len == 4 && !strncmp(buf, "true", 4)) { if (!parser_putbool(p, true)) { return false; } } else if (len == 5 && !strncmp(buf, "false", 5)) { if (!parser_putbool(p, false)) { return false; } } else { upb_status_seterrmsg(&p->status, "Map bool key not 'true' or 'false'"); upb_env_reporterror(p->env, &p->status); return false; } multipart_end(p); break; case UPB_TYPE_STRING: case UPB_TYPE_BYTES: { upb_sink subsink; upb_selector_t sel = getsel_for_handlertype(p, UPB_HANDLER_STARTSTR); upb_sink_startstr(&p->top->sink, sel, len, &subsink); sel = getsel_for_handlertype(p, UPB_HANDLER_STRING); upb_sink_putstring(&subsink, sel, buf, len, NULL); sel = getsel_for_handlertype(p, UPB_HANDLER_ENDSTR); upb_sink_endstr(&p->top->sink, sel); multipart_end(p); break; } default: upb_status_seterrmsg(&p->status, "Invalid field type for map key"); upb_env_reporterror(p->env, &p->status); return false; } return true; } /* Helper: emit one map entry (as a submessage in the map field sequence). This * is invoked from end_membername(), at the end of the map entry's key string, * with the map key in the accumulate buffer. It parses the key from that * buffer, emits the handler calls to start the mapentry submessage (setting up * its subframe in the process), and sets up state in the subframe so that the * value parser (invoked next) will emit the mapentry's value field and then * end the mapentry message. */ static bool handle_mapentry(upb_json_parser *p) { const upb_fielddef *mapfield; const upb_msgdef *mapentrymsg; upb_jsonparser_frame *inner; upb_selector_t sel; /* Map entry: p->top->sink is the seq frame, so we need to start a frame * for the mapentry itself, and then set |f| in that frame so that the map * value field is parsed, and also set a flag to end the frame after the * map-entry value is parsed. */ if (!check_stack(p)) return false; mapfield = p->top->mapfield; mapentrymsg = upb_fielddef_msgsubdef(mapfield); inner = p->top + 1; p->top->f = mapfield; sel = getsel_for_handlertype(p, UPB_HANDLER_STARTSUBMSG); upb_sink_startsubmsg(&p->top->sink, sel, &inner->sink); inner->m = mapentrymsg; inner->name_table = NULL; inner->mapfield = mapfield; inner->is_map = false; /* Don't set this to true *yet* -- we reuse parsing handlers below to push * the key field value to the sink, and these handlers will pop the frame * if they see is_mapentry (when invoked by the parser state machine, they * would have just seen the map-entry value, not key). */ inner->is_mapentry = false; p->top = inner; /* send STARTMSG in submsg frame. */ upb_sink_startmsg(&p->top->sink); parse_mapentry_key(p); /* Set up the value field to receive the map-entry value. */ p->top->f = upb_msgdef_itof(p->top->m, UPB_MAPENTRY_VALUE); p->top->is_mapentry = true; /* set up to pop frame after value is parsed. */ p->top->mapfield = mapfield; if (p->top->f == NULL) { upb_status_seterrmsg(&p->status, "mapentry message has no value"); upb_env_reporterror(p->env, &p->status); return false; } return true; } static bool end_membername(upb_json_parser *p) { UPB_ASSERT(!p->top->f); if (p->top->is_map) { return handle_mapentry(p); } else { size_t len; const char *buf = accumulate_getptr(p, &len); upb_value v; if (upb_strtable_lookup2(p->top->name_table, buf, len, &v)) { p->top->f = upb_value_getconstptr(v); multipart_end(p); return true; } else { /* TODO(haberman): Ignore unknown fields if requested/configured to do * so. */ upb_status_seterrf(&p->status, "No such field: %.*s\n", (int)len, buf); upb_env_reporterror(p->env, &p->status); return false; } } } static void end_member(upb_json_parser *p) { /* If we just parsed a map-entry value, end that frame too. */ if (p->top->is_mapentry) { upb_status s = UPB_STATUS_INIT; upb_selector_t sel; bool ok; const upb_fielddef *mapfield; UPB_ASSERT(p->top > p->stack); /* send ENDMSG on submsg. */ upb_sink_endmsg(&p->top->sink, &s); mapfield = p->top->mapfield; /* send ENDSUBMSG in repeated-field-of-mapentries frame. */ p->top--; ok = upb_handlers_getselector(mapfield, UPB_HANDLER_ENDSUBMSG, &sel); UPB_ASSERT(ok); upb_sink_endsubmsg(&p->top->sink, sel); } p->top->f = NULL; } static bool start_subobject(upb_json_parser *p) { UPB_ASSERT(p->top->f); if (upb_fielddef_ismap(p->top->f)) { upb_jsonparser_frame *inner; upb_selector_t sel; /* Beginning of a map. Start a new parser frame in a repeated-field * context. */ if (!check_stack(p)) return false; inner = p->top + 1; sel = getsel_for_handlertype(p, UPB_HANDLER_STARTSEQ); upb_sink_startseq(&p->top->sink, sel, &inner->sink); inner->m = upb_fielddef_msgsubdef(p->top->f); inner->name_table = NULL; inner->mapfield = p->top->f; inner->f = NULL; inner->is_map = true; inner->is_mapentry = false; p->top = inner; return true; } else if (upb_fielddef_issubmsg(p->top->f)) { upb_jsonparser_frame *inner; upb_selector_t sel; /* Beginning of a subobject. Start a new parser frame in the submsg * context. */ if (!check_stack(p)) return false; inner = p->top + 1; sel = getsel_for_handlertype(p, UPB_HANDLER_STARTSUBMSG); upb_sink_startsubmsg(&p->top->sink, sel, &inner->sink); inner->m = upb_fielddef_msgsubdef(p->top->f); set_name_table(p, inner); inner->f = NULL; inner->is_map = false; inner->is_mapentry = false; p->top = inner; return true; } else { upb_status_seterrf(&p->status, "Object specified for non-message/group field: %s", upb_fielddef_name(p->top->f)); upb_env_reporterror(p->env, &p->status); return false; } } static void end_subobject(upb_json_parser *p) { if (p->top->is_map) { upb_selector_t sel; p->top--; sel = getsel_for_handlertype(p, UPB_HANDLER_ENDSEQ); upb_sink_endseq(&p->top->sink, sel); } else { upb_selector_t sel; p->top--; sel = getsel_for_handlertype(p, UPB_HANDLER_ENDSUBMSG); upb_sink_endsubmsg(&p->top->sink, sel); } } static bool start_array(upb_json_parser *p) { upb_jsonparser_frame *inner; upb_selector_t sel; UPB_ASSERT(p->top->f); if (!upb_fielddef_isseq(p->top->f)) { upb_status_seterrf(&p->status, "Array specified for non-repeated field: %s", upb_fielddef_name(p->top->f)); upb_env_reporterror(p->env, &p->status); return false; } if (!check_stack(p)) return false; inner = p->top + 1; sel = getsel_for_handlertype(p, UPB_HANDLER_STARTSEQ); upb_sink_startseq(&p->top->sink, sel, &inner->sink); inner->m = p->top->m; inner->name_table = NULL; inner->f = p->top->f; inner->is_map = false; inner->is_mapentry = false; p->top = inner; return true; } static void end_array(upb_json_parser *p) { upb_selector_t sel; UPB_ASSERT(p->top > p->stack); p->top--; sel = getsel_for_handlertype(p, UPB_HANDLER_ENDSEQ); upb_sink_endseq(&p->top->sink, sel); } static void start_object(upb_json_parser *p) { if (!p->top->is_map) { upb_sink_startmsg(&p->top->sink); } } static void end_object(upb_json_parser *p) { if (!p->top->is_map) { upb_status status; upb_status_clear(&status); upb_sink_endmsg(&p->top->sink, &status); if (!upb_ok(&status)) { upb_env_reporterror(p->env, &status); } } } #define CHECK_RETURN_TOP(x) if (!(x)) goto error /* The actual parser **********************************************************/ /* What follows is the Ragel parser itself. The language is specified in Ragel * and the actions call our C functions above. * * Ragel has an extensive set of functionality, and we use only a small part of * it. There are many action types but we only use a few: * * ">" -- transition into a machine * "%" -- transition out of a machine * "@" -- transition into a final state of a machine. * * "@" transitions are tricky because a machine can transition into a final * state repeatedly. But in some cases we know this can't happen, for example * a string which is delimited by a final '"' can only transition into its * final state once, when the closing '"' is seen. */ #line 1244 "upb/json/parser.rl" #line 1156 "upb/json/parser.c" static const char _json_actions[] = { 0, 1, 0, 1, 2, 1, 3, 1, 5, 1, 6, 1, 7, 1, 8, 1, 10, 1, 12, 1, 13, 1, 14, 1, 15, 1, 16, 1, 17, 1, 21, 1, 25, 1, 27, 2, 3, 8, 2, 4, 5, 2, 6, 2, 2, 6, 8, 2, 11, 9, 2, 13, 15, 2, 14, 15, 2, 18, 1, 2, 19, 27, 2, 20, 9, 2, 22, 27, 2, 23, 27, 2, 24, 27, 2, 26, 27, 3, 14, 11, 9 }; static const unsigned char _json_key_offsets[] = { 0, 0, 4, 9, 14, 15, 19, 24, 29, 34, 38, 42, 45, 48, 50, 54, 58, 60, 62, 67, 69, 71, 80, 86, 92, 98, 104, 106, 115, 116, 116, 116, 121, 126, 131, 132, 133, 134, 135, 135, 136, 137, 138, 138, 139, 140, 141, 141, 146, 151, 152, 156, 161, 166, 171, 175, 175, 178, 178, 178 }; static const char _json_trans_keys[] = { 32, 123, 9, 13, 32, 34, 125, 9, 13, 32, 34, 125, 9, 13, 34, 32, 58, 9, 13, 32, 93, 125, 9, 13, 32, 44, 125, 9, 13, 32, 44, 125, 9, 13, 32, 34, 9, 13, 45, 48, 49, 57, 48, 49, 57, 46, 69, 101, 48, 57, 69, 101, 48, 57, 43, 45, 48, 57, 48, 57, 48, 57, 46, 69, 101, 48, 57, 34, 92, 34, 92, 34, 47, 92, 98, 102, 110, 114, 116, 117, 48, 57, 65, 70, 97, 102, 48, 57, 65, 70, 97, 102, 48, 57, 65, 70, 97, 102, 48, 57, 65, 70, 97, 102, 34, 92, 34, 45, 91, 102, 110, 116, 123, 48, 57, 34, 32, 93, 125, 9, 13, 32, 44, 93, 9, 13, 32, 93, 125, 9, 13, 97, 108, 115, 101, 117, 108, 108, 114, 117, 101, 32, 34, 125, 9, 13, 32, 34, 125, 9, 13, 34, 32, 58, 9, 13, 32, 93, 125, 9, 13, 32, 44, 125, 9, 13, 32, 44, 125, 9, 13, 32, 34, 9, 13, 32, 9, 13, 0 }; static const char _json_single_lengths[] = { 0, 2, 3, 3, 1, 2, 3, 3, 3, 2, 2, 1, 3, 0, 2, 2, 0, 0, 3, 2, 2, 9, 0, 0, 0, 0, 2, 7, 1, 0, 0, 3, 3, 3, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 3, 3, 1, 2, 3, 3, 3, 2, 0, 1, 0, 0, 0 }; static const char _json_range_lengths[] = { 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 3, 3, 3, 3, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0 }; static const short _json_index_offsets[] = { 0, 0, 4, 9, 14, 16, 20, 25, 30, 35, 39, 43, 46, 50, 52, 56, 60, 62, 64, 69, 72, 75, 85, 89, 93, 97, 101, 104, 113, 115, 116, 117, 122, 127, 132, 134, 136, 138, 140, 141, 143, 145, 147, 148, 150, 152, 154, 155, 160, 165, 167, 171, 176, 181, 186, 190, 191, 194, 195, 196 }; static const char _json_indicies[] = { 0, 2, 0, 1, 3, 4, 5, 3, 1, 6, 7, 8, 6, 1, 9, 1, 10, 11, 10, 1, 11, 1, 1, 11, 12, 13, 14, 15, 13, 1, 16, 17, 8, 16, 1, 17, 7, 17, 1, 18, 19, 20, 1, 19, 20, 1, 22, 23, 23, 21, 24, 1, 23, 23, 24, 21, 25, 25, 26, 1, 26, 1, 26, 21, 22, 23, 23, 20, 21, 28, 29, 27, 31, 32, 30, 33, 33, 33, 33, 33, 33, 33, 33, 34, 1, 35, 35, 35, 1, 36, 36, 36, 1, 37, 37, 37, 1, 38, 38, 38, 1, 40, 41, 39, 42, 43, 44, 45, 46, 47, 48, 43, 1, 49, 1, 50, 51, 53, 54, 1, 53, 52, 55, 56, 54, 55, 1, 56, 1, 1, 56, 52, 57, 1, 58, 1, 59, 1, 60, 1, 61, 62, 1, 63, 1, 64, 1, 65, 66, 1, 67, 1, 68, 1, 69, 70, 71, 72, 70, 1, 73, 74, 75, 73, 1, 76, 1, 77, 78, 77, 1, 78, 1, 1, 78, 79, 80, 81, 82, 80, 1, 83, 84, 75, 83, 1, 84, 74, 84, 1, 85, 86, 86, 1, 1, 1, 1, 0 }; static const char _json_trans_targs[] = { 1, 0, 2, 3, 4, 56, 3, 4, 56, 5, 5, 6, 7, 8, 9, 56, 8, 9, 11, 12, 18, 57, 13, 15, 14, 16, 17, 20, 58, 21, 20, 58, 21, 19, 22, 23, 24, 25, 26, 20, 58, 21, 28, 30, 31, 34, 39, 43, 47, 29, 59, 59, 32, 31, 29, 32, 33, 35, 36, 37, 38, 59, 40, 41, 42, 59, 44, 45, 46, 59, 48, 49, 55, 48, 49, 55, 50, 50, 51, 52, 53, 54, 55, 53, 54, 59, 56 }; static const char _json_trans_actions[] = { 0, 0, 0, 21, 77, 53, 0, 47, 23, 17, 0, 0, 15, 19, 19, 50, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 3, 13, 0, 0, 35, 5, 11, 0, 38, 7, 7, 7, 41, 44, 9, 62, 56, 25, 0, 0, 0, 31, 29, 33, 59, 15, 0, 27, 0, 0, 0, 0, 0, 0, 68, 0, 0, 0, 71, 0, 0, 0, 65, 21, 77, 53, 0, 47, 23, 17, 0, 0, 15, 19, 19, 50, 0, 0, 74, 0 }; static const int json_start = 1; static const int json_en_number_machine = 10; static const int json_en_string_machine = 19; static const int json_en_value_machine = 27; static const int json_en_main = 1; #line 1247 "upb/json/parser.rl" size_t parse(void *closure, const void *hd, const char *buf, size_t size, const upb_bufhandle *handle) { upb_json_parser *parser = closure; /* Variables used by Ragel's generated code. */ int cs = parser->current_state; int *stack = parser->parser_stack; int top = parser->parser_top; const char *p = buf; const char *pe = buf + size; parser->handle = handle; UPB_UNUSED(hd); UPB_UNUSED(handle); capture_resume(parser, buf); #line 1327 "upb/json/parser.c" { int _klen; unsigned int _trans; const char *_acts; unsigned int _nacts; const char *_keys; if ( p == pe ) goto _test_eof; if ( cs == 0 ) goto _out; _resume: _keys = _json_trans_keys + _json_key_offsets[cs]; _trans = _json_index_offsets[cs]; _klen = _json_single_lengths[cs]; if ( _klen > 0 ) { const char *_lower = _keys; const char *_mid; const char *_upper = _keys + _klen - 1; while (1) { if ( _upper < _lower ) break; _mid = _lower + ((_upper-_lower) >> 1); if ( (*p) < *_mid ) _upper = _mid - 1; else if ( (*p) > *_mid ) _lower = _mid + 1; else { _trans += (unsigned int)(_mid - _keys); goto _match; } } _keys += _klen; _trans += _klen; } _klen = _json_range_lengths[cs]; if ( _klen > 0 ) { const char *_lower = _keys; const char *_mid; const char *_upper = _keys + (_klen<<1) - 2; while (1) { if ( _upper < _lower ) break; _mid = _lower + (((_upper-_lower) >> 1) & ~1); if ( (*p) < _mid[0] ) _upper = _mid - 2; else if ( (*p) > _mid[1] ) _lower = _mid + 2; else { _trans += (unsigned int)((_mid - _keys)>>1); goto _match; } } _trans += _klen; } _match: _trans = _json_indicies[_trans]; cs = _json_trans_targs[_trans]; if ( _json_trans_actions[_trans] == 0 ) goto _again; _acts = _json_actions + _json_trans_actions[_trans]; _nacts = (unsigned int) *_acts++; while ( _nacts-- > 0 ) { switch ( *_acts++ ) { case 0: #line 1159 "upb/json/parser.rl" { p--; {cs = stack[--top]; goto _again;} } break; case 1: #line 1160 "upb/json/parser.rl" { p--; {stack[top++] = cs; cs = 10; goto _again;} } break; case 2: #line 1164 "upb/json/parser.rl" { start_text(parser, p); } break; case 3: #line 1165 "upb/json/parser.rl" { CHECK_RETURN_TOP(end_text(parser, p)); } break; case 4: #line 1171 "upb/json/parser.rl" { start_hex(parser); } break; case 5: #line 1172 "upb/json/parser.rl" { hexdigit(parser, p); } break; case 6: #line 1173 "upb/json/parser.rl" { CHECK_RETURN_TOP(end_hex(parser)); } break; case 7: #line 1179 "upb/json/parser.rl" { CHECK_RETURN_TOP(escape(parser, p)); } break; case 8: #line 1185 "upb/json/parser.rl" { p--; {cs = stack[--top]; goto _again;} } break; case 9: #line 1188 "upb/json/parser.rl" { {stack[top++] = cs; cs = 19; goto _again;} } break; case 10: #line 1190 "upb/json/parser.rl" { p--; {stack[top++] = cs; cs = 27; goto _again;} } break; case 11: #line 1195 "upb/json/parser.rl" { start_member(parser); } break; case 12: #line 1196 "upb/json/parser.rl" { CHECK_RETURN_TOP(end_membername(parser)); } break; case 13: #line 1199 "upb/json/parser.rl" { end_member(parser); } break; case 14: #line 1205 "upb/json/parser.rl" { start_object(parser); } break; case 15: #line 1208 "upb/json/parser.rl" { end_object(parser); } break; case 16: #line 1214 "upb/json/parser.rl" { CHECK_RETURN_TOP(start_array(parser)); } break; case 17: #line 1218 "upb/json/parser.rl" { end_array(parser); } break; case 18: #line 1223 "upb/json/parser.rl" { start_number(parser, p); } break; case 19: #line 1224 "upb/json/parser.rl" { CHECK_RETURN_TOP(end_number(parser, p)); } break; case 20: #line 1226 "upb/json/parser.rl" { CHECK_RETURN_TOP(start_stringval(parser)); } break; case 21: #line 1227 "upb/json/parser.rl" { CHECK_RETURN_TOP(end_stringval(parser)); } break; case 22: #line 1229 "upb/json/parser.rl" { CHECK_RETURN_TOP(parser_putbool(parser, true)); } break; case 23: #line 1231 "upb/json/parser.rl" { CHECK_RETURN_TOP(parser_putbool(parser, false)); } break; case 24: #line 1233 "upb/json/parser.rl" { /* null value */ } break; case 25: #line 1235 "upb/json/parser.rl" { CHECK_RETURN_TOP(start_subobject(parser)); } break; case 26: #line 1236 "upb/json/parser.rl" { end_subobject(parser); } break; case 27: #line 1241 "upb/json/parser.rl" { p--; {cs = stack[--top]; goto _again;} } break; #line 1513 "upb/json/parser.c" } } _again: if ( cs == 0 ) goto _out; if ( ++p != pe ) goto _resume; _test_eof: {} _out: {} } #line 1268 "upb/json/parser.rl" if (p != pe) { upb_status_seterrf(&parser->status, "Parse error at '%.*s'\n", pe - p, p); upb_env_reporterror(parser->env, &parser->status); } else { capture_suspend(parser, &p); } error: /* Save parsing state back to parser. */ parser->current_state = cs; parser->parser_top = top; return p - buf; } bool end(void *closure, const void *hd) { UPB_UNUSED(closure); UPB_UNUSED(hd); /* Prevent compile warning on unused static constants. */ UPB_UNUSED(json_start); UPB_UNUSED(json_en_number_machine); UPB_UNUSED(json_en_string_machine); UPB_UNUSED(json_en_value_machine); UPB_UNUSED(json_en_main); return true; } static void json_parser_reset(upb_json_parser *p) { int cs; int top; p->top = p->stack; p->top->f = NULL; p->top->is_map = false; p->top->is_mapentry = false; /* Emit Ragel initialization of the parser. */ #line 1567 "upb/json/parser.c" { cs = json_start; top = 0; } #line 1308 "upb/json/parser.rl" p->current_state = cs; p->parser_top = top; accumulate_clear(p); p->multipart_state = MULTIPART_INACTIVE; p->capture = NULL; p->accumulated = NULL; upb_status_clear(&p->status); } static void visit_json_parsermethod(const upb_refcounted *r, upb_refcounted_visit *visit, void *closure) { const upb_json_parsermethod *method = (upb_json_parsermethod*)r; visit(r, upb_msgdef_upcast2(method->msg), closure); } static void free_json_parsermethod(upb_refcounted *r) { upb_json_parsermethod *method = (upb_json_parsermethod*)r; upb_inttable_iter i; upb_inttable_begin(&i, &method->name_tables); for(; !upb_inttable_done(&i); upb_inttable_next(&i)) { upb_value val = upb_inttable_iter_value(&i); upb_strtable *t = upb_value_getptr(val); upb_strtable_uninit(t); upb_gfree(t); } upb_inttable_uninit(&method->name_tables); upb_gfree(r); } static void add_jsonname_table(upb_json_parsermethod *m, const upb_msgdef* md) { upb_msg_field_iter i; upb_strtable *t; /* It would be nice to stack-allocate this, but protobufs do not limit the * length of fields to any reasonable limit. */ char *buf = NULL; size_t len = 0; if (upb_inttable_lookupptr(&m->name_tables, md, NULL)) { return; } /* TODO(haberman): handle malloc failure. */ t = upb_gmalloc(sizeof(*t)); upb_strtable_init(t, UPB_CTYPE_CONSTPTR); upb_inttable_insertptr(&m->name_tables, md, upb_value_ptr(t)); for(upb_msg_field_begin(&i, md); !upb_msg_field_done(&i); upb_msg_field_next(&i)) { const upb_fielddef *f = upb_msg_iter_field(&i); /* Add an entry for the JSON name. */ size_t field_len = upb_fielddef_getjsonname(f, buf, len); if (field_len > len) { size_t len2; buf = upb_grealloc(buf, 0, field_len); len = field_len; len2 = upb_fielddef_getjsonname(f, buf, len); UPB_ASSERT(len == len2); } upb_strtable_insert(t, buf, upb_value_constptr(f)); if (strcmp(buf, upb_fielddef_name(f)) != 0) { /* Since the JSON name is different from the regular field name, add an * entry for the raw name (compliant proto3 JSON parsers must accept * both). */ upb_strtable_insert(t, upb_fielddef_name(f), upb_value_constptr(f)); } if (upb_fielddef_issubmsg(f)) { add_jsonname_table(m, upb_fielddef_msgsubdef(f)); } } upb_gfree(buf); } /* Public API *****************************************************************/ upb_json_parser *upb_json_parser_create(upb_env *env, const upb_json_parsermethod *method, upb_sink *output) { #ifndef NDEBUG const size_t size_before = upb_env_bytesallocated(env); #endif upb_json_parser *p = upb_env_malloc(env, sizeof(upb_json_parser)); if (!p) return false; p->env = env; p->method = method; p->limit = p->stack + UPB_JSON_MAX_DEPTH; p->accumulate_buf = NULL; p->accumulate_buf_size = 0; upb_bytessink_reset(&p->input_, &method->input_handler_, p); json_parser_reset(p); upb_sink_reset(&p->top->sink, output->handlers, output->closure); p->top->m = upb_handlers_msgdef(output->handlers); set_name_table(p, p->top); /* If this fails, uncomment and increase the value in parser.h. */ /* fprintf(stderr, "%zd\n", upb_env_bytesallocated(env) - size_before); */ UPB_ASSERT_DEBUGVAR(upb_env_bytesallocated(env) - size_before <= UPB_JSON_PARSER_SIZE); return p; } upb_bytessink *upb_json_parser_input(upb_json_parser *p) { return &p->input_; } upb_json_parsermethod *upb_json_parsermethod_new(const upb_msgdef* md, const void* owner) { static const struct upb_refcounted_vtbl vtbl = {visit_json_parsermethod, free_json_parsermethod}; upb_json_parsermethod *ret = upb_gmalloc(sizeof(*ret)); upb_refcounted_init(upb_json_parsermethod_upcast_mutable(ret), &vtbl, owner); ret->msg = md; upb_ref2(md, ret); upb_byteshandler_init(&ret->input_handler_); upb_byteshandler_setstring(&ret->input_handler_, parse, ret); upb_byteshandler_setendstr(&ret->input_handler_, end, ret); upb_inttable_init(&ret->name_tables, UPB_CTYPE_PTR); add_jsonname_table(ret, md); return ret; } const upb_byteshandler *upb_json_parsermethod_inputhandler( const upb_json_parsermethod *m) { return &m->input_handler_; } /* ** This currently uses snprintf() to format primitives, and could be optimized ** further. */ #include #include struct upb_json_printer { upb_sink input_; /* BytesSink closure. */ void *subc_; upb_bytessink *output_; /* We track the depth so that we know when to emit startstr/endstr on the * output. */ int depth_; /* Have we emitted the first element? This state is necessary to emit commas * without leaving a trailing comma in arrays/maps. We keep this state per * frame depth. * * Why max_depth * 2? UPB_MAX_HANDLER_DEPTH counts depth as nested messages. * We count frames (contexts in which we separate elements by commas) as both * repeated fields and messages (maps), and the worst case is a * message->repeated field->submessage->repeated field->... nesting. */ bool first_elem_[UPB_MAX_HANDLER_DEPTH * 2]; }; /* StringPiece; a pointer plus a length. */ typedef struct { char *ptr; size_t len; } strpc; void freestrpc(void *ptr) { strpc *pc = ptr; upb_gfree(pc->ptr); upb_gfree(pc); } /* Convert fielddef name to JSON name and return as a string piece. */ strpc *newstrpc(upb_handlers *h, const upb_fielddef *f, bool preserve_fieldnames) { /* TODO(haberman): handle malloc failure. */ strpc *ret = upb_gmalloc(sizeof(*ret)); if (preserve_fieldnames) { ret->ptr = upb_gstrdup(upb_fielddef_name(f)); ret->len = strlen(ret->ptr); } else { size_t len; ret->len = upb_fielddef_getjsonname(f, NULL, 0); ret->ptr = upb_gmalloc(ret->len); len = upb_fielddef_getjsonname(f, ret->ptr, ret->len); UPB_ASSERT(len == ret->len); ret->len--; /* NULL */ } upb_handlers_addcleanup(h, ret, freestrpc); return ret; } /* ------------ JSON string printing: values, maps, arrays ------------------ */ static void print_data( upb_json_printer *p, const char *buf, unsigned int len) { /* TODO: Will need to change if we support pushback from the sink. */ size_t n = upb_bytessink_putbuf(p->output_, p->subc_, buf, len, NULL); UPB_ASSERT(n == len); } static void print_comma(upb_json_printer *p) { if (!p->first_elem_[p->depth_]) { print_data(p, ",", 1); } p->first_elem_[p->depth_] = false; } /* Helpers that print properly formatted elements to the JSON output stream. */ /* Used for escaping control chars in strings. */ static const char kControlCharLimit = 0x20; UPB_INLINE bool is_json_escaped(char c) { /* See RFC 4627. */ unsigned char uc = (unsigned char)c; return uc < kControlCharLimit || uc == '"' || uc == '\\'; } UPB_INLINE const char* json_nice_escape(char c) { switch (c) { case '"': return "\\\""; case '\\': return "\\\\"; case '\b': return "\\b"; case '\f': return "\\f"; case '\n': return "\\n"; case '\r': return "\\r"; case '\t': return "\\t"; default: return NULL; } } /* Write a properly escaped string chunk. The surrounding quotes are *not* * printed; this is so that the caller has the option of emitting the string * content in chunks. */ static void putstring(upb_json_printer *p, const char *buf, unsigned int len) { const char* unescaped_run = NULL; unsigned int i; for (i = 0; i < len; i++) { char c = buf[i]; /* Handle escaping. */ if (is_json_escaped(c)) { /* Use a "nice" escape, like \n, if one exists for this character. */ const char* escape = json_nice_escape(c); /* If we don't have a specific 'nice' escape code, use a \uXXXX-style * escape. */ char escape_buf[8]; if (!escape) { unsigned char byte = (unsigned char)c; _upb_snprintf(escape_buf, sizeof(escape_buf), "\\u%04x", (int)byte); escape = escape_buf; } /* N.B. that we assume that the input encoding is equal to the output * encoding (both UTF-8 for now), so for chars >= 0x20 and != \, ", we * can simply pass the bytes through. */ /* If there's a current run of unescaped chars, print that run first. */ if (unescaped_run) { print_data(p, unescaped_run, &buf[i] - unescaped_run); unescaped_run = NULL; } /* Then print the escape code. */ print_data(p, escape, strlen(escape)); } else { /* Add to the current unescaped run of characters. */ if (unescaped_run == NULL) { unescaped_run = &buf[i]; } } } /* If the string ended in a run of unescaped characters, print that last run. */ if (unescaped_run) { print_data(p, unescaped_run, &buf[len] - unescaped_run); } } #define CHKLENGTH(x) if (!(x)) return -1; /* Helpers that format floating point values according to our custom formats. * Right now we use %.8g and %.17g for float/double, respectively, to match * proto2::util::JsonFormat's defaults. May want to change this later. */ static size_t fmt_double(double val, char* buf, size_t length) { size_t n = _upb_snprintf(buf, length, "%.17g", val); CHKLENGTH(n > 0 && n < length); return n; } static size_t fmt_float(float val, char* buf, size_t length) { size_t n = _upb_snprintf(buf, length, "%.8g", val); CHKLENGTH(n > 0 && n < length); return n; } static size_t fmt_bool(bool val, char* buf, size_t length) { size_t n = _upb_snprintf(buf, length, "%s", (val ? "true" : "false")); CHKLENGTH(n > 0 && n < length); return n; } static size_t fmt_int64(long val, char* buf, size_t length) { size_t n = _upb_snprintf(buf, length, "%ld", val); CHKLENGTH(n > 0 && n < length); return n; } static size_t fmt_uint64(unsigned long long val, char* buf, size_t length) { size_t n = _upb_snprintf(buf, length, "%llu", val); CHKLENGTH(n > 0 && n < length); return n; } /* Print a map key given a field name. Called by scalar field handlers and by * startseq for repeated fields. */ static bool putkey(void *closure, const void *handler_data) { upb_json_printer *p = closure; const strpc *key = handler_data; print_comma(p); print_data(p, "\"", 1); putstring(p, key->ptr, key->len); print_data(p, "\":", 2); return true; } #define CHKFMT(val) if ((val) == (size_t)-1) return false; #define CHK(val) if (!(val)) return false; #define TYPE_HANDLERS(type, fmt_func) \ static bool put##type(void *closure, const void *handler_data, type val) { \ upb_json_printer *p = closure; \ char data[64]; \ size_t length = fmt_func(val, data, sizeof(data)); \ UPB_UNUSED(handler_data); \ CHKFMT(length); \ print_data(p, data, length); \ return true; \ } \ static bool scalar_##type(void *closure, const void *handler_data, \ type val) { \ CHK(putkey(closure, handler_data)); \ CHK(put##type(closure, handler_data, val)); \ return true; \ } \ static bool repeated_##type(void *closure, const void *handler_data, \ type val) { \ upb_json_printer *p = closure; \ print_comma(p); \ CHK(put##type(closure, handler_data, val)); \ return true; \ } #define TYPE_HANDLERS_MAPKEY(type, fmt_func) \ static bool putmapkey_##type(void *closure, const void *handler_data, \ type val) { \ upb_json_printer *p = closure; \ print_data(p, "\"", 1); \ CHK(put##type(closure, handler_data, val)); \ print_data(p, "\":", 2); \ return true; \ } TYPE_HANDLERS(double, fmt_double) TYPE_HANDLERS(float, fmt_float) TYPE_HANDLERS(bool, fmt_bool) TYPE_HANDLERS(int32_t, fmt_int64) TYPE_HANDLERS(uint32_t, fmt_int64) TYPE_HANDLERS(int64_t, fmt_int64) TYPE_HANDLERS(uint64_t, fmt_uint64) /* double and float are not allowed to be map keys. */ TYPE_HANDLERS_MAPKEY(bool, fmt_bool) TYPE_HANDLERS_MAPKEY(int32_t, fmt_int64) TYPE_HANDLERS_MAPKEY(uint32_t, fmt_int64) TYPE_HANDLERS_MAPKEY(int64_t, fmt_int64) TYPE_HANDLERS_MAPKEY(uint64_t, fmt_uint64) #undef TYPE_HANDLERS #undef TYPE_HANDLERS_MAPKEY typedef struct { void *keyname; const upb_enumdef *enumdef; } EnumHandlerData; static bool scalar_enum(void *closure, const void *handler_data, int32_t val) { const EnumHandlerData *hd = handler_data; upb_json_printer *p = closure; const char *symbolic_name; CHK(putkey(closure, hd->keyname)); symbolic_name = upb_enumdef_iton(hd->enumdef, val); if (symbolic_name) { print_data(p, "\"", 1); putstring(p, symbolic_name, strlen(symbolic_name)); print_data(p, "\"", 1); } else { putint32_t(closure, NULL, val); } return true; } static void print_enum_symbolic_name(upb_json_printer *p, const upb_enumdef *def, int32_t val) { const char *symbolic_name = upb_enumdef_iton(def, val); if (symbolic_name) { print_data(p, "\"", 1); putstring(p, symbolic_name, strlen(symbolic_name)); print_data(p, "\"", 1); } else { putint32_t(p, NULL, val); } } static bool repeated_enum(void *closure, const void *handler_data, int32_t val) { const EnumHandlerData *hd = handler_data; upb_json_printer *p = closure; print_comma(p); print_enum_symbolic_name(p, hd->enumdef, val); return true; } static bool mapvalue_enum(void *closure, const void *handler_data, int32_t val) { const EnumHandlerData *hd = handler_data; upb_json_printer *p = closure; print_enum_symbolic_name(p, hd->enumdef, val); return true; } static void *scalar_startsubmsg(void *closure, const void *handler_data) { return putkey(closure, handler_data) ? closure : UPB_BREAK; } static void *repeated_startsubmsg(void *closure, const void *handler_data) { upb_json_printer *p = closure; UPB_UNUSED(handler_data); print_comma(p); return closure; } static void start_frame(upb_json_printer *p) { p->depth_++; p->first_elem_[p->depth_] = true; print_data(p, "{", 1); } static void end_frame(upb_json_printer *p) { print_data(p, "}", 1); p->depth_--; } static bool printer_startmsg(void *closure, const void *handler_data) { upb_json_printer *p = closure; UPB_UNUSED(handler_data); if (p->depth_ == 0) { upb_bytessink_start(p->output_, 0, &p->subc_); } start_frame(p); return true; } static bool printer_endmsg(void *closure, const void *handler_data, upb_status *s) { upb_json_printer *p = closure; UPB_UNUSED(handler_data); UPB_UNUSED(s); end_frame(p); if (p->depth_ == 0) { upb_bytessink_end(p->output_); } return true; } static void *startseq(void *closure, const void *handler_data) { upb_json_printer *p = closure; CHK(putkey(closure, handler_data)); p->depth_++; p->first_elem_[p->depth_] = true; print_data(p, "[", 1); return closure; } static bool endseq(void *closure, const void *handler_data) { upb_json_printer *p = closure; UPB_UNUSED(handler_data); print_data(p, "]", 1); p->depth_--; return true; } static void *startmap(void *closure, const void *handler_data) { upb_json_printer *p = closure; CHK(putkey(closure, handler_data)); p->depth_++; p->first_elem_[p->depth_] = true; print_data(p, "{", 1); return closure; } static bool endmap(void *closure, const void *handler_data) { upb_json_printer *p = closure; UPB_UNUSED(handler_data); print_data(p, "}", 1); p->depth_--; return true; } static size_t putstr(void *closure, const void *handler_data, const char *str, size_t len, const upb_bufhandle *handle) { upb_json_printer *p = closure; UPB_UNUSED(handler_data); UPB_UNUSED(handle); putstring(p, str, len); return len; } /* This has to Base64 encode the bytes, because JSON has no "bytes" type. */ static size_t putbytes(void *closure, const void *handler_data, const char *str, size_t len, const upb_bufhandle *handle) { upb_json_printer *p = closure; /* This is the regular base64, not the "web-safe" version. */ static const char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; /* Base64-encode. */ char data[16000]; const char *limit = data + sizeof(data); const unsigned char *from = (const unsigned char*)str; char *to = data; size_t remaining = len; size_t bytes; UPB_UNUSED(handler_data); UPB_UNUSED(handle); while (remaining > 2) { /* TODO(haberman): handle encoded lengths > sizeof(data) */ UPB_ASSERT((limit - to) >= 4); to[0] = base64[from[0] >> 2]; to[1] = base64[((from[0] & 0x3) << 4) | (from[1] >> 4)]; to[2] = base64[((from[1] & 0xf) << 2) | (from[2] >> 6)]; to[3] = base64[from[2] & 0x3f]; remaining -= 3; to += 4; from += 3; } switch (remaining) { case 2: to[0] = base64[from[0] >> 2]; to[1] = base64[((from[0] & 0x3) << 4) | (from[1] >> 4)]; to[2] = base64[(from[1] & 0xf) << 2]; to[3] = '='; to += 4; from += 2; break; case 1: to[0] = base64[from[0] >> 2]; to[1] = base64[((from[0] & 0x3) << 4)]; to[2] = '='; to[3] = '='; to += 4; from += 1; break; } bytes = to - data; print_data(p, "\"", 1); putstring(p, data, bytes); print_data(p, "\"", 1); return len; } static void *scalar_startstr(void *closure, const void *handler_data, size_t size_hint) { upb_json_printer *p = closure; UPB_UNUSED(handler_data); UPB_UNUSED(size_hint); CHK(putkey(closure, handler_data)); print_data(p, "\"", 1); return p; } static size_t scalar_str(void *closure, const void *handler_data, const char *str, size_t len, const upb_bufhandle *handle) { CHK(putstr(closure, handler_data, str, len, handle)); return len; } static bool scalar_endstr(void *closure, const void *handler_data) { upb_json_printer *p = closure; UPB_UNUSED(handler_data); print_data(p, "\"", 1); return true; } static void *repeated_startstr(void *closure, const void *handler_data, size_t size_hint) { upb_json_printer *p = closure; UPB_UNUSED(handler_data); UPB_UNUSED(size_hint); print_comma(p); print_data(p, "\"", 1); return p; } static size_t repeated_str(void *closure, const void *handler_data, const char *str, size_t len, const upb_bufhandle *handle) { CHK(putstr(closure, handler_data, str, len, handle)); return len; } static bool repeated_endstr(void *closure, const void *handler_data) { upb_json_printer *p = closure; UPB_UNUSED(handler_data); print_data(p, "\"", 1); return true; } static void *mapkeyval_startstr(void *closure, const void *handler_data, size_t size_hint) { upb_json_printer *p = closure; UPB_UNUSED(handler_data); UPB_UNUSED(size_hint); print_data(p, "\"", 1); return p; } static size_t mapkey_str(void *closure, const void *handler_data, const char *str, size_t len, const upb_bufhandle *handle) { CHK(putstr(closure, handler_data, str, len, handle)); return len; } static bool mapkey_endstr(void *closure, const void *handler_data) { upb_json_printer *p = closure; UPB_UNUSED(handler_data); print_data(p, "\":", 2); return true; } static bool mapvalue_endstr(void *closure, const void *handler_data) { upb_json_printer *p = closure; UPB_UNUSED(handler_data); print_data(p, "\"", 1); return true; } static size_t scalar_bytes(void *closure, const void *handler_data, const char *str, size_t len, const upb_bufhandle *handle) { CHK(putkey(closure, handler_data)); CHK(putbytes(closure, handler_data, str, len, handle)); return len; } static size_t repeated_bytes(void *closure, const void *handler_data, const char *str, size_t len, const upb_bufhandle *handle) { upb_json_printer *p = closure; print_comma(p); CHK(putbytes(closure, handler_data, str, len, handle)); return len; } static size_t mapkey_bytes(void *closure, const void *handler_data, const char *str, size_t len, const upb_bufhandle *handle) { upb_json_printer *p = closure; CHK(putbytes(closure, handler_data, str, len, handle)); print_data(p, ":", 1); return len; } static void set_enum_hd(upb_handlers *h, const upb_fielddef *f, bool preserve_fieldnames, upb_handlerattr *attr) { EnumHandlerData *hd = upb_gmalloc(sizeof(EnumHandlerData)); hd->enumdef = (const upb_enumdef *)upb_fielddef_subdef(f); hd->keyname = newstrpc(h, f, preserve_fieldnames); upb_handlers_addcleanup(h, hd, upb_gfree); upb_handlerattr_sethandlerdata(attr, hd); } /* Set up handlers for a mapentry submessage (i.e., an individual key/value pair * in a map). * * TODO: Handle missing key, missing value, out-of-order key/value, or repeated * key or value cases properly. The right way to do this is to allocate a * temporary structure at the start of a mapentry submessage, store key and * value data in it as key and value handlers are called, and then print the * key/value pair once at the end of the submessage. If we don't do this, we * should at least detect the case and throw an error. However, so far all of * our sources that emit mapentry messages do so canonically (with one key * field, and then one value field), so this is not a pressing concern at the * moment. */ void printer_sethandlers_mapentry(const void *closure, bool preserve_fieldnames, upb_handlers *h) { const upb_msgdef *md = upb_handlers_msgdef(h); /* A mapentry message is printed simply as '"key": value'. Rather than * special-case key and value for every type below, we just handle both * fields explicitly here. */ const upb_fielddef* key_field = upb_msgdef_itof(md, UPB_MAPENTRY_KEY); const upb_fielddef* value_field = upb_msgdef_itof(md, UPB_MAPENTRY_VALUE); upb_handlerattr empty_attr = UPB_HANDLERATTR_INITIALIZER; UPB_UNUSED(closure); switch (upb_fielddef_type(key_field)) { case UPB_TYPE_INT32: upb_handlers_setint32(h, key_field, putmapkey_int32_t, &empty_attr); break; case UPB_TYPE_INT64: upb_handlers_setint64(h, key_field, putmapkey_int64_t, &empty_attr); break; case UPB_TYPE_UINT32: upb_handlers_setuint32(h, key_field, putmapkey_uint32_t, &empty_attr); break; case UPB_TYPE_UINT64: upb_handlers_setuint64(h, key_field, putmapkey_uint64_t, &empty_attr); break; case UPB_TYPE_BOOL: upb_handlers_setbool(h, key_field, putmapkey_bool, &empty_attr); break; case UPB_TYPE_STRING: upb_handlers_setstartstr(h, key_field, mapkeyval_startstr, &empty_attr); upb_handlers_setstring(h, key_field, mapkey_str, &empty_attr); upb_handlers_setendstr(h, key_field, mapkey_endstr, &empty_attr); break; case UPB_TYPE_BYTES: upb_handlers_setstring(h, key_field, mapkey_bytes, &empty_attr); break; default: UPB_ASSERT(false); break; } switch (upb_fielddef_type(value_field)) { case UPB_TYPE_INT32: upb_handlers_setint32(h, value_field, putint32_t, &empty_attr); break; case UPB_TYPE_INT64: upb_handlers_setint64(h, value_field, putint64_t, &empty_attr); break; case UPB_TYPE_UINT32: upb_handlers_setuint32(h, value_field, putuint32_t, &empty_attr); break; case UPB_TYPE_UINT64: upb_handlers_setuint64(h, value_field, putuint64_t, &empty_attr); break; case UPB_TYPE_BOOL: upb_handlers_setbool(h, value_field, putbool, &empty_attr); break; case UPB_TYPE_FLOAT: upb_handlers_setfloat(h, value_field, putfloat, &empty_attr); break; case UPB_TYPE_DOUBLE: upb_handlers_setdouble(h, value_field, putdouble, &empty_attr); break; case UPB_TYPE_STRING: upb_handlers_setstartstr(h, value_field, mapkeyval_startstr, &empty_attr); upb_handlers_setstring(h, value_field, putstr, &empty_attr); upb_handlers_setendstr(h, value_field, mapvalue_endstr, &empty_attr); break; case UPB_TYPE_BYTES: upb_handlers_setstring(h, value_field, putbytes, &empty_attr); break; case UPB_TYPE_ENUM: { upb_handlerattr enum_attr = UPB_HANDLERATTR_INITIALIZER; set_enum_hd(h, value_field, preserve_fieldnames, &enum_attr); upb_handlers_setint32(h, value_field, mapvalue_enum, &enum_attr); upb_handlerattr_uninit(&enum_attr); break; } case UPB_TYPE_MESSAGE: /* No handler necessary -- the submsg handlers will print the message * as appropriate. */ break; } upb_handlerattr_uninit(&empty_attr); } void printer_sethandlers(const void *closure, upb_handlers *h) { const upb_msgdef *md = upb_handlers_msgdef(h); bool is_mapentry = upb_msgdef_mapentry(md); upb_handlerattr empty_attr = UPB_HANDLERATTR_INITIALIZER; upb_msg_field_iter i; const bool *preserve_fieldnames_ptr = closure; const bool preserve_fieldnames = *preserve_fieldnames_ptr; if (is_mapentry) { /* mapentry messages are sufficiently different that we handle them * separately. */ printer_sethandlers_mapentry(closure, preserve_fieldnames, h); return; } upb_handlers_setstartmsg(h, printer_startmsg, &empty_attr); upb_handlers_setendmsg(h, printer_endmsg, &empty_attr); #define TYPE(type, name, ctype) \ case type: \ if (upb_fielddef_isseq(f)) { \ upb_handlers_set##name(h, f, repeated_##ctype, &empty_attr); \ } else { \ upb_handlers_set##name(h, f, scalar_##ctype, &name_attr); \ } \ break; upb_msg_field_begin(&i, md); for(; !upb_msg_field_done(&i); upb_msg_field_next(&i)) { const upb_fielddef *f = upb_msg_iter_field(&i); upb_handlerattr name_attr = UPB_HANDLERATTR_INITIALIZER; upb_handlerattr_sethandlerdata(&name_attr, newstrpc(h, f, preserve_fieldnames)); if (upb_fielddef_ismap(f)) { upb_handlers_setstartseq(h, f, startmap, &name_attr); upb_handlers_setendseq(h, f, endmap, &name_attr); } else if (upb_fielddef_isseq(f)) { upb_handlers_setstartseq(h, f, startseq, &name_attr); upb_handlers_setendseq(h, f, endseq, &empty_attr); } switch (upb_fielddef_type(f)) { TYPE(UPB_TYPE_FLOAT, float, float); TYPE(UPB_TYPE_DOUBLE, double, double); TYPE(UPB_TYPE_BOOL, bool, bool); TYPE(UPB_TYPE_INT32, int32, int32_t); TYPE(UPB_TYPE_UINT32, uint32, uint32_t); TYPE(UPB_TYPE_INT64, int64, int64_t); TYPE(UPB_TYPE_UINT64, uint64, uint64_t); case UPB_TYPE_ENUM: { /* For now, we always emit symbolic names for enums. We may want an * option later to control this behavior, but we will wait for a real * need first. */ upb_handlerattr enum_attr = UPB_HANDLERATTR_INITIALIZER; set_enum_hd(h, f, preserve_fieldnames, &enum_attr); if (upb_fielddef_isseq(f)) { upb_handlers_setint32(h, f, repeated_enum, &enum_attr); } else { upb_handlers_setint32(h, f, scalar_enum, &enum_attr); } upb_handlerattr_uninit(&enum_attr); break; } case UPB_TYPE_STRING: if (upb_fielddef_isseq(f)) { upb_handlers_setstartstr(h, f, repeated_startstr, &empty_attr); upb_handlers_setstring(h, f, repeated_str, &empty_attr); upb_handlers_setendstr(h, f, repeated_endstr, &empty_attr); } else { upb_handlers_setstartstr(h, f, scalar_startstr, &name_attr); upb_handlers_setstring(h, f, scalar_str, &empty_attr); upb_handlers_setendstr(h, f, scalar_endstr, &empty_attr); } break; case UPB_TYPE_BYTES: /* XXX: this doesn't support strings that span buffers yet. The base64 * encoder will need to be made resumable for this to work properly. */ if (upb_fielddef_isseq(f)) { upb_handlers_setstring(h, f, repeated_bytes, &empty_attr); } else { upb_handlers_setstring(h, f, scalar_bytes, &name_attr); } break; case UPB_TYPE_MESSAGE: if (upb_fielddef_isseq(f)) { upb_handlers_setstartsubmsg(h, f, repeated_startsubmsg, &name_attr); } else { upb_handlers_setstartsubmsg(h, f, scalar_startsubmsg, &name_attr); } break; } upb_handlerattr_uninit(&name_attr); } upb_handlerattr_uninit(&empty_attr); #undef TYPE } static void json_printer_reset(upb_json_printer *p) { p->depth_ = 0; } /* Public API *****************************************************************/ upb_json_printer *upb_json_printer_create(upb_env *e, const upb_handlers *h, upb_bytessink *output) { #ifndef NDEBUG size_t size_before = upb_env_bytesallocated(e); #endif upb_json_printer *p = upb_env_malloc(e, sizeof(upb_json_printer)); if (!p) return NULL; p->output_ = output; json_printer_reset(p); upb_sink_reset(&p->input_, h, p); /* If this fails, increase the value in printer.h. */ UPB_ASSERT_DEBUGVAR(upb_env_bytesallocated(e) - size_before <= UPB_JSON_PRINTER_SIZE); return p; } upb_sink *upb_json_printer_input(upb_json_printer *p) { return &p->input_; } const upb_handlers *upb_json_printer_newhandlers(const upb_msgdef *md, bool preserve_fieldnames, const void *owner) { return upb_handlers_newfrozen( md, owner, printer_sethandlers, &preserve_fieldnames); } google-protobuf-3.2.0/ext/google/protobuf_c/protobuf.c0000644000175000017500000001160213042756211022075 0ustar pravipravi// 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" // ----------------------------------------------------------------------------- // Global map from upb {msg,enum}defs to wrapper Descriptor/EnumDescriptor // instances. // ----------------------------------------------------------------------------- // This is a hash table from def objects (encoded by converting pointers to // Ruby integers) to MessageDef/EnumDef instances (as Ruby values). VALUE upb_def_to_ruby_obj_map; VALUE cError; VALUE cParseError; void add_def_obj(const void* def, VALUE value) { rb_hash_aset(upb_def_to_ruby_obj_map, ULL2NUM((intptr_t)def), value); } VALUE get_def_obj(const void* def) { return rb_hash_aref(upb_def_to_ruby_obj_map, ULL2NUM((intptr_t)def)); } // ----------------------------------------------------------------------------- // Utilities. // ----------------------------------------------------------------------------- // Raises a Ruby error if |status| is not OK, using its error message. void check_upb_status(const upb_status* status, const char* msg) { if (!upb_ok(status)) { rb_raise(rb_eRuntimeError, "%s: %s\n", msg, upb_status_errmsg(status)); } } // String encodings: we look these up once, at load time, and then cache them // here. rb_encoding* kRubyStringUtf8Encoding; rb_encoding* kRubyStringASCIIEncoding; rb_encoding* kRubyString8bitEncoding; // Ruby-interned string: "descriptor". We use this identifier to store an // instance variable on message classes we create in order to link them back to // their descriptors. // // We intern this once at module load time then use the interned identifier at // runtime in order to avoid the cost of repeatedly interning in hot paths. const char* kDescriptorInstanceVar = "descriptor"; ID descriptor_instancevar_interned; // ----------------------------------------------------------------------------- // 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. void Init_protobuf_c() { VALUE google = rb_define_module("Google"); VALUE protobuf = rb_define_module_under(google, "Protobuf"); VALUE internal = rb_define_module_under(protobuf, "Internal"); descriptor_instancevar_interned = rb_intern(kDescriptorInstanceVar); DescriptorPool_register(protobuf); Descriptor_register(protobuf); FieldDescriptor_register(protobuf); OneofDescriptor_register(protobuf); EnumDescriptor_register(protobuf); MessageBuilderContext_register(internal); OneofBuilderContext_register(internal); EnumBuilderContext_register(internal); Builder_register(internal); RepeatedField_register(protobuf); Map_register(protobuf); cError = rb_const_get(protobuf, rb_intern("Error")); cParseError = rb_const_get(protobuf, rb_intern("ParseError")); rb_define_singleton_method(protobuf, "deep_copy", Google_Protobuf_deep_copy, 1); kRubyStringUtf8Encoding = rb_utf8_encoding(); kRubyStringASCIIEncoding = rb_usascii_encoding(); kRubyString8bitEncoding = rb_ascii8bit_encoding(); upb_def_to_ruby_obj_map = rb_hash_new(); rb_gc_register_address(&upb_def_to_ruby_obj_map); map_parse_frames = rb_ary_new(); rb_gc_register_address(&map_parse_frames); } google-protobuf-3.2.0/src/0000755000175000017500000000000013043000402014423 5ustar pravipravigoogle-protobuf-3.2.0/src/main/0000755000175000017500000000000013043000403015350 5ustar pravipravigoogle-protobuf-3.2.0/src/main/sentinel.proto0000644000175000017500000000054613042756211020301 0ustar pravipravisyntax = "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; } google-protobuf-3.2.0/src/main/java/0000755000175000017500000000000013043000402016270 5ustar pravipravigoogle-protobuf-3.2.0/src/main/java/com/0000755000175000017500000000000013043000402017046 5ustar pravipravigoogle-protobuf-3.2.0/src/main/java/com/google/0000755000175000017500000000000013043000402020322 5ustar pravipravigoogle-protobuf-3.2.0/src/main/java/com/google/protobuf/0000755000175000017500000000000013043000402022162 5ustar pravipravigoogle-protobuf-3.2.0/src/main/java/com/google/protobuf/jruby/0000755000175000017500000000000013043000403023316 5ustar pravipravigoogle-protobuf-3.2.0/src/main/java/com/google/protobuf/jruby/RubyProtobuf.java0000644000175000017500000000555613042756211026654 0ustar pravipravi/* * 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); } /* * 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); } } } google-protobuf-3.2.0/src/main/java/com/google/protobuf/jruby/RubyEnum.java0000644000175000017500000000762713042756211025761 0ustar pravipravi/* * 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; import org.jruby.RubyModule; import org.jruby.RubyNumeric; 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 rubyEnumDescriptorescriptor = (RubyEnumDescriptor) getDescriptor(context, recv); Descriptors.EnumDescriptor descriptor = rubyEnumDescriptorescriptor.getDescriptor(); Descriptors.EnumValueDescriptor value = descriptor.findValueByNumber(RubyNumeric.num2int(number)); if (value == null) return context.runtime.getNil(); return context.runtime.newSymbol(value.getName()); } /* * 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 rubyEnumDescriptorescriptor = (RubyEnumDescriptor) getDescriptor(context, recv); Descriptors.EnumDescriptor descriptor = rubyEnumDescriptorescriptor.getDescriptor(); Descriptors.EnumValueDescriptor value = descriptor.findValueByName(name.asJavaString()); if (value == null) return context.runtime.getNil(); return context.runtime.newFixnum(value.getNumber()); } /* * 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); } } google-protobuf-3.2.0/src/main/java/com/google/protobuf/jruby/RubyMessageBuilderContext.java0000644000175000017500000002506313042756211031307 0ustar pravipravi/* * 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; import org.jruby.*; import org.jruby.anno.JRubyClass; import org.jruby.anno.JRubyMethod; import org.jruby.runtime.Binding; import org.jruby.runtime.Block; import org.jruby.runtime.ObjectAllocator; import org.jruby.runtime.ThreadContext; import org.jruby.runtime.builtin.IRubyObject; @JRubyClass(name = "MessageBuilderContext") public class RubyMessageBuilderContext extends RubyObject { public static void createRubyMessageBuilderContext(Ruby runtime) { RubyModule protobuf = runtime.getClassFromPath("Google::Protobuf"); RubyClass cMessageBuilderContext = protobuf.defineClassUnder("MessageBuilderContext", runtime.getObject(), new ObjectAllocator() { @Override public IRubyObject allocate(Ruby runtime, RubyClass klazz) { return new RubyMessageBuilderContext(runtime, klazz); } }); cMessageBuilderContext.defineAnnotatedMethods(RubyMessageBuilderContext.class); } public RubyMessageBuilderContext(Ruby ruby, RubyClass klazz) { super(ruby, klazz); } @JRubyMethod public IRubyObject initialize(ThreadContext context, IRubyObject descriptor, IRubyObject rubyBuilder) { this.cFieldDescriptor = (RubyClass) context.runtime.getClassFromPath("Google::Protobuf::FieldDescriptor"); this.cDescriptor = (RubyClass) context.runtime.getClassFromPath("Google::Protobuf::Descriptor"); this.cOneofDescriptor = (RubyClass) context.runtime.getClassFromPath("Google::Protobuf::OneofDescriptor"); this.cOneofBuilderContext = (RubyClass) context.runtime.getClassFromPath("Google::Protobuf::Internal::OneofBuilderContext"); this.descriptor = (RubyDescriptor) descriptor; this.builder = (RubyBuilder) rubyBuilder; return this; } /* * call-seq: * MessageBuilderContext.optional(name, type, number, type_class = nil) * * Defines a new optional field on this message type with the given type, tag * number, and type class (for message and enum fields). The 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=). */ @JRubyMethod(required = 3, optional = 1) public IRubyObject optional(ThreadContext context, IRubyObject[] args) { Ruby runtime = context.runtime; IRubyObject typeClass = runtime.getNil(); if (args.length > 3) typeClass = args[3]; msgdefAddField(context, "optional", args[0], args[1], args[2], typeClass); return context.runtime.getNil(); } /* * call-seq: * MessageBuilderContext.required(name, type, number, type_class = nil) * * Defines a new required field on this message type with the given type, tag * number, and type class (for message and enum fields). The 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=). * * Proto3 does not have required fields, but this method exists for * completeness. Any attempt to add a message type with required fields to a * pool will currently result in an error. */ @JRubyMethod(required = 3, optional = 1) public IRubyObject required(ThreadContext context, IRubyObject[] args) { IRubyObject typeClass = context.runtime.getNil(); if (args.length > 3) typeClass = args[3]; msgdefAddField(context, "required", args[0], args[1], args[2], typeClass); return context.runtime.getNil(); } /* * call-seq: * MessageBuilderContext.repeated(name, type, number, type_class = nil) * * Defines a new repeated field on this message type with the given type, tag * number, and type class (for message and enum fields). The 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=). */ @JRubyMethod(required = 3, optional = 1) public IRubyObject repeated(ThreadContext context, IRubyObject[] args) { IRubyObject typeClass = context.runtime.getNil(); if (args.length > 3) typeClass = args[3]; msgdefAddField(context, "repeated", args[0], args[1], args[2], typeClass); return context.runtime.getNil(); } /* * call-seq: * MessageBuilderContext.map(name, key_type, value_type, number, * value_type_class = nil) * * 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=). */ @JRubyMethod(required = 4, optional = 1) public IRubyObject map(ThreadContext context, IRubyObject[] args) { Ruby runtime = context.runtime; IRubyObject name = args[0]; IRubyObject keyType = args[1]; IRubyObject valueType = args[2]; IRubyObject number = args[3]; IRubyObject typeClass = args.length > 4 ? args[4] : context.runtime.getNil(); // Validate the key type. We can't accept enums, messages, or floats/doubles // as map keys. (We exclude these explicitly, and the field-descriptor setter // below then ensures that the type is one of the remaining valid options.) if (keyType.equals(RubySymbol.newSymbol(runtime, "float")) || keyType.equals(RubySymbol.newSymbol(runtime, "double")) || keyType.equals(RubySymbol.newSymbol(runtime, "enum")) || keyType.equals(RubySymbol.newSymbol(runtime, "message"))) throw runtime.newArgumentError("Cannot add a map field with a float, double, enum, or message type."); // Create a new message descriptor for the map entry message, and create a // repeated submessage field here with that type. RubyDescriptor mapentryDesc = (RubyDescriptor) cDescriptor.newInstance(context, Block.NULL_BLOCK); IRubyObject mapentryDescName = RubySymbol.newSymbol(runtime, name).id2name(context); mapentryDesc.setName(context, mapentryDescName); mapentryDesc.setMapEntry(true); //optional key = 1; RubyFieldDescriptor keyField = (RubyFieldDescriptor) cFieldDescriptor.newInstance(context, Block.NULL_BLOCK); keyField.setName(context, runtime.newString("key")); keyField.setLabel(context, RubySymbol.newSymbol(runtime, "optional")); keyField.setNumber(context, runtime.newFixnum(1)); keyField.setType(context, keyType); mapentryDesc.addField(context, keyField); //optional value = 2; RubyFieldDescriptor valueField = (RubyFieldDescriptor) cFieldDescriptor.newInstance(context, Block.NULL_BLOCK); valueField.setName(context, runtime.newString("value")); valueField.setLabel(context, RubySymbol.newSymbol(runtime, "optional")); valueField.setNumber(context, runtime.newFixnum(2)); valueField.setType(context, valueType); if (! typeClass.isNil()) valueField.setSubmsgName(context, typeClass); mapentryDesc.addField(context, valueField); // Add the map-entry message type to the current builder, and use the type to // create the map field itself. this.builder.pendingList.add(mapentryDesc); msgdefAddField(context, "repeated", name, runtime.newSymbol("message"), number, mapentryDescName); return runtime.getNil(); } @JRubyMethod public IRubyObject oneof(ThreadContext context, IRubyObject name, Block block) { RubyOneofDescriptor oneofdef = (RubyOneofDescriptor) cOneofDescriptor.newInstance(context, Block.NULL_BLOCK); RubyOneofBuilderContext ctx = (RubyOneofBuilderContext) cOneofBuilderContext.newInstance(context, oneofdef, Block.NULL_BLOCK); oneofdef.setName(context, name); Binding binding = block.getBinding(); binding.setSelf(ctx); block.yieldSpecific(context); descriptor.addOneof(context, oneofdef); return context.runtime.getNil(); } private void msgdefAddField(ThreadContext context, String label, IRubyObject name, IRubyObject type, IRubyObject number, IRubyObject typeClass) { descriptor.addField(context, Utils.msgdefCreateField(context, label, name, type, number, typeClass, cFieldDescriptor)); } private RubyDescriptor descriptor; private RubyBuilder builder; private RubyClass cFieldDescriptor; private RubyClass cOneofDescriptor; private RubyClass cOneofBuilderContext; private RubyClass cDescriptor; } google-protobuf-3.2.0/src/main/java/com/google/protobuf/jruby/RubyFieldDescriptor.java0000644000175000017500000002306713042756211030133 0ustar pravipravi/* * 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; import com.google.protobuf.Descriptors; 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 createRubyFileDescriptor(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.new => field * * Returns a new field descriptor. Its name, type, etc. must be set before it is * added to a message type. */ @JRubyMethod public IRubyObject initialize(ThreadContext context) { builder = DescriptorProtos.FieldDescriptorProto.newBuilder(); return this; } /* * call-seq: * FieldDescriptor.label * * Return the label of this field. */ @JRubyMethod(name = "label") public IRubyObject getLabel(ThreadContext context) { return this.label; } /* * call-seq: * FieldDescriptor.label = label * * Sets the label on this field. Cannot be called if field is part of a message * type already in a pool. */ @JRubyMethod(name = "label=") public IRubyObject setLabel(ThreadContext context, IRubyObject value) { String labelName = value.asJavaString(); this.label = context.runtime.newSymbol(labelName.toLowerCase()); this.builder.setLabel( DescriptorProtos.FieldDescriptorProto.Label.valueOf("LABEL_" + labelName.toUpperCase())); return context.runtime.getNil(); } /* * 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.name = name * * Sets the name of this field. Cannot be called once the containing message * type, if any, is added to a pool. */ @JRubyMethod(name = "name=") public IRubyObject setName(ThreadContext context, IRubyObject value) { String nameStr = value.asJavaString(); this.name = context.runtime.newString(nameStr); this.builder.setName(Utils.escapeIdentifier(nameStr)); return context.runtime.getNil(); } @JRubyMethod(name = "subtype") public IRubyObject getSubType(ThreadContext 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, this.builder.getType()); } /* * call-seq: * FieldDescriptor.type = type * * Sets this field's type. Cannot be called if field is part of a message type * already in a pool. */ @JRubyMethod(name = "type=") public IRubyObject setType(ThreadContext context, IRubyObject value) { this.builder.setType(DescriptorProtos.FieldDescriptorProto.Type.valueOf("TYPE_" + value.asJavaString().toUpperCase())); return context.runtime.getNil(); } /* * call-seq: * FieldDescriptor.number => number * * Returns this field's number, as a Ruby Integer, or nil if not yet set. * */ @JRubyMethod(name = "number") public IRubyObject getnumber(ThreadContext context) { return this.number; } /* * call-seq: * FieldDescriptor.number = number * * Sets the tag number for this field. Cannot be called if field is part of a * message type already in a pool. */ @JRubyMethod(name = "number=") public IRubyObject setNumber(ThreadContext context, IRubyObject value) { this.number = value; this.builder.setNumber(RubyNumeric.num2int(value)); return context.runtime.getNil(); } /* * 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.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 msgRb) { RubyMessage message = (RubyMessage) msgRb; if (message.getDescriptor() != fieldDef.getContainingType()) { throw context.runtime.newTypeError("set method called on wrong message type"); } return message.getField(context, fieldDef); } /* * 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 msgRb, IRubyObject value) { RubyMessage message = (RubyMessage) msgRb; if (message.getDescriptor() != fieldDef.getContainingType()) { throw context.runtime.newTypeError("set method called on wrong message type"); } message.setField(context, fieldDef, value); return context.runtime.getNil(); } protected void setSubType(IRubyObject rubyDescriptor) { this.subType = rubyDescriptor; } protected void setFieldDef(Descriptors.FieldDescriptor fieldDescriptor) { this.fieldDef = fieldDescriptor; } protected void setOneofName(IRubyObject name) { oneofName = name; } protected void setOneofIndex(int index) { hasOneofIndex = true; oneofIndex = index; } protected IRubyObject getOneofName() { return oneofName; } protected Descriptors.FieldDescriptor getFieldDef() { return fieldDef; } protected DescriptorProtos.FieldDescriptorProto build() { if (hasOneofIndex) builder.setOneofIndex(oneofIndex); return this.builder.build(); } private DescriptorProtos.FieldDescriptorProto.Builder builder; private IRubyObject name; private IRubyObject label; private IRubyObject number; private IRubyObject subType; private IRubyObject oneofName; private Descriptors.FieldDescriptor fieldDef; private int oneofIndex; private boolean hasOneofIndex = false; } google-protobuf-3.2.0/src/main/java/com/google/protobuf/jruby/Utils.java0000644000175000017500000003125113042756211025301 0ustar pravipravi/* * 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; import com.google.protobuf.Descriptors; import org.jcodings.Encoding; import org.jcodings.specific.ASCIIEncoding; import org.jcodings.specific.USASCIIEncoding; import org.jcodings.specific.UTF8Encoding; import org.jruby.*; import org.jruby.runtime.Block; import org.jruby.runtime.ThreadContext; import org.jruby.runtime.builtin.IRubyObject; import java.math.BigInteger; public class Utils { public static Descriptors.FieldDescriptor.Type rubyToFieldType(IRubyObject typeClass) { return Descriptors.FieldDescriptor.Type.valueOf(typeClass.asJavaString().toUpperCase()); } public static IRubyObject fieldTypeToRuby(ThreadContext context, Descriptors.FieldDescriptor.Type type) { return fieldTypeToRuby(context, type.name()); } public static IRubyObject fieldTypeToRuby(ThreadContext context, DescriptorProtos.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, Descriptors.FieldDescriptor.Type fieldType, IRubyObject value, RubyModule typeClass) { Ruby runtime = context.runtime; Object val; switch(fieldType) { case INT32: case INT64: case UINT32: case UINT64: if (!isRubyNum(value)) { throw runtime.newTypeError("Expected number type for integral field."); } switch(fieldType) { case INT32: RubyNumeric.num2int(value); break; case INT64: RubyNumeric.num2long(value); break; case UINT32: num2uint(value); break; default: num2ulong(context.runtime, value); break; } checkIntTypePrecision(context, fieldType, value); break; case FLOAT: if (!isRubyNum(value)) throw runtime.newTypeError("Expected number type for float field."); break; case DOUBLE: if (!isRubyNum(value)) throw runtime.newTypeError("Expected number type for double field."); break; case BOOL: if (!(value instanceof RubyBoolean)) throw runtime.newTypeError("Invalid argument for boolean field."); break; case BYTES: case STRING: value = validateStringEncoding(context, fieldType, value); break; case MESSAGE: if (value.getMetaClass() != typeClass) { throw runtime.newTypeError(value, typeClass); } break; case ENUM: if (value instanceof RubySymbol) { Descriptors.EnumDescriptor enumDescriptor = ((RubyEnumDescriptor) typeClass.getInstanceVariable(DESCRIPTOR_INSTANCE_VAR)).getDescriptor(); val = enumDescriptor.findValueByName(value.asJavaString()); if (val == null) throw runtime.newRangeError("Enum value " + value + " is not found."); } else if(!isRubyNum(value)) { throw runtime.newTypeError("Expected number or symbol type for enum field."); } break; default: break; } return value; } public static IRubyObject wrapPrimaryValue(ThreadContext context, Descriptors.FieldDescriptor.Type fieldType, Object value) { Ruby runtime = context.runtime; switch (fieldType) { case INT32: return runtime.newFixnum((Integer) value); case INT64: return runtime.newFixnum((Long) value); case UINT32: return runtime.newFixnum(((Integer) value) & (-1l >>> 32)); 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 = runtime.newString(((ByteString) value).toStringUtf8()); 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); } } public static IRubyObject validateStringEncoding(ThreadContext context, Descriptors.FieldDescriptor.Type type, IRubyObject value) { if (!(value instanceof RubyString)) throw context.runtime.newTypeError("Invalid argument for string field."); switch(type) { case BYTES: value = ((RubyString)value).encode(context, context.runtime.evalScriptlet("Encoding::ASCII_8BIT")); break; case STRING: value = ((RubyString)value).encode(context, context.runtime.evalScriptlet("Encoding::UTF_8")); break; default: break; } value.setFrozen(true); return value; } public static void checkNameAvailability(ThreadContext context, String name) { if (context.runtime.getObject().getConstantAt(name) != null) throw context.runtime.newNameError(name + " is already defined", name); } /** * Replace invalid "." in descriptor with __DOT__ * @param name * @return */ public static String escapeIdentifier(String name) { return name.replace(".", BADNAME_REPLACEMENT); } /** * Replace __DOT__ in descriptor name with "." * @param name * @return */ public static String unescapeIdentifier(String name) { return name.replace(BADNAME_REPLACEMENT, "."); } public static boolean isMapEntry(Descriptors.FieldDescriptor fieldDescriptor) { return fieldDescriptor.getType() == Descriptors.FieldDescriptor.Type.MESSAGE && fieldDescriptor.isRepeated() && fieldDescriptor.getMessageType().getOptions().getMapEntry(); } public static RubyFieldDescriptor msgdefCreateField(ThreadContext context, String label, IRubyObject name, IRubyObject type, IRubyObject number, IRubyObject typeClass, RubyClass cFieldDescriptor) { Ruby runtime = context.runtime; RubyFieldDescriptor fieldDef = (RubyFieldDescriptor) cFieldDescriptor.newInstance(context, Block.NULL_BLOCK); fieldDef.setLabel(context, runtime.newString(label)); fieldDef.setName(context, name); fieldDef.setType(context, type); fieldDef.setNumber(context, number); if (!typeClass.isNil()) { if (!(typeClass instanceof RubyString)) { throw runtime.newArgumentError("expected string for type class"); } fieldDef.setSubmsgName(context, typeClass); } return fieldDef; } protected static void checkIntTypePrecision(ThreadContext context, Descriptors.FieldDescriptor.Type type, IRubyObject value) { if (value instanceof RubyFloat) { double doubleVal = RubyNumeric.num2dbl(value); if (Math.floor(doubleVal) != doubleVal) { throw context.runtime.newRangeError("Non-integral floating point value assigned to integer field."); } } if (type == Descriptors.FieldDescriptor.Type.UINT32 || type == Descriptors.FieldDescriptor.Type.UINT64) { if (RubyNumeric.num2dbl(value) < 0) { throw context.runtime.newRangeError("Assigning negative value to unsigned integer field."); } } } protected static boolean isRubyNum(Object value) { return value instanceof RubyFixnum || value instanceof RubyFloat || value instanceof RubyBignum; } protected static void validateTypeClass(ThreadContext context, Descriptors.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 == Descriptors.FieldDescriptor.Type.MESSAGE) { if (! (descriptor instanceof RubyDescriptor)) { throw runtime.newArgumentError("Descriptor has an incorrect type"); } } else if (type == Descriptors.FieldDescriptor.Type.ENUM) { if (! (descriptor instanceof RubyEnumDescriptor)) { throw runtime.newArgumentError("Descriptor has an incorrect type"); } } } public static String BADNAME_REPLACEMENT = "__DOT__"; public static String DESCRIPTOR_INSTANCE_VAR = "@descriptor"; public static String EQUAL_SIGN = "="; private static BigInteger UINT64_COMPLEMENTARY = new BigInteger("18446744073709551616"); //Math.pow(2, 64) private static long UINT_MAX = 0xffffffffl; } google-protobuf-3.2.0/src/main/java/com/google/protobuf/jruby/RubyDescriptorPool.java0000644000175000017500000001712713042756211030021 0ustar pravipravi/* * 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; import com.google.protobuf.Descriptors; import org.jruby.*; import org.jruby.anno.JRubyClass; import org.jruby.anno.JRubyMethod; import org.jruby.runtime.*; import org.jruby.runtime.builtin.IRubyObject; import java.util.HashMap; 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); } public RubyDescriptorPool(Ruby ruby, RubyClass klazz) { super(ruby, klazz); } @JRubyMethod public IRubyObject initialize(ThreadContext context) { this.symtab = new HashMap(); this.cBuilder = (RubyClass) context.runtime.getClassFromPath("Google::Protobuf::Builder"); this.builder = DescriptorProtos.FileDescriptorProto.newBuilder(); return this; } @JRubyMethod public IRubyObject build(ThreadContext context, Block block) { RubyBuilder ctx = (RubyBuilder) cBuilder.newInstance(context, Block.NULL_BLOCK); if (block.arity() == Arity.ONE_ARGUMENT) { block.yield(context, ctx); } else { Binding binding = block.getBinding(); binding.setSelf(ctx); block.yieldSpecific(context); } ctx.finalizeToPool(context, this); buildFileDescriptor(context); return context.runtime.getNil(); } @JRubyMethod public IRubyObject lookup(ThreadContext context, IRubyObject name) { IRubyObject descriptor = this.symtab.get(name); if (descriptor == null) { return context.runtime.getNil(); } return descriptor; } /* * 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; } protected void addToSymtab(ThreadContext context, RubyDescriptor def) { symtab.put(def.getName(context), def); this.builder.addMessageType(def.getBuilder()); } protected void addToSymtab(ThreadContext context, RubyEnumDescriptor def) { symtab.put(def.getName(context), def); this.builder.addEnumType(def.getBuilder()); } private void buildFileDescriptor(ThreadContext context) { Ruby runtime = context.runtime; try { this.builder.setSyntax("proto3"); final Descriptors.FileDescriptor fileDescriptor = Descriptors.FileDescriptor.buildFrom( this.builder.build(), new Descriptors.FileDescriptor[]{}); for (Descriptors.EnumDescriptor enumDescriptor : fileDescriptor.getEnumTypes()) { String enumName = Utils.unescapeIdentifier(enumDescriptor.getName()); if (enumDescriptor.findValueByNumber(0) == null) { throw runtime.newTypeError("Enum definition " + enumName + " does not contain a value for '0'"); } ((RubyEnumDescriptor) symtab.get(runtime.newString(enumName))) .setDescriptor(enumDescriptor); } for (Descriptors.Descriptor descriptor : fileDescriptor.getMessageTypes()) { RubyDescriptor rubyDescriptor = ((RubyDescriptor) symtab.get(runtime.newString(Utils.unescapeIdentifier(descriptor.getName())))); for (Descriptors.FieldDescriptor fieldDescriptor : descriptor.getFields()) { if (fieldDescriptor.isRequired()) { throw runtime.newTypeError("Required fields are unsupported in proto3"); } RubyFieldDescriptor rubyFieldDescriptor = rubyDescriptor.lookup(fieldDescriptor.getName()); rubyFieldDescriptor.setFieldDef(fieldDescriptor); if (fieldDescriptor.getType() == Descriptors.FieldDescriptor.Type.MESSAGE) { RubyDescriptor subType = (RubyDescriptor) lookup(context, runtime.newString(Utils.unescapeIdentifier(fieldDescriptor.getMessageType().getName()))); rubyFieldDescriptor.setSubType(subType); } if (fieldDescriptor.getType() == Descriptors.FieldDescriptor.Type.ENUM) { RubyEnumDescriptor subType = (RubyEnumDescriptor) lookup(context, runtime.newString(Utils.unescapeIdentifier(fieldDescriptor.getEnumType().getName()))); rubyFieldDescriptor.setSubType(subType); } } rubyDescriptor.setDescriptor(descriptor); } } catch (Descriptors.DescriptorValidationException e) { throw runtime.newRuntimeError(e.getMessage()); } } private static RubyDescriptorPool descriptorPool; private RubyClass cBuilder; private Map symtab; private DescriptorProtos.FileDescriptorProto.Builder builder; } google-protobuf-3.2.0/src/main/java/com/google/protobuf/jruby/RubyMap.java0000644000175000017500000004003013042756211025553 0ustar pravipravi/* * 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; import com.google.protobuf.DynamicMessage; import com.google.protobuf.MapEntry; import org.jruby.*; import org.jruby.anno.JRubyClass; import org.jruby.anno.JRubyMethod; import org.jruby.internal.runtime.methods.DynamicMethod; import org.jruby.runtime.Block; import org.jruby.runtime.ObjectAllocator; import org.jruby.runtime.ThreadContext; import org.jruby.runtime.builtin.IRubyObject; import org.jruby.util.ByteList; 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, :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. */ @JRubyMethod(required = 2, optional = 2) public IRubyObject initialize(ThreadContext context, IRubyObject[] args) { this.table = new HashMap(); this.keyType = Utils.rubyToFieldType(args[0]); this.valueType = Utils.rubyToFieldType(args[1]); switch(keyType) { case INT32: case INT64: case UINT32: case UINT64: case BOOL: case STRING: case BYTES: // 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(); } // Table value type is always UINT64: this ensures enough space to store the // native_slot value. 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) { key = Utils.checkType(context, keyType, key, (RubyModule) valueTypeClass); value = Utils.checkType(context, valueType, value, (RubyModule) valueTypeClass); IRubyObject symbol; if (valueType == Descriptors.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) { if (table.containsKey(key)) return this.table.get(key); return context.runtime.getNil(); } /* * 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 toHash(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 toHash(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.newString(new ByteList(digest.digest())); } 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) { table.clear(); return context.runtime.getNil(); } /* * 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.runtime.getNil(); } /* * 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) { 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 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 entry : table.entrySet()) { newMap.table.put(entry.getKey(), entry.getValue()); } return newMap; } @JRubyMethod(name = {"to_h", "to_hash"}) public RubyHash toHash(ThreadContext context) { return RubyHash.newHash(context.runtime, table, context.runtime.getNil()); } // 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 build(ThreadContext context, RubyDescriptor descriptor) { List list = new ArrayList(); RubyClass rubyClass = (RubyClass) descriptor.msgclass(context); Descriptors.FieldDescriptor keyField = descriptor.lookup("key").getFieldDef(); Descriptors.FieldDescriptor valueField = descriptor.lookup("value").getFieldDef(); 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)); } return list; } protected RubyMap mergeIntoSelf(final ThreadContext context, IRubyObject hashmap) { if (hashmap instanceof RubyHash) { ((RubyHash) hashmap).visitAll(new RubyHash.Visitor() { @Override public void visit(IRubyObject key, IRubyObject val) { indexSet(context, key, val); } }); } else if (hashmap instanceof RubyMap) { RubyMap other = (RubyMap) hashmap; if (!typeCompatible(other)) { throw context.runtime.newTypeError("Attempt to merge Map with mismatching types"); } } else { throw context.runtime.newTypeError("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(); return newMap; } private boolean needTypeclass(Descriptors.FieldDescriptor.Type type) { switch(type) { case MESSAGE: case ENUM: return true; default: return false; } } private Descriptors.FieldDescriptor.Type keyType; private Descriptors.FieldDescriptor.Type valueType; private IRubyObject valueTypeClass; private Map table; } google-protobuf-3.2.0/src/main/java/com/google/protobuf/jruby/RubyMessage.java0000644000175000017500000010663513042756211026440 0ustar pravipravi/* * 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.*; import org.jruby.*; import org.jruby.anno.JRubyMethod; import org.jruby.runtime.Block; import org.jruby.runtime.Helpers; import org.jruby.runtime.ThreadContext; import org.jruby.runtime.builtin.IRubyObject; import org.jruby.util.ByteList; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.HashMap; import java.util.Map; public class RubyMessage extends RubyObject { public RubyMessage(Ruby ruby, RubyClass klazz, Descriptors.Descriptor descriptor) { super(ruby, klazz); this.descriptor = descriptor; } /* * call-seq: * Message.new(kwargs) => new_message * * Creates a new instance of the given message class. Keyword arguments may be * provided with keywords corresponding to field names. * * Note that no literal Message class exists. Only concrete classes per message * type exist, as provided by the #msgclass method on Descriptors after they * have been added to a pool. The method definitions described here on the * Message class are provided on each concrete message class. */ @JRubyMethod(optional = 1) public IRubyObject initialize(final ThreadContext context, IRubyObject[] args) { final Ruby runtime = context.runtime; this.cRepeatedField = (RubyClass) runtime.getClassFromPath("Google::Protobuf::RepeatedField"); this.cMap = (RubyClass) runtime.getClassFromPath("Google::Protobuf::Map"); this.builder = DynamicMessage.newBuilder(this.descriptor); this.repeatedFields = new HashMap(); this.maps = new HashMap(); this.fields = new HashMap(); this.oneofCases = new HashMap(); if (args.length == 1) { if (!(args[0] instanceof RubyHash)) { throw runtime.newArgumentError("expected Hash arguments."); } RubyHash hash = args[0].convertToHash(); hash.visitAll(new RubyHash.Visitor() { @Override public void visit(IRubyObject key, IRubyObject value) { if (!(key instanceof RubySymbol)) throw runtime.newTypeError("Expected symbols as hash keys in initialization map."); final Descriptors.FieldDescriptor fieldDescriptor = findField(context, key); if (Utils.isMapEntry(fieldDescriptor)) { if (!(value instanceof RubyHash)) throw runtime.newArgumentError("Expected Hash object as initializer value for map field '" + key.asJavaString() + "'."); final RubyMap map = newMapForField(context, fieldDescriptor); map.mergeIntoSelf(context, value); maps.put(fieldDescriptor, map); } else if (fieldDescriptor.isRepeated()) { if (!(value instanceof RubyArray)) throw runtime.newArgumentError("Expected array as initializer value for repeated field '" + key.asJavaString() + "'."); RubyRepeatedField repeatedField = rubyToRepeatedField(context, fieldDescriptor, value); addRepeatedField(fieldDescriptor, repeatedField); } else { Descriptors.OneofDescriptor oneof = fieldDescriptor.getContainingOneof(); if (oneof != null) { oneofCases.put(oneof, fieldDescriptor); } fields.put(fieldDescriptor, value); } } }); } return this; } /* * call-seq: * Message.[]=(index, value) * * Sets a field's value by field name. The provided field name should be a * string. */ @JRubyMethod(name = "[]=") public IRubyObject indexSet(ThreadContext context, IRubyObject fieldName, IRubyObject value) { Descriptors.FieldDescriptor fieldDescriptor = findField(context, fieldName); return setField(context, fieldDescriptor, value); } /* * call-seq: * Message.[](index) => value * * Accesses a field's value by field name. The provided field name should be a * string. */ @JRubyMethod(name = "[]") public IRubyObject index(ThreadContext context, IRubyObject fieldName) { Descriptors.FieldDescriptor fieldDescriptor = findField(context, fieldName); return getField(context, fieldDescriptor); } /* * call-seq: * Message.inspect => string * * Returns a human-readable string representing this message. It will be * formatted as "". Each * field's value is represented according to its own #inspect method. */ @JRubyMethod public IRubyObject inspect() { String cname = metaClass.getName(); StringBuilder sb = new StringBuilder("<"); sb.append(cname); sb.append(": "); sb.append(this.layoutInspect()); sb.append(">"); return getRuntime().newString(sb.toString()); } /* * call-seq: * Message.hash => hash_value * * Returns a hash value that represents this message's field values. */ @JRubyMethod public IRubyObject hash(ThreadContext context) { try { MessageDigest digest = MessageDigest.getInstance("SHA-256"); for (RubyMap map : maps.values()) { digest.update((byte) map.hashCode()); } for (RubyRepeatedField repeatedField : repeatedFields.values()) { digest.update((byte) repeatedFields.hashCode()); } for (IRubyObject field : fields.values()) { digest.update((byte) field.hashCode()); } return context.runtime.newString(new ByteList(digest.digest())); } catch (NoSuchAlgorithmException ignore) { return context.runtime.newFixnum(System.identityHashCode(this)); } } /* * call-seq: * Message.==(other) => boolean * * Performs a deep comparison of this message with another. Messages are equal * if they have the same type and if each field is equal according to the :== * method's semantics (a more efficient comparison may actually be done if the * field is of a primitive type). */ @JRubyMethod(name = "==") public IRubyObject eq(ThreadContext context, IRubyObject other) { Ruby runtime = context.runtime; if (!(other instanceof RubyMessage)) return runtime.getFalse(); RubyMessage message = (RubyMessage) other; if (descriptor != message.descriptor) { return runtime.getFalse(); } for (Descriptors.FieldDescriptor fdef : descriptor.getFields()) { IRubyObject thisVal = getField(context, fdef); IRubyObject thatVal = message.getField(context, fdef); IRubyObject ret = thisVal.callMethod(context, "==", thatVal); if (!ret.isTrue()) { return runtime.getFalse(); } } return runtime.getTrue(); } /* * call-seq: * Message.method_missing(*args) * * Provides accessors and setters for message fields according to their field * names. For any field whose name does not conflict with a built-in method, an * accessor is provided with the same name as the field, and a setter is * provided with the name of the field plus the '=' suffix. Thus, given a * message instance 'msg' with field 'foo', the following code is valid: * * msg.foo = 42 * puts msg.foo */ @JRubyMethod(name = "method_missing", rest = true) public IRubyObject methodMissing(ThreadContext context, IRubyObject[] args) { if (args.length == 1) { RubyDescriptor rubyDescriptor = (RubyDescriptor) getDescriptor(context, metaClass); IRubyObject oneofDescriptor = rubyDescriptor.lookupOneof(context, args[0]); if (oneofDescriptor.isNil()) { if (!hasField(args[0])) { return Helpers.invokeSuper(context, this, metaClass, "method_missing", args, Block.NULL_BLOCK); } return index(context, args[0]); } RubyOneofDescriptor rubyOneofDescriptor = (RubyOneofDescriptor) oneofDescriptor; Descriptors.FieldDescriptor fieldDescriptor = oneofCases.get(rubyOneofDescriptor.getOneofDescriptor()); if (fieldDescriptor == null) return context.runtime.getNil(); return context.runtime.newSymbol(fieldDescriptor.getName()); } else { // fieldName is RubySymbol RubyString field = args[0].asString(); RubyString equalSign = context.runtime.newString(Utils.EQUAL_SIGN); if (field.end_with_p(context, equalSign).isTrue()) { field.chomp_bang(context, equalSign); } if (!hasField(field)) { return Helpers.invokeSuper(context, this, metaClass, "method_missing", args, Block.NULL_BLOCK); } return indexSet(context, field, args[1]); } } /** * call-seq: * Message.dup => new_message * Performs a shallow copy of this message and returns the new copy. */ @JRubyMethod public IRubyObject dup(ThreadContext context) { RubyMessage dup = (RubyMessage) metaClass.newInstance(context, Block.NULL_BLOCK); IRubyObject value; for (Descriptors.FieldDescriptor fieldDescriptor : this.descriptor.getFields()) { if (fieldDescriptor.isRepeated()) { dup.addRepeatedField(fieldDescriptor, this.getRepeatedField(context, fieldDescriptor)); } else if (fields.containsKey(fieldDescriptor)) { dup.fields.put(fieldDescriptor, fields.get(fieldDescriptor)); } else if (this.builder.hasField(fieldDescriptor)) { dup.fields.put(fieldDescriptor, wrapField(context, fieldDescriptor, this.builder.getField(fieldDescriptor))); } } for (Descriptors.FieldDescriptor fieldDescriptor : maps.keySet()) { dup.maps.put(fieldDescriptor, maps.get(fieldDescriptor)); } return dup; } /* * call-seq: * Message.descriptor => descriptor * * Class method that returns the Descriptor instance corresponding to this * message class's type. */ @JRubyMethod(name = "descriptor", meta = true) public static IRubyObject getDescriptor(ThreadContext context, IRubyObject recv) { return ((RubyClass) recv).getInstanceVariable(Utils.DESCRIPTOR_INSTANCE_VAR); } /* * call-seq: * MessageClass.encode(msg) => bytes * * Encodes the given message object to its serialized form in protocol buffers * wire format. */ @JRubyMethod(meta = true) public static IRubyObject encode(ThreadContext context, IRubyObject recv, IRubyObject value) { RubyMessage message = (RubyMessage) value; return context.runtime.newString(new ByteList(message.build(context).toByteArray())); } /* * call-seq: * MessageClass.decode(data) => message * * Decodes the given data (as a string containing bytes in protocol buffers wire * format) under the interpretration given by this message class's definition * and returns a message object with the corresponding field values. */ @JRubyMethod(meta = true) public static IRubyObject decode(ThreadContext context, IRubyObject recv, IRubyObject data) { byte[] bin = data.convertToString().getBytes(); RubyMessage ret = (RubyMessage) ((RubyClass) recv).newInstance(context, Block.NULL_BLOCK); try { ret.builder.mergeFrom(bin); } catch (InvalidProtocolBufferException e) { throw context.runtime.newRuntimeError(e.getMessage()); } return ret; } /* * call-seq: * MessageClass.encode_json(msg) => json_string * * Encodes the given message object into its serialized JSON representation. */ @JRubyMethod(name = "encode_json", meta = true) public static IRubyObject encodeJson(ThreadContext context, IRubyObject recv, IRubyObject msgRb) { RubyMessage message = (RubyMessage) msgRb; return Helpers.invoke(context, message.toHash(context), "to_json"); } /* * call-seq: * MessageClass.decode_json(data) => message * * Decodes the given data (as a string containing bytes in protocol buffers wire * format) under the interpretration given by this message class's definition * and returns a message object with the corresponding field values. */ @JRubyMethod(name = "decode_json", meta = true) public static IRubyObject decodeJson(ThreadContext context, IRubyObject recv, IRubyObject json) { Ruby runtime = context.runtime; RubyMessage ret = (RubyMessage) ((RubyClass) recv).newInstance(context, Block.NULL_BLOCK); RubyModule jsonModule = runtime.getClassFromPath("JSON"); RubyHash opts = RubyHash.newHash(runtime); opts.fastASet(runtime.newSymbol("symbolize_names"), runtime.getTrue()); IRubyObject[] args = new IRubyObject[] { Helpers.invoke(context, jsonModule, "parse", json, opts) }; ret.initialize(context, args); return ret; } @JRubyMethod(name = {"to_h", "to_hash"}) public IRubyObject toHash(ThreadContext context) { Ruby runtime = context.runtime; RubyHash ret = RubyHash.newHash(runtime); for (Descriptors.FieldDescriptor fdef : this.descriptor.getFields()) { IRubyObject value = getField(context, fdef); 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"); } } ret.fastASet(runtime.newSymbol(fdef.getName()), value); } return ret; } protected DynamicMessage build(ThreadContext context) { return build(context, 0); } protected DynamicMessage build(ThreadContext context, int depth) { if (depth > SINK_MAXIMUM_NESTING) { throw context.runtime.newRuntimeError("Maximum recursion depth exceeded during encoding."); } for (Descriptors.FieldDescriptor fieldDescriptor : maps.keySet()) { this.builder.clearField(fieldDescriptor); RubyDescriptor mapDescriptor = (RubyDescriptor) getDescriptorForField(context, fieldDescriptor); for (DynamicMessage kv : maps.get(fieldDescriptor).build(context, mapDescriptor)) { this.builder.addRepeatedField(fieldDescriptor, kv); } } for (Descriptors.FieldDescriptor fieldDescriptor : repeatedFields.keySet()) { RubyRepeatedField repeatedField = repeatedFields.get(fieldDescriptor); this.builder.clearField(fieldDescriptor); for (int i = 0; i < repeatedField.size(); i++) { Object item = convert(context, fieldDescriptor, repeatedField.get(i), depth); this.builder.addRepeatedField(fieldDescriptor, item); } } for (Descriptors.FieldDescriptor fieldDescriptor : fields.keySet()) { IRubyObject value = fields.get(fieldDescriptor); this.builder.setField(fieldDescriptor, convert(context, fieldDescriptor, value, depth)); } return this.builder.build(); } protected Descriptors.Descriptor getDescriptor() { return this.descriptor; } // Internal use only, called by Google::Protobuf.deep_copy protected IRubyObject deepCopy(ThreadContext context) { RubyMessage copy = (RubyMessage) metaClass.newInstance(context, Block.NULL_BLOCK); for (Descriptors.FieldDescriptor fdef : this.descriptor.getFields()) { if (fdef.isRepeated()) { copy.addRepeatedField(fdef, this.getRepeatedField(context, fdef).deepCopy(context)); } else if (fields.containsKey(fdef)) { copy.fields.put(fdef, fields.get(fdef)); } else if (this.builder.hasField(fdef)) { copy.fields.put(fdef, wrapField(context, fdef, this.builder.getField(fdef))); } } return copy; } private RubyRepeatedField getRepeatedField(ThreadContext context, Descriptors.FieldDescriptor fieldDescriptor) { if (this.repeatedFields.containsKey(fieldDescriptor)) { return this.repeatedFields.get(fieldDescriptor); } int count = this.builder.getRepeatedFieldCount(fieldDescriptor); RubyRepeatedField ret = repeatedFieldForFieldDescriptor(context, fieldDescriptor); for (int i = 0; i < count; i++) { ret.push(context, wrapField(context, fieldDescriptor, this.builder.getRepeatedField(fieldDescriptor, i))); } addRepeatedField(fieldDescriptor, ret); return ret; } private void addRepeatedField(Descriptors.FieldDescriptor fieldDescriptor, RubyRepeatedField repeatedField) { this.repeatedFields.put(fieldDescriptor, repeatedField); } private IRubyObject buildFrom(ThreadContext context, DynamicMessage dynamicMessage) { this.builder.mergeFrom(dynamicMessage); return this; } private Descriptors.FieldDescriptor findField(ThreadContext context, IRubyObject fieldName) { String nameStr = fieldName.asJavaString(); Descriptors.FieldDescriptor ret = this.descriptor.findFieldByName(Utils.escapeIdentifier(nameStr)); if (ret == null) throw context.runtime.newArgumentError("field " + fieldName.asJavaString() + " is not found"); return ret; } private boolean hasField(IRubyObject fieldName) { String nameStr = fieldName.asJavaString(); return this.descriptor.findFieldByName(Utils.escapeIdentifier(nameStr)) != null; } private void checkRepeatedFieldType(ThreadContext context, IRubyObject value, Descriptors.FieldDescriptor fieldDescriptor) { Ruby runtime = context.runtime; if (!(value instanceof RubyRepeatedField)) { throw runtime.newTypeError("Expected repeated field array"); } } // convert a ruby object to protobuf type, with type check private Object convert(ThreadContext context, Descriptors.FieldDescriptor fieldDescriptor, IRubyObject value, int depth) { Ruby runtime = context.runtime; Object val = null; switch (fieldDescriptor.getType()) { case INT32: case INT64: case UINT32: case UINT64: if (!Utils.isRubyNum(value)) { throw runtime.newTypeError("Expected number type for integral field."); } Utils.checkIntTypePrecision(context, fieldDescriptor.getType(), value); switch (fieldDescriptor.getType()) { case INT32: val = RubyNumeric.num2int(value); break; case INT64: val = RubyNumeric.num2long(value); break; case UINT32: val = Utils.num2uint(value); break; case UINT64: val = Utils.num2ulong(context.runtime, value); break; default: break; } break; case FLOAT: if (!Utils.isRubyNum(value)) throw runtime.newTypeError("Expected number type for float field."); val = (float) RubyNumeric.num2dbl(value); break; case DOUBLE: if (!Utils.isRubyNum(value)) throw runtime.newTypeError("Expected number type for double field."); val = RubyNumeric.num2dbl(value); break; case BOOL: if (!(value instanceof RubyBoolean)) throw runtime.newTypeError("Invalid argument for boolean field."); val = value.isTrue(); break; case BYTES: case STRING: Utils.validateStringEncoding(context, fieldDescriptor.getType(), value); RubyString str = (RubyString) value; switch (fieldDescriptor.getType()) { case BYTES: val = ByteString.copyFrom(str.getBytes()); break; case STRING: val = str.asJavaString(); break; default: break; } break; case MESSAGE: RubyClass typeClass = (RubyClass) ((RubyDescriptor) getDescriptorForField(context, fieldDescriptor)).msgclass(context); if (!value.getMetaClass().equals(typeClass)) throw runtime.newTypeError(value, "Invalid type to assign to submessage field."); val = ((RubyMessage) value).build(context, depth + 1); break; case ENUM: Descriptors.EnumDescriptor enumDescriptor = fieldDescriptor.getEnumType(); if (Utils.isRubyNum(value)) { val = enumDescriptor.findValueByNumberCreatingIfUnknown(RubyNumeric.num2int(value)); } else if (value instanceof RubySymbol) { val = enumDescriptor.findValueByName(value.asJavaString()); } else { throw runtime.newTypeError("Expected number or symbol type for enum field."); } if (val == null) { throw runtime.newRangeError("Enum value " + value + " is not found."); } break; default: break; } return val; } private IRubyObject wrapField(ThreadContext context, Descriptors.FieldDescriptor fieldDescriptor, Object value) { if (value == null) { return context.runtime.getNil(); } Ruby runtime = context.runtime; switch (fieldDescriptor.getType()) { case INT32: case INT64: case UINT32: case UINT64: case FLOAT: case DOUBLE: case BOOL: case BYTES: case STRING: return Utils.wrapPrimaryValue(context, fieldDescriptor.getType(), value); case MESSAGE: RubyClass typeClass = (RubyClass) ((RubyDescriptor) getDescriptorForField(context, fieldDescriptor)).msgclass(context); RubyMessage msg = (RubyMessage) typeClass.newInstance(context, Block.NULL_BLOCK); return msg.buildFrom(context, (DynamicMessage) value); case ENUM: Descriptors.EnumValueDescriptor enumValueDescriptor = (Descriptors.EnumValueDescriptor) value; if (enumValueDescriptor.getIndex() == -1) { // UNKNOWN ENUM VALUE return runtime.newFixnum(enumValueDescriptor.getNumber()); } return runtime.newSymbol(enumValueDescriptor.getName()); default: return runtime.newString(value.toString()); } } private RubyRepeatedField repeatedFieldForFieldDescriptor(ThreadContext context, Descriptors.FieldDescriptor fieldDescriptor) { IRubyObject typeClass = context.runtime.getNilClass(); IRubyObject descriptor = getDescriptorForField(context, fieldDescriptor); Descriptors.FieldDescriptor.Type type = fieldDescriptor.getType(); if (type == Descriptors.FieldDescriptor.Type.MESSAGE) { typeClass = ((RubyDescriptor) descriptor).msgclass(context); } else if (type == Descriptors.FieldDescriptor.Type.ENUM) { typeClass = ((RubyEnumDescriptor) descriptor).enummodule(context); } return new RubyRepeatedField(context.runtime, cRepeatedField, type, typeClass); } protected IRubyObject getField(ThreadContext context, Descriptors.FieldDescriptor fieldDescriptor) { Descriptors.OneofDescriptor oneofDescriptor = fieldDescriptor.getContainingOneof(); if (oneofDescriptor != null) { if (oneofCases.get(oneofDescriptor) == fieldDescriptor) { return fields.get(fieldDescriptor); } else { Descriptors.FieldDescriptor oneofCase = builder.getOneofFieldDescriptor(oneofDescriptor); if (oneofCase != fieldDescriptor) { if (fieldDescriptor.getType() == Descriptors.FieldDescriptor.Type.MESSAGE) { return context.runtime.getNil(); } else { return wrapField(context, fieldDescriptor, fieldDescriptor.getDefaultValue()); } } IRubyObject value = wrapField(context, oneofCase, builder.getField(oneofCase)); fields.put(fieldDescriptor, value); return value; } } if (Utils.isMapEntry(fieldDescriptor)) { RubyMap map = maps.get(fieldDescriptor); if (map == null) { map = newMapForField(context, fieldDescriptor); int mapSize = this.builder.getRepeatedFieldCount(fieldDescriptor); Descriptors.FieldDescriptor keyField = fieldDescriptor.getMessageType().findFieldByNumber(1); Descriptors.FieldDescriptor valueField = fieldDescriptor.getMessageType().findFieldByNumber(2); RubyDescriptor kvDescriptor = (RubyDescriptor) getDescriptorForField(context, fieldDescriptor); RubyClass kvClass = (RubyClass) kvDescriptor.msgclass(context); for (int i = 0; i < mapSize; i++) { RubyMessage kvMessage = (RubyMessage) kvClass.newInstance(context, Block.NULL_BLOCK); DynamicMessage message = (DynamicMessage) this.builder.getRepeatedField(fieldDescriptor, i); kvMessage.buildFrom(context, message); map.indexSet(context, kvMessage.getField(context, keyField), kvMessage.getField(context, valueField)); } maps.put(fieldDescriptor, map); } return map; } if (fieldDescriptor.isRepeated()) { return getRepeatedField(context, fieldDescriptor); } if (fieldDescriptor.getType() != Descriptors.FieldDescriptor.Type.MESSAGE || this.builder.hasField(fieldDescriptor) || fields.containsKey(fieldDescriptor)) { if (fields.containsKey(fieldDescriptor)) { return fields.get(fieldDescriptor); } else { IRubyObject value = wrapField(context, fieldDescriptor, this.builder.getField(fieldDescriptor)); if (this.builder.hasField(fieldDescriptor)) { fields.put(fieldDescriptor, value); } return value; } } return context.runtime.getNil(); } protected IRubyObject setField(ThreadContext context, Descriptors.FieldDescriptor fieldDescriptor, IRubyObject value) { if (Utils.isMapEntry(fieldDescriptor)) { if (!(value instanceof RubyMap)) { throw context.runtime.newTypeError("Expected Map instance"); } RubyMap thisMap = (RubyMap) getField(context, fieldDescriptor); thisMap.mergeIntoSelf(context, value); } else if (fieldDescriptor.isRepeated()) { checkRepeatedFieldType(context, value, fieldDescriptor); if (value instanceof RubyRepeatedField) { addRepeatedField(fieldDescriptor, (RubyRepeatedField) value); } else { RubyArray ary = value.convertToArray(); RubyRepeatedField repeatedField = rubyToRepeatedField(context, fieldDescriptor, ary); addRepeatedField(fieldDescriptor, repeatedField); } } else { Descriptors.OneofDescriptor oneofDescriptor = fieldDescriptor.getContainingOneof(); if (oneofDescriptor != null) { Descriptors.FieldDescriptor oneofCase = oneofCases.get(oneofDescriptor); if (oneofCase != null && oneofCase != fieldDescriptor) { fields.remove(oneofCase); } if (value.isNil()) { oneofCases.remove(oneofDescriptor); fields.remove(fieldDescriptor); } else { oneofCases.put(oneofDescriptor, fieldDescriptor); fields.put(fieldDescriptor, value); } } else { Descriptors.FieldDescriptor.Type fieldType = fieldDescriptor.getType(); IRubyObject typeClass = context.runtime.getObject(); boolean addValue = true; if (fieldType == Descriptors.FieldDescriptor.Type.MESSAGE) { typeClass = ((RubyDescriptor) getDescriptorForField(context, fieldDescriptor)).msgclass(context); if (value.isNil()){ addValue = false; } } else if (fieldType == Descriptors.FieldDescriptor.Type.ENUM) { typeClass = ((RubyEnumDescriptor) getDescriptorForField(context, fieldDescriptor)).enummodule(context); Descriptors.EnumDescriptor enumDescriptor = fieldDescriptor.getEnumType(); if (Utils.isRubyNum(value)) { Descriptors.EnumValueDescriptor val = enumDescriptor.findValueByNumberCreatingIfUnknown(RubyNumeric.num2int(value)); if (val.getIndex() != -1) value = context.runtime.newSymbol(val.getName()); } } if (addValue) { value = Utils.checkType(context, fieldType, value, (RubyModule) typeClass); this.fields.put(fieldDescriptor, value); } else { this.fields.remove(fieldDescriptor); } } } return context.runtime.getNil(); } private String layoutInspect() { ThreadContext context = getRuntime().getCurrentContext(); StringBuilder sb = new StringBuilder(); for (Descriptors.FieldDescriptor fdef : descriptor.getFields()) { sb.append(Utils.unescapeIdentifier(fdef.getName())); sb.append(": "); sb.append(getField(context, fdef).inspect()); sb.append(", "); } return sb.substring(0, sb.length() - 2); } private IRubyObject getDescriptorForField(ThreadContext context, Descriptors.FieldDescriptor fieldDescriptor) { RubyDescriptor thisRbDescriptor = (RubyDescriptor) getDescriptor(context, metaClass); return thisRbDescriptor.lookup(fieldDescriptor.getName()).getSubType(context); } private RubyRepeatedField rubyToRepeatedField(ThreadContext context, Descriptors.FieldDescriptor fieldDescriptor, IRubyObject value) { RubyArray arr = value.convertToArray(); RubyRepeatedField repeatedField = repeatedFieldForFieldDescriptor(context, fieldDescriptor); for (int i = 0; i < arr.size(); i++) { repeatedField.push(context, arr.eltInternal(i)); } return repeatedField; } private RubyMap newMapForField(ThreadContext context, Descriptors.FieldDescriptor fieldDescriptor) { RubyDescriptor mapDescriptor = (RubyDescriptor) getDescriptorForField(context, fieldDescriptor); Descriptors.FieldDescriptor keyField = fieldDescriptor.getMessageType().findFieldByNumber(1); Descriptors.FieldDescriptor valueField = fieldDescriptor.getMessageType().findFieldByNumber(2); IRubyObject keyType = RubySymbol.newSymbol(context.runtime, keyField.getType().name()); IRubyObject valueType = RubySymbol.newSymbol(context.runtime, valueField.getType().name()); if (valueField.getType() == Descriptors.FieldDescriptor.Type.MESSAGE) { RubyFieldDescriptor rubyFieldDescriptor = (RubyFieldDescriptor) mapDescriptor.lookup(context, context.runtime.newString("value")); RubyDescriptor rubyDescriptor = (RubyDescriptor) rubyFieldDescriptor.getSubType(context); return (RubyMap) cMap.newInstance(context, keyType, valueType, rubyDescriptor.msgclass(context), Block.NULL_BLOCK); } else { return (RubyMap) cMap.newInstance(context, keyType, valueType, Block.NULL_BLOCK); } } private Descriptors.FieldDescriptor getOneofCase(Descriptors.OneofDescriptor oneof) { if (oneofCases.containsKey(oneof)) { return oneofCases.get(oneof); } return builder.getOneofFieldDescriptor(oneof); } private Descriptors.Descriptor descriptor; private DynamicMessage.Builder builder; private RubyClass cRepeatedField; private RubyClass cMap; private Map repeatedFields; private Map maps; private Map fields; private Map oneofCases; private static final int SINK_MAXIMUM_NESTING = 64; } google-protobuf-3.2.0/src/main/java/com/google/protobuf/jruby/RubyEnumDescriptor.java0000644000175000017500000001571113042756211030011 0ustar pravipravi/* * 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; import com.google.protobuf.Descriptors; 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.new => enum_descriptor * * Creates a new, empty, enum descriptor. Must be added to a pool before the * enum type can be used. The enum type may only be modified prior to adding to * a pool. */ @JRubyMethod public IRubyObject initialize(ThreadContext context) { this.builder = DescriptorProtos.EnumDescriptorProto.newBuilder(); return this; } /* * 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.name = name * * Sets the name of this enum type. Cannot be called if the enum type has * already been added to a pool. */ @JRubyMethod(name = "name=") public IRubyObject setName(ThreadContext context, IRubyObject name) { this.name = name; this.builder.setName(Utils.escapeIdentifier(name.asJavaString())); return context.runtime.getNil(); } /* * call-seq: * EnumDescriptor.add_value(key, value) * * Adds a new key => value mapping to this enum type. Key must be given as a * Ruby symbol. Cannot be called if the enum type has already been added to a * pool. Will raise an exception if the key or value is already in use. */ @JRubyMethod(name = "add_value") public IRubyObject addValue(ThreadContext context, IRubyObject name, IRubyObject number) { DescriptorProtos.EnumValueDescriptorProto.Builder valueBuilder = DescriptorProtos.EnumValueDescriptorProto.newBuilder(); valueBuilder.setName(name.asJavaString()); valueBuilder.setNumber(RubyNumeric.num2int(number)); this.builder.addValue(valueBuilder); return context.runtime.getNil(); } /* * 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 (Descriptors.EnumValueDescriptor enumValueDescriptor : descriptor.getValues()) { block.yield(context, runtime.newArray(runtime.newSymbol(enumValueDescriptor.getName()), runtime.newFixnum(enumValueDescriptor.getNumber()))); } return runtime.getNil(); } /* * 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) { if (this.klazz == null) { this.klazz = buildModuleFromDescriptor(context); } return this.klazz; } public void setDescriptor(Descriptors.EnumDescriptor descriptor) { this.descriptor = descriptor; } public Descriptors.EnumDescriptor getDescriptor() { return this.descriptor; } public DescriptorProtos.EnumDescriptorProto.Builder getBuilder() { return this.builder; } private RubyModule buildModuleFromDescriptor(ThreadContext context) { Ruby runtime = context.runtime; Utils.checkNameAvailability(context, name.asJavaString()); RubyModule enumModule = RubyModule.newModule(runtime); for (Descriptors.EnumValueDescriptor value : descriptor.getValues()) { enumModule.defineConstant(value.getName(), runtime.newFixnum(value.getNumber())); } enumModule.instance_variable_set(runtime.newString(Utils.DESCRIPTOR_INSTANCE_VAR), this); enumModule.defineAnnotatedMethods(RubyEnum.class); return enumModule; } private IRubyObject name; private RubyModule klazz; private Descriptors.EnumDescriptor descriptor; private DescriptorProtos.EnumDescriptorProto.Builder builder; } google-protobuf-3.2.0/src/main/java/com/google/protobuf/jruby/RubyOneofBuilderContext.java0000644000175000017500000000733113042756211030767 0ustar pravipravi/* * 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.RubyClass; import org.jruby.RubyModule; import org.jruby.RubyObject; 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 = "OneofBuilderContext") public class RubyOneofBuilderContext extends RubyObject { public static void createRubyOneofBuilderContext(Ruby runtime) { RubyModule protobuf = runtime.getClassFromPath("Google::Protobuf"); RubyModule internal = protobuf.defineModuleUnder("Internal"); RubyClass cRubyOneofBuidlerContext = internal.defineClassUnder("OneofBuilderContext", runtime.getObject(), new ObjectAllocator() { @Override public IRubyObject allocate(Ruby ruby, RubyClass rubyClass) { return new RubyOneofBuilderContext(ruby, rubyClass); } }); cRubyOneofBuidlerContext.defineAnnotatedMethods(RubyOneofBuilderContext.class); } public RubyOneofBuilderContext(Ruby ruby, RubyClass rubyClass) { super(ruby, rubyClass); } @JRubyMethod public IRubyObject initialize(ThreadContext context, IRubyObject oneofdef) { this.descriptor = (RubyOneofDescriptor) oneofdef; this.cFieldDescriptor = (RubyClass) context.runtime.getClassFromPath("Google::Protobuf::FieldDescriptor"); return this; } @JRubyMethod(required = 3, optional = 1) public IRubyObject optional(ThreadContext context, IRubyObject[] args) { IRubyObject name = args[0]; IRubyObject type = args[1]; IRubyObject number = args[2]; IRubyObject typeClass = args.length > 3 ? args[3] : context.runtime.getNil(); RubyFieldDescriptor fieldDescriptor = Utils.msgdefCreateField(context, "optional", name, type, number, typeClass, cFieldDescriptor); descriptor.addField(context, fieldDescriptor); return this; } private RubyOneofDescriptor descriptor; private RubyClass cFieldDescriptor; } google-protobuf-3.2.0/src/main/java/com/google/protobuf/jruby/RubyBuilder.java0000644000175000017500000001617013042756211026434 0ustar pravipravi/* * 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.*; import org.jruby.anno.JRubyClass; import org.jruby.anno.JRubyMethod; import org.jruby.runtime.*; import org.jruby.runtime.builtin.IRubyObject; @JRubyClass(name = "Builder") public class RubyBuilder extends RubyObject { public static void createRubyBuilder(Ruby runtime) { RubyModule protobuf = runtime.getClassFromPath("Google::Protobuf"); RubyClass cBuilder = protobuf.defineClassUnder("Builder", runtime.getObject(), new ObjectAllocator() { @Override public IRubyObject allocate(Ruby runtime, RubyClass klazz) { return new RubyBuilder(runtime, klazz); } }); cBuilder.defineAnnotatedMethods(RubyBuilder.class); } public RubyBuilder(Ruby runtime, RubyClass metaClass) { super(runtime, metaClass); this.cDescriptor = (RubyClass) runtime.getClassFromPath("Google::Protobuf::Descriptor"); this.cEnumDescriptor = (RubyClass) runtime.getClassFromPath("Google::Protobuf::EnumDescriptor"); this.cMessageBuilderContext = (RubyClass) runtime.getClassFromPath("Google::Protobuf::MessageBuilderContext"); this.cEnumBuilderContext = (RubyClass) runtime.getClassFromPath("Google::Protobuf::EnumBuilderContext"); } /* * call-seq: * Builder.new => builder * * Creates a new Builder. A Builder can accumulate a set of new message and enum * descriptors and atomically register them into a pool in a way that allows for * (co)recursive type references. */ @JRubyMethod public IRubyObject initialize(ThreadContext context) { Ruby runtime = context.runtime; this.pendingList = runtime.newArray(); return this; } /* * call-seq: * Builder.add_message(name, &block) * * Creates a new, empty descriptor with the given name, and invokes the block in * the context of a MessageBuilderContext on that descriptor. The block can then * call, e.g., MessageBuilderContext#optional and MessageBuilderContext#repeated * methods to define the message fields. * * This is the recommended, idiomatic way to build message definitions. */ @JRubyMethod(name = "add_message") public IRubyObject addMessage(ThreadContext context, IRubyObject name, Block block) { RubyDescriptor msgdef = (RubyDescriptor) cDescriptor.newInstance(context, Block.NULL_BLOCK); IRubyObject ctx = cMessageBuilderContext.newInstance(context, msgdef, this, Block.NULL_BLOCK); msgdef.setName(context, name); if (block.isGiven()) { if (block.arity() == Arity.ONE_ARGUMENT) { block.yield(context, ctx); } else { Binding binding = block.getBinding(); binding.setSelf(ctx); block.yieldSpecific(context); } } this.pendingList.add(msgdef); return context.runtime.getNil(); } /* * call-seq: * Builder.add_enum(name, &block) * * Creates a new, empty enum descriptor with the given name, and invokes the block in * the context of an EnumBuilderContext on that descriptor. The block can then * call EnumBuilderContext#add_value to define the enum values. * * This is the recommended, idiomatic way to build enum definitions. */ @JRubyMethod(name = "add_enum") public IRubyObject addEnum(ThreadContext context, IRubyObject name, Block block) { RubyEnumDescriptor enumDef = (RubyEnumDescriptor) cEnumDescriptor.newInstance(context, Block.NULL_BLOCK); IRubyObject ctx = cEnumBuilderContext.newInstance(context, enumDef, Block.NULL_BLOCK); enumDef.setName(context, name); if (block.isGiven()) { if (block.arity() == Arity.ONE_ARGUMENT) { block.yield(context, ctx); } else { Binding binding = block.getBinding(); binding.setSelf(ctx); block.yieldSpecific(context); } } this.pendingList.add(enumDef); return context.runtime.getNil(); } /* * call-seq: * Builder.finalize_to_pool(pool) * * Adds all accumulated message and enum descriptors created in this builder * context to the given pool. The operation occurs atomically, and all * descriptors can refer to each other (including in cycles). This is the only * way to build (co)recursive message definitions. * * This method is usually called automatically by DescriptorPool#build after it * invokes the given user block in the context of the builder. The user should * not normally need to call this manually because a Builder is not normally * created manually. */ @JRubyMethod(name = "finalize_to_pool") public IRubyObject finalizeToPool(ThreadContext context, IRubyObject rbPool) { RubyDescriptorPool pool = (RubyDescriptorPool) rbPool; for (int i = 0; i < this.pendingList.size(); i++) { IRubyObject defRb = this.pendingList.entry(i); if (defRb instanceof RubyDescriptor) { pool.addToSymtab(context, (RubyDescriptor) defRb); } else { pool.addToSymtab(context, (RubyEnumDescriptor) defRb); } } this.pendingList = context.runtime.newArray(); return context.runtime.getNil(); } protected RubyArray pendingList; private RubyClass cDescriptor, cEnumDescriptor, cMessageBuilderContext, cEnumBuilderContext; } google-protobuf-3.2.0/src/main/java/com/google/protobuf/jruby/RubyEnumBuilderContext.java0000644000175000017500000000653113042756211030626 0ustar pravipravi/* * 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.RubyClass; import org.jruby.RubyModule; import org.jruby.RubyObject; 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 = "EnumBuilderContext") public class RubyEnumBuilderContext extends RubyObject { public static void createRubyEnumBuilderContext(Ruby runtime) { RubyModule protobuf = runtime.getClassFromPath("Google::Protobuf"); RubyClass cMessageBuilderContext = protobuf.defineClassUnder("EnumBuilderContext", runtime.getObject(), new ObjectAllocator() { @Override public IRubyObject allocate(Ruby runtime, RubyClass klazz) { return new RubyEnumBuilderContext(runtime, klazz); } }); cMessageBuilderContext.defineAnnotatedMethods(RubyEnumBuilderContext.class); } public RubyEnumBuilderContext(Ruby ruby, RubyClass klazz) { super(ruby, klazz); } @JRubyMethod public IRubyObject initialize(ThreadContext context, IRubyObject enumDescriptor) { this.enumDescriptor = (RubyEnumDescriptor) enumDescriptor; return this; } /* * call-seq: * EnumBuilder.add_value(name, number) * * Adds the given name => number mapping to the enum type. Name must be a Ruby * symbol. */ @JRubyMethod public IRubyObject value(ThreadContext context, IRubyObject name, IRubyObject number) { this.enumDescriptor.addValue(context, name, number); return context.runtime.getNil(); } private RubyEnumDescriptor enumDescriptor; } google-protobuf-3.2.0/src/main/java/com/google/protobuf/jruby/SentinelOuterClass.java0000644000175000017500000006213213042756211027771 0ustar pravipravi/* * 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 { /** * optional int32 default_int32 = 1; */ int getDefaultInt32(); /** * optional int64 default_int64 = 2; */ long getDefaultInt64(); /** * optional uint32 default_unit32 = 3; */ int getDefaultUnit32(); /** * optional uint64 default_uint64 = 4; */ long getDefaultUint64(); /** * optional string default_string = 5; */ java.lang.String getDefaultString(); /** * optional string default_string = 5; */ com.google.protobuf.ByteString getDefaultStringBytes(); /** * optional bool default_bool = 6; */ boolean getDefaultBool(); /** * optional float default_float = 7; */ float getDefaultFloat(); /** * optional double default_double = 8; */ double getDefaultDouble(); /** * optional bytes default_bytes = 9; */ 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 PARSER = new com.google.protobuf.AbstractParser() { 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 getParserForType() { return PARSER; } public static final int DEFAULT_INT32_FIELD_NUMBER = 1; private int defaultInt32_; /** * optional int32 default_int32 = 1; */ public int getDefaultInt32() { return defaultInt32_; } public static final int DEFAULT_INT64_FIELD_NUMBER = 2; private long defaultInt64_; /** * optional int64 default_int64 = 2; */ public long getDefaultInt64() { return defaultInt64_; } public static final int DEFAULT_UNIT32_FIELD_NUMBER = 3; private int defaultUnit32_; /** * optional uint32 default_unit32 = 3; */ public int getDefaultUnit32() { return defaultUnit32_; } public static final int DEFAULT_UINT64_FIELD_NUMBER = 4; private long defaultUint64_; /** * optional uint64 default_uint64 = 4; */ public long getDefaultUint64() { return defaultUint64_; } public static final int DEFAULT_STRING_FIELD_NUMBER = 5; private java.lang.Object defaultString_; /** * optional string default_string = 5; */ 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; } } /** * optional string default_string = 5; */ 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_; /** * optional bool default_bool = 6; */ public boolean getDefaultBool() { return defaultBool_; } public static final int DEFAULT_FLOAT_FIELD_NUMBER = 7; private float defaultFloat_; /** * optional float default_float = 7; */ public float getDefaultFloat() { return defaultFloat_; } public static final int DEFAULT_DOUBLE_FIELD_NUMBER = 8; private double defaultDouble_; /** * optional double default_double = 8; */ public double getDefaultDouble() { return defaultDouble_; } public static final int DEFAULT_BYTES_FIELD_NUMBER = 9; private com.google.protobuf.ByteString defaultBytes_; /** * optional bytes default_bytes = 9; */ 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 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_ ; /** * optional int32 default_int32 = 1; */ public int getDefaultInt32() { return defaultInt32_; } /** * optional int32 default_int32 = 1; */ public Builder setDefaultInt32(int value) { defaultInt32_ = value; onChanged(); return this; } /** * optional int32 default_int32 = 1; */ public Builder clearDefaultInt32() { defaultInt32_ = 0; onChanged(); return this; } private long defaultInt64_ ; /** * optional int64 default_int64 = 2; */ public long getDefaultInt64() { return defaultInt64_; } /** * optional int64 default_int64 = 2; */ public Builder setDefaultInt64(long value) { defaultInt64_ = value; onChanged(); return this; } /** * optional int64 default_int64 = 2; */ public Builder clearDefaultInt64() { defaultInt64_ = 0L; onChanged(); return this; } private int defaultUnit32_ ; /** * optional uint32 default_unit32 = 3; */ public int getDefaultUnit32() { return defaultUnit32_; } /** * optional uint32 default_unit32 = 3; */ public Builder setDefaultUnit32(int value) { defaultUnit32_ = value; onChanged(); return this; } /** * optional uint32 default_unit32 = 3; */ public Builder clearDefaultUnit32() { defaultUnit32_ = 0; onChanged(); return this; } private long defaultUint64_ ; /** * optional uint64 default_uint64 = 4; */ public long getDefaultUint64() { return defaultUint64_; } /** * optional uint64 default_uint64 = 4; */ public Builder setDefaultUint64(long value) { defaultUint64_ = value; onChanged(); return this; } /** * optional uint64 default_uint64 = 4; */ public Builder clearDefaultUint64() { defaultUint64_ = 0L; onChanged(); return this; } private java.lang.Object defaultString_ = ""; /** * optional string default_string = 5; */ 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; } } /** * optional string default_string = 5; */ 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; } } /** * optional string default_string = 5; */ public Builder setDefaultString( java.lang.String value) { if (value == null) { throw new NullPointerException(); } defaultString_ = value; onChanged(); return this; } /** * optional string default_string = 5; */ public Builder clearDefaultString() { defaultString_ = getDefaultInstance().getDefaultString(); onChanged(); return this; } /** * optional string default_string = 5; */ public Builder setDefaultStringBytes( com.google.protobuf.ByteString value) { if (value == null) { throw new NullPointerException(); } defaultString_ = value; onChanged(); return this; } private boolean defaultBool_ ; /** * optional bool default_bool = 6; */ public boolean getDefaultBool() { return defaultBool_; } /** * optional bool default_bool = 6; */ public Builder setDefaultBool(boolean value) { defaultBool_ = value; onChanged(); return this; } /** * optional bool default_bool = 6; */ public Builder clearDefaultBool() { defaultBool_ = false; onChanged(); return this; } private float defaultFloat_ ; /** * optional float default_float = 7; */ public float getDefaultFloat() { return defaultFloat_; } /** * optional float default_float = 7; */ public Builder setDefaultFloat(float value) { defaultFloat_ = value; onChanged(); return this; } /** * optional float default_float = 7; */ public Builder clearDefaultFloat() { defaultFloat_ = 0F; onChanged(); return this; } private double defaultDouble_ ; /** * optional double default_double = 8; */ public double getDefaultDouble() { return defaultDouble_; } /** * optional double default_double = 8; */ public Builder setDefaultDouble(double value) { defaultDouble_ = value; onChanged(); return this; } /** * optional double default_double = 8; */ public Builder clearDefaultDouble() { defaultDouble_ = 0D; onChanged(); return this; } private com.google.protobuf.ByteString defaultBytes_ = com.google.protobuf.ByteString.EMPTY; /** * optional bytes default_bytes = 9; */ public com.google.protobuf.ByteString getDefaultBytes() { return defaultBytes_; } /** * optional bytes default_bytes = 9; */ public Builder setDefaultBytes(com.google.protobuf.ByteString value) { if (value == null) { throw new NullPointerException(); } defaultBytes_ = value; onChanged(); return this; } /** * optional bytes default_bytes = 9; */ 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) } google-protobuf-3.2.0/src/main/java/com/google/protobuf/jruby/RubyDescriptor.java0000644000175000017500000002361613042756211027167 0ustar pravipravi/* * 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; import com.google.protobuf.Descriptors; 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.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); } public RubyDescriptor(Ruby runtime, RubyClass klazz) { super(runtime, klazz); } /* * call-seq: * Descriptor.new => descriptor * * Creates a new, empty, message type descriptor. At a minimum, its name must be * set before it is added to a pool. It cannot be used to create messages until * it is added to a pool, after which it becomes immutable (as part of a * finalization process). */ @JRubyMethod public IRubyObject initialize(ThreadContext context) { this.builder = DescriptorProtos.DescriptorProto.newBuilder(); this.fieldDefMap = new HashMap(); this.oneofDefs = new HashMap(); return this; } /* * call-seq: * Descriptor.name => name * * Returns the name of this message type as a fully-qualfied string (e.g., * My.Package.MessageType). */ @JRubyMethod(name = "name") public IRubyObject getName(ThreadContext context) { return this.name; } /* * call-seq: * Descriptor.name = name * * Assigns a name to this message type. The descriptor must not have been added * to a pool yet. */ @JRubyMethod(name = "name=") public IRubyObject setName(ThreadContext context, IRubyObject name) { this.name = name; this.builder.setName(Utils.escapeIdentifier(this.name.asJavaString())); return context.runtime.getNil(); } /* * call-seq: * Descriptor.add_field(field) => nil * * Adds the given FieldDescriptor to this message type. The descriptor must not * have been added to a pool yet. Raises an exception if a field with the same * name or number already exists. Sub-type references (e.g. for fields of type * message) are not resolved at this point. */ @JRubyMethod(name = "add_field") public IRubyObject addField(ThreadContext context, IRubyObject obj) { RubyFieldDescriptor fieldDef = (RubyFieldDescriptor) obj; this.fieldDefMap.put(fieldDef.getName(context).asJavaString(), fieldDef); this.builder.addField(fieldDef.build()); return context.runtime.getNil(); } /* * 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 this.fieldDefMap.get(fieldName.asJavaString()); } /* * 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) { if (this.klazz == null) { this.klazz = buildClassFromDescriptor(context); } return this.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 entry : fieldDefMap.entrySet()) { block.yield(context, entry.getValue()); } return context.runtime.getNil(); } /* * call-seq: * Descriptor.add_oneof(oneof) => nil * * Adds the given OneofDescriptor to this message type. This descriptor must not * have been added to a pool yet. Raises an exception if a oneof with the same * name already exists, or if any of the oneof's fields' names or numbers * conflict with an existing field in this message type. All fields in the oneof * are added to the message descriptor. Sub-type references (e.g. for fields of * type message) are not resolved at this point. */ @JRubyMethod(name = "add_oneof") public IRubyObject addOneof(ThreadContext context, IRubyObject obj) { RubyOneofDescriptor def = (RubyOneofDescriptor) obj; builder.addOneofDecl(def.build(builder.getOneofDeclCount())); for (RubyFieldDescriptor fieldDescriptor : def.getFields()) { addField(context, fieldDescriptor); } oneofDefs.put(def.getName(context), def); return context.runtime.getNil(); } /* * 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 : oneofDefs.values()) { block.yieldSpecific(context, oneofDescriptor); } return context.runtime.getNil(); } /* * 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) { if (name instanceof RubySymbol) { name = ((RubySymbol) name).id2name(); } return oneofDefs.containsKey(name) ? oneofDefs.get(name) : context.runtime.getNil(); } public void setDescriptor(Descriptors.Descriptor descriptor) { this.descriptor = descriptor; } public Descriptors.Descriptor getDescriptor() { return this.descriptor; } public DescriptorProtos.DescriptorProto.Builder getBuilder() { return builder; } public void setMapEntry(boolean isMapEntry) { this.builder.setOptions(DescriptorProtos.MessageOptions.newBuilder().setMapEntry(isMapEntry)); } private RubyModule 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); return klass; } protected RubyFieldDescriptor lookup(String fieldName) { return fieldDefMap.get(Utils.unescapeIdentifier(fieldName)); } private IRubyObject name; private RubyModule klazz; private DescriptorProtos.DescriptorProto.Builder builder; private Descriptors.Descriptor descriptor; private Map fieldDefMap; private Map oneofDefs; } google-protobuf-3.2.0/src/main/java/com/google/protobuf/jruby/RubyOneofDescriptor.java0000644000175000017500000001024313042756211030146 0ustar pravipravipackage com.google.protobuf.jruby; import com.google.protobuf.DescriptorProtos; import com.google.protobuf.Descriptors; 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.*; @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); } @JRubyMethod public IRubyObject initialize(ThreadContext context) { builder = DescriptorProtos.OneofDescriptorProto.newBuilder(); fields = new ArrayList(); return this; } /* * call-seq: * OneofDescriptor.name => name * * Returns the name of this oneof. */ @JRubyMethod(name = "name") public IRubyObject getName(ThreadContext context) { return name; } /* * call-seq: * OneofDescriptor.name = name * * Sets a new name for this oneof. The oneof must not have been added to a * message descriptor yet. */ @JRubyMethod(name = "name=") public IRubyObject setName(ThreadContext context, IRubyObject name) { this.name = context.runtime.newString(name.asJavaString()); this.builder.setName(name.asJavaString()); return context.runtime.getNil(); } /* * call-seq: * OneofDescriptor.add_field(field) => nil * * Adds a field to this oneof. The field may have been added to this oneof in * the past, or the message to which this oneof belongs (if any), but may not * have already been added to any other oneof or message. Otherwise, an * exception is raised. * * All fields added to the oneof via this method will be automatically added to * the message to which this oneof belongs, if it belongs to one currently, or * else will be added to any message to which the oneof is later added at the * time that it is added. */ @JRubyMethod(name = "add_field") public IRubyObject addField(ThreadContext context, IRubyObject obj) { RubyFieldDescriptor fieldDescriptor = (RubyFieldDescriptor) obj; fieldDescriptor.setOneofName(this.name); fields.add(fieldDescriptor); return context.runtime.getNil(); } /* * 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.runtime.getNil(); } public DescriptorProtos.OneofDescriptorProto build(int index) { for (RubyFieldDescriptor field: fields) { field.setOneofIndex(index); } return this.builder.build(); } protected Collection getFields() { return fields; } protected Descriptors.OneofDescriptor getOneofDescriptor() { RubyFieldDescriptor fieldDescriptor = fields.get(0); return fieldDescriptor.getFieldDef().getContainingOneof(); } private IRubyObject name; private DescriptorProtos.OneofDescriptorProto.Builder builder; private List fields; } google-protobuf-3.2.0/src/main/java/com/google/protobuf/jruby/RubyRepeatedField.java0000644000175000017500000003564513042756211027553 0ustar pravipravi/* * 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; 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, Descriptors.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 == Descriptors.FieldDescriptor.Type.MESSAGE || fieldType == Descriptors.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, 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 to = RubyNumeric.num2int(range.last(context)); int len = to - beg + 1; 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", "<<"}) public IRubyObject push(ThreadContext context, IRubyObject value) { if (!(fieldType == Descriptors.FieldDescriptor.Type.MESSAGE && value == context.runtime.getNil())) { value = Utils.checkType(context, fieldType, value, (RubyModule) typeClass); } this.storage.add(value); return this.storage; } /* * 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.storage; } /* * call-seq: * RepeatedField.clear * * Clears (removes all elements from) this repeated field. */ @JRubyMethod public IRubyObject clear(ThreadContext context) { this.storage.clear(); return this.storage; } /* * 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.storage; } /* * 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.storage; } @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); for (int i = 0; i < this.storage.size(); i++) { dup.push(context, this.storage.eltInternal(i)); } return dup; } // 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 == Descriptors.FieldDescriptor.Type.MESSAGE) { copy.storage.add(((RubyMessage) value).deepCopy(context)); } else { copy.storage.add(value); } } return copy; } 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, 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 RubyArray storage; private Descriptors.FieldDescriptor.Type fieldType; private IRubyObject typeClass; } google-protobuf-3.2.0/src/main/java/google/0000755000175000017500000000000013043000403017545 5ustar pravipravigoogle-protobuf-3.2.0/src/main/java/google/ProtobufJavaService.java0000644000175000017500000000532413042756211024355 0ustar pravipravi/* * 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"); RubyProtobuf.createProtobuf(ruby); RubyDescriptor.createRubyDescriptor(ruby); RubyBuilder.createRubyBuilder(ruby); RubyFieldDescriptor.createRubyFileDescriptor(ruby); RubyMessageBuilderContext.createRubyMessageBuilderContext(ruby); RubyEnumDescriptor.createRubyEnumDescriptor(ruby); RubyEnumBuilderContext.createRubyEnumBuilderContext(ruby); RubyDescriptorPool.createRubyDescriptorPool(ruby); RubyRepeatedField.createRubyRepeatedField(ruby); RubyFieldDescriptor.createRubyFileDescriptor(ruby); RubyMap.createRubyMap(ruby); RubyOneofDescriptor.createRubyOneofDescriptor(ruby); RubyOneofBuilderContext.createRubyOneofBuilderContext(ruby); return true; } }