예제 #1
0
파일: message.c 프로젝트: hack0303/protobuf
int Message_initialize_kwarg(VALUE key, VALUE val, VALUE _self) {
  MessageHeader* self;
  char *name;
  const upb_fielddef* f;
  TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);

  if (TYPE(key) == T_STRING) {
    name = RSTRING_PTR(key);
  } else if (TYPE(key) == T_SYMBOL) {
    name = RSTRING_PTR(rb_id2str(SYM2ID(key)));
  } else {
    rb_raise(rb_eArgError,
             "Expected string or symbols as hash keys when initializing proto from hash.");
  }

  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 (TYPE(val) == T_NIL) {
    return 0;
  }

  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++) {
      VALUE entry = rb_ary_entry(val, i);
      if (TYPE(entry) == T_HASH && upb_fielddef_issubmsg(f)) {
        entry = create_submsg_from_hash(f, entry);
      }

      RepeatedField_push(ary, entry);
    }
  } else {
    if (TYPE(val) == T_HASH && upb_fielddef_issubmsg(f)) {
      val = create_submsg_from_hash(f, val);
    }

    layout_set(self->descriptor->layout, Message_data(self), f, val);
  }
  return 0;
}
예제 #2
0
파일: message.c 프로젝트: 1nf1corp/protobuf
/*
 * 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--;
  }

  // Check for a oneof name first.
  o = upb_msgdef_ntoo(self->descriptor->msgdef,
                                          name, name_len);
  if (o != NULL) {
    if (setter) {
      rb_raise(rb_eRuntimeError, "Oneof accessors are read-only.");
    }
    return which_oneof_field(self, o);
  }

  // Otherwise, check for a field with that name.
  f = upb_msgdef_ntof(self->descriptor->msgdef,
                                          name, name_len);

  if (f == NULL) {
    return rb_call_super(argc, argv);
  }

  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);
  }
}
예제 #3
0
파일: defs.c 프로젝트: Overruler/protobuf
/*
 * 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;
}
예제 #4
0
파일: message.c 프로젝트: goodleon/protobuf
/*
 * 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;
  TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
  Check_Type(field_name, T_STRING);
  const upb_fielddef* 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;
}
예제 #5
0
파일: message.c 프로젝트: hack0303/protobuf
/*
 * call-seq:
 *     Message.method_missing(*args)
 *
 * Provides accessors and setters and methods to clear and check for presence of
 * 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.
 *
 * It also provides methods of the form 'clear_fieldname' to clear the value
 * of the field 'fieldname'. For basic data types, this will set the default
 * value of the field.
 *
 * Additionally, it provides methods of the form 'has_fieldname?', which returns
 * true if the field 'fieldname' is set in the message object, else false. For
 * 'proto3' syntax, calling this for a basic type field will result in an error.
 */
VALUE Message_method_missing(int argc, VALUE* argv, VALUE _self) {
  MessageHeader* self;
  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.");
  }

  int accessor_type = extract_method_call(argv[0], self, &f, &o);
  if (accessor_type == METHOD_UNKNOWN || (o == NULL && f == NULL) ) {
    return rb_call_super(argc, argv);
  } else if (accessor_type == METHOD_SETTER) {
    if (argc != 2) {
      rb_raise(rb_eArgError, "Expected 2 arguments, received %d", argc);
    }
  } else if (argc != 1) {
    rb_raise(rb_eArgError, "Expected 1 argument, received %d", argc);
  }

  // Return which of the oneof fields are set
  if (o != NULL) {
    if (accessor_type == METHOD_SETTER) {
      rb_raise(rb_eRuntimeError, "Oneof accessors are read-only.");
    }

    const upb_fielddef* oneof_field = which_oneof_field(self, o);
    if (accessor_type == METHOD_PRESENCE) {
      return oneof_field == NULL ? Qfalse : Qtrue;
    } else if (accessor_type == METHOD_CLEAR) {
      if (oneof_field != NULL) {
	layout_clear(self->descriptor->layout, Message_data(self), oneof_field);
      }
      return Qnil;
    } else {
      // METHOD_ACCESSOR
      return oneof_field == NULL ? Qnil :
	ID2SYM(rb_intern(upb_fielddef_name(oneof_field)));
    }
  // Otherwise we're operating on a single proto field
  } else if (accessor_type == METHOD_SETTER) {
    layout_set(self->descriptor->layout, Message_data(self), f, argv[1]);
    return Qnil;
  } else if (accessor_type == METHOD_CLEAR) {
    layout_clear(self->descriptor->layout, Message_data(self), f);
    return Qnil;
  } else if (accessor_type == METHOD_PRESENCE) {
    return layout_has(self->descriptor->layout, Message_data(self), f);
  } else {
    return layout_get(self->descriptor->layout, Message_data(self), f);
  }
}
예제 #6
0
파일: message.c 프로젝트: 1nf1corp/protobuf
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;
}