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); bool field_set; if (field_contains_hasbit(layout, field)) { field_set = slot_is_hasbit_set(layout, storage, field); } else { field_set = true; } if (upb_fielddef_containingoneof(field)) { if (*oneof_case != upb_fielddef_number(field)) { return layout_get_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 if (!field_set) { return layout_get_default(field); } else { return native_slot_get(upb_fielddef_type(field), field_type_class(field), memory); } }
// 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); free(frame); return true; }
/* * 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; }
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); }
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 Qnil; } 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); } }
/* * call-seq: * RepeatedField.pop => value * * Removes the last element and returns it. Throws an exception if the repeated * field is empty. */ VALUE RepeatedField_pop(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); if (self->size == 0) { rb_raise(rb_eRangeError, "Pop from empty repeated field is not allowed."); } int index = self->size - 1; void* memory = (void *) (((uint8_t *)self->elements) + index * element_size); VALUE ret = native_slot_get(field_type, field_type_class, memory); self->size--; return ret; }
/* * 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.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; }
/* * 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); if (self->size == 0) { return Qnil; } int index = self->size - 1; void* memory = (void *) (((uint8_t *)self->elements) + index * element_size); VALUE ret = native_slot_get(field_type, field_type_class, memory); self->size--; return ret; }
/* * call-seq: * RepeatedField.[](index) => value * * Accesses the element at the given index. Returns nil on out-of-bounds */ VALUE RepeatedField_index(VALUE _self, VALUE _index) { 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; int index = index_position(_index, self); if (index < 0 || index >= self->size) { return Qnil; } void* memory = (void *) (((uint8_t *)self->elements) + index * element_size); return native_slot_get(field_type, field_type_class, memory); }
/* * call-seq: * RepeatedField.[](index) => value * * Accesses the element at the given index. Throws an exception on out-of-bounds * errors. */ VALUE RepeatedField_index(VALUE _self, VALUE _index) { 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; int index = NUM2INT(_index); if (index < 0 || index >= self->size) { rb_raise(rb_eRangeError, "Index out of range"); } void* memory = (void *) (((uint8_t *)self->elements) + index * element_size); return native_slot_get(field_type, field_type_class, memory); }
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: * 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: * 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 */ int index = index_position(argv[0], self); if (index < 0 || index >= self->size) { return Qnil; } void* memory = (void *) (((uint8_t *)self->elements) + index * element_size); return native_slot_get(field_type, field_type_class, memory); }else{ /* check if idx is Range */ size_t off; 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.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); VALUE hash = LL2NUM(0); 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); hash = rb_funcall(hash, rb_intern("<<"), 1, INT2NUM(2)); hash = rb_funcall(hash, rb_intern("^"), 1, rb_funcall(elem, rb_intern("hash"), 0)); } return hash; }
/* * 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.to_h => {} * * Returns a Ruby Hash object containing all the values within the map */ VALUE Map_to_h(VALUE _self) { Map* self = ruby_to_Map(_self); VALUE hash = rb_hash_new(); upb_strtable_iter it; for (upb_strtable_begin(&it, &self->table); !upb_strtable_done(&it); upb_strtable_next(&it)) { VALUE key = table_key_to_ruby( self, upb_strtable_iter_key(&it), upb_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 (self->value_type == UPB_TYPE_MESSAGE) { value = Message_to_h(value); } rb_hash_aset(hash, key, value); } return hash; }
/* * 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; }
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; } }