class Google::Protobuf::RepeatedField
Attributes
Public Class Methods
Source
# File lib/google/protobuf/ffi/repeated_field.rb, line 380 def self.construct_for_field(field, arena: nil, values: nil, array: nil) instance = allocate options = {initial_values: values, name: field.name, arena: arena, array: array} if [:enum, :message].include? field.type options[:descriptor] = field.subtype end instance.send(:initialize, field.type, **options) instance end
Constructor that uses the type information from the given FieldDescriptor
to configure the new RepeatedField
instance. @param field [FieldDescriptor] Type information for the new RepeatedField
@param arena [Arena] Owning message’s arena @param values [Enumerable] Initial values @param array [::FFI::Pointer] Existing upb_Array
Source
# File lib/google/protobuf/ffi/repeated_field.rb, line 396 def self.deep_copy(repeated_field) instance = allocate instance.send(:initialize, repeated_field.send(:type), descriptor: repeated_field.send(:descriptor)) instance.send(:resize, repeated_field.length) new_array = instance.send(:array) repeated_field.send(:each_msg_val_with_index) do |element, i| Google::Protobuf::FFI.array_set(new_array, i, message_value_deep_copy(element, repeated_field.send(:type), repeated_field.send(:descriptor), instance.send(:arena))) end instance end
Source
# File lib/google/protobuf/ffi/repeated_field.rb, line 50 def self.new(type, type_class = nil, initial_values = []) instance = allocate # TODO This argument mangling doesn't agree with the type signature in the comments # but is required to make unit tests pass; if type_class.is_a?(Enumerable) and initial_values.empty? and ![:enum, :message].include?(type) initial_values = type_class type_class = nil end instance.send(:initialize, type, type_class: type_class, initial_values: initial_values) instance end
Creates a new repeated field. The provided type must be a Ruby symbol, and an 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.
Source
# File lib/google/protobuf/ffi/repeated_field.rb, line 342 def initialize(type, type_class: nil, initial_values: nil, name: nil, arena: nil, array: nil, descriptor: nil) @name = name || 'RepeatedField' raise ArgumentError.new "Expected argument type to be a Symbol" unless type.is_a? Symbol field_number = Google::Protobuf::FFI::FieldType[type] raise ArgumentError.new "Unsupported type '#{type}'" if field_number.nil? if !descriptor.nil? @descriptor = descriptor elsif [:message, :enum].include? type raise ArgumentError.new "Expected at least 2 arguments for message/enum." if type_class.nil? descriptor = type_class.respond_to?(:descriptor) ? type_class.descriptor : nil raise ArgumentError.new "Type class #{type_class} has no descriptor. Please pass a class or enum as returned by the DescriptorPool." if descriptor.nil? @descriptor = descriptor else @descriptor = nil end @type = type @arena = arena || Google::Protobuf::FFI.create_arena @array = array || Google::Protobuf::FFI.create_array(@arena, @type) unless initial_values.nil? unless initial_values.is_a? Enumerable raise ArgumentError.new "Expected array as initializer value for repeated field '#{name}' (given #{initial_values.class})." end internal_push(*initial_values) end # Should always be the last expression of the initializer to avoid # leaking references to this object before construction is complete. OBJECT_CACHE.try_add(@array.address, self) end
Private Class Methods
Source
# File lib/google/protobuf/repeated_field.rb, line 103 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
Source
# File lib/google/protobuf/repeated_field.rb, line 115 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
Public Instance Methods
Source
# File lib/google/protobuf/ffi/repeated_field.rb, line 260 def +(other) if other.is_a? RepeatedField if type != other.instance_variable_get(:@type) or descriptor != other.instance_variable_get(:@descriptor) raise ArgumentError.new "Attempt to append RepeatedField with different element type." end fuse_arena(other.send(:arena)) super_set = dup other.send(:each_msg_val) do |msg_val| super_set.send(:append_msg_val, msg_val) end super_set elsif other.is_a? Enumerable super_set = dup super_set.push(*other.to_a) else raise ArgumentError.new "Unknown type appending to RepeatedField" end end
Source
# File lib/google/protobuf/ffi/repeated_field.rb, line 157 def <<(element) raise FrozenError if frozen? push element end
Source
# File lib/google/protobuf/ffi/repeated_field.rb, line 221 def ==(other) return true if other.object_id == object_id if other.is_a? RepeatedField return false unless other.length == length each_msg_val_with_index do |msg_val, i| other_msg_val = Google::Protobuf::FFI.get_msgval_at(other.send(:array), i) unless Google::Protobuf::FFI.message_value_equal(msg_val, other_msg_val, type, descriptor) return false end end return true elsif other.is_a? Enumerable return to_ary == other.to_a end false end
Source
# File lib/google/protobuf/ffi/repeated_field.rb, line 76 def [](*args) count = length if args.size < 1 raise ArgumentError.new "Index or range is a required argument." end if args[0].is_a? Range if args.size > 1 raise ArgumentError.new "Expected 1 when passing Range argument, but got #{args.size}" end range = args[0] # Handle begin-less and/or endless ranges, when supported. index_of_first = range.respond_to?(:begin) ? range.begin : range.last index_of_first = 0 if index_of_first.nil? end_of_range = range.respond_to?(:end) ? range.end : range.last index_of_last = end_of_range.nil? ? -1 : end_of_range if index_of_last < 0 index_of_last += count end unless range.exclude_end? and !end_of_range.nil? index_of_last += 1 end index_of_first += count if index_of_first < 0 length = index_of_last - index_of_first return [] if length.zero? elsif args[0].is_a? Integer index_of_first = args[0] index_of_first += count if index_of_first < 0 if args.size > 2 raise ArgumentError.new "Expected 1 or 2 arguments, but got #{args.size}" end if args.size == 1 # No length specified, return one element if array.null? or index_of_first < 0 or index_of_first >= count return nil else return convert_upb_to_ruby(Google::Protobuf::FFI.get_msgval_at(array, index_of_first), type, descriptor, arena) end else length = [args[1],count].min end else raise NotImplementedError end if array.null? or index_of_first < 0 or index_of_first >= count nil else if index_of_first + length > count length = count - index_of_first end if length < 0 nil else subarray(index_of_first, length) end end end
Source
# File lib/google/protobuf/ffi/repeated_field.rb, line 136 def []=(index, value) raise FrozenError if frozen? count = length index += count if index < 0 return nil if index < 0 if index >= count resize(index+1) empty_message_value = Google::Protobuf::FFI::MessageValue.new # Implicitly clear count.upto(index-1) do |i| Google::Protobuf::FFI.array_set(array, i, empty_message_value) end end Google::Protobuf::FFI.array_set(array, index, convert_ruby_to_upb(value, arena, type, descriptor)) nil end
Source
# File lib/google/protobuf/ffi/repeated_field.rb, line 168 def clear raise FrozenError if frozen? resize 0 self end
Source
# File lib/google/protobuf/ffi/repeated_field.rb, line 279 def concat(other) raise ArgumentError.new "Expected Enumerable, but got #{other.class}" unless other.is_a? Enumerable push(*other.to_a) end
Source
# File lib/google/protobuf/ffi/repeated_field.rb, line 211 def dup instance = self.class.allocate instance.send(:initialize, type, descriptor: descriptor, arena: arena) each_msg_val do |element| instance.send(:append_msg_val, element) end instance end
Source
# File lib/google/protobuf/ffi/repeated_field.rb, line 69 def each &block each_msg_val do |element| yield(convert_upb_to_ruby(element, type, descriptor, arena)) end self end
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.
Source
# File lib/google/protobuf/repeated_field.rb, line 92 def empty? self.size == 0 end
Source
# File lib/google/protobuf/repeated_field.rb, line 58 def first(n=nil) if n.nil? return self[0] elsif n < 0 raise ArgumentError, "negative array size" else return self[0...n] end end
Source
# File lib/google/protobuf/ffi/repeated_field.rb, line 197 def freeze if method(:frozen?).super_method.call unless Google::Protobuf::FFI.array_frozen? array raise RuntimeError.new "Underlying representation of repeated field still mutable despite frozen wrapper" end return self end unless Google::Protobuf::FFI.array_frozen? array mini_table = (type == :message) ? Google::Protobuf::FFI.get_mini_table(@descriptor) : nil Google::Protobuf::FFI.array_freeze(array, mini_table) end super end
Freezes the RepeatedField
object. We have to intercept this so we can freeze the underlying representation, not just the Ruby wrapper. Returns self.
Source
# File lib/google/protobuf/ffi/repeated_field.rb, line 184 def frozen? unless Google::Protobuf::FFI.array_frozen? array raise RuntimeError.new "Ruby frozen RepeatedField with mutable representation" if super return false end method(:freeze).super_method.call unless super true end
Is this object frozen? Returns true if either this Ruby wrapper or the underlying representation are frozen. Freezes the wrapper if the underlying representation is already frozen but this wrapper isn’t.
Source
# File lib/google/protobuf/ffi/repeated_field.rb, line 252 def hash return_value = 0 each_msg_val do |msg_val| return_value = Google::Protobuf::FFI.message_value_hash(msg_val, type, descriptor, return_value) end return_value end
Source
# File lib/google/protobuf/repeated_field.rb, line 69 def last(n=nil) if n.nil? return self[-1] elsif n < 0 raise ArgumentError, "negative array size" else start = [self.size-n, 0].max return self[start...self.size] end end
Source
# File lib/google/protobuf/ffi/repeated_field.rb, line 174 def length array.null? ? 0 : Google::Protobuf::FFI.array_size(array) end
Source
# File lib/google/protobuf/repeated_field.rb, line 81 def pop(n=nil) if n results = [] n.times{ results << pop_one } return results else return pop_one end end
Source
# File lib/google/protobuf/ffi/repeated_field.rb, line 152 def push(*elements) raise FrozenError if frozen? internal_push(*elements) end
Source
# File lib/google/protobuf/ffi/repeated_field.rb, line 162 def replace(replacements) raise FrozenError if frozen? clear push(*replacements) end
Source
# File lib/google/protobuf/ffi/repeated_field.rb, line 244 def to_ary return_value = [] each do |element| return_value << element end return_value end
Used when converted implicitly into array, e.g. compared to an Array. Also called as a fallback of Object#to_a
Private Instance Methods
Source
# File lib/google/protobuf/ffi/repeated_field.rb, line 329 def append_msg_val(msg_val) unless Google::Protobuf::FFI.append_array(array, msg_val, arena) raise NoMemoryError.new "Could not allocate room for #{msg_val} in Arena" end end
@param msg_val [Google::Protobuf::FFI::MessageValue] Value to append
Source
# File lib/google/protobuf/ffi/repeated_field.rb, line 322 def each_msg_val &block each_msg_val_with_index do |msg_val, _| yield msg_val end end
Source
# File lib/google/protobuf/ffi/repeated_field.rb, line 315 def each_msg_val_with_index &block n = array.null? ? 0 : Google::Protobuf::FFI.array_size(array) 0.upto(n-1) do |i| yield Google::Protobuf::FFI.get_msgval_at(array, i), i end end
Source
# File lib/google/protobuf/ffi/repeated_field.rb, line 390 def fuse_arena(arena) arena.fuse(arena) end
Source
# File lib/google/protobuf/ffi/repeated_field.rb, line 289 def internal_push(*elements) elements.each do |element| append_msg_val convert_ruby_to_upb(element, arena, type, descriptor) end self end
Source
# File lib/google/protobuf/ffi/repeated_field.rb, line 296 def pop_one raise FrozenError if frozen? count = length return nil if length.zero? last_element = Google::Protobuf::FFI.get_msgval_at(array, count-1) return_value = convert_upb_to_ruby(last_element, type, descriptor, arena) resize(count-1) return_value end
Source
# File lib/google/protobuf/ffi/repeated_field.rb, line 336 def resize(new_size) unless Google::Protobuf::FFI.array_resize(array, new_size, arena) raise NoMemoryError.new "Array resize to #{new_size} failed!" end end
@param new_size [Integer] New size of the array
Source
# File lib/google/protobuf/ffi/repeated_field.rb, line 306 def subarray(start, length) return_result = [] (start..(start + length - 1)).each do |i| element = Google::Protobuf::FFI.get_msgval_at(array, i) return_result << convert_upb_to_ruby(element, type, descriptor, arena) end return_result end