Пример #1
0
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;
}
Пример #2
0
/*
 * 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);

  int index = index_position(_index, self);
  if (index < 0 || index >= (INT_MAX - 1)) {
    return Qnil;
  }
  if (index >= self->size) {
    RepeatedField_reserve(self, index + 1);
    upb_fieldtype_t field_type = self->field_type;
    int element_size = native_slot_size(field_type);
    for (int i = self->size; i <= index; i++) {
      void* elem = (void *)(((uint8_t *)self->elements) + i * element_size);
      native_slot_init(field_type, elem);
    }
    self->size = index + 1;
  }

  void* memory = (void *) (((uint8_t *)self->elements) + index * element_size);
  native_slot_set(field_type, field_type_class, memory, val);
  return Qnil;
}
Пример #3
0
void layout_clear(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 (field_contains_hasbit(layout, field)) {
    slot_clear_hasbit(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_set(upb_fielddef_name(field),
                    upb_fielddef_type(field), field_type_class(field),
                    memory, layout_get_default(field));
  }
}
Пример #4
0
/*
 * 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);
  RepeatedField_reserve(self, self->size + 1);
  int index = self->size;
  void* memory = (void *) (((uint8_t *)self->elements) + index * element_size);
  native_slot_set(field_type, self->field_type_class, memory, val);
  // native_slot_set may raise an error; bump index only after set.
  self->size++;
  return _self;
}
Пример #5
0
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_name(field),
          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_name(field),
                    upb_fielddef_type(field), field_type_class(field),
                    memory, val);
  }

  if (layout->fields[upb_fielddef_index(field)].hasbit !=
      MESSAGE_FIELD_NO_HASBIT) {
    slot_set_hasbit(layout, storage, field);
  }
}
Пример #6
0
/*
 * 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;
    table_key(self, key, keybuf, &keyval, &length);

    upb_value v;
    void* 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;
}