Esempio n. 1
0
File: test_def.c Progetto: atdt/upb
static void test_mapentry_check() {
  upb_status s = UPB_STATUS_INIT;
  upb_msgdef *m = upb_msgdef_new(&m);
  upb_fielddef *f = upb_fielddef_new(&f);
  upb_symtab *symtab = upb_symtab_new(&symtab);
  upb_msgdef *subm = upb_msgdef_new(&subm);
  upb_def *defs[2];

  upb_msgdef_setfullname(m, "TestMessage", &s);
  upb_fielddef_setname(f, "field1", &s);
  upb_fielddef_setnumber(f, 1, &s);
  upb_fielddef_setlabel(f, UPB_LABEL_OPTIONAL);
  upb_fielddef_settype(f, UPB_TYPE_MESSAGE);
  upb_fielddef_setsubdefname(f, ".MapEntry", &s);
  upb_msgdef_addfield(m, f, &f, &s);
  ASSERT(upb_ok(&s));

  upb_msgdef_setfullname(subm, "MapEntry", &s);
  upb_msgdef_setmapentry(subm, true);

  defs[0] = upb_msgdef_upcast_mutable(m);
  defs[1] = upb_msgdef_upcast_mutable(subm);
  upb_symtab_add(symtab, defs, 2, NULL, &s);
  /* Should not have succeeded: non-repeated field pointing to a MapEntry. */
  ASSERT(!upb_ok(&s));

  upb_fielddef_setlabel(f, UPB_LABEL_REPEATED);
  upb_symtab_add(symtab, defs, 2, NULL, &s);
  ASSERT(upb_ok(&s));

  upb_symtab_unref(symtab, &symtab);
  upb_msgdef_unref(subm, &subm);
  upb_msgdef_unref(m, &m);
}
Esempio n. 2
0
File: test_def.c Progetto: atdt/upb
static void test_descriptor_flags() {
  upb_msgdef *m = upb_msgdef_new(&m);
  upb_msgdef *m2;
  upb_status s = UPB_STATUS_INIT;

  ASSERT(upb_msgdef_mapentry(m) == false);
  upb_msgdef_setfullname(m, "TestMessage", &s);
  ASSERT(upb_ok(&s));
  upb_msgdef_setmapentry(m, true);
  ASSERT(upb_msgdef_mapentry(m) == true);
  m2 = upb_msgdef_dup(m, &m2);
  ASSERT(upb_msgdef_mapentry(m2) == true);
  upb_msgdef_unref(m, &m);
  upb_msgdef_unref(m2, &m2);
}
Esempio n. 3
0
/*
 * 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);

  if (argc < 4) {
    rb_raise(rb_eArgError, "Expected at least 4 arguments.");
  }
  VALUE name = argv[0];
  VALUE key_type = argv[1];
  VALUE value_type = argv[2];
  VALUE number = argv[3];
  VALUE 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.
  VALUE mapentry_desc = rb_class_new_instance(0, NULL, cDescriptor);
  VALUE 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 <type> 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 <type> 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 name 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)));
  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")));
  VALUE 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;
}