|
@@ -122,7 +122,7 @@ void DescriptorPool_register(VALUE module) {
|
|
module, "DescriptorPool", rb_cObject);
|
|
module, "DescriptorPool", rb_cObject);
|
|
rb_define_alloc_func(klass, DescriptorPool_alloc);
|
|
rb_define_alloc_func(klass, DescriptorPool_alloc);
|
|
rb_define_method(klass, "add", DescriptorPool_add, 1);
|
|
rb_define_method(klass, "add", DescriptorPool_add, 1);
|
|
- rb_define_method(klass, "build", DescriptorPool_build, 0);
|
|
|
|
|
|
+ rb_define_method(klass, "build", DescriptorPool_build, -1);
|
|
rb_define_method(klass, "lookup", DescriptorPool_lookup, 1);
|
|
rb_define_method(klass, "lookup", DescriptorPool_lookup, 1);
|
|
rb_define_singleton_method(klass, "generated_pool",
|
|
rb_define_singleton_method(klass, "generated_pool",
|
|
DescriptorPool_generated_pool, 0);
|
|
DescriptorPool_generated_pool, 0);
|
|
@@ -181,7 +181,7 @@ VALUE DescriptorPool_add(VALUE _self, VALUE def) {
|
|
* Builder#add_enum within the block as appropriate. This is the recommended,
|
|
* Builder#add_enum within the block as appropriate. This is the recommended,
|
|
* idiomatic way to define new message and enum types.
|
|
* idiomatic way to define new message and enum types.
|
|
*/
|
|
*/
|
|
-VALUE DescriptorPool_build(VALUE _self) {
|
|
|
|
|
|
+VALUE DescriptorPool_build(int argc, VALUE* argv, VALUE _self) {
|
|
VALUE ctx = rb_class_new_instance(0, NULL, cBuilder);
|
|
VALUE ctx = rb_class_new_instance(0, NULL, cBuilder);
|
|
VALUE block = rb_block_proc();
|
|
VALUE block = rb_block_proc();
|
|
rb_funcall_with_block(ctx, rb_intern("instance_eval"), 0, NULL, block);
|
|
rb_funcall_with_block(ctx, rb_intern("instance_eval"), 0, NULL, block);
|
|
@@ -289,6 +289,7 @@ void Descriptor_register(VALUE module) {
|
|
VALUE klass = rb_define_class_under(
|
|
VALUE klass = rb_define_class_under(
|
|
module, "Descriptor", rb_cObject);
|
|
module, "Descriptor", rb_cObject);
|
|
rb_define_alloc_func(klass, Descriptor_alloc);
|
|
rb_define_alloc_func(klass, Descriptor_alloc);
|
|
|
|
+ rb_define_method(klass, "initialize", Descriptor_initialize, 1);
|
|
rb_define_method(klass, "each", Descriptor_each, 0);
|
|
rb_define_method(klass, "each", Descriptor_each, 0);
|
|
rb_define_method(klass, "lookup", Descriptor_lookup, 1);
|
|
rb_define_method(klass, "lookup", Descriptor_lookup, 1);
|
|
rb_define_method(klass, "add_field", Descriptor_add_field, 1);
|
|
rb_define_method(klass, "add_field", Descriptor_add_field, 1);
|
|
@@ -298,11 +299,42 @@ void Descriptor_register(VALUE module) {
|
|
rb_define_method(klass, "msgclass", Descriptor_msgclass, 0);
|
|
rb_define_method(klass, "msgclass", Descriptor_msgclass, 0);
|
|
rb_define_method(klass, "name", Descriptor_name, 0);
|
|
rb_define_method(klass, "name", Descriptor_name, 0);
|
|
rb_define_method(klass, "name=", Descriptor_name_set, 1);
|
|
rb_define_method(klass, "name=", Descriptor_name_set, 1);
|
|
|
|
+ rb_define_method(klass, "file_descriptor", Descriptor_file_descriptor, 0);
|
|
rb_include_module(klass, rb_mEnumerable);
|
|
rb_include_module(klass, rb_mEnumerable);
|
|
rb_gc_register_address(&cDescriptor);
|
|
rb_gc_register_address(&cDescriptor);
|
|
cDescriptor = klass;
|
|
cDescriptor = klass;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/*
|
|
|
|
+ * call-seq:
|
|
|
|
+ * Descriptor.new(file_descriptor)
|
|
|
|
+ *
|
|
|
|
+ * Initializes a new descriptor and assigns a file descriptor to it.
|
|
|
|
+ */
|
|
|
|
+VALUE Descriptor_initialize(VALUE _self, VALUE file_descriptor_rb) {
|
|
|
|
+ DEFINE_SELF(Descriptor, self, _self);
|
|
|
|
+
|
|
|
|
+ FileDescriptor* file_descriptor = ruby_to_FileDescriptor(file_descriptor_rb);
|
|
|
|
+
|
|
|
|
+ CHECK_UPB(
|
|
|
|
+ upb_filedef_addmsg(file_descriptor->filedef, self->msgdef, NULL, &status),
|
|
|
|
+ "Failed to associate message to file descriptor.");
|
|
|
|
+ add_def_obj(file_descriptor->filedef, file_descriptor_rb);
|
|
|
|
+
|
|
|
|
+ return Qnil;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/*
|
|
|
|
+ * call-seq:
|
|
|
|
+ * Descriptor.file_descriptor
|
|
|
|
+ *
|
|
|
|
+ * Returns the FileDescriptor object this message belongs to.
|
|
|
|
+ */
|
|
|
|
+VALUE Descriptor_file_descriptor(VALUE _self) {
|
|
|
|
+ DEFINE_SELF(Descriptor, self, _self);
|
|
|
|
+ return get_def_obj(upb_def_file(self->msgdef));
|
|
|
|
+}
|
|
|
|
+
|
|
/*
|
|
/*
|
|
* call-seq:
|
|
* call-seq:
|
|
* Descriptor.name => name
|
|
* Descriptor.name => name
|
|
@@ -470,6 +502,142 @@ VALUE Descriptor_msgclass(VALUE _self) {
|
|
return self->klass;
|
|
return self->klass;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+// -----------------------------------------------------------------------------
|
|
|
|
+// FileDescriptor.
|
|
|
|
+// -----------------------------------------------------------------------------
|
|
|
|
+
|
|
|
|
+DEFINE_CLASS(FileDescriptor, "Google::Protobuf::FileDescriptor");
|
|
|
|
+
|
|
|
|
+void FileDescriptor_mark(void* _self) {
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void FileDescriptor_free(void* _self) {
|
|
|
|
+ FileDescriptor* self = _self;
|
|
|
|
+ upb_filedef_unref(self->filedef, &self->filedef);
|
|
|
|
+ xfree(self);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/*
|
|
|
|
+ * call-seq:
|
|
|
|
+ * FileDescriptor.new => file
|
|
|
|
+ *
|
|
|
|
+ * Returns a new file descriptor. The syntax must be set before it's passed
|
|
|
|
+ * to a builder.
|
|
|
|
+ */
|
|
|
|
+VALUE FileDescriptor_alloc(VALUE klass) {
|
|
|
|
+ FileDescriptor* self = ALLOC(FileDescriptor);
|
|
|
|
+ VALUE ret = TypedData_Wrap_Struct(klass, &_FileDescriptor_type, self);
|
|
|
|
+ upb_filedef* filedef = upb_filedef_new(&self->filedef);
|
|
|
|
+ self->filedef = filedef;
|
|
|
|
+ return ret;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void FileDescriptor_register(VALUE module) {
|
|
|
|
+ VALUE klass = rb_define_class_under(
|
|
|
|
+ module, "FileDescriptor", rb_cObject);
|
|
|
|
+ rb_define_alloc_func(klass, FileDescriptor_alloc);
|
|
|
|
+ rb_define_method(klass, "initialize", FileDescriptor_initialize, -1);
|
|
|
|
+ rb_define_method(klass, "name", FileDescriptor_name, 0);
|
|
|
|
+ rb_define_method(klass, "syntax", FileDescriptor_syntax, 0);
|
|
|
|
+ rb_define_method(klass, "syntax=", FileDescriptor_syntax_set, 1);
|
|
|
|
+ cFileDescriptor = klass;
|
|
|
|
+ rb_gc_register_address(&cFileDescriptor);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/*
|
|
|
|
+ * call-seq:
|
|
|
|
+ * FileDescriptor.new(name, options = nil) => file
|
|
|
|
+ *
|
|
|
|
+ * Initializes a new file descriptor with the given file name.
|
|
|
|
+ * Also accepts an optional "options" hash, specifying other optional
|
|
|
|
+ * metadata about the file. The options hash currently accepts the following
|
|
|
|
+ * * "syntax": :proto2 or :proto3 (default: :proto3)
|
|
|
|
+ */
|
|
|
|
+VALUE FileDescriptor_initialize(int argc, VALUE* argv, VALUE _self) {
|
|
|
|
+ DEFINE_SELF(FileDescriptor, self, _self);
|
|
|
|
+
|
|
|
|
+ VALUE name_rb;
|
|
|
|
+ VALUE options = Qnil;
|
|
|
|
+ rb_scan_args(argc, argv, "11", &name_rb, &options);
|
|
|
|
+
|
|
|
|
+ if (name_rb != Qnil) {
|
|
|
|
+ Check_Type(name_rb, T_STRING);
|
|
|
|
+ const char* name = get_str(name_rb);
|
|
|
|
+ CHECK_UPB(upb_filedef_setname(self->filedef, name, &status),
|
|
|
|
+ "Error setting file name");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // Default syntax is proto3.
|
|
|
|
+ VALUE syntax = ID2SYM(rb_intern("proto3"));
|
|
|
|
+ if (options != Qnil) {
|
|
|
|
+ Check_Type(options, T_HASH);
|
|
|
|
+
|
|
|
|
+ if (rb_funcall(options, rb_intern("key?"), 1,
|
|
|
|
+ ID2SYM(rb_intern("syntax"))) == Qtrue) {
|
|
|
|
+ syntax = rb_hash_lookup(options, ID2SYM(rb_intern("syntax")));
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ FileDescriptor_syntax_set(_self, syntax);
|
|
|
|
+
|
|
|
|
+ return Qnil;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/*
|
|
|
|
+ * call-seq:
|
|
|
|
+ * FileDescriptor.name => name
|
|
|
|
+ *
|
|
|
|
+ * Returns the name of the file.
|
|
|
|
+ */
|
|
|
|
+VALUE FileDescriptor_name(VALUE _self) {
|
|
|
|
+ DEFINE_SELF(FileDescriptor, self, _self);
|
|
|
|
+ const char* name = upb_filedef_name(self->filedef);
|
|
|
|
+ return name == NULL ? Qnil : rb_str_new2(name);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/*
|
|
|
|
+ * call-seq:
|
|
|
|
+ * FileDescriptor.syntax => syntax
|
|
|
|
+ *
|
|
|
|
+ * Returns this file descriptors syntax.
|
|
|
|
+ *
|
|
|
|
+ * Valid syntax versions are:
|
|
|
|
+ * :proto2 or :proto3.
|
|
|
|
+ */
|
|
|
|
+VALUE FileDescriptor_syntax(VALUE _self) {
|
|
|
|
+ DEFINE_SELF(FileDescriptor, self, _self);
|
|
|
|
+
|
|
|
|
+ switch (upb_filedef_syntax(self->filedef)) {
|
|
|
|
+ case UPB_SYNTAX_PROTO3: return ID2SYM(rb_intern("proto3"));
|
|
|
|
+ case UPB_SYNTAX_PROTO2: return ID2SYM(rb_intern("proto2"));
|
|
|
|
+ default: return Qnil;
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/*
|
|
|
|
+ * call-seq:
|
|
|
|
+ * FileDescriptor.syntax = version
|
|
|
|
+ *
|
|
|
|
+ * Sets this file descriptor's syntax, can be :proto3 or :proto2.
|
|
|
|
+ */
|
|
|
|
+VALUE FileDescriptor_syntax_set(VALUE _self, VALUE syntax_rb) {
|
|
|
|
+ DEFINE_SELF(FileDescriptor, self, _self);
|
|
|
|
+ Check_Type(syntax_rb, T_SYMBOL);
|
|
|
|
+
|
|
|
|
+ upb_syntax_t syntax;
|
|
|
|
+ if (SYM2ID(syntax_rb) == rb_intern("proto3")) {
|
|
|
|
+ syntax = UPB_SYNTAX_PROTO3;
|
|
|
|
+ } else if (SYM2ID(syntax_rb) == rb_intern("proto2")) {
|
|
|
|
+ syntax = UPB_SYNTAX_PROTO2;
|
|
|
|
+ } else {
|
|
|
|
+ rb_raise(rb_eArgError, "Expected :proto3 or :proto3, received '%s'",
|
|
|
|
+ rb_id2name(SYM2ID(syntax_rb)));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ CHECK_UPB(upb_filedef_setsyntax(self->filedef, syntax, &status),
|
|
|
|
+ "Error setting file syntax for proto");
|
|
|
|
+ return Qnil;
|
|
|
|
+}
|
|
|
|
+
|
|
// -----------------------------------------------------------------------------
|
|
// -----------------------------------------------------------------------------
|
|
// FieldDescriptor.
|
|
// FieldDescriptor.
|
|
// -----------------------------------------------------------------------------
|
|
// -----------------------------------------------------------------------------
|
|
@@ -509,6 +677,8 @@ void FieldDescriptor_register(VALUE module) {
|
|
rb_define_method(klass, "name=", FieldDescriptor_name_set, 1);
|
|
rb_define_method(klass, "name=", FieldDescriptor_name_set, 1);
|
|
rb_define_method(klass, "type", FieldDescriptor_type, 0);
|
|
rb_define_method(klass, "type", FieldDescriptor_type, 0);
|
|
rb_define_method(klass, "type=", FieldDescriptor_type_set, 1);
|
|
rb_define_method(klass, "type=", FieldDescriptor_type_set, 1);
|
|
|
|
+ rb_define_method(klass, "default", FieldDescriptor_default, 0);
|
|
|
|
+ rb_define_method(klass, "default=", FieldDescriptor_default_set, 1);
|
|
rb_define_method(klass, "label", FieldDescriptor_label, 0);
|
|
rb_define_method(klass, "label", FieldDescriptor_label, 0);
|
|
rb_define_method(klass, "label=", FieldDescriptor_label_set, 1);
|
|
rb_define_method(klass, "label=", FieldDescriptor_label_set, 1);
|
|
rb_define_method(klass, "number", FieldDescriptor_number, 0);
|
|
rb_define_method(klass, "number", FieldDescriptor_number, 0);
|
|
@@ -516,6 +686,8 @@ void FieldDescriptor_register(VALUE module) {
|
|
rb_define_method(klass, "submsg_name", FieldDescriptor_submsg_name, 0);
|
|
rb_define_method(klass, "submsg_name", FieldDescriptor_submsg_name, 0);
|
|
rb_define_method(klass, "submsg_name=", FieldDescriptor_submsg_name_set, 1);
|
|
rb_define_method(klass, "submsg_name=", FieldDescriptor_submsg_name_set, 1);
|
|
rb_define_method(klass, "subtype", FieldDescriptor_subtype, 0);
|
|
rb_define_method(klass, "subtype", FieldDescriptor_subtype, 0);
|
|
|
|
+ rb_define_method(klass, "has?", FieldDescriptor_has, 1);
|
|
|
|
+ rb_define_method(klass, "clear", FieldDescriptor_clear, 1);
|
|
rb_define_method(klass, "get", FieldDescriptor_get, 1);
|
|
rb_define_method(klass, "get", FieldDescriptor_get, 1);
|
|
rb_define_method(klass, "set", FieldDescriptor_set, 2);
|
|
rb_define_method(klass, "set", FieldDescriptor_set, 2);
|
|
rb_gc_register_address(&cFieldDescriptor);
|
|
rb_gc_register_address(&cFieldDescriptor);
|
|
@@ -691,6 +863,71 @@ VALUE FieldDescriptor_type_set(VALUE _self, VALUE type) {
|
|
return Qnil;
|
|
return Qnil;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/*
|
|
|
|
+ * call-seq:
|
|
|
|
+ * FieldDescriptor.default => default
|
|
|
|
+ *
|
|
|
|
+ * Returns this field's default, as a Ruby object, or nil if not yet set.
|
|
|
|
+ */
|
|
|
|
+VALUE FieldDescriptor_default(VALUE _self) {
|
|
|
|
+ DEFINE_SELF(FieldDescriptor, self, _self);
|
|
|
|
+ return layout_get_default(self->fielddef);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/*
|
|
|
|
+ * call-seq:
|
|
|
|
+ * FieldDescriptor.default = default
|
|
|
|
+ *
|
|
|
|
+ * Sets this field's default value. Raises an exception when calling with
|
|
|
|
+ * proto syntax 3.
|
|
|
|
+ */
|
|
|
|
+VALUE FieldDescriptor_default_set(VALUE _self, VALUE default_value) {
|
|
|
|
+ DEFINE_SELF(FieldDescriptor, self, _self);
|
|
|
|
+ upb_fielddef* mut_def = check_field_notfrozen(self->fielddef);
|
|
|
|
+
|
|
|
|
+ switch (upb_fielddef_type(mut_def)) {
|
|
|
|
+ case UPB_TYPE_FLOAT:
|
|
|
|
+ upb_fielddef_setdefaultfloat(mut_def, NUM2DBL(default_value));
|
|
|
|
+ break;
|
|
|
|
+ case UPB_TYPE_DOUBLE:
|
|
|
|
+ upb_fielddef_setdefaultdouble(mut_def, NUM2DBL(default_value));
|
|
|
|
+ break;
|
|
|
|
+ case UPB_TYPE_BOOL:
|
|
|
|
+ if (!RB_TYPE_P(default_value, T_TRUE) &&
|
|
|
|
+ !RB_TYPE_P(default_value, T_FALSE) &&
|
|
|
|
+ !RB_TYPE_P(default_value, T_NIL)) {
|
|
|
|
+ rb_raise(cTypeError, "Expected boolean for default value.");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ upb_fielddef_setdefaultbool(mut_def, RTEST(default_value));
|
|
|
|
+ break;
|
|
|
|
+ case UPB_TYPE_ENUM:
|
|
|
|
+ case UPB_TYPE_INT32:
|
|
|
|
+ upb_fielddef_setdefaultint32(mut_def, NUM2INT(default_value));
|
|
|
|
+ break;
|
|
|
|
+ case UPB_TYPE_INT64:
|
|
|
|
+ upb_fielddef_setdefaultint64(mut_def, NUM2INT(default_value));
|
|
|
|
+ break;
|
|
|
|
+ case UPB_TYPE_UINT32:
|
|
|
|
+ upb_fielddef_setdefaultuint32(mut_def, NUM2UINT(default_value));
|
|
|
|
+ break;
|
|
|
|
+ case UPB_TYPE_UINT64:
|
|
|
|
+ upb_fielddef_setdefaultuint64(mut_def, NUM2UINT(default_value));
|
|
|
|
+ break;
|
|
|
|
+ case UPB_TYPE_STRING:
|
|
|
|
+ case UPB_TYPE_BYTES:
|
|
|
|
+ CHECK_UPB(upb_fielddef_setdefaultcstr(mut_def, StringValuePtr(default_value),
|
|
|
|
+ &status),
|
|
|
|
+ "Error setting default string");
|
|
|
|
+ break;
|
|
|
|
+ default:
|
|
|
|
+ rb_raise(rb_eArgError, "Defaults not supported on field %s.%s",
|
|
|
|
+ upb_fielddef_fullname(mut_def), upb_fielddef_name(mut_def));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return Qnil;
|
|
|
|
+}
|
|
|
|
+
|
|
/*
|
|
/*
|
|
* call-seq:
|
|
* call-seq:
|
|
* FieldDescriptor.label => label
|
|
* FieldDescriptor.label => label
|
|
@@ -859,6 +1096,44 @@ VALUE FieldDescriptor_get(VALUE _self, VALUE msg_rb) {
|
|
return layout_get(msg->descriptor->layout, Message_data(msg), self->fielddef);
|
|
return layout_get(msg->descriptor->layout, Message_data(msg), self->fielddef);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/*
|
|
|
|
+ * call-seq:
|
|
|
|
+ * FieldDescriptor.has?(message) => boolean
|
|
|
|
+ *
|
|
|
|
+ * Returns whether the value is set on the given message. Raises an
|
|
|
|
+ * exception when calling with proto syntax 3.
|
|
|
|
+ */
|
|
|
|
+VALUE FieldDescriptor_has(VALUE _self, VALUE msg_rb) {
|
|
|
|
+ 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(cTypeError, "has method called on wrong message type");
|
|
|
|
+ } else if (!upb_fielddef_haspresence(self->fielddef)) {
|
|
|
|
+ rb_raise(rb_eArgError, "does not track presence");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return layout_has(msg->descriptor->layout, Message_data(msg), self->fielddef);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/*
|
|
|
|
+ * call-seq:
|
|
|
|
+ * FieldDescriptor.clear(message)
|
|
|
|
+ *
|
|
|
|
+ * Clears the field from the message if it's set.
|
|
|
|
+ */
|
|
|
|
+VALUE FieldDescriptor_clear(VALUE _self, VALUE msg_rb) {
|
|
|
|
+ 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(cTypeError, "has method called on wrong message type");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ layout_clear(msg->descriptor->layout, Message_data(msg), self->fielddef);
|
|
|
|
+ return Qnil;
|
|
|
|
+}
|
|
|
|
+
|
|
/*
|
|
/*
|
|
* call-seq:
|
|
* call-seq:
|
|
* FieldDescriptor.set(message, value)
|
|
* FieldDescriptor.set(message, value)
|
|
@@ -1029,6 +1304,7 @@ void EnumDescriptor_register(VALUE module) {
|
|
VALUE klass = rb_define_class_under(
|
|
VALUE klass = rb_define_class_under(
|
|
module, "EnumDescriptor", rb_cObject);
|
|
module, "EnumDescriptor", rb_cObject);
|
|
rb_define_alloc_func(klass, EnumDescriptor_alloc);
|
|
rb_define_alloc_func(klass, EnumDescriptor_alloc);
|
|
|
|
+ rb_define_method(klass, "initialize", EnumDescriptor_initialize, 1);
|
|
rb_define_method(klass, "name", EnumDescriptor_name, 0);
|
|
rb_define_method(klass, "name", EnumDescriptor_name, 0);
|
|
rb_define_method(klass, "name=", EnumDescriptor_name_set, 1);
|
|
rb_define_method(klass, "name=", EnumDescriptor_name_set, 1);
|
|
rb_define_method(klass, "add_value", EnumDescriptor_add_value, 2);
|
|
rb_define_method(klass, "add_value", EnumDescriptor_add_value, 2);
|
|
@@ -1036,11 +1312,41 @@ void EnumDescriptor_register(VALUE module) {
|
|
rb_define_method(klass, "lookup_value", EnumDescriptor_lookup_value, 1);
|
|
rb_define_method(klass, "lookup_value", EnumDescriptor_lookup_value, 1);
|
|
rb_define_method(klass, "each", EnumDescriptor_each, 0);
|
|
rb_define_method(klass, "each", EnumDescriptor_each, 0);
|
|
rb_define_method(klass, "enummodule", EnumDescriptor_enummodule, 0);
|
|
rb_define_method(klass, "enummodule", EnumDescriptor_enummodule, 0);
|
|
|
|
+ rb_define_method(klass, "file_descriptor", EnumDescriptor_file_descriptor, 0);
|
|
rb_include_module(klass, rb_mEnumerable);
|
|
rb_include_module(klass, rb_mEnumerable);
|
|
rb_gc_register_address(&cEnumDescriptor);
|
|
rb_gc_register_address(&cEnumDescriptor);
|
|
cEnumDescriptor = klass;
|
|
cEnumDescriptor = klass;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/*
|
|
|
|
+ * call-seq:
|
|
|
|
+ * Descriptor.new(file_descriptor)
|
|
|
|
+ *
|
|
|
|
+ * Initializes a new descriptor and assigns a file descriptor to it.
|
|
|
|
+ */
|
|
|
|
+VALUE EnumDescriptor_initialize(VALUE _self, VALUE file_descriptor_rb) {
|
|
|
|
+ DEFINE_SELF(EnumDescriptor, self, _self);
|
|
|
|
+ FileDescriptor* file_descriptor = ruby_to_FileDescriptor(file_descriptor_rb);
|
|
|
|
+ CHECK_UPB(
|
|
|
|
+ upb_filedef_addenum(file_descriptor->filedef, self->enumdef,
|
|
|
|
+ NULL, &status),
|
|
|
|
+ "Failed to associate enum to file descriptor.");
|
|
|
|
+ add_def_obj(file_descriptor->filedef, file_descriptor_rb);
|
|
|
|
+
|
|
|
|
+ return Qnil;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/*
|
|
|
|
+ * call-seq:
|
|
|
|
+ * Descriptor.file_descriptor
|
|
|
|
+ *
|
|
|
|
+ * Returns the FileDescriptor object this enum belongs to.
|
|
|
|
+ */
|
|
|
|
+VALUE EnumDescriptor_file_descriptor(VALUE _self) {
|
|
|
|
+ DEFINE_SELF(EnumDescriptor, self, _self);
|
|
|
|
+ return get_def_obj(upb_def_file(self->enumdef));
|
|
|
|
+}
|
|
|
|
+
|
|
/*
|
|
/*
|
|
* call-seq:
|
|
* call-seq:
|
|
* EnumDescriptor.name => name
|
|
* EnumDescriptor.name => name
|
|
@@ -1223,34 +1529,56 @@ VALUE MessageBuilderContext_initialize(VALUE _self,
|
|
return Qnil;
|
|
return Qnil;
|
|
}
|
|
}
|
|
|
|
|
|
-static VALUE msgdef_add_field(VALUE msgdef,
|
|
|
|
|
|
+static VALUE msgdef_add_field(VALUE msgdef_rb,
|
|
const char* label, VALUE name,
|
|
const char* label, VALUE name,
|
|
VALUE type, VALUE number,
|
|
VALUE type, VALUE number,
|
|
- VALUE type_class) {
|
|
|
|
- VALUE fielddef = rb_class_new_instance(0, NULL, cFieldDescriptor);
|
|
|
|
|
|
+ VALUE type_class,
|
|
|
|
+ VALUE options) {
|
|
|
|
+ VALUE fielddef_rb = rb_class_new_instance(0, NULL, cFieldDescriptor);
|
|
VALUE name_str = rb_str_new2(rb_id2name(SYM2ID(name)));
|
|
VALUE name_str = rb_str_new2(rb_id2name(SYM2ID(name)));
|
|
|
|
|
|
- rb_funcall(fielddef, rb_intern("label="), 1, ID2SYM(rb_intern(label)));
|
|
|
|
- rb_funcall(fielddef, rb_intern("name="), 1, name_str);
|
|
|
|
- rb_funcall(fielddef, rb_intern("type="), 1, type);
|
|
|
|
- rb_funcall(fielddef, rb_intern("number="), 1, number);
|
|
|
|
|
|
+ rb_funcall(fielddef_rb, rb_intern("label="), 1, ID2SYM(rb_intern(label)));
|
|
|
|
+ rb_funcall(fielddef_rb, rb_intern("name="), 1, name_str);
|
|
|
|
+ rb_funcall(fielddef_rb, rb_intern("type="), 1, type);
|
|
|
|
+ rb_funcall(fielddef_rb, rb_intern("number="), 1, number);
|
|
|
|
|
|
if (type_class != Qnil) {
|
|
if (type_class != Qnil) {
|
|
- if (TYPE(type_class) != T_STRING) {
|
|
|
|
- rb_raise(rb_eArgError, "Expected string for type class");
|
|
|
|
- }
|
|
|
|
|
|
+ Check_Type(type_class, T_STRING);
|
|
|
|
+
|
|
// Make it an absolute type name by prepending a dot.
|
|
// Make it an absolute type name by prepending a dot.
|
|
type_class = rb_str_append(rb_str_new2("."), type_class);
|
|
type_class = rb_str_append(rb_str_new2("."), type_class);
|
|
- rb_funcall(fielddef, rb_intern("submsg_name="), 1, type_class);
|
|
|
|
|
|
+ rb_funcall(fielddef_rb, rb_intern("submsg_name="), 1, type_class);
|
|
}
|
|
}
|
|
|
|
|
|
- rb_funcall(msgdef, rb_intern("add_field"), 1, fielddef);
|
|
|
|
- return fielddef;
|
|
|
|
|
|
+ if (options != Qnil) {
|
|
|
|
+ Check_Type(options, T_HASH);
|
|
|
|
+
|
|
|
|
+ if (rb_funcall(options, rb_intern("key?"), 1,
|
|
|
|
+ ID2SYM(rb_intern("default"))) == Qtrue) {
|
|
|
|
+ Descriptor* msgdef = ruby_to_Descriptor(msgdef_rb);
|
|
|
|
+ if (upb_msgdef_syntax((upb_msgdef*)msgdef->msgdef) == UPB_SYNTAX_PROTO3) {
|
|
|
|
+ rb_raise(rb_eArgError, "Cannot set :default when using proto3 syntax.");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ FieldDescriptor* fielddef = ruby_to_FieldDescriptor(fielddef_rb);
|
|
|
|
+ if (!upb_fielddef_haspresence((upb_fielddef*)fielddef->fielddef) ||
|
|
|
|
+ upb_fielddef_issubmsg((upb_fielddef*)fielddef->fielddef)) {
|
|
|
|
+ rb_raise(rb_eArgError, "Cannot set :default on this kind of field.");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ rb_funcall(fielddef_rb, rb_intern("default="), 1,
|
|
|
|
+ rb_hash_lookup(options, ID2SYM(rb_intern("default"))));
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ rb_funcall(msgdef_rb, rb_intern("add_field"), 1, fielddef_rb);
|
|
|
|
+ return fielddef_rb;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
/*
|
|
* call-seq:
|
|
* call-seq:
|
|
- * MessageBuilderContext.optional(name, type, number, type_class = nil)
|
|
|
|
|
|
+ * MessageBuilderContext.optional(name, type, number, type_class = nil,
|
|
|
|
+ * options = nil)
|
|
*
|
|
*
|
|
* Defines a new optional field on this message type with the given type, tag
|
|
* Defines a new optional field on this message type with the given type, tag
|
|
* number, and type class (for message and enum fields). The type must be a Ruby
|
|
* number, and type class (for message and enum fields). The type must be a Ruby
|
|
@@ -1259,23 +1587,26 @@ static VALUE msgdef_add_field(VALUE msgdef,
|
|
*/
|
|
*/
|
|
VALUE MessageBuilderContext_optional(int argc, VALUE* argv, VALUE _self) {
|
|
VALUE MessageBuilderContext_optional(int argc, VALUE* argv, VALUE _self) {
|
|
DEFINE_SELF(MessageBuilderContext, self, _self);
|
|
DEFINE_SELF(MessageBuilderContext, self, _self);
|
|
- VALUE name, type, number, type_class;
|
|
|
|
|
|
+ VALUE name, type, number;
|
|
|
|
+ VALUE type_class, options = Qnil;
|
|
|
|
|
|
- if (argc < 3) {
|
|
|
|
- rb_raise(rb_eArgError, "Expected at least 3 arguments.");
|
|
|
|
|
|
+ rb_scan_args(argc, argv, "32", &name, &type, &number, &type_class, &options);
|
|
|
|
+
|
|
|
|
+ // Allow passing (name, type, number, options) or
|
|
|
|
+ // (name, type, number, type_class, options)
|
|
|
|
+ if (argc == 4 && RB_TYPE_P(type_class, T_HASH)) {
|
|
|
|
+ options = type_class;
|
|
|
|
+ type_class = Qnil;
|
|
}
|
|
}
|
|
- name = argv[0];
|
|
|
|
- type = argv[1];
|
|
|
|
- number = argv[2];
|
|
|
|
- type_class = (argc > 3) ? argv[3] : Qnil;
|
|
|
|
|
|
|
|
return msgdef_add_field(self->descriptor, "optional",
|
|
return msgdef_add_field(self->descriptor, "optional",
|
|
- name, type, number, type_class);
|
|
|
|
|
|
+ name, type, number, type_class, options);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
/*
|
|
* call-seq:
|
|
* call-seq:
|
|
- * MessageBuilderContext.required(name, type, number, type_class = nil)
|
|
|
|
|
|
+ * MessageBuilderContext.required(name, type, number, type_class = nil,
|
|
|
|
+ * options = nil)
|
|
*
|
|
*
|
|
* Defines a new required field on this message type with the given type, tag
|
|
* Defines a new required field on this message type with the given type, tag
|
|
* number, and type class (for message and enum fields). The type must be a Ruby
|
|
* number, and type class (for message and enum fields). The type must be a Ruby
|
|
@@ -1288,18 +1619,20 @@ VALUE MessageBuilderContext_optional(int argc, VALUE* argv, VALUE _self) {
|
|
*/
|
|
*/
|
|
VALUE MessageBuilderContext_required(int argc, VALUE* argv, VALUE _self) {
|
|
VALUE MessageBuilderContext_required(int argc, VALUE* argv, VALUE _self) {
|
|
DEFINE_SELF(MessageBuilderContext, self, _self);
|
|
DEFINE_SELF(MessageBuilderContext, self, _self);
|
|
- VALUE name, type, number, type_class;
|
|
|
|
|
|
+ VALUE name, type, number;
|
|
|
|
+ VALUE type_class, options = Qnil;
|
|
|
|
|
|
- if (argc < 3) {
|
|
|
|
- rb_raise(rb_eArgError, "Expected at least 3 arguments.");
|
|
|
|
|
|
+ rb_scan_args(argc, argv, "32", &name, &type, &number, &type_class, &options);
|
|
|
|
+
|
|
|
|
+ // Allow passing (name, type, number, options) or
|
|
|
|
+ // (name, type, number, type_class, options)
|
|
|
|
+ if (argc == 4 && RB_TYPE_P(type_class, T_HASH)) {
|
|
|
|
+ options = type_class;
|
|
|
|
+ type_class = Qnil;
|
|
}
|
|
}
|
|
- name = argv[0];
|
|
|
|
- type = argv[1];
|
|
|
|
- number = argv[2];
|
|
|
|
- type_class = (argc > 3) ? argv[3] : Qnil;
|
|
|
|
|
|
|
|
return msgdef_add_field(self->descriptor, "required",
|
|
return msgdef_add_field(self->descriptor, "required",
|
|
- name, type, number, type_class);
|
|
|
|
|
|
+ name, type, number, type_class, options);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
/*
|
|
@@ -1324,7 +1657,7 @@ VALUE MessageBuilderContext_repeated(int argc, VALUE* argv, VALUE _self) {
|
|
type_class = (argc > 3) ? argv[3] : Qnil;
|
|
type_class = (argc > 3) ? argv[3] : Qnil;
|
|
|
|
|
|
return msgdef_add_field(self->descriptor, "repeated",
|
|
return msgdef_add_field(self->descriptor, "repeated",
|
|
- name, type, number, type_class);
|
|
|
|
|
|
+ name, type, number, type_class, Qnil);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
/*
|
|
@@ -1365,9 +1698,17 @@ VALUE MessageBuilderContext_map(int argc, VALUE* argv, VALUE _self) {
|
|
"type.");
|
|
"type.");
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ Descriptor* descriptor = ruby_to_Descriptor(self->descriptor);
|
|
|
|
+ if (upb_msgdef_syntax(descriptor->msgdef) == UPB_SYNTAX_PROTO2) {
|
|
|
|
+ rb_raise(rb_eArgError,
|
|
|
|
+ "Cannot add a native map field using proto2 syntax.");
|
|
|
|
+ }
|
|
|
|
+
|
|
// Create a new message descriptor for the map entry message, and create a
|
|
// Create a new message descriptor for the map entry message, and create a
|
|
// repeated submessage field here with that type.
|
|
// repeated submessage field here with that type.
|
|
- mapentry_desc = rb_class_new_instance(0, NULL, cDescriptor);
|
|
|
|
|
|
+ VALUE file_descriptor_rb =
|
|
|
|
+ rb_funcall(self->descriptor, rb_intern("file_descriptor"), 0);
|
|
|
|
+ mapentry_desc = rb_class_new_instance(1, &file_descriptor_rb, cDescriptor);
|
|
mapentry_desc_name = rb_funcall(self->descriptor, rb_intern("name"), 0);
|
|
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, "_MapEntry_");
|
|
mapentry_desc_name = rb_str_cat2(mapentry_desc_name,
|
|
mapentry_desc_name = rb_str_cat2(mapentry_desc_name,
|
|
@@ -1410,8 +1751,8 @@ VALUE MessageBuilderContext_map(int argc, VALUE* argv, VALUE _self) {
|
|
{
|
|
{
|
|
// Add the map-entry message type to the current builder, and use the type
|
|
// Add the map-entry message type to the current builder, and use the type
|
|
// to create the map field itself.
|
|
// to create the map field itself.
|
|
- Builder* builder_self = ruby_to_Builder(self->builder);
|
|
|
|
- rb_ary_push(builder_self->pending_list, mapentry_desc);
|
|
|
|
|
|
+ Builder* builder = ruby_to_Builder(self->builder);
|
|
|
|
+ rb_ary_push(builder->pending_list, mapentry_desc);
|
|
}
|
|
}
|
|
|
|
|
|
{
|
|
{
|
|
@@ -1514,7 +1855,8 @@ VALUE OneofBuilderContext_initialize(VALUE _self,
|
|
|
|
|
|
/*
|
|
/*
|
|
* call-seq:
|
|
* call-seq:
|
|
- * OneofBuilderContext.optional(name, type, number, type_class = nil)
|
|
|
|
|
|
+ * OneofBuilderContext.optional(name, type, number, type_class = nil,
|
|
|
|
+ * default_value = nil)
|
|
*
|
|
*
|
|
* Defines a new optional field in this oneof with the given type, tag number,
|
|
* Defines a new optional field in this oneof with the given type, tag number,
|
|
* and type class (for message and enum fields). The type must be a Ruby symbol
|
|
* and type class (for message and enum fields). The type must be a Ruby symbol
|
|
@@ -1523,18 +1865,13 @@ VALUE OneofBuilderContext_initialize(VALUE _self,
|
|
*/
|
|
*/
|
|
VALUE OneofBuilderContext_optional(int argc, VALUE* argv, VALUE _self) {
|
|
VALUE OneofBuilderContext_optional(int argc, VALUE* argv, VALUE _self) {
|
|
DEFINE_SELF(OneofBuilderContext, self, _self);
|
|
DEFINE_SELF(OneofBuilderContext, self, _self);
|
|
- VALUE name, type, number, type_class;
|
|
|
|
|
|
+ VALUE name, type, number;
|
|
|
|
+ VALUE type_class, options = Qnil;
|
|
|
|
|
|
- if (argc < 3) {
|
|
|
|
- rb_raise(rb_eArgError, "Expected at least 3 arguments.");
|
|
|
|
- }
|
|
|
|
- name = argv[0];
|
|
|
|
- type = argv[1];
|
|
|
|
- number = argv[2];
|
|
|
|
- type_class = (argc > 3) ? argv[3] : Qnil;
|
|
|
|
|
|
+ rb_scan_args(argc, argv, "32", &name, &type, &number, &type_class, &options);
|
|
|
|
|
|
return msgdef_add_field(self->descriptor, "optional",
|
|
return msgdef_add_field(self->descriptor, "optional",
|
|
- name, type, number, type_class);
|
|
|
|
|
|
+ name, type, number, type_class, options);
|
|
}
|
|
}
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// -----------------------------------------------------------------------------
|
|
@@ -1604,6 +1941,112 @@ VALUE EnumBuilderContext_value(VALUE _self, VALUE name, VALUE number) {
|
|
return enumdef_add_value(self->enumdesc, name, number);
|
|
return enumdef_add_value(self->enumdesc, name, number);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+
|
|
|
|
+// -----------------------------------------------------------------------------
|
|
|
|
+// FileBuilderContext.
|
|
|
|
+// -----------------------------------------------------------------------------
|
|
|
|
+
|
|
|
|
+DEFINE_CLASS(FileBuilderContext,
|
|
|
|
+ "Google::Protobuf::Internal::FileBuilderContext");
|
|
|
|
+
|
|
|
|
+void FileBuilderContext_mark(void* _self) {
|
|
|
|
+ FileBuilderContext* self = _self;
|
|
|
|
+ rb_gc_mark(self->pending_list);
|
|
|
|
+ rb_gc_mark(self->file_descriptor);
|
|
|
|
+ rb_gc_mark(self->builder);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void FileBuilderContext_free(void* _self) {
|
|
|
|
+ FileBuilderContext* self = _self;
|
|
|
|
+ xfree(self);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+VALUE FileBuilderContext_alloc(VALUE klass) {
|
|
|
|
+ FileBuilderContext* self = ALLOC(FileBuilderContext);
|
|
|
|
+ VALUE ret = TypedData_Wrap_Struct(klass, &_FileBuilderContext_type, self);
|
|
|
|
+ self->pending_list = Qnil;
|
|
|
|
+ self->file_descriptor = Qnil;
|
|
|
|
+ self->builder = Qnil;
|
|
|
|
+ return ret;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void FileBuilderContext_register(VALUE module) {
|
|
|
|
+ VALUE klass = rb_define_class_under(module, "FileBuilderContext", rb_cObject);
|
|
|
|
+ rb_define_alloc_func(klass, FileBuilderContext_alloc);
|
|
|
|
+ rb_define_method(klass, "initialize", FileBuilderContext_initialize, 2);
|
|
|
|
+ rb_define_method(klass, "add_message", FileBuilderContext_add_message, 1);
|
|
|
|
+ rb_define_method(klass, "add_enum", FileBuilderContext_add_enum, 1);
|
|
|
|
+ rb_gc_register_address(&cFileBuilderContext);
|
|
|
|
+ cFileBuilderContext = klass;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/*
|
|
|
|
+ * call-seq:
|
|
|
|
+ * FileBuilderContext.new(file_descriptor, builder) => context
|
|
|
|
+ *
|
|
|
|
+ * Create a new file builder context for the given file descriptor and
|
|
|
|
+ * builder context. This class is intended to serve as a DSL context to be used
|
|
|
|
+ * with #instance_eval.
|
|
|
|
+ */
|
|
|
|
+VALUE FileBuilderContext_initialize(VALUE _self, VALUE file_descriptor,
|
|
|
|
+ VALUE builder) {
|
|
|
|
+ DEFINE_SELF(FileBuilderContext, self, _self);
|
|
|
|
+ self->pending_list = rb_ary_new();
|
|
|
|
+ self->file_descriptor = file_descriptor;
|
|
|
|
+ self->builder = builder;
|
|
|
|
+ return Qnil;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/*
|
|
|
|
+ * call-seq:
|
|
|
|
+ * FileBuilderContext.add_message(name, &block)
|
|
|
|
+ *
|
|
|
|
+ * Creates a new, empty descriptor with the given name, and invokes the block in
|
|
|
|
+ * the context of a MessageBuilderContext on that descriptor. The block can then
|
|
|
|
+ * call, e.g., MessageBuilderContext#optional and MessageBuilderContext#repeated
|
|
|
|
+ * methods to define the message fields.
|
|
|
|
+ *
|
|
|
|
+ * This is the recommended, idiomatic way to build message definitions.
|
|
|
|
+ */
|
|
|
|
+VALUE FileBuilderContext_add_message(VALUE _self, VALUE name) {
|
|
|
|
+ DEFINE_SELF(FileBuilderContext, self, _self);
|
|
|
|
+ VALUE msgdef = rb_class_new_instance(1, &self->file_descriptor, cDescriptor);
|
|
|
|
+ VALUE args[2] = { msgdef, self->builder };
|
|
|
|
+ VALUE ctx = rb_class_new_instance(2, args, cMessageBuilderContext);
|
|
|
|
+ VALUE block = rb_block_proc();
|
|
|
|
+ rb_funcall(msgdef, rb_intern("name="), 1, name);
|
|
|
|
+ rb_funcall_with_block(ctx, rb_intern("instance_eval"), 0, NULL, block);
|
|
|
|
+ rb_ary_push(self->pending_list, msgdef);
|
|
|
|
+ return Qnil;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/*
|
|
|
|
+ * call-seq:
|
|
|
|
+ * FileBuilderContext.add_enum(name, &block)
|
|
|
|
+ *
|
|
|
|
+ * Creates a new, empty enum descriptor with the given name, and invokes the
|
|
|
|
+ * block in the context of an EnumBuilderContext on that descriptor. The block
|
|
|
|
+ * can then call EnumBuilderContext#add_value to define the enum values.
|
|
|
|
+ *
|
|
|
|
+ * This is the recommended, idiomatic way to build enum definitions.
|
|
|
|
+ */
|
|
|
|
+VALUE FileBuilderContext_add_enum(VALUE _self, VALUE name) {
|
|
|
|
+ DEFINE_SELF(FileBuilderContext, self, _self);
|
|
|
|
+ VALUE enumdef =
|
|
|
|
+ rb_class_new_instance(1, &self->file_descriptor, cEnumDescriptor);
|
|
|
|
+ VALUE ctx = rb_class_new_instance(1, &enumdef, cEnumBuilderContext);
|
|
|
|
+ VALUE block = rb_block_proc();
|
|
|
|
+ rb_funcall(enumdef, rb_intern("name="), 1, name);
|
|
|
|
+ rb_funcall_with_block(ctx, rb_intern("instance_eval"), 0, NULL, block);
|
|
|
|
+ rb_ary_push(self->pending_list, enumdef);
|
|
|
|
+ return Qnil;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+VALUE FileBuilderContext_pending_descriptors(VALUE _self) {
|
|
|
|
+ DEFINE_SELF(FileBuilderContext, self, _self);
|
|
|
|
+ return self->pending_list;
|
|
|
|
+}
|
|
|
|
+
|
|
// -----------------------------------------------------------------------------
|
|
// -----------------------------------------------------------------------------
|
|
// Builder.
|
|
// Builder.
|
|
// -----------------------------------------------------------------------------
|
|
// -----------------------------------------------------------------------------
|
|
@@ -1613,6 +2056,7 @@ DEFINE_CLASS(Builder, "Google::Protobuf::Internal::Builder");
|
|
void Builder_mark(void* _self) {
|
|
void Builder_mark(void* _self) {
|
|
Builder* self = _self;
|
|
Builder* self = _self;
|
|
rb_gc_mark(self->pending_list);
|
|
rb_gc_mark(self->pending_list);
|
|
|
|
+ rb_gc_mark(self->default_file_descriptor);
|
|
}
|
|
}
|
|
|
|
|
|
void Builder_free(void* _self) {
|
|
void Builder_free(void* _self) {
|
|
@@ -1635,15 +2079,17 @@ VALUE Builder_alloc(VALUE klass) {
|
|
klass, &_Builder_type, self);
|
|
klass, &_Builder_type, self);
|
|
self->pending_list = Qnil;
|
|
self->pending_list = Qnil;
|
|
self->defs = NULL;
|
|
self->defs = NULL;
|
|
|
|
+ self->default_file_descriptor = Qnil;
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
|
|
void Builder_register(VALUE module) {
|
|
void Builder_register(VALUE module) {
|
|
VALUE klass = rb_define_class_under(module, "Builder", rb_cObject);
|
|
VALUE klass = rb_define_class_under(module, "Builder", rb_cObject);
|
|
- rb_define_alloc_func(klass, Builder_alloc);
|
|
|
|
|
|
+ rb_define_alloc_func(klass, Builder_alloc);
|
|
|
|
+ rb_define_method(klass, "initialize", Builder_initialize, 0);
|
|
|
|
+ rb_define_method(klass, "add_file", Builder_add_file, -1);
|
|
rb_define_method(klass, "add_message", Builder_add_message, 1);
|
|
rb_define_method(klass, "add_message", Builder_add_message, 1);
|
|
rb_define_method(klass, "add_enum", Builder_add_enum, 1);
|
|
rb_define_method(klass, "add_enum", Builder_add_enum, 1);
|
|
- rb_define_method(klass, "initialize", Builder_initialize, 0);
|
|
|
|
rb_define_method(klass, "finalize_to_pool", Builder_finalize_to_pool, 1);
|
|
rb_define_method(klass, "finalize_to_pool", Builder_finalize_to_pool, 1);
|
|
rb_gc_register_address(&cBuilder);
|
|
rb_gc_register_address(&cBuilder);
|
|
cBuilder = klass;
|
|
cBuilder = klass;
|
|
@@ -1651,13 +2097,40 @@ void Builder_register(VALUE module) {
|
|
|
|
|
|
/*
|
|
/*
|
|
* call-seq:
|
|
* call-seq:
|
|
- * Builder.new(d) => builder
|
|
|
|
|
|
+ * Builder.new
|
|
*
|
|
*
|
|
- * Create a new message builder.
|
|
|
|
|
|
+ * Initializes a new builder.
|
|
*/
|
|
*/
|
|
VALUE Builder_initialize(VALUE _self) {
|
|
VALUE Builder_initialize(VALUE _self) {
|
|
DEFINE_SELF(Builder, self, _self);
|
|
DEFINE_SELF(Builder, self, _self);
|
|
self->pending_list = rb_ary_new();
|
|
self->pending_list = rb_ary_new();
|
|
|
|
+ VALUE file_name = Qnil;
|
|
|
|
+ self->default_file_descriptor =
|
|
|
|
+ rb_class_new_instance(1, &file_name, cFileDescriptor);
|
|
|
|
+ return Qnil;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/*
|
|
|
|
+ * call-seq:
|
|
|
|
+ * Builder.add_file(name, options = nil, &block)
|
|
|
|
+ *
|
|
|
|
+ * Creates a new, file descriptor with the given name and options and invokes
|
|
|
|
+ * the block in the context of a FileBuilderContext on that descriptor. The
|
|
|
|
+ * block can then call FileBuilderContext#add_message or
|
|
|
|
+ * FileBuilderContext#add_enum to define new messages or enums, respectively.
|
|
|
|
+ *
|
|
|
|
+ * This is the recommended, idiomatic way to build file descriptors.
|
|
|
|
+ */
|
|
|
|
+VALUE Builder_add_file(int argc, VALUE* argv, VALUE _self) {
|
|
|
|
+ DEFINE_SELF(Builder, self, _self);
|
|
|
|
+ VALUE file_descriptor = rb_class_new_instance(argc, argv, cFileDescriptor);
|
|
|
|
+ VALUE args[2] = { file_descriptor, _self };
|
|
|
|
+ VALUE ctx = rb_class_new_instance(2, args, cFileBuilderContext);
|
|
|
|
+ VALUE block = rb_block_proc();
|
|
|
|
+ rb_funcall_with_block(ctx, rb_intern("instance_eval"), 0, NULL, block);
|
|
|
|
+
|
|
|
|
+ rb_ary_concat(self->pending_list,
|
|
|
|
+ FileBuilderContext_pending_descriptors(ctx));
|
|
return Qnil;
|
|
return Qnil;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -1665,16 +2138,17 @@ VALUE Builder_initialize(VALUE _self) {
|
|
* call-seq:
|
|
* call-seq:
|
|
* Builder.add_message(name, &block)
|
|
* Builder.add_message(name, &block)
|
|
*
|
|
*
|
|
- * Creates a new, empty descriptor with the given name, and invokes the block in
|
|
|
|
- * the context of a MessageBuilderContext on that descriptor. The block can then
|
|
|
|
- * call, e.g., MessageBuilderContext#optional and MessageBuilderContext#repeated
|
|
|
|
- * methods to define the message fields.
|
|
|
|
|
|
+ * Old and deprecated way to create a new descriptor.
|
|
|
|
+ * See FileBuilderContext.add_message for the recommended way.
|
|
*
|
|
*
|
|
- * This is the recommended, idiomatic way to build message definitions.
|
|
|
|
|
|
+ * Exists for backwards compatibility to allow building descriptor pool for
|
|
|
|
+ * files generated by protoc which don't add messages within "add_file" block.
|
|
|
|
+ * Descriptors created this way get assigned to a default empty FileDescriptor.
|
|
*/
|
|
*/
|
|
VALUE Builder_add_message(VALUE _self, VALUE name) {
|
|
VALUE Builder_add_message(VALUE _self, VALUE name) {
|
|
DEFINE_SELF(Builder, self, _self);
|
|
DEFINE_SELF(Builder, self, _self);
|
|
- VALUE msgdef = rb_class_new_instance(0, NULL, cDescriptor);
|
|
|
|
|
|
+ VALUE msgdef =
|
|
|
|
+ rb_class_new_instance(1, &self->default_file_descriptor, cDescriptor);
|
|
VALUE args[2] = { msgdef, _self };
|
|
VALUE args[2] = { msgdef, _self };
|
|
VALUE ctx = rb_class_new_instance(2, args, cMessageBuilderContext);
|
|
VALUE ctx = rb_class_new_instance(2, args, cMessageBuilderContext);
|
|
VALUE block = rb_block_proc();
|
|
VALUE block = rb_block_proc();
|
|
@@ -1688,15 +2162,18 @@ VALUE Builder_add_message(VALUE _self, VALUE name) {
|
|
* call-seq:
|
|
* call-seq:
|
|
* Builder.add_enum(name, &block)
|
|
* Builder.add_enum(name, &block)
|
|
*
|
|
*
|
|
- * Creates a new, empty enum descriptor with the given name, and invokes the
|
|
|
|
- * block in the context of an EnumBuilderContext on that descriptor. The block
|
|
|
|
- * can then call EnumBuilderContext#add_value to define the enum values.
|
|
|
|
|
|
+ * Old and deprecated way to create a new enum descriptor.
|
|
|
|
+ * See FileBuilderContext.add_enum for the recommended way.
|
|
*
|
|
*
|
|
- * This is the recommended, idiomatic way to build enum definitions.
|
|
|
|
|
|
+ * Exists for backwards compatibility to allow building descriptor pool for
|
|
|
|
+ * files generated by protoc which don't add enums within "add_file" block.
|
|
|
|
+ * Enum descriptors created this way get assigned to a default empty
|
|
|
|
+ * FileDescriptor.
|
|
*/
|
|
*/
|
|
VALUE Builder_add_enum(VALUE _self, VALUE name) {
|
|
VALUE Builder_add_enum(VALUE _self, VALUE name) {
|
|
DEFINE_SELF(Builder, self, _self);
|
|
DEFINE_SELF(Builder, self, _self);
|
|
- VALUE enumdef = rb_class_new_instance(0, NULL, cEnumDescriptor);
|
|
|
|
|
|
+ VALUE enumdef =
|
|
|
|
+ rb_class_new_instance(1, &self->default_file_descriptor, cEnumDescriptor);
|
|
VALUE ctx = rb_class_new_instance(1, &enumdef, cEnumBuilderContext);
|
|
VALUE ctx = rb_class_new_instance(1, &enumdef, cEnumBuilderContext);
|
|
VALUE block = rb_block_proc();
|
|
VALUE block = rb_block_proc();
|
|
rb_funcall(enumdef, rb_intern("name="), 1, name);
|
|
rb_funcall(enumdef, rb_intern("name="), 1, name);
|
|
@@ -1705,7 +2182,7 @@ VALUE Builder_add_enum(VALUE _self, VALUE name) {
|
|
return Qnil;
|
|
return Qnil;
|
|
}
|
|
}
|
|
|
|
|
|
-static void validate_msgdef(const upb_msgdef* msgdef) {
|
|
|
|
|
|
+static void proto3_validate_msgdef(const upb_msgdef* msgdef) {
|
|
// Verify that no required fields exist. proto3 does not support these.
|
|
// Verify that no required fields exist. proto3 does not support these.
|
|
upb_msg_field_iter it;
|
|
upb_msg_field_iter it;
|
|
for (upb_msg_field_begin(&it, msgdef);
|
|
for (upb_msg_field_begin(&it, msgdef);
|
|
@@ -1718,7 +2195,7 @@ static void validate_msgdef(const upb_msgdef* msgdef) {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-static void validate_enumdef(const upb_enumdef* enumdef) {
|
|
|
|
|
|
+static void proto3_validate_enumdef(const upb_enumdef* enumdef) {
|
|
// Verify that an entry exists with integer value 0. (This is the default
|
|
// Verify that an entry exists with integer value 0. (This is the default
|
|
// value.)
|
|
// value.)
|
|
const char* lookup = upb_enumdef_iton(enumdef, 0);
|
|
const char* lookup = upb_enumdef_iton(enumdef, 0);
|
|
@@ -1753,10 +2230,16 @@ VALUE Builder_finalize_to_pool(VALUE _self, VALUE pool_rb) {
|
|
VALUE def_rb = rb_ary_entry(self->pending_list, i);
|
|
VALUE def_rb = rb_ary_entry(self->pending_list, i);
|
|
if (CLASS_OF(def_rb) == cDescriptor) {
|
|
if (CLASS_OF(def_rb) == cDescriptor) {
|
|
self->defs[i] = (upb_def*)ruby_to_Descriptor(def_rb)->msgdef;
|
|
self->defs[i] = (upb_def*)ruby_to_Descriptor(def_rb)->msgdef;
|
|
- validate_msgdef((const upb_msgdef*)self->defs[i]);
|
|
|
|
|
|
+
|
|
|
|
+ if (upb_filedef_syntax(upb_def_file(self->defs[i])) == UPB_SYNTAX_PROTO3) {
|
|
|
|
+ proto3_validate_msgdef((const upb_msgdef*)self->defs[i]);
|
|
|
|
+ }
|
|
} else if (CLASS_OF(def_rb) == cEnumDescriptor) {
|
|
} else if (CLASS_OF(def_rb) == cEnumDescriptor) {
|
|
self->defs[i] = (upb_def*)ruby_to_EnumDescriptor(def_rb)->enumdef;
|
|
self->defs[i] = (upb_def*)ruby_to_EnumDescriptor(def_rb)->enumdef;
|
|
- validate_enumdef((const upb_enumdef*)self->defs[i]);
|
|
|
|
|
|
+
|
|
|
|
+ if (upb_filedef_syntax(upb_def_file(self->defs[i])) == UPB_SYNTAX_PROTO3) {
|
|
|
|
+ proto3_validate_enumdef((const upb_enumdef*)self->defs[i]);
|
|
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|