Run all JRuby source files through google-java-format.
This commit is contained in:
parent
8e7f936696
commit
5b28ae70c0
@ -35,6 +35,8 @@ package com.google.protobuf.jruby;
|
||||
import com.google.protobuf.Descriptors.Descriptor;
|
||||
import com.google.protobuf.Descriptors.FieldDescriptor;
|
||||
import com.google.protobuf.Descriptors.OneofDescriptor;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import org.jruby.*;
|
||||
import org.jruby.anno.JRubyClass;
|
||||
import org.jruby.anno.JRubyMethod;
|
||||
@ -44,182 +46,186 @@ import org.jruby.runtime.ObjectAllocator;
|
||||
import org.jruby.runtime.ThreadContext;
|
||||
import org.jruby.runtime.builtin.IRubyObject;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
@JRubyClass(name = "Descriptor", include = "Enumerable")
|
||||
public class RubyDescriptor extends RubyObject {
|
||||
public static void createRubyDescriptor(Ruby runtime) {
|
||||
RubyModule protobuf = runtime.getClassFromPath("Google::Protobuf");
|
||||
RubyClass cDescriptor = protobuf.defineClassUnder("Descriptor", runtime.getObject(), new ObjectAllocator() {
|
||||
@Override
|
||||
public IRubyObject allocate(Ruby runtime, RubyClass klazz) {
|
||||
public static void createRubyDescriptor(Ruby runtime) {
|
||||
RubyModule protobuf = runtime.getClassFromPath("Google::Protobuf");
|
||||
RubyClass cDescriptor =
|
||||
protobuf.defineClassUnder(
|
||||
"Descriptor",
|
||||
runtime.getObject(),
|
||||
new ObjectAllocator() {
|
||||
@Override
|
||||
public IRubyObject allocate(Ruby runtime, RubyClass klazz) {
|
||||
return new RubyDescriptor(runtime, klazz);
|
||||
}
|
||||
});
|
||||
cDescriptor.includeModule(runtime.getEnumerable());
|
||||
cDescriptor.defineAnnotatedMethods(RubyDescriptor.class);
|
||||
cFieldDescriptor = (RubyClass) runtime.getClassFromPath("Google::Protobuf::FieldDescriptor");
|
||||
cOneofDescriptor = (RubyClass) runtime.getClassFromPath("Google::Protobuf::OneofDescriptor");
|
||||
}
|
||||
});
|
||||
cDescriptor.includeModule(runtime.getEnumerable());
|
||||
cDescriptor.defineAnnotatedMethods(RubyDescriptor.class);
|
||||
cFieldDescriptor = (RubyClass) runtime.getClassFromPath("Google::Protobuf::FieldDescriptor");
|
||||
cOneofDescriptor = (RubyClass) runtime.getClassFromPath("Google::Protobuf::OneofDescriptor");
|
||||
}
|
||||
|
||||
public RubyDescriptor(Ruby runtime, RubyClass klazz) {
|
||||
super(runtime, klazz);
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Descriptor.name => name
|
||||
*
|
||||
* Returns the name of this message type as a fully-qualified string (e.g.,
|
||||
* My.Package.MessageType).
|
||||
*/
|
||||
@JRubyMethod(name = "name")
|
||||
public IRubyObject getName(ThreadContext context) {
|
||||
return name;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Descriptor.lookup(name) => FieldDescriptor
|
||||
*
|
||||
* Returns the field descriptor for the field with the given name, if present,
|
||||
* or nil if none.
|
||||
*/
|
||||
@JRubyMethod
|
||||
public IRubyObject lookup(ThreadContext context, IRubyObject fieldName) {
|
||||
return Helpers.nullToNil(fieldDescriptors.get(fieldName), context.nil);
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Descriptor.msgclass => message_klass
|
||||
*
|
||||
* Returns the Ruby class created for this message type. Valid only once the
|
||||
* message type has been added to a pool.
|
||||
*/
|
||||
@JRubyMethod
|
||||
public IRubyObject msgclass(ThreadContext context) {
|
||||
return klazz;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Descriptor.each(&block)
|
||||
*
|
||||
* Iterates over fields in this message type, yielding to the block on each one.
|
||||
*/
|
||||
@JRubyMethod
|
||||
public IRubyObject each(ThreadContext context, Block block) {
|
||||
for (Map.Entry<IRubyObject, RubyFieldDescriptor> entry : fieldDescriptors.entrySet()) {
|
||||
block.yield(context, entry.getValue());
|
||||
}
|
||||
return context.nil;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Descriptor.file_descriptor
|
||||
*
|
||||
* Returns the FileDescriptor object this message belongs to.
|
||||
*/
|
||||
@JRubyMethod(name = "file_descriptor")
|
||||
public IRubyObject getFileDescriptor(ThreadContext context) {
|
||||
return RubyFileDescriptor.getRubyFileDescriptor(context, descriptor);
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Descriptor.each_oneof(&block) => nil
|
||||
*
|
||||
* Invokes the given block for each oneof in this message type, passing the
|
||||
* corresponding OneofDescriptor.
|
||||
*/
|
||||
@JRubyMethod(name = "each_oneof")
|
||||
public IRubyObject eachOneof(ThreadContext context, Block block) {
|
||||
for (RubyOneofDescriptor oneofDescriptor : oneofDescriptors.values()) {
|
||||
block.yieldSpecific(context, oneofDescriptor);
|
||||
}
|
||||
return context.nil;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Descriptor.lookup_oneof(name) => OneofDescriptor
|
||||
*
|
||||
* Returns the oneof descriptor for the oneof with the given name, if present,
|
||||
* or nil if none.
|
||||
*/
|
||||
@JRubyMethod(name = "lookup_oneof")
|
||||
public IRubyObject lookupOneof(ThreadContext context, IRubyObject name) {
|
||||
return Helpers.nullToNil(oneofDescriptors.get(Utils.symToString(name)), context.nil);
|
||||
}
|
||||
|
||||
protected FieldDescriptor getField(String name) {
|
||||
return descriptor.findFieldByName(name);
|
||||
}
|
||||
|
||||
protected void setDescriptor(
|
||||
ThreadContext context, Descriptor descriptor, RubyDescriptorPool pool) {
|
||||
Ruby runtime = context.runtime;
|
||||
Map<FieldDescriptor, RubyFieldDescriptor> cache = new HashMap();
|
||||
this.descriptor = descriptor;
|
||||
|
||||
// Populate the field caches
|
||||
fieldDescriptors = new HashMap<IRubyObject, RubyFieldDescriptor>();
|
||||
oneofDescriptors = new HashMap<IRubyObject, RubyOneofDescriptor>();
|
||||
|
||||
for (FieldDescriptor fieldDescriptor : descriptor.getFields()) {
|
||||
RubyFieldDescriptor fd =
|
||||
(RubyFieldDescriptor) cFieldDescriptor.newInstance(context, Block.NULL_BLOCK);
|
||||
fd.setDescriptor(context, fieldDescriptor, pool);
|
||||
fieldDescriptors.put(runtime.newString(fieldDescriptor.getName()), fd);
|
||||
cache.put(fieldDescriptor, fd);
|
||||
}
|
||||
|
||||
public RubyDescriptor(Ruby runtime, RubyClass klazz) {
|
||||
super(runtime, klazz);
|
||||
for (OneofDescriptor oneofDescriptor : descriptor.getRealOneofs()) {
|
||||
RubyOneofDescriptor ood =
|
||||
(RubyOneofDescriptor) cOneofDescriptor.newInstance(context, Block.NULL_BLOCK);
|
||||
ood.setDescriptor(context, oneofDescriptor, cache);
|
||||
oneofDescriptors.put(runtime.newString(oneofDescriptor.getName()), ood);
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Descriptor.name => name
|
||||
*
|
||||
* Returns the name of this message type as a fully-qualified string (e.g.,
|
||||
* My.Package.MessageType).
|
||||
*/
|
||||
@JRubyMethod(name = "name")
|
||||
public IRubyObject getName(ThreadContext context) {
|
||||
return name;
|
||||
}
|
||||
// Make sure our class is built
|
||||
this.klazz = buildClassFromDescriptor(context);
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Descriptor.lookup(name) => FieldDescriptor
|
||||
*
|
||||
* Returns the field descriptor for the field with the given name, if present,
|
||||
* or nil if none.
|
||||
*/
|
||||
@JRubyMethod
|
||||
public IRubyObject lookup(ThreadContext context, IRubyObject fieldName) {
|
||||
return Helpers.nullToNil(fieldDescriptors.get(fieldName), context.nil);
|
||||
}
|
||||
protected void setName(IRubyObject name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Descriptor.msgclass => message_klass
|
||||
*
|
||||
* Returns the Ruby class created for this message type. Valid only once the
|
||||
* message type has been added to a pool.
|
||||
*/
|
||||
@JRubyMethod
|
||||
public IRubyObject msgclass(ThreadContext context) {
|
||||
return klazz;
|
||||
}
|
||||
private RubyClass buildClassFromDescriptor(ThreadContext context) {
|
||||
Ruby runtime = context.runtime;
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Descriptor.each(&block)
|
||||
*
|
||||
* Iterates over fields in this message type, yielding to the block on each one.
|
||||
*/
|
||||
@JRubyMethod
|
||||
public IRubyObject each(ThreadContext context, Block block) {
|
||||
for (Map.Entry<IRubyObject, RubyFieldDescriptor> entry : fieldDescriptors.entrySet()) {
|
||||
block.yield(context, entry.getValue());
|
||||
}
|
||||
return context.nil;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Descriptor.file_descriptor
|
||||
*
|
||||
* Returns the FileDescriptor object this message belongs to.
|
||||
*/
|
||||
@JRubyMethod(name = "file_descriptor")
|
||||
public IRubyObject getFileDescriptor(ThreadContext context) {
|
||||
return RubyFileDescriptor.getRubyFileDescriptor(context, descriptor);
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Descriptor.each_oneof(&block) => nil
|
||||
*
|
||||
* Invokes the given block for each oneof in this message type, passing the
|
||||
* corresponding OneofDescriptor.
|
||||
*/
|
||||
@JRubyMethod(name = "each_oneof")
|
||||
public IRubyObject eachOneof(ThreadContext context, Block block) {
|
||||
for (RubyOneofDescriptor oneofDescriptor : oneofDescriptors.values()) {
|
||||
block.yieldSpecific(context, oneofDescriptor);
|
||||
}
|
||||
return context.nil;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Descriptor.lookup_oneof(name) => OneofDescriptor
|
||||
*
|
||||
* Returns the oneof descriptor for the oneof with the given name, if present,
|
||||
* or nil if none.
|
||||
*/
|
||||
@JRubyMethod(name = "lookup_oneof")
|
||||
public IRubyObject lookupOneof(ThreadContext context, IRubyObject name) {
|
||||
return Helpers.nullToNil(oneofDescriptors.get(Utils.symToString(name)), context.nil);
|
||||
}
|
||||
|
||||
protected FieldDescriptor getField(String name) {
|
||||
return descriptor.findFieldByName(name);
|
||||
}
|
||||
|
||||
protected void setDescriptor(ThreadContext context, Descriptor descriptor, RubyDescriptorPool pool) {
|
||||
Ruby runtime = context.runtime;
|
||||
Map<FieldDescriptor, RubyFieldDescriptor> cache = new HashMap();
|
||||
this.descriptor = descriptor;
|
||||
|
||||
// Populate the field caches
|
||||
fieldDescriptors = new HashMap<IRubyObject, RubyFieldDescriptor>();
|
||||
oneofDescriptors = new HashMap<IRubyObject, RubyOneofDescriptor>();
|
||||
|
||||
for (FieldDescriptor fieldDescriptor : descriptor.getFields()) {
|
||||
RubyFieldDescriptor fd = (RubyFieldDescriptor) cFieldDescriptor.newInstance(context, Block.NULL_BLOCK);
|
||||
fd.setDescriptor(context, fieldDescriptor, pool);
|
||||
fieldDescriptors.put(runtime.newString(fieldDescriptor.getName()), fd);
|
||||
cache.put(fieldDescriptor, fd);
|
||||
}
|
||||
|
||||
for (OneofDescriptor oneofDescriptor : descriptor.getRealOneofs()) {
|
||||
RubyOneofDescriptor ood = (RubyOneofDescriptor) cOneofDescriptor.newInstance(context, Block.NULL_BLOCK);
|
||||
ood.setDescriptor(context, oneofDescriptor, cache);
|
||||
oneofDescriptors.put(runtime.newString(oneofDescriptor.getName()), ood);
|
||||
}
|
||||
|
||||
// Make sure our class is built
|
||||
this.klazz = buildClassFromDescriptor(context);
|
||||
}
|
||||
|
||||
protected void setName(IRubyObject name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
private RubyClass buildClassFromDescriptor(ThreadContext context) {
|
||||
Ruby runtime = context.runtime;
|
||||
|
||||
ObjectAllocator allocator = new ObjectAllocator() {
|
||||
@Override
|
||||
public IRubyObject allocate(Ruby runtime, RubyClass klazz) {
|
||||
return new RubyMessage(runtime, klazz, descriptor);
|
||||
}
|
||||
ObjectAllocator allocator =
|
||||
new ObjectAllocator() {
|
||||
@Override
|
||||
public IRubyObject allocate(Ruby runtime, RubyClass klazz) {
|
||||
return new RubyMessage(runtime, klazz, descriptor);
|
||||
}
|
||||
};
|
||||
|
||||
// rb_define_class_id
|
||||
RubyClass klass = RubyClass.newClass(runtime, runtime.getObject());
|
||||
klass.setAllocator(allocator);
|
||||
klass.makeMetaClass(runtime.getObject().getMetaClass());
|
||||
klass.inherit(runtime.getObject());
|
||||
RubyModule messageExts = runtime.getClassFromPath("Google::Protobuf::MessageExts");
|
||||
klass.include(new IRubyObject[] {messageExts});
|
||||
klass.instance_variable_set(runtime.newString(Utils.DESCRIPTOR_INSTANCE_VAR), this);
|
||||
klass.defineAnnotatedMethods(RubyMessage.class);
|
||||
// Workaround for https://github.com/jruby/jruby/issues/7154
|
||||
klass.searchMethod("respond_to?").setIsBuiltin(false);
|
||||
return klass;
|
||||
}
|
||||
// rb_define_class_id
|
||||
RubyClass klass = RubyClass.newClass(runtime, runtime.getObject());
|
||||
klass.setAllocator(allocator);
|
||||
klass.makeMetaClass(runtime.getObject().getMetaClass());
|
||||
klass.inherit(runtime.getObject());
|
||||
RubyModule messageExts = runtime.getClassFromPath("Google::Protobuf::MessageExts");
|
||||
klass.include(new IRubyObject[] {messageExts});
|
||||
klass.instance_variable_set(runtime.newString(Utils.DESCRIPTOR_INSTANCE_VAR), this);
|
||||
klass.defineAnnotatedMethods(RubyMessage.class);
|
||||
// Workaround for https://github.com/jruby/jruby/issues/7154
|
||||
klass.searchMethod("respond_to?").setIsBuiltin(false);
|
||||
return klass;
|
||||
}
|
||||
|
||||
private static RubyClass cFieldDescriptor;
|
||||
private static RubyClass cOneofDescriptor;
|
||||
private static RubyClass cFieldDescriptor;
|
||||
private static RubyClass cOneofDescriptor;
|
||||
|
||||
private Descriptor descriptor;
|
||||
private IRubyObject name;
|
||||
private Map<IRubyObject, RubyFieldDescriptor> fieldDescriptors;
|
||||
private Map<IRubyObject, RubyOneofDescriptor> oneofDescriptors;
|
||||
private RubyClass klazz;
|
||||
private Descriptor descriptor;
|
||||
private IRubyObject name;
|
||||
private Map<IRubyObject, RubyFieldDescriptor> fieldDescriptors;
|
||||
private Map<IRubyObject, RubyOneofDescriptor> oneofDescriptors;
|
||||
private RubyClass klazz;
|
||||
}
|
||||
|
@ -38,6 +38,10 @@ import com.google.protobuf.Descriptors.DescriptorValidationException;
|
||||
import com.google.protobuf.Descriptors.EnumDescriptor;
|
||||
import com.google.protobuf.Descriptors.FileDescriptor;
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.jruby.*;
|
||||
import org.jruby.anno.JRubyClass;
|
||||
import org.jruby.anno.JRubyMethod;
|
||||
@ -45,136 +49,147 @@ import org.jruby.exceptions.RaiseException;
|
||||
import org.jruby.runtime.*;
|
||||
import org.jruby.runtime.builtin.IRubyObject;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@JRubyClass(name = "DescriptorPool")
|
||||
public class RubyDescriptorPool extends RubyObject {
|
||||
public static void createRubyDescriptorPool(Ruby runtime) {
|
||||
RubyModule protobuf = runtime.getClassFromPath("Google::Protobuf");
|
||||
RubyClass cDescriptorPool = protobuf.defineClassUnder("DescriptorPool", runtime.getObject(), new ObjectAllocator() {
|
||||
@Override
|
||||
public IRubyObject allocate(Ruby runtime, RubyClass klazz) {
|
||||
public static void createRubyDescriptorPool(Ruby runtime) {
|
||||
RubyModule protobuf = runtime.getClassFromPath("Google::Protobuf");
|
||||
RubyClass cDescriptorPool =
|
||||
protobuf.defineClassUnder(
|
||||
"DescriptorPool",
|
||||
runtime.getObject(),
|
||||
new ObjectAllocator() {
|
||||
@Override
|
||||
public IRubyObject allocate(Ruby runtime, RubyClass klazz) {
|
||||
return new RubyDescriptorPool(runtime, klazz);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
cDescriptorPool.defineAnnotatedMethods(RubyDescriptorPool.class);
|
||||
descriptorPool = (RubyDescriptorPool) cDescriptorPool.newInstance(runtime.getCurrentContext(), Block.NULL_BLOCK);
|
||||
cDescriptor = (RubyClass) runtime.getClassFromPath("Google::Protobuf::Descriptor");
|
||||
cEnumDescriptor = (RubyClass) runtime.getClassFromPath("Google::Protobuf::EnumDescriptor");
|
||||
cDescriptorPool.defineAnnotatedMethods(RubyDescriptorPool.class);
|
||||
descriptorPool =
|
||||
(RubyDescriptorPool)
|
||||
cDescriptorPool.newInstance(runtime.getCurrentContext(), Block.NULL_BLOCK);
|
||||
cDescriptor = (RubyClass) runtime.getClassFromPath("Google::Protobuf::Descriptor");
|
||||
cEnumDescriptor = (RubyClass) runtime.getClassFromPath("Google::Protobuf::EnumDescriptor");
|
||||
}
|
||||
|
||||
public RubyDescriptorPool(Ruby runtime, RubyClass klazz) {
|
||||
super(runtime, klazz);
|
||||
this.fileDescriptors = new ArrayList<>();
|
||||
this.symtab = new HashMap<IRubyObject, IRubyObject>();
|
||||
}
|
||||
|
||||
@JRubyMethod
|
||||
public IRubyObject build(ThreadContext context, Block block) {
|
||||
RubyClass cBuilder =
|
||||
(RubyClass) context.runtime.getClassFromPath("Google::Protobuf::Internal::Builder");
|
||||
RubyBasicObject ctx = (RubyBasicObject) cBuilder.newInstance(context, this, Block.NULL_BLOCK);
|
||||
ctx.instance_eval(context, block);
|
||||
ctx.callMethod(context, "build"); // Needs to be called to support the deprecated syntax
|
||||
return context.nil;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* DescriptorPool.lookup(name) => descriptor
|
||||
*
|
||||
* Finds a Descriptor or EnumDescriptor by name and returns it, or nil if none
|
||||
* exists with the given name.
|
||||
*
|
||||
* This currently lazy loads the ruby descriptor objects as they are requested.
|
||||
* This allows us to leave the heavy lifting to the java library
|
||||
*/
|
||||
@JRubyMethod
|
||||
public IRubyObject lookup(ThreadContext context, IRubyObject name) {
|
||||
return Helpers.nullToNil(symtab.get(name), context.nil);
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* DescriptorPool.generated_pool => descriptor_pool
|
||||
*
|
||||
* Class method that returns the global DescriptorPool. This is a singleton into
|
||||
* which generated-code message and enum types are registered. The user may also
|
||||
* register types in this pool for convenience so that they do not have to hold
|
||||
* a reference to a private pool instance.
|
||||
*/
|
||||
@JRubyMethod(meta = true, name = "generated_pool")
|
||||
public static IRubyObject generatedPool(ThreadContext context, IRubyObject recv) {
|
||||
return descriptorPool;
|
||||
}
|
||||
|
||||
@JRubyMethod(required = 1)
|
||||
public IRubyObject add_serialized_file(ThreadContext context, IRubyObject data) {
|
||||
byte[] bin = data.convertToString().getBytes();
|
||||
try {
|
||||
FileDescriptorProto.Builder builder = FileDescriptorProto.newBuilder().mergeFrom(bin);
|
||||
registerFileDescriptor(context, builder);
|
||||
} catch (InvalidProtocolBufferException e) {
|
||||
throw RaiseException.from(
|
||||
context.runtime,
|
||||
(RubyClass) context.runtime.getClassFromPath("Google::Protobuf::ParseError"),
|
||||
e.getMessage());
|
||||
}
|
||||
return context.nil;
|
||||
}
|
||||
|
||||
protected void registerFileDescriptor(
|
||||
ThreadContext context, FileDescriptorProto.Builder builder) {
|
||||
final FileDescriptor fd;
|
||||
try {
|
||||
fd = FileDescriptor.buildFrom(builder.build(), existingFileDescriptors());
|
||||
} catch (DescriptorValidationException e) {
|
||||
throw context.runtime.newRuntimeError(e.getMessage());
|
||||
}
|
||||
|
||||
public RubyDescriptorPool(Ruby runtime, RubyClass klazz) {
|
||||
super(runtime, klazz);
|
||||
this.fileDescriptors = new ArrayList<>();
|
||||
this.symtab = new HashMap<IRubyObject, IRubyObject>();
|
||||
String packageName = fd.getPackage();
|
||||
if (!packageName.isEmpty()) {
|
||||
packageName = packageName + ".";
|
||||
}
|
||||
|
||||
@JRubyMethod
|
||||
public IRubyObject build(ThreadContext context, Block block) {
|
||||
RubyClass cBuilder = (RubyClass) context.runtime.getClassFromPath("Google::Protobuf::Internal::Builder");
|
||||
RubyBasicObject ctx = (RubyBasicObject) cBuilder.newInstance(context, this, Block.NULL_BLOCK);
|
||||
ctx.instance_eval(context, block);
|
||||
ctx.callMethod(context, "build"); // Needs to be called to support the deprecated syntax
|
||||
return context.nil;
|
||||
}
|
||||
// Need to make sure enums are registered first in case anything references them
|
||||
for (EnumDescriptor ed : fd.getEnumTypes()) registerEnumDescriptor(context, ed, packageName);
|
||||
for (Descriptor message : fd.getMessageTypes())
|
||||
registerDescriptor(context, message, packageName);
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* DescriptorPool.lookup(name) => descriptor
|
||||
*
|
||||
* Finds a Descriptor or EnumDescriptor by name and returns it, or nil if none
|
||||
* exists with the given name.
|
||||
*
|
||||
* This currently lazy loads the ruby descriptor objects as they are requested.
|
||||
* This allows us to leave the heavy lifting to the java library
|
||||
*/
|
||||
@JRubyMethod
|
||||
public IRubyObject lookup(ThreadContext context, IRubyObject name) {
|
||||
return Helpers.nullToNil(symtab.get(name), context.nil);
|
||||
}
|
||||
// Mark this as a loaded file
|
||||
fileDescriptors.add(fd);
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* DescriptorPool.generated_pool => descriptor_pool
|
||||
*
|
||||
* Class method that returns the global DescriptorPool. This is a singleton into
|
||||
* which generated-code message and enum types are registered. The user may also
|
||||
* register types in this pool for convenience so that they do not have to hold
|
||||
* a reference to a private pool instance.
|
||||
*/
|
||||
@JRubyMethod(meta = true, name = "generated_pool")
|
||||
public static IRubyObject generatedPool(ThreadContext context, IRubyObject recv) {
|
||||
return descriptorPool;
|
||||
}
|
||||
private void registerDescriptor(ThreadContext context, Descriptor descriptor, String parentPath) {
|
||||
String fullName = parentPath + descriptor.getName();
|
||||
String fullPath = fullName + ".";
|
||||
RubyString name = context.runtime.newString(fullName);
|
||||
|
||||
@JRubyMethod(required = 1)
|
||||
public IRubyObject add_serialized_file (ThreadContext context, IRubyObject data ) {
|
||||
byte[] bin = data.convertToString().getBytes();
|
||||
try {
|
||||
FileDescriptorProto.Builder builder = FileDescriptorProto.newBuilder().mergeFrom(bin);
|
||||
registerFileDescriptor(context, builder);
|
||||
} catch (InvalidProtocolBufferException e) {
|
||||
throw RaiseException.from(context.runtime, (RubyClass) context.runtime.getClassFromPath("Google::Protobuf::ParseError"), e.getMessage());
|
||||
}
|
||||
return context.nil;
|
||||
}
|
||||
RubyDescriptor des = (RubyDescriptor) cDescriptor.newInstance(context, Block.NULL_BLOCK);
|
||||
des.setName(name);
|
||||
des.setDescriptor(context, descriptor, this);
|
||||
symtab.put(name, des);
|
||||
|
||||
protected void registerFileDescriptor(ThreadContext context, FileDescriptorProto.Builder builder) {
|
||||
final FileDescriptor fd;
|
||||
try {
|
||||
fd = FileDescriptor.buildFrom(builder.build(), existingFileDescriptors());
|
||||
} catch (DescriptorValidationException e) {
|
||||
throw context.runtime.newRuntimeError(e.getMessage());
|
||||
}
|
||||
// Need to make sure enums are registered first in case anything references them
|
||||
for (EnumDescriptor ed : descriptor.getEnumTypes())
|
||||
registerEnumDescriptor(context, ed, fullPath);
|
||||
for (Descriptor message : descriptor.getNestedTypes())
|
||||
registerDescriptor(context, message, fullPath);
|
||||
}
|
||||
|
||||
String packageName = fd.getPackage();
|
||||
if (!packageName.isEmpty()) {
|
||||
packageName = packageName + ".";
|
||||
}
|
||||
private void registerEnumDescriptor(
|
||||
ThreadContext context, EnumDescriptor descriptor, String parentPath) {
|
||||
RubyString name = context.runtime.newString(parentPath + descriptor.getName());
|
||||
RubyEnumDescriptor des =
|
||||
(RubyEnumDescriptor) cEnumDescriptor.newInstance(context, Block.NULL_BLOCK);
|
||||
des.setName(name);
|
||||
des.setDescriptor(context, descriptor);
|
||||
symtab.put(name, des);
|
||||
}
|
||||
|
||||
// Need to make sure enums are registered first in case anything references them
|
||||
for (EnumDescriptor ed : fd.getEnumTypes()) registerEnumDescriptor(context, ed, packageName);
|
||||
for (Descriptor message : fd.getMessageTypes()) registerDescriptor(context, message, packageName);
|
||||
private FileDescriptor[] existingFileDescriptors() {
|
||||
return fileDescriptors.toArray(new FileDescriptor[fileDescriptors.size()]);
|
||||
}
|
||||
|
||||
// Mark this as a loaded file
|
||||
fileDescriptors.add(fd);
|
||||
}
|
||||
private static RubyClass cDescriptor;
|
||||
private static RubyClass cEnumDescriptor;
|
||||
private static RubyDescriptorPool descriptorPool;
|
||||
|
||||
private void registerDescriptor(ThreadContext context, Descriptor descriptor, String parentPath) {
|
||||
String fullName = parentPath + descriptor.getName();
|
||||
String fullPath = fullName + ".";
|
||||
RubyString name = context.runtime.newString(fullName);
|
||||
|
||||
RubyDescriptor des = (RubyDescriptor) cDescriptor.newInstance(context, Block.NULL_BLOCK);
|
||||
des.setName(name);
|
||||
des.setDescriptor(context, descriptor, this);
|
||||
symtab.put(name, des);
|
||||
|
||||
// Need to make sure enums are registered first in case anything references them
|
||||
for (EnumDescriptor ed : descriptor.getEnumTypes()) registerEnumDescriptor(context, ed, fullPath);
|
||||
for (Descriptor message : descriptor.getNestedTypes()) registerDescriptor(context, message, fullPath);
|
||||
}
|
||||
|
||||
private void registerEnumDescriptor(ThreadContext context, EnumDescriptor descriptor, String parentPath) {
|
||||
RubyString name = context.runtime.newString(parentPath + descriptor.getName());
|
||||
RubyEnumDescriptor des = (RubyEnumDescriptor) cEnumDescriptor.newInstance(context, Block.NULL_BLOCK);
|
||||
des.setName(name);
|
||||
des.setDescriptor(context, descriptor);
|
||||
symtab.put(name, des);
|
||||
}
|
||||
|
||||
private FileDescriptor[] existingFileDescriptors() {
|
||||
return fileDescriptors.toArray(new FileDescriptor[fileDescriptors.size()]);
|
||||
}
|
||||
|
||||
private static RubyClass cDescriptor;
|
||||
private static RubyClass cEnumDescriptor;
|
||||
private static RubyDescriptorPool descriptorPool;
|
||||
|
||||
private List<FileDescriptor> fileDescriptors;
|
||||
private Map<IRubyObject, IRubyObject> symtab;
|
||||
private List<FileDescriptor> fileDescriptors;
|
||||
private Map<IRubyObject, IRubyObject> symtab;
|
||||
}
|
||||
|
@ -38,41 +38,41 @@ import org.jruby.runtime.ThreadContext;
|
||||
import org.jruby.runtime.builtin.IRubyObject;
|
||||
|
||||
public class RubyEnum {
|
||||
/*
|
||||
* call-seq:
|
||||
* Enum.lookup(number) => name
|
||||
*
|
||||
* This module method, provided on each generated enum module, looks up an enum
|
||||
* value by number and returns its name as a Ruby symbol, or nil if not found.
|
||||
*/
|
||||
@JRubyMethod(meta = true)
|
||||
public static IRubyObject lookup(ThreadContext context, IRubyObject recv, IRubyObject number) {
|
||||
RubyEnumDescriptor rubyEnumDescriptor = (RubyEnumDescriptor) getDescriptor(context, recv);
|
||||
return rubyEnumDescriptor.numberToName(context, number);
|
||||
}
|
||||
/*
|
||||
* call-seq:
|
||||
* Enum.lookup(number) => name
|
||||
*
|
||||
* This module method, provided on each generated enum module, looks up an enum
|
||||
* value by number and returns its name as a Ruby symbol, or nil if not found.
|
||||
*/
|
||||
@JRubyMethod(meta = true)
|
||||
public static IRubyObject lookup(ThreadContext context, IRubyObject recv, IRubyObject number) {
|
||||
RubyEnumDescriptor rubyEnumDescriptor = (RubyEnumDescriptor) getDescriptor(context, recv);
|
||||
return rubyEnumDescriptor.numberToName(context, number);
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Enum.resolve(name) => number
|
||||
*
|
||||
* This module method, provided on each generated enum module, looks up an enum
|
||||
* value by name (as a Ruby symbol) and returns its name, or nil if not found.
|
||||
*/
|
||||
@JRubyMethod(meta = true)
|
||||
public static IRubyObject resolve(ThreadContext context, IRubyObject recv, IRubyObject name) {
|
||||
RubyEnumDescriptor rubyEnumDescriptor = (RubyEnumDescriptor) getDescriptor(context, recv);
|
||||
return rubyEnumDescriptor.nameToNumber(context, name);
|
||||
}
|
||||
/*
|
||||
* call-seq:
|
||||
* Enum.resolve(name) => number
|
||||
*
|
||||
* This module method, provided on each generated enum module, looks up an enum
|
||||
* value by name (as a Ruby symbol) and returns its name, or nil if not found.
|
||||
*/
|
||||
@JRubyMethod(meta = true)
|
||||
public static IRubyObject resolve(ThreadContext context, IRubyObject recv, IRubyObject name) {
|
||||
RubyEnumDescriptor rubyEnumDescriptor = (RubyEnumDescriptor) getDescriptor(context, recv);
|
||||
return rubyEnumDescriptor.nameToNumber(context, name);
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Enum.descriptor
|
||||
*
|
||||
* This module method, provided on each generated enum module, returns the
|
||||
* EnumDescriptor corresponding to this enum type.
|
||||
*/
|
||||
@JRubyMethod(meta = true, name = "descriptor")
|
||||
public static IRubyObject getDescriptor(ThreadContext context, IRubyObject recv) {
|
||||
return ((RubyModule) recv).getInstanceVariable(Utils.DESCRIPTOR_INSTANCE_VAR);
|
||||
}
|
||||
/*
|
||||
* call-seq:
|
||||
* Enum.descriptor
|
||||
*
|
||||
* This module method, provided on each generated enum module, returns the
|
||||
* EnumDescriptor corresponding to this enum type.
|
||||
*/
|
||||
@JRubyMethod(meta = true, name = "descriptor")
|
||||
public static IRubyObject getDescriptor(ThreadContext context, IRubyObject recv) {
|
||||
return ((RubyModule) recv).getInstanceVariable(Utils.DESCRIPTOR_INSTANCE_VAR);
|
||||
}
|
||||
}
|
||||
|
@ -39,8 +39,8 @@ import com.google.protobuf.Descriptors.FileDescriptor;
|
||||
import org.jruby.Ruby;
|
||||
import org.jruby.RubyClass;
|
||||
import org.jruby.RubyModule;
|
||||
import org.jruby.RubyObject;
|
||||
import org.jruby.RubyNumeric;
|
||||
import org.jruby.RubyObject;
|
||||
import org.jruby.anno.JRubyClass;
|
||||
import org.jruby.anno.JRubyMethod;
|
||||
import org.jruby.runtime.Block;
|
||||
@ -50,132 +50,147 @@ import org.jruby.runtime.builtin.IRubyObject;
|
||||
|
||||
@JRubyClass(name = "EnumDescriptor", include = "Enumerable")
|
||||
public class RubyEnumDescriptor extends RubyObject {
|
||||
public static void createRubyEnumDescriptor(Ruby runtime) {
|
||||
RubyModule mProtobuf = runtime.getClassFromPath("Google::Protobuf");
|
||||
RubyClass cEnumDescriptor = mProtobuf.defineClassUnder("EnumDescriptor", runtime.getObject(), new ObjectAllocator() {
|
||||
@Override
|
||||
public IRubyObject allocate(Ruby runtime, RubyClass klazz) {
|
||||
public static void createRubyEnumDescriptor(Ruby runtime) {
|
||||
RubyModule mProtobuf = runtime.getClassFromPath("Google::Protobuf");
|
||||
RubyClass cEnumDescriptor =
|
||||
mProtobuf.defineClassUnder(
|
||||
"EnumDescriptor",
|
||||
runtime.getObject(),
|
||||
new ObjectAllocator() {
|
||||
@Override
|
||||
public IRubyObject allocate(Ruby runtime, RubyClass klazz) {
|
||||
return new RubyEnumDescriptor(runtime, klazz);
|
||||
}
|
||||
});
|
||||
cEnumDescriptor.includeModule(runtime.getEnumerable());
|
||||
cEnumDescriptor.defineAnnotatedMethods(RubyEnumDescriptor.class);
|
||||
}
|
||||
});
|
||||
cEnumDescriptor.includeModule(runtime.getEnumerable());
|
||||
cEnumDescriptor.defineAnnotatedMethods(RubyEnumDescriptor.class);
|
||||
}
|
||||
|
||||
public RubyEnumDescriptor(Ruby runtime, RubyClass klazz) {
|
||||
super(runtime, klazz);
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* EnumDescriptor.name => name
|
||||
*
|
||||
* Returns the name of this enum type.
|
||||
*/
|
||||
@JRubyMethod(name = "name")
|
||||
public IRubyObject getName(ThreadContext context) {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* EnumDescriptor.each(&block)
|
||||
*
|
||||
* Iterates over key => value mappings in this enum's definition, yielding to
|
||||
* the block with (key, value) arguments for each one.
|
||||
*/
|
||||
@JRubyMethod
|
||||
public IRubyObject each(ThreadContext context, Block block) {
|
||||
Ruby runtime = context.runtime;
|
||||
for (EnumValueDescriptor enumValueDescriptor : descriptor.getValues()) {
|
||||
block.yield(
|
||||
context,
|
||||
runtime.newArray(
|
||||
runtime.newSymbol(enumValueDescriptor.getName()),
|
||||
runtime.newFixnum(enumValueDescriptor.getNumber())));
|
||||
}
|
||||
return context.nil;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* EnumDescriptor.enummodule => module
|
||||
*
|
||||
* Returns the Ruby module corresponding to this enum type. Cannot be called
|
||||
* until the enum descriptor has been added to a pool.
|
||||
*/
|
||||
@JRubyMethod
|
||||
public IRubyObject enummodule(ThreadContext context) {
|
||||
return module;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* EnumDescriptor.file_descriptor
|
||||
*
|
||||
* Returns the FileDescriptor object this enum belongs to.
|
||||
*/
|
||||
@JRubyMethod(name = "file_descriptor")
|
||||
public IRubyObject getFileDescriptor(ThreadContext context) {
|
||||
return RubyFileDescriptor.getRubyFileDescriptor(context, descriptor);
|
||||
}
|
||||
|
||||
public boolean isValidValue(ThreadContext context, IRubyObject value) {
|
||||
EnumValueDescriptor enumValue;
|
||||
|
||||
if (Utils.isRubyNum(value)) {
|
||||
enumValue = descriptor.findValueByNumberCreatingIfUnknown(RubyNumeric.num2int(value));
|
||||
} else {
|
||||
enumValue = descriptor.findValueByName(value.asJavaString());
|
||||
}
|
||||
|
||||
public RubyEnumDescriptor(Ruby runtime, RubyClass klazz) {
|
||||
super(runtime, klazz);
|
||||
return enumValue != null;
|
||||
}
|
||||
|
||||
protected IRubyObject nameToNumber(ThreadContext context, IRubyObject name) {
|
||||
EnumValueDescriptor value = descriptor.findValueByName(name.asJavaString());
|
||||
return value == null ? context.nil : context.runtime.newFixnum(value.getNumber());
|
||||
}
|
||||
|
||||
protected IRubyObject numberToName(ThreadContext context, IRubyObject number) {
|
||||
EnumValueDescriptor value = descriptor.findValueByNumber(RubyNumeric.num2int(number));
|
||||
return value == null ? context.nil : context.runtime.newSymbol(value.getName());
|
||||
}
|
||||
|
||||
protected void setDescriptor(ThreadContext context, EnumDescriptor descriptor) {
|
||||
this.descriptor = descriptor;
|
||||
this.module = buildModuleFromDescriptor(context);
|
||||
}
|
||||
|
||||
protected void setName(IRubyObject name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
private RubyModule buildModuleFromDescriptor(ThreadContext context) {
|
||||
Ruby runtime = context.runtime;
|
||||
|
||||
RubyModule enumModule = RubyModule.newModule(runtime);
|
||||
boolean defaultValueRequiredButNotFound =
|
||||
descriptor.getFile().getSyntax() == FileDescriptor.Syntax.PROTO3;
|
||||
for (EnumValueDescriptor value : descriptor.getValues()) {
|
||||
String name = value.getName();
|
||||
// Make sure its a valid constant name before trying to create it
|
||||
if (Character.isUpperCase(name.codePointAt(0))) {
|
||||
enumModule.defineConstant(name, runtime.newFixnum(value.getNumber()));
|
||||
} else {
|
||||
runtime
|
||||
.getWarnings()
|
||||
.warn(
|
||||
"Enum value "
|
||||
+ name
|
||||
+ " does not start with an uppercase letter as is required for Ruby"
|
||||
+ " constants.");
|
||||
}
|
||||
if (value.getNumber() == 0) {
|
||||
defaultValueRequiredButNotFound = false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* EnumDescriptor.name => name
|
||||
*
|
||||
* Returns the name of this enum type.
|
||||
*/
|
||||
@JRubyMethod(name = "name")
|
||||
public IRubyObject getName(ThreadContext context) {
|
||||
return this.name;
|
||||
if (defaultValueRequiredButNotFound) {
|
||||
throw Utils.createTypeError(
|
||||
context, "Enum definition " + name + " does not contain a value for '0'");
|
||||
}
|
||||
enumModule.instance_variable_set(runtime.newString(Utils.DESCRIPTOR_INSTANCE_VAR), this);
|
||||
enumModule.defineAnnotatedMethods(RubyEnum.class);
|
||||
return enumModule;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* EnumDescriptor.each(&block)
|
||||
*
|
||||
* Iterates over key => value mappings in this enum's definition, yielding to
|
||||
* the block with (key, value) arguments for each one.
|
||||
*/
|
||||
@JRubyMethod
|
||||
public IRubyObject each(ThreadContext context, Block block) {
|
||||
Ruby runtime = context.runtime;
|
||||
for (EnumValueDescriptor enumValueDescriptor : descriptor.getValues()) {
|
||||
block.yield(context, runtime.newArray(runtime.newSymbol(enumValueDescriptor.getName()),
|
||||
runtime.newFixnum(enumValueDescriptor.getNumber())));
|
||||
}
|
||||
return context.nil;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* EnumDescriptor.enummodule => module
|
||||
*
|
||||
* Returns the Ruby module corresponding to this enum type. Cannot be called
|
||||
* until the enum descriptor has been added to a pool.
|
||||
*/
|
||||
@JRubyMethod
|
||||
public IRubyObject enummodule(ThreadContext context) {
|
||||
return module;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* EnumDescriptor.file_descriptor
|
||||
*
|
||||
* Returns the FileDescriptor object this enum belongs to.
|
||||
*/
|
||||
@JRubyMethod(name = "file_descriptor")
|
||||
public IRubyObject getFileDescriptor(ThreadContext context) {
|
||||
return RubyFileDescriptor.getRubyFileDescriptor(context, descriptor);
|
||||
}
|
||||
|
||||
public boolean isValidValue(ThreadContext context, IRubyObject value) {
|
||||
EnumValueDescriptor enumValue;
|
||||
|
||||
if (Utils.isRubyNum(value)) {
|
||||
enumValue = descriptor.findValueByNumberCreatingIfUnknown(RubyNumeric.num2int(value));
|
||||
} else {
|
||||
enumValue = descriptor.findValueByName(value.asJavaString());
|
||||
}
|
||||
|
||||
return enumValue != null;
|
||||
}
|
||||
|
||||
protected IRubyObject nameToNumber(ThreadContext context, IRubyObject name) {
|
||||
EnumValueDescriptor value = descriptor.findValueByName(name.asJavaString());
|
||||
return value == null ? context.nil : context.runtime.newFixnum(value.getNumber());
|
||||
}
|
||||
|
||||
protected IRubyObject numberToName(ThreadContext context, IRubyObject number) {
|
||||
EnumValueDescriptor value = descriptor.findValueByNumber(RubyNumeric.num2int(number));
|
||||
return value == null ? context.nil : context.runtime.newSymbol(value.getName());
|
||||
}
|
||||
|
||||
protected void setDescriptor(ThreadContext context, EnumDescriptor descriptor) {
|
||||
this.descriptor = descriptor;
|
||||
this.module = buildModuleFromDescriptor(context);
|
||||
}
|
||||
|
||||
protected void setName(IRubyObject name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
private RubyModule buildModuleFromDescriptor(ThreadContext context) {
|
||||
Ruby runtime = context.runtime;
|
||||
|
||||
RubyModule enumModule = RubyModule.newModule(runtime);
|
||||
boolean defaultValueRequiredButNotFound = descriptor.getFile().getSyntax() == FileDescriptor.Syntax.PROTO3;
|
||||
for (EnumValueDescriptor value : descriptor.getValues()) {
|
||||
String name = value.getName();
|
||||
// Make sure its a valid constant name before trying to create it
|
||||
if (Character.isUpperCase(name.codePointAt(0))) {
|
||||
enumModule.defineConstant(name, runtime.newFixnum(value.getNumber()));
|
||||
} else {
|
||||
runtime.getWarnings().warn("Enum value " + name + " does not start with an uppercase letter as is required for Ruby constants.");
|
||||
}
|
||||
if (value.getNumber() == 0) {
|
||||
defaultValueRequiredButNotFound = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (defaultValueRequiredButNotFound) {
|
||||
throw Utils.createTypeError(context, "Enum definition " + name + " does not contain a value for '0'");
|
||||
}
|
||||
enumModule.instance_variable_set(runtime.newString(Utils.DESCRIPTOR_INSTANCE_VAR), this);
|
||||
enumModule.defineAnnotatedMethods(RubyEnum.class);
|
||||
return enumModule;
|
||||
}
|
||||
|
||||
private EnumDescriptor descriptor;
|
||||
private EnumDescriptorProto.Builder builder;
|
||||
private IRubyObject name;
|
||||
private RubyModule module;
|
||||
private EnumDescriptor descriptor;
|
||||
private EnumDescriptorProto.Builder builder;
|
||||
private IRubyObject name;
|
||||
private RubyModule module;
|
||||
}
|
||||
|
@ -43,228 +43,237 @@ import org.jruby.runtime.builtin.IRubyObject;
|
||||
|
||||
@JRubyClass(name = "FieldDescriptor")
|
||||
public class RubyFieldDescriptor extends RubyObject {
|
||||
public static void createRubyFieldDescriptor(Ruby runtime) {
|
||||
RubyModule mProtobuf = runtime.getClassFromPath("Google::Protobuf");
|
||||
RubyClass cFieldDescriptor = mProtobuf.defineClassUnder("FieldDescriptor", runtime.getObject(), new ObjectAllocator() {
|
||||
@Override
|
||||
public IRubyObject allocate(Ruby runtime, RubyClass klazz) {
|
||||
public static void createRubyFieldDescriptor(Ruby runtime) {
|
||||
RubyModule mProtobuf = runtime.getClassFromPath("Google::Protobuf");
|
||||
RubyClass cFieldDescriptor =
|
||||
mProtobuf.defineClassUnder(
|
||||
"FieldDescriptor",
|
||||
runtime.getObject(),
|
||||
new ObjectAllocator() {
|
||||
@Override
|
||||
public IRubyObject allocate(Ruby runtime, RubyClass klazz) {
|
||||
return new RubyFieldDescriptor(runtime, klazz);
|
||||
}
|
||||
});
|
||||
cFieldDescriptor.defineAnnotatedMethods(RubyFieldDescriptor.class);
|
||||
}
|
||||
});
|
||||
cFieldDescriptor.defineAnnotatedMethods(RubyFieldDescriptor.class);
|
||||
}
|
||||
|
||||
public RubyFieldDescriptor(Ruby runtime, RubyClass klazz) {
|
||||
super(runtime, klazz);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.label => label
|
||||
*
|
||||
* Returns this field's label (i.e., plurality), as a Ruby symbol.
|
||||
*
|
||||
* Valid field labels are:
|
||||
* :optional, :repeated
|
||||
*/
|
||||
@JRubyMethod(name = "label")
|
||||
public IRubyObject getLabel(ThreadContext context) {
|
||||
if (label == null) {
|
||||
calculateLabel(context);
|
||||
}
|
||||
return label;
|
||||
}
|
||||
|
||||
public RubyFieldDescriptor(Ruby runtime, RubyClass klazz) {
|
||||
super(runtime, klazz);
|
||||
/*
|
||||
* call-seq:
|
||||
* FieldDescriptor.name => name
|
||||
*
|
||||
* Returns the name of this field as a Ruby String, or nil if it is not set.
|
||||
*/
|
||||
@JRubyMethod(name = "name")
|
||||
public IRubyObject getName(ThreadContext context) {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* FieldDescriptor.subtype => message_or_enum_descriptor
|
||||
*
|
||||
* Returns the message or enum descriptor corresponding to this field's type if
|
||||
* it is a message or enum field, respectively, or nil otherwise. Cannot be
|
||||
* called *until* the containing message type is added to a pool (and thus
|
||||
* resolved).
|
||||
*/
|
||||
@JRubyMethod(name = "subtype")
|
||||
public IRubyObject getSubtype(ThreadContext context) {
|
||||
if (subtype == null) {
|
||||
calculateSubtype(context);
|
||||
}
|
||||
return subtype;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.type => type
|
||||
*
|
||||
* Returns this field's type, as a Ruby symbol, or nil if not yet set.
|
||||
*
|
||||
* Valid field types are:
|
||||
* :int32, :int64, :uint32, :uint64, :float, :double, :bool, :string,
|
||||
* :bytes, :message.
|
||||
*/
|
||||
@JRubyMethod(name = "type")
|
||||
public IRubyObject getType(ThreadContext context) {
|
||||
return Utils.fieldTypeToRuby(context, descriptor.getType());
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* FieldDescriptor.label => label
|
||||
*
|
||||
* Returns this field's label (i.e., plurality), as a Ruby symbol.
|
||||
*
|
||||
* Valid field labels are:
|
||||
* :optional, :repeated
|
||||
*/
|
||||
@JRubyMethod(name = "label")
|
||||
public IRubyObject getLabel(ThreadContext context) {
|
||||
if (label == null) {
|
||||
calculateLabel(context);
|
||||
}
|
||||
return label;
|
||||
/*
|
||||
* call-seq:
|
||||
* FieldDescriptor.number => number
|
||||
*
|
||||
* Returns the tag number for this field.
|
||||
*/
|
||||
@JRubyMethod(name = "number")
|
||||
public IRubyObject getNumber(ThreadContext context) {
|
||||
return this.number;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* FieldDescriptor.submsg_name => submsg_name
|
||||
*
|
||||
* Returns the name of the message or enum type corresponding to this field, if
|
||||
* it is a message or enum field (respectively), or nil otherwise. This type
|
||||
* name will be resolved within the context of the pool to which the containing
|
||||
* message type is added.
|
||||
*/
|
||||
// VALUE FieldDescriptor_submsg_name(VALUE _self) {
|
||||
// DEFINE_SELF(FieldDescriptor, self, _self);
|
||||
// switch (upb_fielddef_type(self->fielddef)) {
|
||||
// case UPB_TYPE_ENUM:
|
||||
// return rb_str_new2(
|
||||
// upb_enumdef_fullname(upb_fielddef_enumsubdef(self->fielddef)));
|
||||
// case UPB_TYPE_MESSAGE:
|
||||
// return rb_str_new2(
|
||||
// upb_msgdef_fullname(upb_fielddef_msgsubdef(self->fielddef)));
|
||||
// default:
|
||||
// return Qnil;
|
||||
// }
|
||||
// }
|
||||
/*
|
||||
* call-seq:
|
||||
* FieldDescriptor.submsg_name = submsg_name
|
||||
*
|
||||
* Sets the name of the message or enum type corresponding to this field, if it
|
||||
* is a message or enum field (respectively). This type name will be resolved
|
||||
* within the context of the pool to which the containing message type is added.
|
||||
* Cannot be called on field that are not of message or enum type, or on fields
|
||||
* that are part of a message type already added to a pool.
|
||||
*/
|
||||
// @JRubyMethod(name = "submsg_name=")
|
||||
// public IRubyObject setSubmsgName(ThreadContext context, IRubyObject name) {
|
||||
// this.builder.setTypeName("." + Utils.escapeIdentifier(name.asJavaString()));
|
||||
// return context.runtime.getNil();
|
||||
// }
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* FieldDescriptor.clear(message)
|
||||
*
|
||||
* Clears the field from the message if it's set.
|
||||
*/
|
||||
@JRubyMethod(name = "clear")
|
||||
public IRubyObject clearValue(ThreadContext context, IRubyObject message) {
|
||||
return ((RubyMessage) message).clearField(context, descriptor);
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* FieldDescriptor.get(message) => value
|
||||
*
|
||||
* Returns the value set for this field on the given message. Raises an
|
||||
* exception if message is of the wrong type.
|
||||
*/
|
||||
@JRubyMethod(name = "get")
|
||||
public IRubyObject getValue(ThreadContext context, IRubyObject message) {
|
||||
return ((RubyMessage) message).getField(context, descriptor);
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* FieldDescriptor.has?(message) => boolean
|
||||
*
|
||||
* Returns whether the value is set on the given message. Raises an
|
||||
* exception when calling for fields that do not have presence.
|
||||
*/
|
||||
@JRubyMethod(name = "has?")
|
||||
public IRubyObject has(ThreadContext context, IRubyObject message) {
|
||||
return ((RubyMessage) message).hasField(context, descriptor);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
@JRubyMethod(name = "set")
|
||||
public IRubyObject setValue(ThreadContext context, IRubyObject message, IRubyObject value) {
|
||||
((RubyMessage) message).setField(context, descriptor, value);
|
||||
return context.nil;
|
||||
}
|
||||
|
||||
protected void setDescriptor(
|
||||
ThreadContext context, FieldDescriptor descriptor, RubyDescriptorPool pool) {
|
||||
if (descriptor.isRequired()
|
||||
&& descriptor.getFile().getSyntax() == FileDescriptor.Syntax.PROTO3) {
|
||||
throw Utils.createTypeError(
|
||||
context,
|
||||
descriptor.getName()
|
||||
+ " is labeled required but required fields are unsupported in proto3");
|
||||
}
|
||||
this.descriptor = descriptor;
|
||||
this.name = context.runtime.newString(descriptor.getName());
|
||||
this.pool = pool;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* FieldDescriptor.name => name
|
||||
*
|
||||
* Returns the name of this field as a Ruby String, or nil if it is not set.
|
||||
*/
|
||||
@JRubyMethod(name = "name")
|
||||
public IRubyObject getName(ThreadContext context) {
|
||||
return this.name;
|
||||
private void calculateLabel(ThreadContext context) {
|
||||
if (descriptor.isRepeated()) {
|
||||
this.label = context.runtime.newSymbol("repeated");
|
||||
} else if (descriptor.isOptional()) {
|
||||
this.label = context.runtime.newSymbol("optional");
|
||||
} else {
|
||||
this.label = context.nil;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* FieldDescriptor.subtype => message_or_enum_descriptor
|
||||
*
|
||||
* Returns the message or enum descriptor corresponding to this field's type if
|
||||
* it is a message or enum field, respectively, or nil otherwise. Cannot be
|
||||
* called *until* the containing message type is added to a pool (and thus
|
||||
* resolved).
|
||||
*/
|
||||
@JRubyMethod(name = "subtype")
|
||||
public IRubyObject getSubtype(ThreadContext context) {
|
||||
if (subtype == null) {
|
||||
calculateSubtype(context);
|
||||
}
|
||||
return subtype;
|
||||
private void calculateSubtype(ThreadContext context) {
|
||||
FieldDescriptor.Type fdType = descriptor.getType();
|
||||
if (fdType == FieldDescriptor.Type.MESSAGE) {
|
||||
RubyString messageName = context.runtime.newString(descriptor.getMessageType().getFullName());
|
||||
this.subtype = pool.lookup(context, messageName);
|
||||
} else if (fdType == FieldDescriptor.Type.ENUM) {
|
||||
RubyString enumName = context.runtime.newString(descriptor.getEnumType().getFullName());
|
||||
this.subtype = pool.lookup(context, enumName);
|
||||
} else {
|
||||
this.subtype = context.nil;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* FieldDescriptor.type => type
|
||||
*
|
||||
* Returns this field's type, as a Ruby symbol, or nil if not yet set.
|
||||
*
|
||||
* Valid field types are:
|
||||
* :int32, :int64, :uint32, :uint64, :float, :double, :bool, :string,
|
||||
* :bytes, :message.
|
||||
*/
|
||||
@JRubyMethod(name = "type")
|
||||
public IRubyObject getType(ThreadContext context) {
|
||||
return Utils.fieldTypeToRuby(context, descriptor.getType());
|
||||
}
|
||||
private static final String DOT = ".";
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* FieldDescriptor.number => number
|
||||
*
|
||||
* Returns the tag number for this field.
|
||||
*/
|
||||
@JRubyMethod(name = "number")
|
||||
public IRubyObject getNumber(ThreadContext context) {
|
||||
return this.number;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* FieldDescriptor.submsg_name => submsg_name
|
||||
*
|
||||
* Returns the name of the message or enum type corresponding to this field, if
|
||||
* it is a message or enum field (respectively), or nil otherwise. This type
|
||||
* name will be resolved within the context of the pool to which the containing
|
||||
* message type is added.
|
||||
*/
|
||||
// VALUE FieldDescriptor_submsg_name(VALUE _self) {
|
||||
// DEFINE_SELF(FieldDescriptor, self, _self);
|
||||
// switch (upb_fielddef_type(self->fielddef)) {
|
||||
// case UPB_TYPE_ENUM:
|
||||
// return rb_str_new2(
|
||||
// upb_enumdef_fullname(upb_fielddef_enumsubdef(self->fielddef)));
|
||||
// case UPB_TYPE_MESSAGE:
|
||||
// return rb_str_new2(
|
||||
// upb_msgdef_fullname(upb_fielddef_msgsubdef(self->fielddef)));
|
||||
// default:
|
||||
// return Qnil;
|
||||
// }
|
||||
// }
|
||||
/*
|
||||
* call-seq:
|
||||
* FieldDescriptor.submsg_name = submsg_name
|
||||
*
|
||||
* Sets the name of the message or enum type corresponding to this field, if it
|
||||
* is a message or enum field (respectively). This type name will be resolved
|
||||
* within the context of the pool to which the containing message type is added.
|
||||
* Cannot be called on field that are not of message or enum type, or on fields
|
||||
* that are part of a message type already added to a pool.
|
||||
*/
|
||||
// @JRubyMethod(name = "submsg_name=")
|
||||
// public IRubyObject setSubmsgName(ThreadContext context, IRubyObject name) {
|
||||
// this.builder.setTypeName("." + Utils.escapeIdentifier(name.asJavaString()));
|
||||
// return context.runtime.getNil();
|
||||
// }
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* FieldDescriptor.clear(message)
|
||||
*
|
||||
* Clears the field from the message if it's set.
|
||||
*/
|
||||
@JRubyMethod(name = "clear")
|
||||
public IRubyObject clearValue(ThreadContext context, IRubyObject message) {
|
||||
return ((RubyMessage) message).clearField(context, descriptor);
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* FieldDescriptor.get(message) => value
|
||||
*
|
||||
* Returns the value set for this field on the given message. Raises an
|
||||
* exception if message is of the wrong type.
|
||||
*/
|
||||
@JRubyMethod(name = "get")
|
||||
public IRubyObject getValue(ThreadContext context, IRubyObject message) {
|
||||
return ((RubyMessage) message).getField(context, descriptor);
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* FieldDescriptor.has?(message) => boolean
|
||||
*
|
||||
* Returns whether the value is set on the given message. Raises an
|
||||
* exception when calling for fields that do not have presence.
|
||||
*/
|
||||
@JRubyMethod(name = "has?")
|
||||
public IRubyObject has(ThreadContext context, IRubyObject message) {
|
||||
return ((RubyMessage) message).hasField(context, descriptor);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
@JRubyMethod(name = "set")
|
||||
public IRubyObject setValue(ThreadContext context, IRubyObject message, IRubyObject value) {
|
||||
((RubyMessage) message).setField(context, descriptor, value);
|
||||
return context.nil;
|
||||
}
|
||||
|
||||
protected void setDescriptor(ThreadContext context, FieldDescriptor descriptor, RubyDescriptorPool pool) {
|
||||
if (descriptor.isRequired() && descriptor.getFile().getSyntax() == FileDescriptor.Syntax.PROTO3) {
|
||||
throw Utils.createTypeError(context, descriptor.getName() + " is labeled required but required fields are unsupported in proto3");
|
||||
}
|
||||
this.descriptor = descriptor;
|
||||
this.name = context.runtime.newString(descriptor.getName());
|
||||
this.pool = pool;
|
||||
}
|
||||
|
||||
private void calculateLabel(ThreadContext context) {
|
||||
if (descriptor.isRepeated()) {
|
||||
this.label = context.runtime.newSymbol("repeated");
|
||||
} else if (descriptor.isOptional()) {
|
||||
this.label = context.runtime.newSymbol("optional");
|
||||
} else {
|
||||
this.label = context.nil;
|
||||
}
|
||||
}
|
||||
|
||||
private void calculateSubtype(ThreadContext context) {
|
||||
FieldDescriptor.Type fdType = descriptor.getType();
|
||||
if (fdType == FieldDescriptor.Type.MESSAGE) {
|
||||
RubyString messageName = context.runtime.newString(descriptor.getMessageType().getFullName());
|
||||
this.subtype = pool.lookup(context, messageName);
|
||||
} else if (fdType == FieldDescriptor.Type.ENUM) {
|
||||
RubyString enumName = context.runtime.newString(descriptor.getEnumType().getFullName());
|
||||
this.subtype = pool.lookup(context, enumName);
|
||||
} else {
|
||||
this.subtype = context.nil;
|
||||
}
|
||||
}
|
||||
|
||||
private static final String DOT = ".";
|
||||
|
||||
private FieldDescriptor descriptor;
|
||||
private IRubyObject name;
|
||||
private IRubyObject label;
|
||||
private IRubyObject number;
|
||||
private IRubyObject subtype;
|
||||
private RubyDescriptorPool pool;
|
||||
private FieldDescriptor descriptor;
|
||||
private IRubyObject name;
|
||||
private IRubyObject label;
|
||||
private IRubyObject number;
|
||||
private IRubyObject subtype;
|
||||
private RubyDescriptorPool pool;
|
||||
}
|
||||
|
@ -32,7 +32,6 @@
|
||||
|
||||
package com.google.protobuf.jruby;
|
||||
|
||||
import com.google.protobuf.Descriptors.Descriptor;
|
||||
import com.google.protobuf.Descriptors.FileDescriptor;
|
||||
import com.google.protobuf.Descriptors.FileDescriptor.Syntax.*;
|
||||
import com.google.protobuf.Descriptors.GenericDescriptor;
|
||||
@ -46,61 +45,67 @@ import org.jruby.runtime.builtin.IRubyObject;
|
||||
|
||||
@JRubyClass(name = "FileDescriptor")
|
||||
public class RubyFileDescriptor extends RubyObject {
|
||||
public static void createRubyFileDescriptor(Ruby runtime) {
|
||||
RubyModule mProtobuf = runtime.getClassFromPath("Google::Protobuf");
|
||||
cFileDescriptor = mProtobuf.defineClassUnder("FileDescriptor", runtime.getObject(), new ObjectAllocator() {
|
||||
@Override
|
||||
public IRubyObject allocate(Ruby runtime, RubyClass klazz) {
|
||||
public static void createRubyFileDescriptor(Ruby runtime) {
|
||||
RubyModule mProtobuf = runtime.getClassFromPath("Google::Protobuf");
|
||||
cFileDescriptor =
|
||||
mProtobuf.defineClassUnder(
|
||||
"FileDescriptor",
|
||||
runtime.getObject(),
|
||||
new ObjectAllocator() {
|
||||
@Override
|
||||
public IRubyObject allocate(Ruby runtime, RubyClass klazz) {
|
||||
return new RubyFileDescriptor(runtime, klazz);
|
||||
}
|
||||
});
|
||||
cFileDescriptor.defineAnnotatedMethods(RubyFileDescriptor.class);
|
||||
}
|
||||
});
|
||||
cFileDescriptor.defineAnnotatedMethods(RubyFileDescriptor.class);
|
||||
}
|
||||
|
||||
public static RubyFileDescriptor getRubyFileDescriptor(
|
||||
ThreadContext context, GenericDescriptor descriptor) {
|
||||
RubyFileDescriptor rfd =
|
||||
(RubyFileDescriptor) cFileDescriptor.newInstance(context, Block.NULL_BLOCK);
|
||||
rfd.fileDescriptor = descriptor.getFile();
|
||||
return rfd;
|
||||
}
|
||||
|
||||
public RubyFileDescriptor(Ruby runtime, RubyClass klazz) {
|
||||
super(runtime, klazz);
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* FileDescriptor.name => name
|
||||
*
|
||||
* Returns the name of the file.
|
||||
*/
|
||||
@JRubyMethod(name = "name")
|
||||
public IRubyObject getName(ThreadContext context) {
|
||||
String name = fileDescriptor.getName();
|
||||
return name == null ? context.nil : context.runtime.newString(name);
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* FileDescriptor.syntax => syntax
|
||||
*
|
||||
* Returns this file descriptors syntax.
|
||||
*
|
||||
* Valid syntax versions are:
|
||||
* :proto2 or :proto3.
|
||||
*/
|
||||
@JRubyMethod(name = "syntax")
|
||||
public IRubyObject getSyntax(ThreadContext context) {
|
||||
switch (fileDescriptor.getSyntax()) {
|
||||
case PROTO2:
|
||||
return context.runtime.newSymbol("proto2");
|
||||
case PROTO3:
|
||||
return context.runtime.newSymbol("proto3");
|
||||
default:
|
||||
return context.nil;
|
||||
}
|
||||
}
|
||||
|
||||
public static RubyFileDescriptor getRubyFileDescriptor(ThreadContext context, GenericDescriptor descriptor) {
|
||||
RubyFileDescriptor rfd = (RubyFileDescriptor) cFileDescriptor.newInstance(context, Block.NULL_BLOCK);
|
||||
rfd.fileDescriptor = descriptor.getFile();
|
||||
return rfd;
|
||||
}
|
||||
private static RubyClass cFileDescriptor;
|
||||
|
||||
public RubyFileDescriptor(Ruby runtime, RubyClass klazz) {
|
||||
super(runtime, klazz);
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* FileDescriptor.name => name
|
||||
*
|
||||
* Returns the name of the file.
|
||||
*/
|
||||
@JRubyMethod(name = "name")
|
||||
public IRubyObject getName(ThreadContext context) {
|
||||
String name = fileDescriptor.getName();
|
||||
return name == null ? context.nil : context.runtime.newString(name);
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* FileDescriptor.syntax => syntax
|
||||
*
|
||||
* Returns this file descriptors syntax.
|
||||
*
|
||||
* Valid syntax versions are:
|
||||
* :proto2 or :proto3.
|
||||
*/
|
||||
@JRubyMethod(name = "syntax")
|
||||
public IRubyObject getSyntax(ThreadContext context) {
|
||||
switch (fileDescriptor.getSyntax()) {
|
||||
case PROTO2:
|
||||
return context.runtime.newSymbol("proto2");
|
||||
case PROTO3:
|
||||
return context.runtime.newSymbol("proto3");
|
||||
default:
|
||||
return context.nil;
|
||||
}
|
||||
}
|
||||
|
||||
private static RubyClass cFileDescriptor;
|
||||
|
||||
private FileDescriptor fileDescriptor;
|
||||
private FileDescriptor fileDescriptor;
|
||||
}
|
||||
|
@ -34,6 +34,13 @@ package com.google.protobuf.jruby;
|
||||
|
||||
import com.google.protobuf.Descriptors.FieldDescriptor;
|
||||
import com.google.protobuf.DynamicMessage;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.jruby.*;
|
||||
import org.jruby.anno.JRubyClass;
|
||||
import org.jruby.anno.JRubyMethod;
|
||||
@ -43,432 +50,438 @@ import org.jruby.runtime.ObjectAllocator;
|
||||
import org.jruby.runtime.ThreadContext;
|
||||
import org.jruby.runtime.builtin.IRubyObject;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@JRubyClass(name = "Map", include = "Enumerable")
|
||||
public class RubyMap extends RubyObject {
|
||||
public static void createRubyMap(Ruby runtime) {
|
||||
RubyModule protobuf = runtime.getClassFromPath("Google::Protobuf");
|
||||
RubyClass cMap = protobuf.defineClassUnder("Map", runtime.getObject(), new ObjectAllocator() {
|
||||
@Override
|
||||
public IRubyObject allocate(Ruby ruby, RubyClass rubyClass) {
|
||||
public static void createRubyMap(Ruby runtime) {
|
||||
RubyModule protobuf = runtime.getClassFromPath("Google::Protobuf");
|
||||
RubyClass cMap =
|
||||
protobuf.defineClassUnder(
|
||||
"Map",
|
||||
runtime.getObject(),
|
||||
new ObjectAllocator() {
|
||||
@Override
|
||||
public IRubyObject allocate(Ruby ruby, RubyClass rubyClass) {
|
||||
return new RubyMap(ruby, rubyClass);
|
||||
}
|
||||
});
|
||||
cMap.includeModule(runtime.getEnumerable());
|
||||
cMap.defineAnnotatedMethods(RubyMap.class);
|
||||
}
|
||||
|
||||
public RubyMap(Ruby ruby, RubyClass rubyClass) {
|
||||
super(ruby, rubyClass);
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Map.new(key_type, value_type, value_typeclass = nil, init_hashmap = {})
|
||||
* => new map
|
||||
*
|
||||
* Allocates a new Map container. This constructor may be called with 2, 3, or 4
|
||||
* arguments. The first two arguments are always present and are symbols (taking
|
||||
* on the same values as field-type symbols in message descriptors) that
|
||||
* indicate the type of the map key and value fields.
|
||||
*
|
||||
* The supported key types are: :int32, :int64, :uint32, :uint64, :fixed32,
|
||||
* :fixed64, :sfixed32, :sfixed64, :sint32, :sint64, :bool, :string, :bytes.
|
||||
*
|
||||
* The supported value types are: :int32, :int64, :uint32, :uint64, :fixed32,
|
||||
* :fixed64, :sfixed32, :sfixed64, :sint32, :sint64, :bool, :string, :bytes,
|
||||
* :enum, :message.
|
||||
*
|
||||
* The third argument, value_typeclass, must be present if value_type is :enum
|
||||
* or :message. As in RepeatedField#new, this argument must be a message class
|
||||
* (for :message) or enum module (for :enum).
|
||||
*
|
||||
* The last argument, if present, provides initial content for map. Note that
|
||||
* this may be an ordinary Ruby hashmap or another Map instance with identical
|
||||
* key and value types. Also note that this argument may be present whether or
|
||||
* not value_typeclass is present (and it is unambiguously separate from
|
||||
* value_typeclass because value_typeclass's presence is strictly determined by
|
||||
* value_type). The contents of this initial hashmap or Map instance are
|
||||
* shallow-copied into the new Map: the original map is unmodified, but
|
||||
* references to underlying objects will be shared if the value type is a
|
||||
* message type.
|
||||
*/
|
||||
@JRubyMethod(required = 2, optional = 2)
|
||||
public IRubyObject initialize(ThreadContext context, IRubyObject[] args) {
|
||||
this.table = new HashMap<IRubyObject, IRubyObject>();
|
||||
this.keyType = Utils.rubyToFieldType(args[0]);
|
||||
this.valueType = Utils.rubyToFieldType(args[1]);
|
||||
|
||||
switch (keyType) {
|
||||
case STRING:
|
||||
case BYTES:
|
||||
this.keyTypeIsString = true;
|
||||
break;
|
||||
case INT32:
|
||||
case INT64:
|
||||
case SINT32:
|
||||
case SINT64:
|
||||
case UINT32:
|
||||
case UINT64:
|
||||
case FIXED32:
|
||||
case FIXED64:
|
||||
case SFIXED32:
|
||||
case SFIXED64:
|
||||
case BOOL:
|
||||
// These are OK.
|
||||
break;
|
||||
default:
|
||||
throw context.runtime.newArgumentError("Invalid key type for map.");
|
||||
}
|
||||
|
||||
int initValueArg = 2;
|
||||
if (needTypeclass(this.valueType) && args.length > 2) {
|
||||
this.valueTypeClass = args[2];
|
||||
Utils.validateTypeClass(context, this.valueType, this.valueTypeClass);
|
||||
initValueArg = 3;
|
||||
} else {
|
||||
this.valueTypeClass = context.runtime.getNilClass();
|
||||
}
|
||||
|
||||
if (args.length > initValueArg) {
|
||||
mergeIntoSelf(context, args[initValueArg]);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
@JRubyMethod(name = "[]=")
|
||||
public IRubyObject indexSet(ThreadContext context, IRubyObject key, IRubyObject value) {
|
||||
checkFrozen();
|
||||
|
||||
/*
|
||||
* String types for keys return a different error than
|
||||
* other types for keys, so deal with them specifically first
|
||||
*/
|
||||
if (keyTypeIsString && !(key instanceof RubySymbol || key instanceof RubyString)) {
|
||||
throw Utils.createTypeError(context, "Expected string for map key");
|
||||
}
|
||||
key = Utils.checkType(context, keyType, "key", key, (RubyModule) valueTypeClass);
|
||||
value = Utils.checkType(context, valueType, "value", value, (RubyModule) valueTypeClass);
|
||||
IRubyObject symbol;
|
||||
if (valueType == FieldDescriptor.Type.ENUM
|
||||
&& Utils.isRubyNum(value)
|
||||
&& !(symbol = RubyEnum.lookup(context, valueTypeClass, value)).isNil()) {
|
||||
value = symbol;
|
||||
}
|
||||
this.table.put(key, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Map.[](key) => value
|
||||
*
|
||||
* Accesses the element at the given key. Throws an exception if the key type is
|
||||
* incorrect. Returns nil when the key is not present in the map.
|
||||
*/
|
||||
@JRubyMethod(name = "[]")
|
||||
public IRubyObject index(ThreadContext context, IRubyObject key) {
|
||||
key = Utils.symToString(key);
|
||||
return Helpers.nullToNil(table.get(key), context.nil);
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Map.==(other) => boolean
|
||||
*
|
||||
* Compares this map to another. Maps are equal if they have identical key sets,
|
||||
* and for each key, the values in both maps compare equal. Elements are
|
||||
* compared as per normal Ruby semantics, by calling their :== methods (or
|
||||
* performing a more efficient comparison for primitive types).
|
||||
*
|
||||
* Maps with dissimilar key types or value types/typeclasses are never equal,
|
||||
* even if value comparison (for example, between integers and floats) would
|
||||
* have otherwise indicated that every element has equal value.
|
||||
*/
|
||||
@JRubyMethod(name = "==")
|
||||
public IRubyObject eq(ThreadContext context, IRubyObject _other) {
|
||||
if (_other instanceof RubyHash) return singleLevelHash(context).op_equal(context, _other);
|
||||
RubyMap other = (RubyMap) _other;
|
||||
if (this == other) return context.runtime.getTrue();
|
||||
if (!typeCompatible(other) || this.table.size() != other.table.size())
|
||||
return context.runtime.getFalse();
|
||||
for (IRubyObject key : table.keySet()) {
|
||||
if (!other.table.containsKey(key)) return context.runtime.getFalse();
|
||||
if (!other.table.get(key).equals(table.get(key))) return context.runtime.getFalse();
|
||||
}
|
||||
return context.runtime.getTrue();
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
@JRubyMethod
|
||||
public IRubyObject inspect() {
|
||||
return singleLevelHash(getRuntime().getCurrentContext()).inspect();
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Map.hash => hash_value
|
||||
*
|
||||
* Returns a hash value based on this map's contents.
|
||||
*/
|
||||
@JRubyMethod
|
||||
public IRubyObject hash(ThreadContext context) {
|
||||
try {
|
||||
MessageDigest digest = MessageDigest.getInstance("SHA-256");
|
||||
for (IRubyObject key : table.keySet()) {
|
||||
digest.update((byte) key.hashCode());
|
||||
digest.update((byte) table.get(key).hashCode());
|
||||
}
|
||||
return context.runtime.newFixnum(ByteBuffer.wrap(digest.digest()).getLong());
|
||||
} catch (NoSuchAlgorithmException ignore) {
|
||||
return context.runtime.newFixnum(System.identityHashCode(table));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Map.keys => [list_of_keys]
|
||||
*
|
||||
* Returns the list of keys contained in the map, in unspecified order.
|
||||
*/
|
||||
@JRubyMethod
|
||||
public IRubyObject keys(ThreadContext context) {
|
||||
return RubyArray.newArray(context.runtime, table.keySet());
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Map.values => [list_of_values]
|
||||
*
|
||||
* Returns the list of values contained in the map, in unspecified order.
|
||||
*/
|
||||
@JRubyMethod
|
||||
public IRubyObject values(ThreadContext context) {
|
||||
return RubyArray.newArray(context.runtime, table.values());
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Map.clear
|
||||
*
|
||||
* Removes all entries from the map.
|
||||
*/
|
||||
@JRubyMethod
|
||||
public IRubyObject clear(ThreadContext context) {
|
||||
checkFrozen();
|
||||
table.clear();
|
||||
return context.nil;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
@JRubyMethod
|
||||
public IRubyObject each(ThreadContext context, Block block) {
|
||||
for (IRubyObject key : table.keySet()) {
|
||||
block.yieldSpecific(context, key, table.get(key));
|
||||
}
|
||||
return context.nil;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
@JRubyMethod
|
||||
public IRubyObject delete(ThreadContext context, IRubyObject key) {
|
||||
checkFrozen();
|
||||
return table.remove(key);
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Map.has_key?(key) => bool
|
||||
*
|
||||
* Returns true if the given key is present in the map. Throws an exception if
|
||||
* the key has the wrong type.
|
||||
*/
|
||||
@JRubyMethod(name = "has_key?")
|
||||
public IRubyObject hasKey(ThreadContext context, IRubyObject key) {
|
||||
return this.table.containsKey(key) ? context.runtime.getTrue() : context.runtime.getFalse();
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Map.length
|
||||
*
|
||||
* Returns the number of entries (key-value pairs) in the map.
|
||||
*/
|
||||
@JRubyMethod(name = {"length", "size"})
|
||||
public IRubyObject length(ThreadContext context) {
|
||||
return context.runtime.newFixnum(this.table.size());
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Map.dup => new_map
|
||||
*
|
||||
* Duplicates this map with a shallow copy. References to all non-primitive
|
||||
* element objects (e.g., submessages) are shared.
|
||||
*/
|
||||
@JRubyMethod
|
||||
public IRubyObject dup(ThreadContext context) {
|
||||
RubyMap newMap = newThisType(context);
|
||||
for (Map.Entry<IRubyObject, IRubyObject> entry : table.entrySet()) {
|
||||
newMap.table.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
return newMap;
|
||||
}
|
||||
|
||||
@JRubyMethod(name = "to_h")
|
||||
public RubyHash toHash(ThreadContext context) {
|
||||
Map<IRubyObject, IRubyObject> mapForHash = new HashMap();
|
||||
|
||||
table.forEach(
|
||||
(key, value) -> {
|
||||
if (!value.isNil()) {
|
||||
if (value.respondsTo("to_h")) {
|
||||
value = Helpers.invoke(context, value, "to_h");
|
||||
} else if (value.respondsTo("to_a")) {
|
||||
value = Helpers.invoke(context, value, "to_a");
|
||||
}
|
||||
});
|
||||
cMap.includeModule(runtime.getEnumerable());
|
||||
cMap.defineAnnotatedMethods(RubyMap.class);
|
||||
}
|
||||
|
||||
public RubyMap(Ruby ruby, RubyClass rubyClass) {
|
||||
super(ruby, rubyClass);
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Map.new(key_type, value_type, value_typeclass = nil, init_hashmap = {})
|
||||
* => new map
|
||||
*
|
||||
* Allocates a new Map container. This constructor may be called with 2, 3, or 4
|
||||
* arguments. The first two arguments are always present and are symbols (taking
|
||||
* on the same values as field-type symbols in message descriptors) that
|
||||
* indicate the type of the map key and value fields.
|
||||
*
|
||||
* The supported key types are: :int32, :int64, :uint32, :uint64, :fixed32,
|
||||
* :fixed64, :sfixed32, :sfixed64, :sint32, :sint64, :bool, :string, :bytes.
|
||||
*
|
||||
* The supported value types are: :int32, :int64, :uint32, :uint64, :fixed32,
|
||||
* :fixed64, :sfixed32, :sfixed64, :sint32, :sint64, :bool, :string, :bytes,
|
||||
* :enum, :message.
|
||||
*
|
||||
* The third argument, value_typeclass, must be present if value_type is :enum
|
||||
* or :message. As in RepeatedField#new, this argument must be a message class
|
||||
* (for :message) or enum module (for :enum).
|
||||
*
|
||||
* The last argument, if present, provides initial content for map. Note that
|
||||
* this may be an ordinary Ruby hashmap or another Map instance with identical
|
||||
* key and value types. Also note that this argument may be present whether or
|
||||
* not value_typeclass is present (and it is unambiguously separate from
|
||||
* value_typeclass because value_typeclass's presence is strictly determined by
|
||||
* value_type). The contents of this initial hashmap or Map instance are
|
||||
* shallow-copied into the new Map: the original map is unmodified, but
|
||||
* references to underlying objects will be shared if the value type is a
|
||||
* message type.
|
||||
*/
|
||||
@JRubyMethod(required = 2, optional = 2)
|
||||
public IRubyObject initialize(ThreadContext context, IRubyObject[] args) {
|
||||
this.table = new HashMap<IRubyObject, IRubyObject>();
|
||||
this.keyType = Utils.rubyToFieldType(args[0]);
|
||||
this.valueType = Utils.rubyToFieldType(args[1]);
|
||||
|
||||
switch(keyType) {
|
||||
case STRING:
|
||||
case BYTES:
|
||||
this.keyTypeIsString = true;
|
||||
break;
|
||||
case INT32:
|
||||
case INT64:
|
||||
case SINT32:
|
||||
case SINT64:
|
||||
case UINT32:
|
||||
case UINT64:
|
||||
case FIXED32:
|
||||
case FIXED64:
|
||||
case SFIXED32:
|
||||
case SFIXED64:
|
||||
case BOOL:
|
||||
// These are OK.
|
||||
break;
|
||||
default:
|
||||
throw context.runtime.newArgumentError("Invalid key type for map.");
|
||||
}
|
||||
|
||||
int initValueArg = 2;
|
||||
if (needTypeclass(this.valueType) && args.length > 2) {
|
||||
this.valueTypeClass = args[2];
|
||||
Utils.validateTypeClass(context, this.valueType, this.valueTypeClass);
|
||||
initValueArg = 3;
|
||||
} else {
|
||||
this.valueTypeClass = context.runtime.getNilClass();
|
||||
}
|
||||
|
||||
if (args.length > initValueArg) {
|
||||
mergeIntoSelf(context, args[initValueArg]);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
@JRubyMethod(name = "[]=")
|
||||
public IRubyObject indexSet(ThreadContext context, IRubyObject key, IRubyObject value) {
|
||||
checkFrozen();
|
||||
|
||||
/*
|
||||
* String types for keys return a different error than
|
||||
* other types for keys, so deal with them specifically first
|
||||
*/
|
||||
if (keyTypeIsString && !(key instanceof RubySymbol || key instanceof RubyString)) {
|
||||
throw Utils.createTypeError(context, "Expected string for map key");
|
||||
}
|
||||
key = Utils.checkType(context, keyType, "key", key, (RubyModule) valueTypeClass);
|
||||
value = Utils.checkType(context, valueType, "value", value, (RubyModule) valueTypeClass);
|
||||
IRubyObject symbol;
|
||||
if (valueType == FieldDescriptor.Type.ENUM &&
|
||||
Utils.isRubyNum(value) &&
|
||||
! (symbol = RubyEnum.lookup(context, valueTypeClass, value)).isNil()) {
|
||||
value = symbol;
|
||||
}
|
||||
this.table.put(key, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Map.[](key) => value
|
||||
*
|
||||
* Accesses the element at the given key. Throws an exception if the key type is
|
||||
* incorrect. Returns nil when the key is not present in the map.
|
||||
*/
|
||||
@JRubyMethod(name = "[]")
|
||||
public IRubyObject index(ThreadContext context, IRubyObject key) {
|
||||
key = Utils.symToString(key);
|
||||
return Helpers.nullToNil(table.get(key), context.nil);
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Map.==(other) => boolean
|
||||
*
|
||||
* Compares this map to another. Maps are equal if they have identical key sets,
|
||||
* and for each key, the values in both maps compare equal. Elements are
|
||||
* compared as per normal Ruby semantics, by calling their :== methods (or
|
||||
* performing a more efficient comparison for primitive types).
|
||||
*
|
||||
* Maps with dissimilar key types or value types/typeclasses are never equal,
|
||||
* even if value comparison (for example, between integers and floats) would
|
||||
* have otherwise indicated that every element has equal value.
|
||||
*/
|
||||
@JRubyMethod(name = "==")
|
||||
public IRubyObject eq(ThreadContext context, IRubyObject _other) {
|
||||
if (_other instanceof RubyHash)
|
||||
return singleLevelHash(context).op_equal(context, _other);
|
||||
RubyMap other = (RubyMap) _other;
|
||||
if (this == other) return context.runtime.getTrue();
|
||||
if (!typeCompatible(other) || this.table.size() != other.table.size())
|
||||
return context.runtime.getFalse();
|
||||
for (IRubyObject key : table.keySet()) {
|
||||
if (! other.table.containsKey(key))
|
||||
return context.runtime.getFalse();
|
||||
if (! other.table.get(key).equals(table.get(key)))
|
||||
return context.runtime.getFalse();
|
||||
}
|
||||
return context.runtime.getTrue();
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
@JRubyMethod
|
||||
public IRubyObject inspect() {
|
||||
return singleLevelHash(getRuntime().getCurrentContext()).inspect();
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Map.hash => hash_value
|
||||
*
|
||||
* Returns a hash value based on this map's contents.
|
||||
*/
|
||||
@JRubyMethod
|
||||
public IRubyObject hash(ThreadContext context) {
|
||||
try {
|
||||
MessageDigest digest = MessageDigest.getInstance("SHA-256");
|
||||
for (IRubyObject key : table.keySet()) {
|
||||
digest.update((byte) key.hashCode());
|
||||
digest.update((byte) table.get(key).hashCode());
|
||||
}
|
||||
return context.runtime.newFixnum(ByteBuffer.wrap(digest.digest()).getLong());
|
||||
} catch (NoSuchAlgorithmException ignore) {
|
||||
return context.runtime.newFixnum(System.identityHashCode(table));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Map.keys => [list_of_keys]
|
||||
*
|
||||
* Returns the list of keys contained in the map, in unspecified order.
|
||||
*/
|
||||
@JRubyMethod
|
||||
public IRubyObject keys(ThreadContext context) {
|
||||
return RubyArray.newArray(context.runtime, table.keySet());
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Map.values => [list_of_values]
|
||||
*
|
||||
* Returns the list of values contained in the map, in unspecified order.
|
||||
*/
|
||||
@JRubyMethod
|
||||
public IRubyObject values(ThreadContext context) {
|
||||
return RubyArray.newArray(context.runtime, table.values());
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Map.clear
|
||||
*
|
||||
* Removes all entries from the map.
|
||||
*/
|
||||
@JRubyMethod
|
||||
public IRubyObject clear(ThreadContext context) {
|
||||
checkFrozen();
|
||||
table.clear();
|
||||
return context.nil;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
@JRubyMethod
|
||||
public IRubyObject each(ThreadContext context, Block block) {
|
||||
for (IRubyObject key : table.keySet()) {
|
||||
block.yieldSpecific(context, key, table.get(key));
|
||||
}
|
||||
return context.nil;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
@JRubyMethod
|
||||
public IRubyObject delete(ThreadContext context, IRubyObject key) {
|
||||
checkFrozen();
|
||||
return table.remove(key);
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Map.has_key?(key) => bool
|
||||
*
|
||||
* Returns true if the given key is present in the map. Throws an exception if
|
||||
* the key has the wrong type.
|
||||
*/
|
||||
@JRubyMethod(name = "has_key?")
|
||||
public IRubyObject hasKey(ThreadContext context, IRubyObject key) {
|
||||
return this.table.containsKey(key) ? context.runtime.getTrue() : context.runtime.getFalse();
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Map.length
|
||||
*
|
||||
* Returns the number of entries (key-value pairs) in the map.
|
||||
*/
|
||||
@JRubyMethod(name = {"length", "size"})
|
||||
public IRubyObject length(ThreadContext context) {
|
||||
return context.runtime.newFixnum(this.table.size());
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Map.dup => new_map
|
||||
*
|
||||
* Duplicates this map with a shallow copy. References to all non-primitive
|
||||
* element objects (e.g., submessages) are shared.
|
||||
*/
|
||||
@JRubyMethod
|
||||
public IRubyObject dup(ThreadContext context) {
|
||||
RubyMap newMap = newThisType(context);
|
||||
for (Map.Entry<IRubyObject, IRubyObject> entry : table.entrySet()) {
|
||||
newMap.table.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
return newMap;
|
||||
}
|
||||
|
||||
@JRubyMethod(name = "to_h")
|
||||
public RubyHash toHash(ThreadContext context) {
|
||||
Map<IRubyObject, IRubyObject> mapForHash = new HashMap();
|
||||
|
||||
table.forEach((key, value) -> {
|
||||
if (!value.isNil()) {
|
||||
if (value.respondsTo("to_h")) {
|
||||
value = Helpers.invoke(context, value, "to_h");
|
||||
} else if (value.respondsTo("to_a")) {
|
||||
value = Helpers.invoke(context, value, "to_a");
|
||||
}
|
||||
mapForHash.put(key, value);
|
||||
}
|
||||
mapForHash.put(key, value);
|
||||
}
|
||||
});
|
||||
|
||||
return RubyHash.newHash(context.runtime, mapForHash, context.nil);
|
||||
}
|
||||
return RubyHash.newHash(context.runtime, mapForHash, context.nil);
|
||||
}
|
||||
|
||||
// Used by Google::Protobuf.deep_copy but not exposed directly.
|
||||
protected IRubyObject deepCopy(ThreadContext context) {
|
||||
RubyMap newMap = newThisType(context);
|
||||
switch (valueType) {
|
||||
case MESSAGE:
|
||||
for (IRubyObject key : table.keySet()) {
|
||||
RubyMessage message = (RubyMessage) table.get(key);
|
||||
newMap.table.put(key.dup(), message.deepCopy(context));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
for (IRubyObject key : table.keySet()) {
|
||||
newMap.table.put(key.dup(), table.get(key).dup());
|
||||
}
|
||||
}
|
||||
return newMap;
|
||||
}
|
||||
|
||||
protected List<DynamicMessage> build(ThreadContext context, RubyDescriptor descriptor, int depth, int recursionLimit) {
|
||||
List<DynamicMessage> list = new ArrayList<DynamicMessage>();
|
||||
RubyClass rubyClass = (RubyClass) descriptor.msgclass(context);
|
||||
FieldDescriptor keyField = descriptor.getField("key");
|
||||
FieldDescriptor valueField = descriptor.getField("value");
|
||||
// Used by Google::Protobuf.deep_copy but not exposed directly.
|
||||
protected IRubyObject deepCopy(ThreadContext context) {
|
||||
RubyMap newMap = newThisType(context);
|
||||
switch (valueType) {
|
||||
case MESSAGE:
|
||||
for (IRubyObject key : table.keySet()) {
|
||||
RubyMessage mapMessage = (RubyMessage) rubyClass.newInstance(context, Block.NULL_BLOCK);
|
||||
mapMessage.setField(context, keyField, key);
|
||||
mapMessage.setField(context, valueField, table.get(key));
|
||||
list.add(mapMessage.build(context, depth + 1, recursionLimit));
|
||||
RubyMessage message = (RubyMessage) table.get(key);
|
||||
newMap.table.put(key.dup(), message.deepCopy(context));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
for (IRubyObject key : table.keySet()) {
|
||||
newMap.table.put(key.dup(), table.get(key).dup());
|
||||
}
|
||||
return list;
|
||||
}
|
||||
return newMap;
|
||||
}
|
||||
|
||||
protected RubyMap mergeIntoSelf(final ThreadContext context, IRubyObject hashmap) {
|
||||
if (hashmap instanceof RubyHash) {
|
||||
((RubyHash) hashmap).visitAll(context, new RubyHash.Visitor() {
|
||||
protected List<DynamicMessage> build(
|
||||
ThreadContext context, RubyDescriptor descriptor, int depth, int recursionLimit) {
|
||||
List<DynamicMessage> list = new ArrayList<DynamicMessage>();
|
||||
RubyClass rubyClass = (RubyClass) descriptor.msgclass(context);
|
||||
FieldDescriptor keyField = descriptor.getField("key");
|
||||
FieldDescriptor valueField = descriptor.getField("value");
|
||||
for (IRubyObject key : table.keySet()) {
|
||||
RubyMessage mapMessage = (RubyMessage) rubyClass.newInstance(context, Block.NULL_BLOCK);
|
||||
mapMessage.setField(context, keyField, key);
|
||||
mapMessage.setField(context, valueField, table.get(key));
|
||||
list.add(mapMessage.build(context, depth + 1, recursionLimit));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
protected RubyMap mergeIntoSelf(final ThreadContext context, IRubyObject hashmap) {
|
||||
if (hashmap instanceof RubyHash) {
|
||||
((RubyHash) hashmap)
|
||||
.visitAll(
|
||||
context,
|
||||
new RubyHash.Visitor() {
|
||||
@Override
|
||||
public void visit(IRubyObject key, IRubyObject val) {
|
||||
if (val instanceof RubyHash && !valueTypeClass.isNil()) {
|
||||
val = ((RubyClass) valueTypeClass).newInstance(context, val, Block.NULL_BLOCK);
|
||||
}
|
||||
indexSet(context, key, val);
|
||||
if (val instanceof RubyHash && !valueTypeClass.isNil()) {
|
||||
val = ((RubyClass) valueTypeClass).newInstance(context, val, Block.NULL_BLOCK);
|
||||
}
|
||||
indexSet(context, key, val);
|
||||
}
|
||||
}, null);
|
||||
} else if (hashmap instanceof RubyMap) {
|
||||
RubyMap other = (RubyMap) hashmap;
|
||||
if (!typeCompatible(other)) {
|
||||
throw Utils.createTypeError(context, "Attempt to merge Map with mismatching types");
|
||||
}
|
||||
} else {
|
||||
throw Utils.createTypeError(context, "Unknown type merging into Map");
|
||||
}
|
||||
return this;
|
||||
},
|
||||
null);
|
||||
} else if (hashmap instanceof RubyMap) {
|
||||
RubyMap other = (RubyMap) hashmap;
|
||||
if (!typeCompatible(other)) {
|
||||
throw Utils.createTypeError(context, "Attempt to merge Map with mismatching types");
|
||||
}
|
||||
} else {
|
||||
throw Utils.createTypeError(context, "Unknown type merging into Map");
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
protected boolean typeCompatible(RubyMap other) {
|
||||
return this.keyType == other.keyType &&
|
||||
this.valueType == other.valueType &&
|
||||
this.valueTypeClass == other.valueTypeClass;
|
||||
protected boolean typeCompatible(RubyMap other) {
|
||||
return this.keyType == other.keyType
|
||||
&& this.valueType == other.valueType
|
||||
&& this.valueTypeClass == other.valueTypeClass;
|
||||
}
|
||||
|
||||
private RubyMap newThisType(ThreadContext context) {
|
||||
RubyMap newMap;
|
||||
if (needTypeclass(valueType)) {
|
||||
newMap =
|
||||
(RubyMap)
|
||||
metaClass.newInstance(
|
||||
context,
|
||||
Utils.fieldTypeToRuby(context, keyType),
|
||||
Utils.fieldTypeToRuby(context, valueType),
|
||||
valueTypeClass,
|
||||
Block.NULL_BLOCK);
|
||||
} else {
|
||||
newMap =
|
||||
(RubyMap)
|
||||
metaClass.newInstance(
|
||||
context,
|
||||
Utils.fieldTypeToRuby(context, keyType),
|
||||
Utils.fieldTypeToRuby(context, valueType),
|
||||
Block.NULL_BLOCK);
|
||||
}
|
||||
newMap.table = new HashMap<IRubyObject, IRubyObject>();
|
||||
return newMap;
|
||||
}
|
||||
|
||||
private RubyMap newThisType(ThreadContext context) {
|
||||
RubyMap newMap;
|
||||
if (needTypeclass(valueType)) {
|
||||
newMap = (RubyMap) metaClass.newInstance(context,
|
||||
Utils.fieldTypeToRuby(context, keyType),
|
||||
Utils.fieldTypeToRuby(context, valueType),
|
||||
valueTypeClass, Block.NULL_BLOCK);
|
||||
} else {
|
||||
newMap = (RubyMap) metaClass.newInstance(context,
|
||||
Utils.fieldTypeToRuby(context, keyType),
|
||||
Utils.fieldTypeToRuby(context, valueType),
|
||||
Block.NULL_BLOCK);
|
||||
}
|
||||
newMap.table = new HashMap<IRubyObject, IRubyObject>();
|
||||
return newMap;
|
||||
/*
|
||||
* toHash calls toHash on values, for some camparisons we only need
|
||||
* a hash with the original objects still as values
|
||||
*/
|
||||
private RubyHash singleLevelHash(ThreadContext context) {
|
||||
return RubyHash.newHash(context.runtime, table, context.nil);
|
||||
}
|
||||
|
||||
private boolean needTypeclass(FieldDescriptor.Type type) {
|
||||
switch (type) {
|
||||
case MESSAGE:
|
||||
case ENUM:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* toHash calls toHash on values, for some camparisons we only need
|
||||
* a hash with the original objects still as values
|
||||
*/
|
||||
private RubyHash singleLevelHash(ThreadContext context) {
|
||||
return RubyHash.newHash(context.runtime, table, context.nil);
|
||||
}
|
||||
|
||||
private boolean needTypeclass(FieldDescriptor.Type type) {
|
||||
switch(type) {
|
||||
case MESSAGE:
|
||||
case ENUM:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private FieldDescriptor.Type keyType;
|
||||
private FieldDescriptor.Type valueType;
|
||||
private IRubyObject valueTypeClass;
|
||||
private Map<IRubyObject, IRubyObject> table;
|
||||
private boolean keyTypeIsString = false;
|
||||
private FieldDescriptor.Type keyType;
|
||||
private FieldDescriptor.Type valueType;
|
||||
private IRubyObject valueTypeClass;
|
||||
private Map<IRubyObject, IRubyObject> table;
|
||||
private boolean keyTypeIsString = false;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -2,6 +2,10 @@ package com.google.protobuf.jruby;
|
||||
|
||||
import com.google.protobuf.Descriptors.FieldDescriptor;
|
||||
import com.google.protobuf.Descriptors.OneofDescriptor;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.jruby.Ruby;
|
||||
import org.jruby.RubyClass;
|
||||
import org.jruby.RubyModule;
|
||||
@ -13,74 +17,76 @@ import org.jruby.runtime.ObjectAllocator;
|
||||
import org.jruby.runtime.ThreadContext;
|
||||
import org.jruby.runtime.builtin.IRubyObject;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@JRubyClass(name = "OneofDescriptor", include = "Enumerable")
|
||||
public class RubyOneofDescriptor extends RubyObject {
|
||||
|
||||
public static void createRubyOneofDescriptor(Ruby runtime) {
|
||||
RubyModule protobuf = runtime.getClassFromPath("Google::Protobuf");
|
||||
RubyClass cRubyOneofDescriptor = protobuf.defineClassUnder("OneofDescriptor", runtime.getObject(), new ObjectAllocator() {
|
||||
@Override
|
||||
public IRubyObject allocate(Ruby ruby, RubyClass rubyClass) {
|
||||
public static void createRubyOneofDescriptor(Ruby runtime) {
|
||||
RubyModule protobuf = runtime.getClassFromPath("Google::Protobuf");
|
||||
RubyClass cRubyOneofDescriptor =
|
||||
protobuf.defineClassUnder(
|
||||
"OneofDescriptor",
|
||||
runtime.getObject(),
|
||||
new ObjectAllocator() {
|
||||
@Override
|
||||
public IRubyObject allocate(Ruby ruby, RubyClass rubyClass) {
|
||||
return new RubyOneofDescriptor(ruby, rubyClass);
|
||||
}
|
||||
});
|
||||
cRubyOneofDescriptor.defineAnnotatedMethods(RubyOneofDescriptor.class);
|
||||
cRubyOneofDescriptor.includeModule(runtime.getEnumerable());
|
||||
}
|
||||
});
|
||||
cRubyOneofDescriptor.defineAnnotatedMethods(RubyOneofDescriptor.class);
|
||||
cRubyOneofDescriptor.includeModule(runtime.getEnumerable());
|
||||
}
|
||||
|
||||
public RubyOneofDescriptor(Ruby ruby, RubyClass rubyClass) {
|
||||
super(ruby, rubyClass);
|
||||
fields = new ArrayList<RubyFieldDescriptor>();
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* OneofDescriptor.name => name
|
||||
*
|
||||
* Returns the name of this oneof.
|
||||
*/
|
||||
@JRubyMethod(name = "name")
|
||||
public IRubyObject getName(ThreadContext context) {
|
||||
return name;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* OneofDescriptor.each(&block) => nil
|
||||
*
|
||||
* Iterates through fields in this oneof, yielding to the block on each one.
|
||||
*/
|
||||
@JRubyMethod
|
||||
public IRubyObject each(ThreadContext context, Block block) {
|
||||
for (RubyFieldDescriptor field : fields) {
|
||||
block.yieldSpecific(context, field);
|
||||
}
|
||||
return context.nil;
|
||||
}
|
||||
|
||||
public RubyOneofDescriptor(Ruby ruby, RubyClass rubyClass) {
|
||||
super(ruby, rubyClass);
|
||||
fields = new ArrayList<RubyFieldDescriptor>();
|
||||
protected Collection<RubyFieldDescriptor> getFields() {
|
||||
return fields;
|
||||
}
|
||||
|
||||
protected OneofDescriptor getDescriptor() {
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
protected void setDescriptor(
|
||||
ThreadContext context,
|
||||
OneofDescriptor descriptor,
|
||||
Map<FieldDescriptor, RubyFieldDescriptor> fieldCache) {
|
||||
this.descriptor = descriptor;
|
||||
this.name = context.runtime.newString(descriptor.getName());
|
||||
|
||||
for (FieldDescriptor fd : descriptor.getFields()) {
|
||||
fields.add(fieldCache.get(fd));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* OneofDescriptor.name => name
|
||||
*
|
||||
* Returns the name of this oneof.
|
||||
*/
|
||||
@JRubyMethod(name = "name")
|
||||
public IRubyObject getName(ThreadContext context) {
|
||||
return name;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* OneofDescriptor.each(&block) => nil
|
||||
*
|
||||
* Iterates through fields in this oneof, yielding to the block on each one.
|
||||
*/
|
||||
@JRubyMethod
|
||||
public IRubyObject each(ThreadContext context, Block block) {
|
||||
for (RubyFieldDescriptor field : fields) {
|
||||
block.yieldSpecific(context, field);
|
||||
}
|
||||
return context.nil;
|
||||
}
|
||||
|
||||
protected Collection<RubyFieldDescriptor> getFields() {
|
||||
return fields;
|
||||
}
|
||||
|
||||
protected OneofDescriptor getDescriptor() {
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
protected void setDescriptor(ThreadContext context, OneofDescriptor descriptor, Map<FieldDescriptor, RubyFieldDescriptor> fieldCache) {
|
||||
this.descriptor = descriptor;
|
||||
this.name = context.runtime.newString(descriptor.getName());
|
||||
|
||||
for (FieldDescriptor fd : descriptor.getFields()) {
|
||||
fields.add(fieldCache.get(fd));
|
||||
}
|
||||
}
|
||||
|
||||
private IRubyObject name;
|
||||
private List<RubyFieldDescriptor> fields;
|
||||
private OneofDescriptor descriptor;
|
||||
private IRubyObject name;
|
||||
private List<RubyFieldDescriptor> fields;
|
||||
private OneofDescriptor descriptor;
|
||||
}
|
||||
|
@ -42,41 +42,42 @@ import org.jruby.runtime.builtin.IRubyObject;
|
||||
@JRubyModule(name = "Protobuf")
|
||||
public class RubyProtobuf {
|
||||
|
||||
public static void createProtobuf(Ruby runtime) {
|
||||
RubyModule mGoogle = runtime.getModule("Google");
|
||||
RubyModule mProtobuf = mGoogle.defineModuleUnder("Protobuf");
|
||||
mProtobuf.defineAnnotatedMethods(RubyProtobuf.class);
|
||||
RubyModule mInternal = mProtobuf.defineModuleUnder("Internal");
|
||||
}
|
||||
public static void createProtobuf(Ruby runtime) {
|
||||
RubyModule mGoogle = runtime.getModule("Google");
|
||||
RubyModule mProtobuf = mGoogle.defineModuleUnder("Protobuf");
|
||||
mProtobuf.defineAnnotatedMethods(RubyProtobuf.class);
|
||||
RubyModule mInternal = mProtobuf.defineModuleUnder("Internal");
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Google::Protobuf.deep_copy(obj) => copy_of_obj
|
||||
*
|
||||
* Performs a deep copy of either a RepeatedField instance or a message object,
|
||||
* recursively copying its members.
|
||||
*/
|
||||
@JRubyMethod(name = "deep_copy", meta = true)
|
||||
public static IRubyObject deepCopy(ThreadContext context, IRubyObject self, IRubyObject message) {
|
||||
if (message instanceof RubyMessage) {
|
||||
return ((RubyMessage) message).deepCopy(context);
|
||||
} else if (message instanceof RubyRepeatedField) {
|
||||
return ((RubyRepeatedField) message).deepCopy(context);
|
||||
} else {
|
||||
return ((RubyMap) message).deepCopy(context);
|
||||
}
|
||||
/*
|
||||
* call-seq:
|
||||
* Google::Protobuf.deep_copy(obj) => copy_of_obj
|
||||
*
|
||||
* Performs a deep copy of either a RepeatedField instance or a message object,
|
||||
* recursively copying its members.
|
||||
*/
|
||||
@JRubyMethod(name = "deep_copy", meta = true)
|
||||
public static IRubyObject deepCopy(ThreadContext context, IRubyObject self, IRubyObject message) {
|
||||
if (message instanceof RubyMessage) {
|
||||
return ((RubyMessage) message).deepCopy(context);
|
||||
} else if (message instanceof RubyRepeatedField) {
|
||||
return ((RubyRepeatedField) message).deepCopy(context);
|
||||
} else {
|
||||
return ((RubyMap) message).deepCopy(context);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Google::Protobuf.discard_unknown(msg)
|
||||
*
|
||||
* Discard unknown fields in the given message object and recursively discard
|
||||
* unknown fields in submessages.
|
||||
*/
|
||||
@JRubyMethod(name = "discard_unknown", meta = true)
|
||||
public static IRubyObject discardUnknown(ThreadContext context, IRubyObject self, IRubyObject message) {
|
||||
((RubyMessage) message).discardUnknownFields(context);
|
||||
return context.nil;
|
||||
}
|
||||
/*
|
||||
* call-seq:
|
||||
* Google::Protobuf.discard_unknown(msg)
|
||||
*
|
||||
* Discard unknown fields in the given message object and recursively discard
|
||||
* unknown fields in submessages.
|
||||
*/
|
||||
@JRubyMethod(name = "discard_unknown", meta = true)
|
||||
public static IRubyObject discardUnknown(
|
||||
ThreadContext context, IRubyObject self, IRubyObject message) {
|
||||
((RubyMessage) message).discardUnknownFields(context);
|
||||
return context.nil;
|
||||
}
|
||||
}
|
||||
|
@ -40,384 +40,391 @@ import org.jruby.runtime.Block;
|
||||
import org.jruby.runtime.ObjectAllocator;
|
||||
import org.jruby.runtime.ThreadContext;
|
||||
import org.jruby.runtime.builtin.IRubyObject;
|
||||
import java.util.Arrays;
|
||||
|
||||
@JRubyClass(name = "RepeatedClass", include = "Enumerable")
|
||||
public class RubyRepeatedField extends RubyObject {
|
||||
public static void createRubyRepeatedField(Ruby runtime) {
|
||||
RubyModule mProtobuf = runtime.getClassFromPath("Google::Protobuf");
|
||||
RubyClass cRepeatedField = mProtobuf.defineClassUnder("RepeatedField", runtime.getObject(),
|
||||
new ObjectAllocator() {
|
||||
@Override
|
||||
public IRubyObject allocate(Ruby runtime, RubyClass klazz) {
|
||||
return new RubyRepeatedField(runtime, klazz);
|
||||
}
|
||||
});
|
||||
cRepeatedField.defineAnnotatedMethods(RubyRepeatedField.class);
|
||||
cRepeatedField.includeModule(runtime.getEnumerable());
|
||||
public static void createRubyRepeatedField(Ruby runtime) {
|
||||
RubyModule mProtobuf = runtime.getClassFromPath("Google::Protobuf");
|
||||
RubyClass cRepeatedField =
|
||||
mProtobuf.defineClassUnder(
|
||||
"RepeatedField",
|
||||
runtime.getObject(),
|
||||
new ObjectAllocator() {
|
||||
@Override
|
||||
public IRubyObject allocate(Ruby runtime, RubyClass klazz) {
|
||||
return new RubyRepeatedField(runtime, klazz);
|
||||
}
|
||||
});
|
||||
cRepeatedField.defineAnnotatedMethods(RubyRepeatedField.class);
|
||||
cRepeatedField.includeModule(runtime.getEnumerable());
|
||||
}
|
||||
|
||||
public RubyRepeatedField(Ruby runtime, RubyClass klazz) {
|
||||
super(runtime, klazz);
|
||||
}
|
||||
|
||||
public RubyRepeatedField(
|
||||
Ruby runtime, RubyClass klazz, FieldDescriptor.Type fieldType, IRubyObject typeClass) {
|
||||
this(runtime, klazz);
|
||||
this.fieldType = fieldType;
|
||||
this.storage = runtime.newArray();
|
||||
this.typeClass = typeClass;
|
||||
}
|
||||
|
||||
@JRubyMethod(required = 1, optional = 2)
|
||||
public IRubyObject initialize(ThreadContext context, IRubyObject[] args) {
|
||||
Ruby runtime = context.runtime;
|
||||
this.storage = runtime.newArray();
|
||||
IRubyObject ary = null;
|
||||
if (!(args[0] instanceof RubySymbol)) {
|
||||
throw runtime.newArgumentError("Expected Symbol for type name");
|
||||
}
|
||||
this.fieldType = Utils.rubyToFieldType(args[0]);
|
||||
if (fieldType == FieldDescriptor.Type.MESSAGE || fieldType == FieldDescriptor.Type.ENUM) {
|
||||
if (args.length < 2)
|
||||
throw runtime.newArgumentError("Expected at least 2 arguments for message/enum");
|
||||
typeClass = args[1];
|
||||
if (args.length > 2) ary = args[2];
|
||||
Utils.validateTypeClass(context, fieldType, typeClass);
|
||||
} else {
|
||||
if (args.length > 2) throw runtime.newArgumentError("Too many arguments: expected 1 or 2");
|
||||
if (args.length > 1) ary = args[1];
|
||||
}
|
||||
if (ary != null) {
|
||||
RubyArray arr = ary.convertToArray();
|
||||
for (int i = 0; i < arr.size(); i++) {
|
||||
this.storage.add(arr.eltInternal(i));
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
@JRubyMethod(name = "[]=")
|
||||
public IRubyObject indexSet(ThreadContext context, IRubyObject index, IRubyObject value) {
|
||||
int arrIndex = normalizeArrayIndex(index);
|
||||
value = Utils.checkType(context, fieldType, name, value, (RubyModule) typeClass);
|
||||
IRubyObject defaultValue = defaultValue(context);
|
||||
for (int i = this.storage.size(); i < arrIndex; i++) {
|
||||
this.storage.set(i, defaultValue);
|
||||
}
|
||||
this.storage.set(arrIndex, value);
|
||||
return context.runtime.getNil();
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* RepeatedField.[](index) => value
|
||||
*
|
||||
* Accesses the element at the given index. Returns nil on out-of-bounds
|
||||
*/
|
||||
@JRubyMethod(
|
||||
required = 1,
|
||||
optional = 1,
|
||||
name = {"at", "[]"})
|
||||
public IRubyObject index(ThreadContext context, IRubyObject[] args) {
|
||||
if (args.length == 1) {
|
||||
IRubyObject arg = args[0];
|
||||
if (Utils.isRubyNum(arg)) {
|
||||
/* standard case */
|
||||
int arrIndex = normalizeArrayIndex(arg);
|
||||
if (arrIndex < 0 || arrIndex >= this.storage.size()) {
|
||||
return context.runtime.getNil();
|
||||
}
|
||||
return this.storage.eltInternal(arrIndex);
|
||||
} else if (arg instanceof RubyRange) {
|
||||
RubyRange range = ((RubyRange) arg);
|
||||
|
||||
int beg = RubyNumeric.num2int(range.first(context));
|
||||
int len = RubyNumeric.num2int(range.size(context));
|
||||
|
||||
if (len == 0) return context.runtime.newEmptyArray();
|
||||
|
||||
return this.storage.subseq(beg, len);
|
||||
}
|
||||
}
|
||||
/* assume 2 arguments */
|
||||
int beg = RubyNumeric.num2int(args[0]);
|
||||
int len = RubyNumeric.num2int(args[1]);
|
||||
if (beg < 0) {
|
||||
beg += this.storage.size();
|
||||
}
|
||||
if (beg >= this.storage.size()) {
|
||||
return context.runtime.getNil();
|
||||
}
|
||||
return this.storage.subseq(beg, len);
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* RepeatedField.push(value)
|
||||
*
|
||||
* Adds a new element to the repeated field.
|
||||
*/
|
||||
@JRubyMethod(
|
||||
name = {"push", "<<"},
|
||||
required = 1,
|
||||
rest = true)
|
||||
public IRubyObject push(ThreadContext context, IRubyObject[] args) {
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
IRubyObject val = args[i];
|
||||
if (fieldType != FieldDescriptor.Type.MESSAGE || !val.isNil()) {
|
||||
val = Utils.checkType(context, fieldType, name, val, (RubyModule) typeClass);
|
||||
}
|
||||
storage.add(val);
|
||||
}
|
||||
|
||||
public RubyRepeatedField(Ruby runtime, RubyClass klazz) {
|
||||
super(runtime, klazz);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public RubyRepeatedField(Ruby runtime, RubyClass klazz, FieldDescriptor.Type fieldType, IRubyObject typeClass) {
|
||||
this(runtime, klazz);
|
||||
this.fieldType = fieldType;
|
||||
this.storage = runtime.newArray();
|
||||
this.typeClass = typeClass;
|
||||
}
|
||||
/*
|
||||
* private Ruby method used by RepeatedField.pop
|
||||
*/
|
||||
@JRubyMethod(visibility = org.jruby.runtime.Visibility.PRIVATE)
|
||||
public IRubyObject pop_one(ThreadContext context) {
|
||||
IRubyObject ret = this.storage.last();
|
||||
this.storage.remove(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@JRubyMethod(required = 1, optional = 2)
|
||||
public IRubyObject initialize(ThreadContext context, IRubyObject[] args) {
|
||||
Ruby runtime = context.runtime;
|
||||
this.storage = runtime.newArray();
|
||||
IRubyObject ary = null;
|
||||
if (!(args[0] instanceof RubySymbol)) {
|
||||
throw runtime.newArgumentError("Expected Symbol for type name");
|
||||
}
|
||||
this.fieldType = Utils.rubyToFieldType(args[0]);
|
||||
if (fieldType == FieldDescriptor.Type.MESSAGE
|
||||
|| fieldType == FieldDescriptor.Type.ENUM) {
|
||||
if (args.length < 2)
|
||||
throw runtime.newArgumentError("Expected at least 2 arguments for message/enum");
|
||||
typeClass = args[1];
|
||||
if (args.length > 2)
|
||||
ary = args[2];
|
||||
Utils.validateTypeClass(context, fieldType, typeClass);
|
||||
} else {
|
||||
if (args.length > 2)
|
||||
throw runtime.newArgumentError("Too many arguments: expected 1 or 2");
|
||||
if (args.length > 1)
|
||||
ary = args[1];
|
||||
}
|
||||
if (ary != null) {
|
||||
RubyArray arr = ary.convertToArray();
|
||||
for (int i = 0; i < arr.size(); i++) {
|
||||
this.storage.add(arr.eltInternal(i));
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
/*
|
||||
* call-seq:
|
||||
* RepeatedField.replace(list)
|
||||
*
|
||||
* Replaces the contents of the repeated field with the given list of elements.
|
||||
*/
|
||||
@JRubyMethod
|
||||
public IRubyObject replace(ThreadContext context, IRubyObject list) {
|
||||
RubyArray arr = (RubyArray) list;
|
||||
checkArrayElementType(context, arr);
|
||||
this.storage = arr;
|
||||
return this;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
@JRubyMethod(name = "[]=")
|
||||
public IRubyObject indexSet(ThreadContext context, IRubyObject index, IRubyObject value) {
|
||||
int arrIndex = normalizeArrayIndex(index);
|
||||
value = Utils.checkType(context, fieldType, name, value, (RubyModule) typeClass);
|
||||
IRubyObject defaultValue = defaultValue(context);
|
||||
for (int i = this.storage.size(); i < arrIndex; i++) {
|
||||
this.storage.set(i, defaultValue);
|
||||
}
|
||||
this.storage.set(arrIndex, value);
|
||||
/*
|
||||
* call-seq:
|
||||
* RepeatedField.clear
|
||||
*
|
||||
* Clears (removes all elements from) this repeated field.
|
||||
*/
|
||||
@JRubyMethod
|
||||
public IRubyObject clear(ThreadContext context) {
|
||||
this.storage.clear();
|
||||
return this;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* RepeatedField.length
|
||||
*
|
||||
* Returns the length of this repeated field.
|
||||
*/
|
||||
@JRubyMethod(name = {"length", "size"})
|
||||
public IRubyObject length(ThreadContext context) {
|
||||
return context.runtime.newFixnum(this.storage.size());
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* RepeatedField.+(other) => repeated field
|
||||
*
|
||||
* Returns a new repeated field that contains the concatenated list of this
|
||||
* repeated field's elements and other's elements. The other (second) list may
|
||||
* be either another repeated field or a Ruby array.
|
||||
*/
|
||||
@JRubyMethod(name = {"+"})
|
||||
public IRubyObject plus(ThreadContext context, IRubyObject list) {
|
||||
RubyRepeatedField dup = (RubyRepeatedField) dup(context);
|
||||
if (list instanceof RubyArray) {
|
||||
checkArrayElementType(context, (RubyArray) list);
|
||||
dup.storage.addAll((RubyArray) list);
|
||||
} else {
|
||||
RubyRepeatedField repeatedField = (RubyRepeatedField) list;
|
||||
if (!fieldType.equals(repeatedField.fieldType)
|
||||
|| (typeClass != null && !typeClass.equals(repeatedField.typeClass)))
|
||||
throw context.runtime.newArgumentError(
|
||||
"Attempt to append RepeatedField with different element type.");
|
||||
dup.storage.addAll((RubyArray) repeatedField.toArray(context));
|
||||
}
|
||||
return dup;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* RepeatedField.concat(other) => self
|
||||
*
|
||||
* concats the passed in array to self. Returns a Ruby array.
|
||||
*/
|
||||
@JRubyMethod
|
||||
public IRubyObject concat(ThreadContext context, IRubyObject list) {
|
||||
if (list instanceof RubyArray) {
|
||||
checkArrayElementType(context, (RubyArray) list);
|
||||
this.storage.addAll((RubyArray) list);
|
||||
} else {
|
||||
RubyRepeatedField repeatedField = (RubyRepeatedField) list;
|
||||
if (!fieldType.equals(repeatedField.fieldType)
|
||||
|| (typeClass != null && !typeClass.equals(repeatedField.typeClass)))
|
||||
throw context.runtime.newArgumentError(
|
||||
"Attempt to append RepeatedField with different element type.");
|
||||
this.storage.addAll((RubyArray) repeatedField.toArray(context));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* RepeatedField.hash => hash_value
|
||||
*
|
||||
* Returns a hash value computed from this repeated field's elements.
|
||||
*/
|
||||
@JRubyMethod
|
||||
public IRubyObject hash(ThreadContext context) {
|
||||
int hashCode = this.storage.hashCode();
|
||||
return context.runtime.newFixnum(hashCode);
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* RepeatedField.==(other) => boolean
|
||||
*
|
||||
* Compares this repeated field to another. Repeated fields are equal if their
|
||||
* element types are equal, their lengths are equal, and each element is equal.
|
||||
* Elements are compared as per normal Ruby semantics, by calling their :==
|
||||
* methods (or performing a more efficient comparison for primitive types).
|
||||
*/
|
||||
@JRubyMethod(name = "==")
|
||||
public IRubyObject eq(ThreadContext context, IRubyObject other) {
|
||||
return this.toArray(context).op_equal(context, other);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
@JRubyMethod
|
||||
public IRubyObject each(ThreadContext context, Block block) {
|
||||
this.storage.each(context, block);
|
||||
return this;
|
||||
}
|
||||
|
||||
@JRubyMethod(name = {"to_ary", "to_a"})
|
||||
public IRubyObject toArray(ThreadContext context) {
|
||||
return this.storage;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* RepeatedField.dup => repeated_field
|
||||
*
|
||||
* Duplicates this repeated field with a shallow copy. References to all
|
||||
* non-primitive element objects (e.g., submessages) are shared.
|
||||
*/
|
||||
@JRubyMethod
|
||||
public IRubyObject dup(ThreadContext context) {
|
||||
RubyRepeatedField dup = new RubyRepeatedField(context.runtime, metaClass, fieldType, typeClass);
|
||||
dup.push(context, storage.toJavaArray());
|
||||
return dup;
|
||||
}
|
||||
|
||||
@JRubyMethod
|
||||
public IRubyObject inspect() {
|
||||
return storage.inspect();
|
||||
}
|
||||
|
||||
// Java API
|
||||
protected IRubyObject get(int index) {
|
||||
return this.storage.eltInternal(index);
|
||||
}
|
||||
|
||||
protected RubyRepeatedField deepCopy(ThreadContext context) {
|
||||
RubyRepeatedField copy =
|
||||
new RubyRepeatedField(context.runtime, metaClass, fieldType, typeClass);
|
||||
for (int i = 0; i < size(); i++) {
|
||||
IRubyObject value = storage.eltInternal(i);
|
||||
if (fieldType == FieldDescriptor.Type.MESSAGE) {
|
||||
copy.storage.add(((RubyMessage) value).deepCopy(context));
|
||||
} else {
|
||||
copy.storage.add(value);
|
||||
}
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
protected void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
protected int size() {
|
||||
return this.storage.size();
|
||||
}
|
||||
|
||||
private IRubyObject defaultValue(ThreadContext context) {
|
||||
SentinelOuterClass.Sentinel sentinel = SentinelOuterClass.Sentinel.getDefaultInstance();
|
||||
Object value;
|
||||
switch (fieldType) {
|
||||
case INT32:
|
||||
value = sentinel.getDefaultInt32();
|
||||
break;
|
||||
case INT64:
|
||||
value = sentinel.getDefaultInt64();
|
||||
break;
|
||||
case UINT32:
|
||||
value = sentinel.getDefaultUnit32();
|
||||
break;
|
||||
case UINT64:
|
||||
value = sentinel.getDefaultUint64();
|
||||
break;
|
||||
case FLOAT:
|
||||
value = sentinel.getDefaultFloat();
|
||||
break;
|
||||
case DOUBLE:
|
||||
value = sentinel.getDefaultDouble();
|
||||
break;
|
||||
case BOOL:
|
||||
value = sentinel.getDefaultBool();
|
||||
break;
|
||||
case BYTES:
|
||||
value = sentinel.getDefaultBytes();
|
||||
break;
|
||||
case STRING:
|
||||
value = sentinel.getDefaultString();
|
||||
break;
|
||||
case ENUM:
|
||||
IRubyObject defaultEnumLoc = context.runtime.newFixnum(0);
|
||||
return RubyEnum.lookup(context, typeClass, defaultEnumLoc);
|
||||
default:
|
||||
return context.runtime.getNil();
|
||||
}
|
||||
return Utils.wrapPrimaryValue(context, fieldType, value);
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* RepeatedField.[](index) => value
|
||||
*
|
||||
* Accesses the element at the given index. Returns nil on out-of-bounds
|
||||
*/
|
||||
@JRubyMethod(required=1, optional=1, name = {"at", "[]"})
|
||||
public IRubyObject index(ThreadContext context, IRubyObject[] args) {
|
||||
if (args.length == 1){
|
||||
IRubyObject arg = args[0];
|
||||
if (Utils.isRubyNum(arg)) {
|
||||
/* standard case */
|
||||
int arrIndex = normalizeArrayIndex(arg);
|
||||
if (arrIndex < 0 || arrIndex >= this.storage.size()) {
|
||||
return context.runtime.getNil();
|
||||
}
|
||||
return this.storage.eltInternal(arrIndex);
|
||||
} else if (arg instanceof RubyRange) {
|
||||
RubyRange range = ((RubyRange) arg);
|
||||
|
||||
int beg = RubyNumeric.num2int(range.first(context));
|
||||
int len = RubyNumeric.num2int(range.size(context));
|
||||
|
||||
if (len == 0) return context.runtime.newEmptyArray();
|
||||
|
||||
return this.storage.subseq(beg, len);
|
||||
}
|
||||
}
|
||||
/* assume 2 arguments */
|
||||
int beg = RubyNumeric.num2int(args[0]);
|
||||
int len = RubyNumeric.num2int(args[1]);
|
||||
if (beg < 0) {
|
||||
beg += this.storage.size();
|
||||
}
|
||||
if (beg >= this.storage.size()) {
|
||||
return context.runtime.getNil();
|
||||
}
|
||||
return this.storage.subseq(beg, len);
|
||||
private void checkArrayElementType(ThreadContext context, RubyArray arr) {
|
||||
for (int i = 0; i < arr.getLength(); i++) {
|
||||
Utils.checkType(context, fieldType, name, arr.eltInternal(i), (RubyModule) typeClass);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* RepeatedField.push(value)
|
||||
*
|
||||
* Adds a new element to the repeated field.
|
||||
*/
|
||||
@JRubyMethod(name = {"push", "<<"}, required = 1, rest = true)
|
||||
public IRubyObject push(ThreadContext context, IRubyObject[] args) {
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
IRubyObject val = args[i];
|
||||
if (fieldType != FieldDescriptor.Type.MESSAGE || !val.isNil()) {
|
||||
val = Utils.checkType(context, fieldType, name, val, (RubyModule) typeClass);
|
||||
}
|
||||
storage.add(val);
|
||||
}
|
||||
|
||||
return this;
|
||||
private int normalizeArrayIndex(IRubyObject index) {
|
||||
int arrIndex = RubyNumeric.num2int(index);
|
||||
int arrSize = this.storage.size();
|
||||
if (arrIndex < 0 && arrSize > 0) {
|
||||
arrIndex = arrSize + arrIndex;
|
||||
}
|
||||
return arrIndex;
|
||||
}
|
||||
|
||||
/*
|
||||
* private Ruby method used by RepeatedField.pop
|
||||
*/
|
||||
@JRubyMethod(visibility = org.jruby.runtime.Visibility.PRIVATE)
|
||||
public IRubyObject pop_one(ThreadContext context) {
|
||||
IRubyObject ret = this.storage.last();
|
||||
this.storage.remove(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* RepeatedField.replace(list)
|
||||
*
|
||||
* Replaces the contents of the repeated field with the given list of elements.
|
||||
*/
|
||||
@JRubyMethod
|
||||
public IRubyObject replace(ThreadContext context, IRubyObject list) {
|
||||
RubyArray arr = (RubyArray) list;
|
||||
checkArrayElementType(context, arr);
|
||||
this.storage = arr;
|
||||
return this;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* RepeatedField.clear
|
||||
*
|
||||
* Clears (removes all elements from) this repeated field.
|
||||
*/
|
||||
@JRubyMethod
|
||||
public IRubyObject clear(ThreadContext context) {
|
||||
this.storage.clear();
|
||||
return this;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* RepeatedField.length
|
||||
*
|
||||
* Returns the length of this repeated field.
|
||||
*/
|
||||
@JRubyMethod(name = {"length", "size"})
|
||||
public IRubyObject length(ThreadContext context) {
|
||||
return context.runtime.newFixnum(this.storage.size());
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* RepeatedField.+(other) => repeated field
|
||||
*
|
||||
* Returns a new repeated field that contains the concatenated list of this
|
||||
* repeated field's elements and other's elements. The other (second) list may
|
||||
* be either another repeated field or a Ruby array.
|
||||
*/
|
||||
@JRubyMethod(name = {"+"})
|
||||
public IRubyObject plus(ThreadContext context, IRubyObject list) {
|
||||
RubyRepeatedField dup = (RubyRepeatedField) dup(context);
|
||||
if (list instanceof RubyArray) {
|
||||
checkArrayElementType(context, (RubyArray) list);
|
||||
dup.storage.addAll((RubyArray) list);
|
||||
} else {
|
||||
RubyRepeatedField repeatedField = (RubyRepeatedField) list;
|
||||
if (! fieldType.equals(repeatedField.fieldType) || (typeClass != null && !
|
||||
typeClass.equals(repeatedField.typeClass)))
|
||||
throw context.runtime.newArgumentError("Attempt to append RepeatedField with different element type.");
|
||||
dup.storage.addAll((RubyArray) repeatedField.toArray(context));
|
||||
}
|
||||
return dup;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* RepeatedField.concat(other) => self
|
||||
*
|
||||
* concats the passed in array to self. Returns a Ruby array.
|
||||
*/
|
||||
@JRubyMethod
|
||||
public IRubyObject concat(ThreadContext context, IRubyObject list) {
|
||||
if (list instanceof RubyArray) {
|
||||
checkArrayElementType(context, (RubyArray) list);
|
||||
this.storage.addAll((RubyArray) list);
|
||||
} else {
|
||||
RubyRepeatedField repeatedField = (RubyRepeatedField) list;
|
||||
if (! fieldType.equals(repeatedField.fieldType) || (typeClass != null && !
|
||||
typeClass.equals(repeatedField.typeClass)))
|
||||
throw context.runtime.newArgumentError("Attempt to append RepeatedField with different element type.");
|
||||
this.storage.addAll((RubyArray) repeatedField.toArray(context));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* RepeatedField.hash => hash_value
|
||||
*
|
||||
* Returns a hash value computed from this repeated field's elements.
|
||||
*/
|
||||
@JRubyMethod
|
||||
public IRubyObject hash(ThreadContext context) {
|
||||
int hashCode = this.storage.hashCode();
|
||||
return context.runtime.newFixnum(hashCode);
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* RepeatedField.==(other) => boolean
|
||||
*
|
||||
* Compares this repeated field to another. Repeated fields are equal if their
|
||||
* element types are equal, their lengths are equal, and each element is equal.
|
||||
* Elements are compared as per normal Ruby semantics, by calling their :==
|
||||
* methods (or performing a more efficient comparison for primitive types).
|
||||
*/
|
||||
@JRubyMethod(name = "==")
|
||||
public IRubyObject eq(ThreadContext context, IRubyObject other) {
|
||||
return this.toArray(context).op_equal(context, other);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
@JRubyMethod
|
||||
public IRubyObject each(ThreadContext context, Block block) {
|
||||
this.storage.each(context, block);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@JRubyMethod(name = {"to_ary", "to_a"})
|
||||
public IRubyObject toArray(ThreadContext context) {
|
||||
return this.storage;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* RepeatedField.dup => repeated_field
|
||||
*
|
||||
* Duplicates this repeated field with a shallow copy. References to all
|
||||
* non-primitive element objects (e.g., submessages) are shared.
|
||||
*/
|
||||
@JRubyMethod
|
||||
public IRubyObject dup(ThreadContext context) {
|
||||
RubyRepeatedField dup = new RubyRepeatedField(context.runtime, metaClass, fieldType, typeClass);
|
||||
dup.push(context, storage.toJavaArray());
|
||||
return dup;
|
||||
}
|
||||
|
||||
@JRubyMethod
|
||||
public IRubyObject inspect() {
|
||||
return storage.inspect();
|
||||
}
|
||||
|
||||
// Java API
|
||||
protected IRubyObject get(int index) {
|
||||
return this.storage.eltInternal(index);
|
||||
}
|
||||
|
||||
protected RubyRepeatedField deepCopy(ThreadContext context) {
|
||||
RubyRepeatedField copy = new RubyRepeatedField(context.runtime, metaClass, fieldType, typeClass);
|
||||
for (int i = 0; i < size(); i++) {
|
||||
IRubyObject value = storage.eltInternal(i);
|
||||
if (fieldType == FieldDescriptor.Type.MESSAGE) {
|
||||
copy.storage.add(((RubyMessage) value).deepCopy(context));
|
||||
} else {
|
||||
copy.storage.add(value);
|
||||
}
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
protected void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
protected int size() {
|
||||
return this.storage.size();
|
||||
}
|
||||
|
||||
private IRubyObject defaultValue(ThreadContext context) {
|
||||
SentinelOuterClass.Sentinel sentinel = SentinelOuterClass.Sentinel.getDefaultInstance();
|
||||
Object value;
|
||||
switch (fieldType) {
|
||||
case INT32:
|
||||
value = sentinel.getDefaultInt32();
|
||||
break;
|
||||
case INT64:
|
||||
value = sentinel.getDefaultInt64();
|
||||
break;
|
||||
case UINT32:
|
||||
value = sentinel.getDefaultUnit32();
|
||||
break;
|
||||
case UINT64:
|
||||
value = sentinel.getDefaultUint64();
|
||||
break;
|
||||
case FLOAT:
|
||||
value = sentinel.getDefaultFloat();
|
||||
break;
|
||||
case DOUBLE:
|
||||
value = sentinel.getDefaultDouble();
|
||||
break;
|
||||
case BOOL:
|
||||
value = sentinel.getDefaultBool();
|
||||
break;
|
||||
case BYTES:
|
||||
value = sentinel.getDefaultBytes();
|
||||
break;
|
||||
case STRING:
|
||||
value = sentinel.getDefaultString();
|
||||
break;
|
||||
case ENUM:
|
||||
IRubyObject defaultEnumLoc = context.runtime.newFixnum(0);
|
||||
return RubyEnum.lookup(context, typeClass, defaultEnumLoc);
|
||||
default:
|
||||
return context.runtime.getNil();
|
||||
}
|
||||
return Utils.wrapPrimaryValue(context, fieldType, value);
|
||||
}
|
||||
|
||||
private void checkArrayElementType(ThreadContext context, RubyArray arr) {
|
||||
for (int i = 0; i < arr.getLength(); i++) {
|
||||
Utils.checkType(context, fieldType, name, arr.eltInternal(i), (RubyModule) typeClass);
|
||||
}
|
||||
}
|
||||
|
||||
private int normalizeArrayIndex(IRubyObject index) {
|
||||
int arrIndex = RubyNumeric.num2int(index);
|
||||
int arrSize = this.storage.size();
|
||||
if (arrIndex < 0 && arrSize > 0) {
|
||||
arrIndex = arrSize + arrIndex;
|
||||
}
|
||||
return arrIndex;
|
||||
}
|
||||
|
||||
private FieldDescriptor.Type fieldType;
|
||||
private IRubyObject typeClass;
|
||||
private RubyArray storage;
|
||||
private String name;
|
||||
private FieldDescriptor.Type fieldType;
|
||||
private IRubyObject typeClass;
|
||||
private RubyArray storage;
|
||||
private String name;
|
||||
}
|
||||
|
@ -37,74 +37,53 @@ package com.google.protobuf.jruby;
|
||||
|
||||
public final class SentinelOuterClass {
|
||||
private SentinelOuterClass() {}
|
||||
public static void registerAllExtensions(
|
||||
com.google.protobuf.ExtensionRegistry registry) {
|
||||
}
|
||||
public interface SentinelOrBuilder extends
|
||||
|
||||
public static void registerAllExtensions(com.google.protobuf.ExtensionRegistry registry) {}
|
||||
|
||||
public interface SentinelOrBuilder
|
||||
extends
|
||||
// @@protoc_insertion_point(interface_extends:com.google.protobuf.jruby.Sentinel)
|
||||
com.google.protobuf.MessageOrBuilder {
|
||||
|
||||
/**
|
||||
* <code>optional int32 default_int32 = 1;</code>
|
||||
*/
|
||||
/** <code>optional int32 default_int32 = 1;</code> */
|
||||
int getDefaultInt32();
|
||||
|
||||
/**
|
||||
* <code>optional int64 default_int64 = 2;</code>
|
||||
*/
|
||||
/** <code>optional int64 default_int64 = 2;</code> */
|
||||
long getDefaultInt64();
|
||||
|
||||
/**
|
||||
* <code>optional uint32 default_unit32 = 3;</code>
|
||||
*/
|
||||
/** <code>optional uint32 default_unit32 = 3;</code> */
|
||||
int getDefaultUnit32();
|
||||
|
||||
/**
|
||||
* <code>optional uint64 default_uint64 = 4;</code>
|
||||
*/
|
||||
/** <code>optional uint64 default_uint64 = 4;</code> */
|
||||
long getDefaultUint64();
|
||||
|
||||
/**
|
||||
* <code>optional string default_string = 5;</code>
|
||||
*/
|
||||
/** <code>optional string default_string = 5;</code> */
|
||||
java.lang.String getDefaultString();
|
||||
/**
|
||||
* <code>optional string default_string = 5;</code>
|
||||
*/
|
||||
com.google.protobuf.ByteString
|
||||
getDefaultStringBytes();
|
||||
/** <code>optional string default_string = 5;</code> */
|
||||
com.google.protobuf.ByteString getDefaultStringBytes();
|
||||
|
||||
/**
|
||||
* <code>optional bool default_bool = 6;</code>
|
||||
*/
|
||||
/** <code>optional bool default_bool = 6;</code> */
|
||||
boolean getDefaultBool();
|
||||
|
||||
/**
|
||||
* <code>optional float default_float = 7;</code>
|
||||
*/
|
||||
/** <code>optional float default_float = 7;</code> */
|
||||
float getDefaultFloat();
|
||||
|
||||
/**
|
||||
* <code>optional double default_double = 8;</code>
|
||||
*/
|
||||
/** <code>optional double default_double = 8;</code> */
|
||||
double getDefaultDouble();
|
||||
|
||||
/**
|
||||
* <code>optional bytes default_bytes = 9;</code>
|
||||
*/
|
||||
/** <code>optional bytes default_bytes = 9;</code> */
|
||||
com.google.protobuf.ByteString getDefaultBytes();
|
||||
}
|
||||
/**
|
||||
* Protobuf type {@code com.google.protobuf.jruby.Sentinel}
|
||||
*/
|
||||
public static final class Sentinel extends
|
||||
com.google.protobuf.GeneratedMessage implements
|
||||
/** Protobuf type {@code com.google.protobuf.jruby.Sentinel} */
|
||||
public static final class Sentinel extends com.google.protobuf.GeneratedMessage
|
||||
implements
|
||||
// @@protoc_insertion_point(message_implements:com.google.protobuf.jruby.Sentinel)
|
||||
SentinelOrBuilder {
|
||||
// Use Sentinel.newBuilder() to construct.
|
||||
private Sentinel(com.google.protobuf.GeneratedMessage.Builder builder) {
|
||||
super(builder);
|
||||
}
|
||||
|
||||
private Sentinel() {
|
||||
defaultInt32_ = 0;
|
||||
defaultInt64_ = 0L;
|
||||
@ -118,40 +97,42 @@ public final class SentinelOuterClass {
|
||||
}
|
||||
|
||||
@java.lang.Override
|
||||
public final com.google.protobuf.UnknownFieldSet
|
||||
getUnknownFields() {
|
||||
public final com.google.protobuf.UnknownFieldSet getUnknownFields() {
|
||||
return com.google.protobuf.UnknownFieldSet.getDefaultInstance();
|
||||
}
|
||||
public static final com.google.protobuf.Descriptors.Descriptor
|
||||
getDescriptor() {
|
||||
return com.google.protobuf.jruby.SentinelOuterClass.internal_static_com_google_protobuf_jruby_Sentinel_descriptor;
|
||||
|
||||
public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() {
|
||||
return com.google.protobuf.jruby.SentinelOuterClass
|
||||
.internal_static_com_google_protobuf_jruby_Sentinel_descriptor;
|
||||
}
|
||||
|
||||
protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
|
||||
internalGetFieldAccessorTable() {
|
||||
return com.google.protobuf.jruby.SentinelOuterClass.internal_static_com_google_protobuf_jruby_Sentinel_fieldAccessorTable
|
||||
return com.google.protobuf.jruby.SentinelOuterClass
|
||||
.internal_static_com_google_protobuf_jruby_Sentinel_fieldAccessorTable
|
||||
.ensureFieldAccessorsInitialized(
|
||||
com.google.protobuf.jruby.SentinelOuterClass.Sentinel.class, com.google.protobuf.jruby.SentinelOuterClass.Sentinel.Builder.class);
|
||||
com.google.protobuf.jruby.SentinelOuterClass.Sentinel.class,
|
||||
com.google.protobuf.jruby.SentinelOuterClass.Sentinel.Builder.class);
|
||||
}
|
||||
|
||||
public static final com.google.protobuf.Parser<Sentinel> PARSER =
|
||||
new com.google.protobuf.AbstractParser<Sentinel>() {
|
||||
public Sentinel parsePartialFrom(
|
||||
com.google.protobuf.CodedInputStream input,
|
||||
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
|
||||
throws com.google.protobuf.InvalidProtocolBufferException {
|
||||
Builder builder = newBuilder();
|
||||
try {
|
||||
builder.mergeFrom(input, extensionRegistry);
|
||||
} catch (com.google.protobuf.InvalidProtocolBufferException e) {
|
||||
throw e.setUnfinishedMessage(builder.buildPartial());
|
||||
} catch (java.io.IOException e) {
|
||||
throw new com.google.protobuf.InvalidProtocolBufferException(
|
||||
e.getMessage()).setUnfinishedMessage(builder.buildPartial());
|
||||
}
|
||||
return builder.buildPartial();
|
||||
}
|
||||
};
|
||||
public Sentinel parsePartialFrom(
|
||||
com.google.protobuf.CodedInputStream input,
|
||||
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
|
||||
throws com.google.protobuf.InvalidProtocolBufferException {
|
||||
Builder builder = newBuilder();
|
||||
try {
|
||||
builder.mergeFrom(input, extensionRegistry);
|
||||
} catch (com.google.protobuf.InvalidProtocolBufferException e) {
|
||||
throw e.setUnfinishedMessage(builder.buildPartial());
|
||||
} catch (java.io.IOException e) {
|
||||
throw new com.google.protobuf.InvalidProtocolBufferException(e.getMessage())
|
||||
.setUnfinishedMessage(builder.buildPartial());
|
||||
}
|
||||
return builder.buildPartial();
|
||||
}
|
||||
};
|
||||
|
||||
@java.lang.Override
|
||||
public com.google.protobuf.Parser<Sentinel> getParserForType() {
|
||||
@ -160,52 +141,41 @@ public final class SentinelOuterClass {
|
||||
|
||||
public static final int DEFAULT_INT32_FIELD_NUMBER = 1;
|
||||
private int defaultInt32_;
|
||||
/**
|
||||
* <code>optional int32 default_int32 = 1;</code>
|
||||
*/
|
||||
/** <code>optional int32 default_int32 = 1;</code> */
|
||||
public int getDefaultInt32() {
|
||||
return defaultInt32_;
|
||||
}
|
||||
|
||||
public static final int DEFAULT_INT64_FIELD_NUMBER = 2;
|
||||
private long defaultInt64_;
|
||||
/**
|
||||
* <code>optional int64 default_int64 = 2;</code>
|
||||
*/
|
||||
/** <code>optional int64 default_int64 = 2;</code> */
|
||||
public long getDefaultInt64() {
|
||||
return defaultInt64_;
|
||||
}
|
||||
|
||||
public static final int DEFAULT_UNIT32_FIELD_NUMBER = 3;
|
||||
private int defaultUnit32_;
|
||||
/**
|
||||
* <code>optional uint32 default_unit32 = 3;</code>
|
||||
*/
|
||||
/** <code>optional uint32 default_unit32 = 3;</code> */
|
||||
public int getDefaultUnit32() {
|
||||
return defaultUnit32_;
|
||||
}
|
||||
|
||||
public static final int DEFAULT_UINT64_FIELD_NUMBER = 4;
|
||||
private long defaultUint64_;
|
||||
/**
|
||||
* <code>optional uint64 default_uint64 = 4;</code>
|
||||
*/
|
||||
/** <code>optional uint64 default_uint64 = 4;</code> */
|
||||
public long getDefaultUint64() {
|
||||
return defaultUint64_;
|
||||
}
|
||||
|
||||
public static final int DEFAULT_STRING_FIELD_NUMBER = 5;
|
||||
private java.lang.Object defaultString_;
|
||||
/**
|
||||
* <code>optional string default_string = 5;</code>
|
||||
*/
|
||||
/** <code>optional string default_string = 5;</code> */
|
||||
public java.lang.String getDefaultString() {
|
||||
java.lang.Object ref = defaultString_;
|
||||
if (ref instanceof java.lang.String) {
|
||||
return (java.lang.String) ref;
|
||||
} else {
|
||||
com.google.protobuf.ByteString bs =
|
||||
(com.google.protobuf.ByteString) ref;
|
||||
com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref;
|
||||
java.lang.String s = bs.toStringUtf8();
|
||||
if (bs.isValidUtf8()) {
|
||||
defaultString_ = s;
|
||||
@ -213,16 +183,12 @@ public final class SentinelOuterClass {
|
||||
return s;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* <code>optional string default_string = 5;</code>
|
||||
*/
|
||||
public com.google.protobuf.ByteString
|
||||
getDefaultStringBytes() {
|
||||
/** <code>optional string default_string = 5;</code> */
|
||||
public com.google.protobuf.ByteString getDefaultStringBytes() {
|
||||
java.lang.Object ref = defaultString_;
|
||||
if (ref instanceof java.lang.String) {
|
||||
com.google.protobuf.ByteString b =
|
||||
com.google.protobuf.ByteString.copyFromUtf8(
|
||||
(java.lang.String) ref);
|
||||
com.google.protobuf.ByteString.copyFromUtf8((java.lang.String) ref);
|
||||
defaultString_ = b;
|
||||
return b;
|
||||
} else {
|
||||
@ -232,36 +198,28 @@ public final class SentinelOuterClass {
|
||||
|
||||
public static final int DEFAULT_BOOL_FIELD_NUMBER = 6;
|
||||
private boolean defaultBool_;
|
||||
/**
|
||||
* <code>optional bool default_bool = 6;</code>
|
||||
*/
|
||||
/** <code>optional bool default_bool = 6;</code> */
|
||||
public boolean getDefaultBool() {
|
||||
return defaultBool_;
|
||||
}
|
||||
|
||||
public static final int DEFAULT_FLOAT_FIELD_NUMBER = 7;
|
||||
private float defaultFloat_;
|
||||
/**
|
||||
* <code>optional float default_float = 7;</code>
|
||||
*/
|
||||
/** <code>optional float default_float = 7;</code> */
|
||||
public float getDefaultFloat() {
|
||||
return defaultFloat_;
|
||||
}
|
||||
|
||||
public static final int DEFAULT_DOUBLE_FIELD_NUMBER = 8;
|
||||
private double defaultDouble_;
|
||||
/**
|
||||
* <code>optional double default_double = 8;</code>
|
||||
*/
|
||||
/** <code>optional double default_double = 8;</code> */
|
||||
public double getDefaultDouble() {
|
||||
return defaultDouble_;
|
||||
}
|
||||
|
||||
public static final int DEFAULT_BYTES_FIELD_NUMBER = 9;
|
||||
private com.google.protobuf.ByteString defaultBytes_;
|
||||
/**
|
||||
* <code>optional bytes default_bytes = 9;</code>
|
||||
*/
|
||||
/** <code>optional bytes default_bytes = 9;</code> */
|
||||
public com.google.protobuf.ByteString getDefaultBytes() {
|
||||
return defaultBytes_;
|
||||
}
|
||||
@ -271,47 +229,52 @@ public final class SentinelOuterClass {
|
||||
throws com.google.protobuf.InvalidProtocolBufferException {
|
||||
return PARSER.parseFrom(data);
|
||||
}
|
||||
|
||||
public static com.google.protobuf.jruby.SentinelOuterClass.Sentinel parseFrom(
|
||||
com.google.protobuf.ByteString data,
|
||||
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
|
||||
throws com.google.protobuf.InvalidProtocolBufferException {
|
||||
return PARSER.parseFrom(data, extensionRegistry);
|
||||
}
|
||||
|
||||
public static com.google.protobuf.jruby.SentinelOuterClass.Sentinel parseFrom(byte[] data)
|
||||
throws com.google.protobuf.InvalidProtocolBufferException {
|
||||
return PARSER.parseFrom(data);
|
||||
}
|
||||
|
||||
public static com.google.protobuf.jruby.SentinelOuterClass.Sentinel parseFrom(
|
||||
byte[] data,
|
||||
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
|
||||
byte[] data, com.google.protobuf.ExtensionRegistryLite extensionRegistry)
|
||||
throws com.google.protobuf.InvalidProtocolBufferException {
|
||||
return PARSER.parseFrom(data, extensionRegistry);
|
||||
}
|
||||
public static com.google.protobuf.jruby.SentinelOuterClass.Sentinel parseFrom(java.io.InputStream input)
|
||||
throws java.io.IOException {
|
||||
|
||||
public static com.google.protobuf.jruby.SentinelOuterClass.Sentinel parseFrom(
|
||||
java.io.InputStream input) throws java.io.IOException {
|
||||
return PARSER.parseFrom(input);
|
||||
}
|
||||
|
||||
public static com.google.protobuf.jruby.SentinelOuterClass.Sentinel parseFrom(
|
||||
java.io.InputStream input,
|
||||
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
|
||||
java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry)
|
||||
throws java.io.IOException {
|
||||
return PARSER.parseFrom(input, extensionRegistry);
|
||||
}
|
||||
public static com.google.protobuf.jruby.SentinelOuterClass.Sentinel parseDelimitedFrom(java.io.InputStream input)
|
||||
throws java.io.IOException {
|
||||
|
||||
public static com.google.protobuf.jruby.SentinelOuterClass.Sentinel parseDelimitedFrom(
|
||||
java.io.InputStream input) throws java.io.IOException {
|
||||
return PARSER.parseDelimitedFrom(input);
|
||||
}
|
||||
|
||||
public static com.google.protobuf.jruby.SentinelOuterClass.Sentinel parseDelimitedFrom(
|
||||
java.io.InputStream input,
|
||||
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
|
||||
java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry)
|
||||
throws java.io.IOException {
|
||||
return PARSER.parseDelimitedFrom(input, extensionRegistry);
|
||||
}
|
||||
|
||||
public static com.google.protobuf.jruby.SentinelOuterClass.Sentinel parseFrom(
|
||||
com.google.protobuf.CodedInputStream input)
|
||||
throws java.io.IOException {
|
||||
com.google.protobuf.CodedInputStream input) throws java.io.IOException {
|
||||
return PARSER.parseFrom(input);
|
||||
}
|
||||
|
||||
public static com.google.protobuf.jruby.SentinelOuterClass.Sentinel parseFrom(
|
||||
com.google.protobuf.CodedInputStream input,
|
||||
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
|
||||
@ -319,36 +282,45 @@ public final class SentinelOuterClass {
|
||||
return PARSER.parseFrom(input, extensionRegistry);
|
||||
}
|
||||
|
||||
public static Builder newBuilder() { return new Builder(); }
|
||||
public Builder newBuilderForType() { return newBuilder(); }
|
||||
public static Builder newBuilder(com.google.protobuf.jruby.SentinelOuterClass.Sentinel prototype) {
|
||||
public static Builder newBuilder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
public Builder newBuilderForType() {
|
||||
return newBuilder();
|
||||
}
|
||||
|
||||
public static Builder newBuilder(
|
||||
com.google.protobuf.jruby.SentinelOuterClass.Sentinel prototype) {
|
||||
return newBuilder().mergeFrom(prototype);
|
||||
}
|
||||
public Builder toBuilder() { return newBuilder(this); }
|
||||
|
||||
public Builder toBuilder() {
|
||||
return newBuilder(this);
|
||||
}
|
||||
|
||||
@java.lang.Override
|
||||
protected Builder newBuilderForType(
|
||||
com.google.protobuf.GeneratedMessage.BuilderParent parent) {
|
||||
protected Builder newBuilderForType(com.google.protobuf.GeneratedMessage.BuilderParent parent) {
|
||||
Builder builder = new Builder(parent);
|
||||
return builder;
|
||||
}
|
||||
/**
|
||||
* Protobuf type {@code com.google.protobuf.jruby.Sentinel}
|
||||
*/
|
||||
public static final class Builder extends
|
||||
com.google.protobuf.GeneratedMessage.Builder<Builder> implements
|
||||
/** Protobuf type {@code com.google.protobuf.jruby.Sentinel} */
|
||||
public static final class Builder extends com.google.protobuf.GeneratedMessage.Builder<Builder>
|
||||
implements
|
||||
// @@protoc_insertion_point(builder_implements:com.google.protobuf.jruby.Sentinel)
|
||||
com.google.protobuf.jruby.SentinelOuterClass.SentinelOrBuilder {
|
||||
public static final com.google.protobuf.Descriptors.Descriptor
|
||||
getDescriptor() {
|
||||
return com.google.protobuf.jruby.SentinelOuterClass.internal_static_com_google_protobuf_jruby_Sentinel_descriptor;
|
||||
public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() {
|
||||
return com.google.protobuf.jruby.SentinelOuterClass
|
||||
.internal_static_com_google_protobuf_jruby_Sentinel_descriptor;
|
||||
}
|
||||
|
||||
protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
|
||||
internalGetFieldAccessorTable() {
|
||||
return com.google.protobuf.jruby.SentinelOuterClass.internal_static_com_google_protobuf_jruby_Sentinel_fieldAccessorTable
|
||||
return com.google.protobuf.jruby.SentinelOuterClass
|
||||
.internal_static_com_google_protobuf_jruby_Sentinel_fieldAccessorTable
|
||||
.ensureFieldAccessorsInitialized(
|
||||
com.google.protobuf.jruby.SentinelOuterClass.Sentinel.class, com.google.protobuf.jruby.SentinelOuterClass.Sentinel.Builder.class);
|
||||
com.google.protobuf.jruby.SentinelOuterClass.Sentinel.class,
|
||||
com.google.protobuf.jruby.SentinelOuterClass.Sentinel.Builder.class);
|
||||
}
|
||||
|
||||
// Construct using com.google.protobuf.jruby.SentinelOuterClass.Sentinel.newBuilder()
|
||||
@ -356,15 +328,15 @@ public final class SentinelOuterClass {
|
||||
maybeForceBuilderInitialization();
|
||||
}
|
||||
|
||||
private Builder(
|
||||
com.google.protobuf.GeneratedMessage.BuilderParent parent) {
|
||||
private Builder(com.google.protobuf.GeneratedMessage.BuilderParent parent) {
|
||||
super(parent);
|
||||
maybeForceBuilderInitialization();
|
||||
}
|
||||
|
||||
private void maybeForceBuilderInitialization() {
|
||||
if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {
|
||||
}
|
||||
if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {}
|
||||
}
|
||||
|
||||
public Builder clear() {
|
||||
super.clear();
|
||||
defaultInt32_ = 0;
|
||||
@ -388,9 +360,9 @@ public final class SentinelOuterClass {
|
||||
return this;
|
||||
}
|
||||
|
||||
public com.google.protobuf.Descriptors.Descriptor
|
||||
getDescriptorForType() {
|
||||
return com.google.protobuf.jruby.SentinelOuterClass.internal_static_com_google_protobuf_jruby_Sentinel_descriptor;
|
||||
public com.google.protobuf.Descriptors.Descriptor getDescriptorForType() {
|
||||
return com.google.protobuf.jruby.SentinelOuterClass
|
||||
.internal_static_com_google_protobuf_jruby_Sentinel_descriptor;
|
||||
}
|
||||
|
||||
public com.google.protobuf.jruby.SentinelOuterClass.Sentinel getDefaultInstanceForType() {
|
||||
@ -406,7 +378,8 @@ public final class SentinelOuterClass {
|
||||
}
|
||||
|
||||
public com.google.protobuf.jruby.SentinelOuterClass.Sentinel buildPartial() {
|
||||
com.google.protobuf.jruby.SentinelOuterClass.Sentinel result = new com.google.protobuf.jruby.SentinelOuterClass.Sentinel(this);
|
||||
com.google.protobuf.jruby.SentinelOuterClass.Sentinel result =
|
||||
new com.google.protobuf.jruby.SentinelOuterClass.Sentinel(this);
|
||||
result.defaultInt32_ = defaultInt32_;
|
||||
result.defaultInt64_ = defaultInt64_;
|
||||
result.defaultUnit32_ = defaultUnit32_;
|
||||
@ -420,26 +393,19 @@ public final class SentinelOuterClass {
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
private int defaultInt32_ ;
|
||||
/**
|
||||
* <code>optional int32 default_int32 = 1;</code>
|
||||
*/
|
||||
private int defaultInt32_;
|
||||
/** <code>optional int32 default_int32 = 1;</code> */
|
||||
public int getDefaultInt32() {
|
||||
return defaultInt32_;
|
||||
}
|
||||
/**
|
||||
* <code>optional int32 default_int32 = 1;</code>
|
||||
*/
|
||||
/** <code>optional int32 default_int32 = 1;</code> */
|
||||
public Builder setDefaultInt32(int value) {
|
||||
|
||||
defaultInt32_ = value;
|
||||
onChanged();
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* <code>optional int32 default_int32 = 1;</code>
|
||||
*/
|
||||
/** <code>optional int32 default_int32 = 1;</code> */
|
||||
public Builder clearDefaultInt32() {
|
||||
|
||||
defaultInt32_ = 0;
|
||||
@ -447,25 +413,19 @@ public final class SentinelOuterClass {
|
||||
return this;
|
||||
}
|
||||
|
||||
private long defaultInt64_ ;
|
||||
/**
|
||||
* <code>optional int64 default_int64 = 2;</code>
|
||||
*/
|
||||
private long defaultInt64_;
|
||||
/** <code>optional int64 default_int64 = 2;</code> */
|
||||
public long getDefaultInt64() {
|
||||
return defaultInt64_;
|
||||
}
|
||||
/**
|
||||
* <code>optional int64 default_int64 = 2;</code>
|
||||
*/
|
||||
/** <code>optional int64 default_int64 = 2;</code> */
|
||||
public Builder setDefaultInt64(long value) {
|
||||
|
||||
defaultInt64_ = value;
|
||||
onChanged();
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* <code>optional int64 default_int64 = 2;</code>
|
||||
*/
|
||||
/** <code>optional int64 default_int64 = 2;</code> */
|
||||
public Builder clearDefaultInt64() {
|
||||
|
||||
defaultInt64_ = 0L;
|
||||
@ -473,25 +433,19 @@ public final class SentinelOuterClass {
|
||||
return this;
|
||||
}
|
||||
|
||||
private int defaultUnit32_ ;
|
||||
/**
|
||||
* <code>optional uint32 default_unit32 = 3;</code>
|
||||
*/
|
||||
private int defaultUnit32_;
|
||||
/** <code>optional uint32 default_unit32 = 3;</code> */
|
||||
public int getDefaultUnit32() {
|
||||
return defaultUnit32_;
|
||||
}
|
||||
/**
|
||||
* <code>optional uint32 default_unit32 = 3;</code>
|
||||
*/
|
||||
/** <code>optional uint32 default_unit32 = 3;</code> */
|
||||
public Builder setDefaultUnit32(int value) {
|
||||
|
||||
defaultUnit32_ = value;
|
||||
onChanged();
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* <code>optional uint32 default_unit32 = 3;</code>
|
||||
*/
|
||||
/** <code>optional uint32 default_unit32 = 3;</code> */
|
||||
public Builder clearDefaultUnit32() {
|
||||
|
||||
defaultUnit32_ = 0;
|
||||
@ -499,25 +453,19 @@ public final class SentinelOuterClass {
|
||||
return this;
|
||||
}
|
||||
|
||||
private long defaultUint64_ ;
|
||||
/**
|
||||
* <code>optional uint64 default_uint64 = 4;</code>
|
||||
*/
|
||||
private long defaultUint64_;
|
||||
/** <code>optional uint64 default_uint64 = 4;</code> */
|
||||
public long getDefaultUint64() {
|
||||
return defaultUint64_;
|
||||
}
|
||||
/**
|
||||
* <code>optional uint64 default_uint64 = 4;</code>
|
||||
*/
|
||||
/** <code>optional uint64 default_uint64 = 4;</code> */
|
||||
public Builder setDefaultUint64(long value) {
|
||||
|
||||
defaultUint64_ = value;
|
||||
onChanged();
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* <code>optional uint64 default_uint64 = 4;</code>
|
||||
*/
|
||||
/** <code>optional uint64 default_uint64 = 4;</code> */
|
||||
public Builder clearDefaultUint64() {
|
||||
|
||||
defaultUint64_ = 0L;
|
||||
@ -526,14 +474,11 @@ public final class SentinelOuterClass {
|
||||
}
|
||||
|
||||
private java.lang.Object defaultString_ = "";
|
||||
/**
|
||||
* <code>optional string default_string = 5;</code>
|
||||
*/
|
||||
/** <code>optional string default_string = 5;</code> */
|
||||
public java.lang.String getDefaultString() {
|
||||
java.lang.Object ref = defaultString_;
|
||||
if (!(ref instanceof java.lang.String)) {
|
||||
com.google.protobuf.ByteString bs =
|
||||
(com.google.protobuf.ByteString) ref;
|
||||
com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref;
|
||||
java.lang.String s = bs.toStringUtf8();
|
||||
if (bs.isValidUtf8()) {
|
||||
defaultString_ = s;
|
||||
@ -543,77 +488,59 @@ public final class SentinelOuterClass {
|
||||
return (java.lang.String) ref;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* <code>optional string default_string = 5;</code>
|
||||
*/
|
||||
public com.google.protobuf.ByteString
|
||||
getDefaultStringBytes() {
|
||||
/** <code>optional string default_string = 5;</code> */
|
||||
public com.google.protobuf.ByteString getDefaultStringBytes() {
|
||||
java.lang.Object ref = defaultString_;
|
||||
if (ref instanceof String) {
|
||||
com.google.protobuf.ByteString b =
|
||||
com.google.protobuf.ByteString.copyFromUtf8(
|
||||
(java.lang.String) ref);
|
||||
com.google.protobuf.ByteString.copyFromUtf8((java.lang.String) ref);
|
||||
defaultString_ = b;
|
||||
return b;
|
||||
} else {
|
||||
return (com.google.protobuf.ByteString) ref;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* <code>optional string default_string = 5;</code>
|
||||
*/
|
||||
public Builder setDefaultString(
|
||||
java.lang.String value) {
|
||||
/** <code>optional string default_string = 5;</code> */
|
||||
public Builder setDefaultString(java.lang.String value) {
|
||||
if (value == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
throw new NullPointerException();
|
||||
}
|
||||
|
||||
defaultString_ = value;
|
||||
onChanged();
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* <code>optional string default_string = 5;</code>
|
||||
*/
|
||||
/** <code>optional string default_string = 5;</code> */
|
||||
public Builder clearDefaultString() {
|
||||
|
||||
defaultString_ = getDefaultInstance().getDefaultString();
|
||||
onChanged();
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* <code>optional string default_string = 5;</code>
|
||||
*/
|
||||
public Builder setDefaultStringBytes(
|
||||
com.google.protobuf.ByteString value) {
|
||||
/** <code>optional string default_string = 5;</code> */
|
||||
public Builder setDefaultStringBytes(com.google.protobuf.ByteString value) {
|
||||
if (value == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
throw new NullPointerException();
|
||||
}
|
||||
|
||||
defaultString_ = value;
|
||||
onChanged();
|
||||
return this;
|
||||
}
|
||||
|
||||
private boolean defaultBool_ ;
|
||||
/**
|
||||
* <code>optional bool default_bool = 6;</code>
|
||||
*/
|
||||
private boolean defaultBool_;
|
||||
/** <code>optional bool default_bool = 6;</code> */
|
||||
public boolean getDefaultBool() {
|
||||
return defaultBool_;
|
||||
}
|
||||
/**
|
||||
* <code>optional bool default_bool = 6;</code>
|
||||
*/
|
||||
/** <code>optional bool default_bool = 6;</code> */
|
||||
public Builder setDefaultBool(boolean value) {
|
||||
|
||||
defaultBool_ = value;
|
||||
onChanged();
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* <code>optional bool default_bool = 6;</code>
|
||||
*/
|
||||
/** <code>optional bool default_bool = 6;</code> */
|
||||
public Builder clearDefaultBool() {
|
||||
|
||||
defaultBool_ = false;
|
||||
@ -621,25 +548,19 @@ public final class SentinelOuterClass {
|
||||
return this;
|
||||
}
|
||||
|
||||
private float defaultFloat_ ;
|
||||
/**
|
||||
* <code>optional float default_float = 7;</code>
|
||||
*/
|
||||
private float defaultFloat_;
|
||||
/** <code>optional float default_float = 7;</code> */
|
||||
public float getDefaultFloat() {
|
||||
return defaultFloat_;
|
||||
}
|
||||
/**
|
||||
* <code>optional float default_float = 7;</code>
|
||||
*/
|
||||
/** <code>optional float default_float = 7;</code> */
|
||||
public Builder setDefaultFloat(float value) {
|
||||
|
||||
defaultFloat_ = value;
|
||||
onChanged();
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* <code>optional float default_float = 7;</code>
|
||||
*/
|
||||
/** <code>optional float default_float = 7;</code> */
|
||||
public Builder clearDefaultFloat() {
|
||||
|
||||
defaultFloat_ = 0F;
|
||||
@ -647,25 +568,19 @@ public final class SentinelOuterClass {
|
||||
return this;
|
||||
}
|
||||
|
||||
private double defaultDouble_ ;
|
||||
/**
|
||||
* <code>optional double default_double = 8;</code>
|
||||
*/
|
||||
private double defaultDouble_;
|
||||
/** <code>optional double default_double = 8;</code> */
|
||||
public double getDefaultDouble() {
|
||||
return defaultDouble_;
|
||||
}
|
||||
/**
|
||||
* <code>optional double default_double = 8;</code>
|
||||
*/
|
||||
/** <code>optional double default_double = 8;</code> */
|
||||
public Builder setDefaultDouble(double value) {
|
||||
|
||||
defaultDouble_ = value;
|
||||
onChanged();
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* <code>optional double default_double = 8;</code>
|
||||
*/
|
||||
/** <code>optional double default_double = 8;</code> */
|
||||
public Builder clearDefaultDouble() {
|
||||
|
||||
defaultDouble_ = 0D;
|
||||
@ -674,33 +589,28 @@ public final class SentinelOuterClass {
|
||||
}
|
||||
|
||||
private com.google.protobuf.ByteString defaultBytes_ = com.google.protobuf.ByteString.EMPTY;
|
||||
/**
|
||||
* <code>optional bytes default_bytes = 9;</code>
|
||||
*/
|
||||
/** <code>optional bytes default_bytes = 9;</code> */
|
||||
public com.google.protobuf.ByteString getDefaultBytes() {
|
||||
return defaultBytes_;
|
||||
}
|
||||
/**
|
||||
* <code>optional bytes default_bytes = 9;</code>
|
||||
*/
|
||||
/** <code>optional bytes default_bytes = 9;</code> */
|
||||
public Builder setDefaultBytes(com.google.protobuf.ByteString value) {
|
||||
if (value == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
throw new NullPointerException();
|
||||
}
|
||||
|
||||
defaultBytes_ = value;
|
||||
onChanged();
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* <code>optional bytes default_bytes = 9;</code>
|
||||
*/
|
||||
/** <code>optional bytes default_bytes = 9;</code> */
|
||||
public Builder clearDefaultBytes() {
|
||||
|
||||
defaultBytes_ = getDefaultInstance().getDefaultBytes();
|
||||
onChanged();
|
||||
return this;
|
||||
}
|
||||
|
||||
public final Builder setUnknownFields(
|
||||
final com.google.protobuf.UnknownFieldSet unknownFields) {
|
||||
return this;
|
||||
@ -711,12 +621,13 @@ public final class SentinelOuterClass {
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
// @@protoc_insertion_point(builder_scope:com.google.protobuf.jruby.Sentinel)
|
||||
}
|
||||
|
||||
// @@protoc_insertion_point(class_scope:com.google.protobuf.jruby.Sentinel)
|
||||
private static final com.google.protobuf.jruby.SentinelOuterClass.Sentinel defaultInstance;static {
|
||||
private static final com.google.protobuf.jruby.SentinelOuterClass.Sentinel defaultInstance;
|
||||
|
||||
static {
|
||||
defaultInstance = new com.google.protobuf.jruby.SentinelOuterClass.Sentinel();
|
||||
}
|
||||
|
||||
@ -727,49 +638,55 @@ public final class SentinelOuterClass {
|
||||
public com.google.protobuf.jruby.SentinelOuterClass.Sentinel getDefaultInstanceForType() {
|
||||
return defaultInstance;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static final com.google.protobuf.Descriptors.Descriptor
|
||||
internal_static_com_google_protobuf_jruby_Sentinel_descriptor;
|
||||
private static
|
||||
com.google.protobuf.GeneratedMessage.FieldAccessorTable
|
||||
internal_static_com_google_protobuf_jruby_Sentinel_descriptor;
|
||||
private static com.google.protobuf.GeneratedMessage.FieldAccessorTable
|
||||
internal_static_com_google_protobuf_jruby_Sentinel_fieldAccessorTable;
|
||||
|
||||
public static com.google.protobuf.Descriptors.FileDescriptor
|
||||
getDescriptor() {
|
||||
public static com.google.protobuf.Descriptors.FileDescriptor getDescriptor() {
|
||||
return descriptor;
|
||||
}
|
||||
private static com.google.protobuf.Descriptors.FileDescriptor
|
||||
descriptor;
|
||||
|
||||
private static com.google.protobuf.Descriptors.FileDescriptor descriptor;
|
||||
|
||||
static {
|
||||
java.lang.String[] descriptorData = {
|
||||
"\n\016sentinel.proto\022\031com.google.protobuf.jr" +
|
||||
"uby\"\334\001\n\010Sentinel\022\025\n\rdefault_int32\030\001 \001(\005\022" +
|
||||
"\025\n\rdefault_int64\030\002 \001(\003\022\026\n\016default_unit32" +
|
||||
"\030\003 \001(\r\022\026\n\016default_uint64\030\004 \001(\004\022\026\n\016defaul" +
|
||||
"t_string\030\005 \001(\t\022\024\n\014default_bool\030\006 \001(\010\022\025\n\r" +
|
||||
"default_float\030\007 \001(\002\022\026\n\016default_double\030\010 " +
|
||||
"\001(\001\022\025\n\rdefault_bytes\030\t \001(\014B\002H\002b\006proto3"
|
||||
"\n\016sentinel.proto\022\031com.google.protobuf.jr"
|
||||
+ "uby\"\334\001\n\010Sentinel\022\025\n\rdefault_int32\030\001 \001(\005\022"
|
||||
+ "\025\n\rdefault_int64\030\002 \001(\003\022\026\n\016default_unit32"
|
||||
+ "\030\003 \001(\r\022\026\n\016default_uint64\030\004 \001(\004\022\026\n\016defaul"
|
||||
+ "t_string\030\005 \001(\t\022\024\n\014default_bool\030\006 \001(\010\022\025\n\r"
|
||||
+ "default_float\030\007 \001(\002\022\026\n\016default_double\030\010 "
|
||||
+ "\001(\001\022\025\n\rdefault_bytes\030\t \001(\014B\002H\002b\006proto3"
|
||||
};
|
||||
com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
|
||||
new com.google.protobuf.Descriptors.FileDescriptor. InternalDescriptorAssigner() {
|
||||
new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() {
|
||||
public com.google.protobuf.ExtensionRegistry assignDescriptors(
|
||||
com.google.protobuf.Descriptors.FileDescriptor root) {
|
||||
descriptor = root;
|
||||
return null;
|
||||
}
|
||||
};
|
||||
com.google.protobuf.Descriptors.FileDescriptor
|
||||
.internalBuildGeneratedFileFrom(descriptorData,
|
||||
new com.google.protobuf.Descriptors.FileDescriptor[] {
|
||||
}, assigner);
|
||||
com.google.protobuf.Descriptors.FileDescriptor.internalBuildGeneratedFileFrom(
|
||||
descriptorData, new com.google.protobuf.Descriptors.FileDescriptor[] {}, assigner);
|
||||
internal_static_com_google_protobuf_jruby_Sentinel_descriptor =
|
||||
getDescriptor().getMessageTypes().get(0);
|
||||
internal_static_com_google_protobuf_jruby_Sentinel_fieldAccessorTable = new
|
||||
com.google.protobuf.GeneratedMessage.FieldAccessorTable(
|
||||
internal_static_com_google_protobuf_jruby_Sentinel_descriptor,
|
||||
new java.lang.String[] { "DefaultInt32", "DefaultInt64", "DefaultUnit32", "DefaultUint64", "DefaultString", "DefaultBool", "DefaultFloat", "DefaultDouble", "DefaultBytes", });
|
||||
getDescriptor().getMessageTypes().get(0);
|
||||
internal_static_com_google_protobuf_jruby_Sentinel_fieldAccessorTable =
|
||||
new com.google.protobuf.GeneratedMessage.FieldAccessorTable(
|
||||
internal_static_com_google_protobuf_jruby_Sentinel_descriptor,
|
||||
new java.lang.String[] {
|
||||
"DefaultInt32",
|
||||
"DefaultInt64",
|
||||
"DefaultUnit32",
|
||||
"DefaultUint64",
|
||||
"DefaultString",
|
||||
"DefaultBool",
|
||||
"DefaultFloat",
|
||||
"DefaultDouble",
|
||||
"DefaultBytes",
|
||||
});
|
||||
}
|
||||
|
||||
// @@protoc_insertion_point(outer_class_scope)
|
||||
|
@ -35,6 +35,7 @@ package com.google.protobuf.jruby;
|
||||
import com.google.protobuf.ByteString;
|
||||
import com.google.protobuf.DescriptorProtos.FieldDescriptorProto;
|
||||
import com.google.protobuf.Descriptors.FieldDescriptor;
|
||||
import java.math.BigInteger;
|
||||
import org.jcodings.specific.ASCIIEncoding;
|
||||
import org.jruby.*;
|
||||
import org.jruby.exceptions.RaiseException;
|
||||
@ -44,302 +45,363 @@ import org.jruby.runtime.Helpers;
|
||||
import org.jruby.runtime.ThreadContext;
|
||||
import org.jruby.runtime.builtin.IRubyObject;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
public class Utils {
|
||||
public static FieldDescriptor.Type rubyToFieldType(IRubyObject typeClass) {
|
||||
return FieldDescriptor.Type.valueOf(typeClass.asJavaString().toUpperCase());
|
||||
}
|
||||
public static FieldDescriptor.Type rubyToFieldType(IRubyObject typeClass) {
|
||||
return FieldDescriptor.Type.valueOf(typeClass.asJavaString().toUpperCase());
|
||||
}
|
||||
|
||||
public static IRubyObject fieldTypeToRuby(ThreadContext context, FieldDescriptor.Type type) {
|
||||
return fieldTypeToRuby(context, type.name());
|
||||
}
|
||||
public static IRubyObject fieldTypeToRuby(ThreadContext context, FieldDescriptor.Type type) {
|
||||
return fieldTypeToRuby(context, type.name());
|
||||
}
|
||||
|
||||
public static IRubyObject fieldTypeToRuby(ThreadContext context, FieldDescriptorProto.Type type) {
|
||||
return fieldTypeToRuby(context, type.name());
|
||||
}
|
||||
public static IRubyObject fieldTypeToRuby(ThreadContext context, FieldDescriptorProto.Type type) {
|
||||
return fieldTypeToRuby(context, type.name());
|
||||
}
|
||||
|
||||
private static IRubyObject fieldTypeToRuby(ThreadContext context, String typeName) {
|
||||
private static IRubyObject fieldTypeToRuby(ThreadContext context, String typeName) {
|
||||
|
||||
return context.runtime.newSymbol(typeName.replace("TYPE_", "").toLowerCase());
|
||||
}
|
||||
return context.runtime.newSymbol(typeName.replace("TYPE_", "").toLowerCase());
|
||||
}
|
||||
|
||||
public static IRubyObject checkType(ThreadContext context, FieldDescriptor.Type fieldType,
|
||||
String fieldName, IRubyObject value, RubyModule typeClass) {
|
||||
Ruby runtime = context.runtime;
|
||||
public static IRubyObject checkType(
|
||||
ThreadContext context,
|
||||
FieldDescriptor.Type fieldType,
|
||||
String fieldName,
|
||||
IRubyObject value,
|
||||
RubyModule typeClass) {
|
||||
Ruby runtime = context.runtime;
|
||||
|
||||
switch(fieldType) {
|
||||
case SFIXED32:
|
||||
case SFIXED64:
|
||||
case FIXED64:
|
||||
case SINT64:
|
||||
case SINT32:
|
||||
case FIXED32:
|
||||
case INT32:
|
||||
case INT64:
|
||||
case UINT32:
|
||||
case UINT64:
|
||||
if (!isRubyNum(value))
|
||||
throw createExpectedTypeError(context, "number", "integral", fieldName, value);
|
||||
switch (fieldType) {
|
||||
case SFIXED32:
|
||||
case SFIXED64:
|
||||
case FIXED64:
|
||||
case SINT64:
|
||||
case SINT32:
|
||||
case FIXED32:
|
||||
case INT32:
|
||||
case INT64:
|
||||
case UINT32:
|
||||
case UINT64:
|
||||
if (!isRubyNum(value))
|
||||
throw createExpectedTypeError(context, "number", "integral", fieldName, value);
|
||||
|
||||
if (value instanceof RubyFloat) {
|
||||
double doubleVal = RubyNumeric.num2dbl(value);
|
||||
if (Math.floor(doubleVal) != doubleVal) {
|
||||
throw runtime.newRangeError("Non-integral floating point value assigned to integer field '" + fieldName + "' (given " + value.getMetaClass() + ").");
|
||||
}
|
||||
}
|
||||
if (fieldType == FieldDescriptor.Type.UINT32 || fieldType == FieldDescriptor.Type.UINT64 ||
|
||||
fieldType == FieldDescriptor.Type.FIXED32 || fieldType == FieldDescriptor.Type.FIXED64) {
|
||||
if (((RubyNumeric) value).isNegative()) {
|
||||
throw runtime.newRangeError("Assigning negative value to unsigned integer field '" + fieldName + "' (given " + value.getMetaClass() + ").");
|
||||
}
|
||||
}
|
||||
|
||||
switch(fieldType) {
|
||||
case INT32:
|
||||
RubyNumeric.num2int(value);
|
||||
break;
|
||||
case UINT32:
|
||||
case FIXED32:
|
||||
num2uint(value);
|
||||
break;
|
||||
case UINT64:
|
||||
case FIXED64:
|
||||
num2ulong(context.runtime, value);
|
||||
break;
|
||||
default:
|
||||
RubyNumeric.num2long(value);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case FLOAT:
|
||||
if (!isRubyNum(value))
|
||||
throw createExpectedTypeError(context, "number", "float", fieldName, value);
|
||||
break;
|
||||
case DOUBLE:
|
||||
if (!isRubyNum(value))
|
||||
throw createExpectedTypeError(context, "number", "double", fieldName, value);
|
||||
break;
|
||||
case BOOL:
|
||||
if (!(value instanceof RubyBoolean))
|
||||
throw createInvalidTypeError(context, "boolean", fieldName, value);
|
||||
break;
|
||||
case BYTES:
|
||||
value = validateAndEncodeString(context, "bytes", fieldName, value, "Encoding::ASCII_8BIT");
|
||||
break;
|
||||
case STRING:
|
||||
value = validateAndEncodeString(context, "string", fieldName, symToString(value), "Encoding::UTF_8");
|
||||
break;
|
||||
case MESSAGE:
|
||||
if (value.getMetaClass() != typeClass) {
|
||||
// See if we can convert the value before flagging it as invalid
|
||||
String className = typeClass.getName();
|
||||
|
||||
if (className.equals("Google::Protobuf::Timestamp") && value instanceof RubyTime) {
|
||||
RubyTime rt = (RubyTime) value;
|
||||
RubyHash timestampArgs =
|
||||
Helpers.constructHash(runtime,
|
||||
runtime.newString("nanos"), rt.nsec(), false,
|
||||
runtime.newString("seconds"), rt.to_i(), false);
|
||||
return ((RubyClass) typeClass).newInstance(context, timestampArgs, Block.NULL_BLOCK);
|
||||
|
||||
} else if (className.equals("Google::Protobuf::Duration") && value instanceof RubyNumeric) {
|
||||
IRubyObject seconds;
|
||||
if (value instanceof RubyFloat) {
|
||||
seconds = ((RubyFloat) value).truncate(context);
|
||||
} else if (value instanceof RubyRational) {
|
||||
seconds = ((RubyRational) value).to_i(context);
|
||||
} else if (value instanceof RubyBigDecimal) {
|
||||
seconds = ((RubyBigDecimal) value).to_int(context);
|
||||
} else {
|
||||
seconds = ((RubyInteger) value).to_i();
|
||||
}
|
||||
|
||||
IRubyObject nanos = ((RubyNumeric) value).remainder(context, RubyFixnum.one(runtime));
|
||||
if (nanos instanceof RubyFloat) {
|
||||
nanos = ((RubyFloat) nanos).op_mul(context, 1000000000);
|
||||
} else if (nanos instanceof RubyRational) {
|
||||
nanos = ((RubyRational) nanos).op_mul(context, runtime.newFixnum(1000000000));
|
||||
} else if (nanos instanceof RubyBigDecimal) {
|
||||
nanos = ((RubyBigDecimal) nanos).op_mul(context, runtime.newFixnum(1000000000));
|
||||
} else {
|
||||
nanos = ((RubyInteger) nanos).op_mul(context, 1000000000);
|
||||
}
|
||||
|
||||
RubyHash durationArgs =
|
||||
Helpers.constructHash(runtime,
|
||||
runtime.newString("nanos"), ((RubyNumeric) nanos).round(context), false,
|
||||
runtime.newString("seconds"), seconds, false);
|
||||
return ((RubyClass) typeClass).newInstance(context, durationArgs, Block.NULL_BLOCK);
|
||||
}
|
||||
|
||||
// Not able to convert so flag as invalid
|
||||
throw createTypeError(context, "Invalid type " + value.getMetaClass() + " to assign to submessage field '" + fieldName + "'.");
|
||||
}
|
||||
|
||||
break;
|
||||
case ENUM:
|
||||
boolean isValid = ((RubyEnumDescriptor) typeClass.getInstanceVariable(DESCRIPTOR_INSTANCE_VAR)).isValidValue(context, value);
|
||||
if (!isValid) {
|
||||
throw runtime.newRangeError("Unknown symbol value for enum field '" + fieldName + "'.");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
public static IRubyObject wrapPrimaryValue(ThreadContext context, FieldDescriptor.Type fieldType, Object value) {
|
||||
return wrapPrimaryValue(context, fieldType, value, false);
|
||||
}
|
||||
|
||||
public static IRubyObject wrapPrimaryValue(ThreadContext context, FieldDescriptor.Type fieldType, Object value, boolean encodeBytes) {
|
||||
Ruby runtime = context.runtime;
|
||||
switch (fieldType) {
|
||||
case INT32:
|
||||
case SFIXED32:
|
||||
case SINT32:
|
||||
return runtime.newFixnum((Integer) value);
|
||||
case SFIXED64:
|
||||
case SINT64:
|
||||
case INT64:
|
||||
return runtime.newFixnum((Long) value);
|
||||
case FIXED32:
|
||||
case UINT32:
|
||||
return runtime.newFixnum(((Integer) value) & (-1l >>> 32));
|
||||
case FIXED64:
|
||||
case UINT64:
|
||||
long ret = (Long) value;
|
||||
return ret >= 0 ? runtime.newFixnum(ret) :
|
||||
RubyBignum.newBignum(runtime, UINT64_COMPLEMENTARY.add(new BigInteger(ret + "")));
|
||||
case FLOAT:
|
||||
return runtime.newFloat((Float) value);
|
||||
case DOUBLE:
|
||||
return runtime.newFloat((Double) value);
|
||||
case BOOL:
|
||||
return (Boolean) value ? runtime.getTrue() : runtime.getFalse();
|
||||
case BYTES: {
|
||||
IRubyObject wrapped = encodeBytes ?
|
||||
RubyString.newString(runtime, ((ByteString) value).toStringUtf8(), ASCIIEncoding.INSTANCE) :
|
||||
RubyString.newString(runtime, ((ByteString) value).toByteArray());
|
||||
wrapped.setFrozen(true);
|
||||
return wrapped;
|
||||
}
|
||||
case STRING: {
|
||||
IRubyObject wrapped = runtime.newString(value.toString());
|
||||
wrapped.setFrozen(true);
|
||||
return wrapped;
|
||||
}
|
||||
default:
|
||||
return runtime.getNil();
|
||||
}
|
||||
}
|
||||
|
||||
public static int num2uint(IRubyObject value) {
|
||||
long longVal = RubyNumeric.num2long(value);
|
||||
if (longVal > UINT_MAX)
|
||||
throw value.getRuntime().newRangeError("Integer " + longVal + " too big to convert to 'unsigned int'");
|
||||
long num = longVal;
|
||||
if (num > Integer.MAX_VALUE || num < Integer.MIN_VALUE)
|
||||
// encode to UINT32
|
||||
num = (-longVal ^ (-1l >>> 32) ) + 1;
|
||||
RubyNumeric.checkInt(value, num);
|
||||
return (int) num;
|
||||
}
|
||||
|
||||
public static long num2ulong(Ruby runtime, IRubyObject value) {
|
||||
if (value instanceof RubyFloat) {
|
||||
RubyBignum bignum = RubyBignum.newBignum(runtime, ((RubyFloat) value).getDoubleValue());
|
||||
return RubyBignum.big2ulong(bignum);
|
||||
} else if (value instanceof RubyBignum) {
|
||||
return RubyBignum.big2ulong((RubyBignum) value);
|
||||
} else {
|
||||
return RubyNumeric.num2long(value);
|
||||
double doubleVal = RubyNumeric.num2dbl(value);
|
||||
if (Math.floor(doubleVal) != doubleVal) {
|
||||
throw runtime.newRangeError(
|
||||
"Non-integral floating point value assigned to integer field '"
|
||||
+ fieldName
|
||||
+ "' (given "
|
||||
+ value.getMetaClass()
|
||||
+ ").");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper to make it easier to support symbols being passed instead of strings
|
||||
*/
|
||||
public static IRubyObject symToString(IRubyObject sym) {
|
||||
if (sym instanceof RubySymbol) {
|
||||
return ((RubySymbol) sym).id2name();
|
||||
if (fieldType == FieldDescriptor.Type.UINT32
|
||||
|| fieldType == FieldDescriptor.Type.UINT64
|
||||
|| fieldType == FieldDescriptor.Type.FIXED32
|
||||
|| fieldType == FieldDescriptor.Type.FIXED64) {
|
||||
if (((RubyNumeric) value).isNegative()) {
|
||||
throw runtime.newRangeError(
|
||||
"Assigning negative value to unsigned integer field '"
|
||||
+ fieldName
|
||||
+ "' (given "
|
||||
+ value.getMetaClass()
|
||||
+ ").");
|
||||
}
|
||||
}
|
||||
return sym;
|
||||
}
|
||||
|
||||
public static void checkNameAvailability(ThreadContext context, String name) {
|
||||
if (context.runtime.getObject().getConstantAt(name) != null)
|
||||
throw context.runtime.newNameError(name + " is already defined", name);
|
||||
}
|
||||
|
||||
public static boolean isMapEntry(FieldDescriptor fieldDescriptor) {
|
||||
return fieldDescriptor.getType() == FieldDescriptor.Type.MESSAGE &&
|
||||
fieldDescriptor.isRepeated() &&
|
||||
fieldDescriptor.getMessageType().getOptions().getMapEntry();
|
||||
}
|
||||
|
||||
public static RaiseException createTypeError(ThreadContext context, String message) {
|
||||
if (cTypeError == null) {
|
||||
cTypeError = (RubyClass) context.runtime.getClassFromPath("Google::Protobuf::TypeError");
|
||||
switch (fieldType) {
|
||||
case INT32:
|
||||
RubyNumeric.num2int(value);
|
||||
break;
|
||||
case UINT32:
|
||||
case FIXED32:
|
||||
num2uint(value);
|
||||
break;
|
||||
case UINT64:
|
||||
case FIXED64:
|
||||
num2ulong(context.runtime, value);
|
||||
break;
|
||||
default:
|
||||
RubyNumeric.num2long(value);
|
||||
break;
|
||||
}
|
||||
return RaiseException.from(context.runtime, cTypeError, message);
|
||||
}
|
||||
break;
|
||||
case FLOAT:
|
||||
if (!isRubyNum(value))
|
||||
throw createExpectedTypeError(context, "number", "float", fieldName, value);
|
||||
break;
|
||||
case DOUBLE:
|
||||
if (!isRubyNum(value))
|
||||
throw createExpectedTypeError(context, "number", "double", fieldName, value);
|
||||
break;
|
||||
case BOOL:
|
||||
if (!(value instanceof RubyBoolean))
|
||||
throw createInvalidTypeError(context, "boolean", fieldName, value);
|
||||
break;
|
||||
case BYTES:
|
||||
value = validateAndEncodeString(context, "bytes", fieldName, value, "Encoding::ASCII_8BIT");
|
||||
break;
|
||||
case STRING:
|
||||
value =
|
||||
validateAndEncodeString(
|
||||
context, "string", fieldName, symToString(value), "Encoding::UTF_8");
|
||||
break;
|
||||
case MESSAGE:
|
||||
if (value.getMetaClass() != typeClass) {
|
||||
// See if we can convert the value before flagging it as invalid
|
||||
String className = typeClass.getName();
|
||||
|
||||
public static RaiseException createExpectedTypeError(ThreadContext context, String type, String fieldType, String fieldName, IRubyObject value) {
|
||||
return createTypeError(context, String.format(EXPECTED_TYPE_ERROR_FORMAT, type, fieldType, fieldName, value.getMetaClass()));
|
||||
}
|
||||
if (className.equals("Google::Protobuf::Timestamp") && value instanceof RubyTime) {
|
||||
RubyTime rt = (RubyTime) value;
|
||||
RubyHash timestampArgs =
|
||||
Helpers.constructHash(
|
||||
runtime,
|
||||
runtime.newString("nanos"),
|
||||
rt.nsec(),
|
||||
false,
|
||||
runtime.newString("seconds"),
|
||||
rt.to_i(),
|
||||
false);
|
||||
return ((RubyClass) typeClass).newInstance(context, timestampArgs, Block.NULL_BLOCK);
|
||||
|
||||
public static RaiseException createInvalidTypeError(ThreadContext context, String fieldType, String fieldName, IRubyObject value) {
|
||||
return createTypeError(context, String.format(INVALID_TYPE_ERROR_FORMAT, fieldType, fieldName, value.getMetaClass()));
|
||||
}
|
||||
|
||||
protected static boolean isRubyNum(Object value) {
|
||||
return value instanceof RubyFixnum || value instanceof RubyFloat || value instanceof RubyBignum;
|
||||
}
|
||||
|
||||
protected static void validateTypeClass(ThreadContext context, FieldDescriptor.Type type, IRubyObject value) {
|
||||
Ruby runtime = context.runtime;
|
||||
if (!(value instanceof RubyModule)) {
|
||||
throw runtime.newArgumentError("TypeClass has incorrect type");
|
||||
}
|
||||
RubyModule klass = (RubyModule) value;
|
||||
IRubyObject descriptor = klass.getInstanceVariable(DESCRIPTOR_INSTANCE_VAR);
|
||||
if (descriptor.isNil()) {
|
||||
throw runtime.newArgumentError("Type class has no descriptor. Please pass a " +
|
||||
"class or enum as returned by the DescriptorPool.");
|
||||
}
|
||||
if (type == FieldDescriptor.Type.MESSAGE) {
|
||||
if (! (descriptor instanceof RubyDescriptor)) {
|
||||
throw runtime.newArgumentError("Descriptor has an incorrect type");
|
||||
} else if (className.equals("Google::Protobuf::Duration")
|
||||
&& value instanceof RubyNumeric) {
|
||||
IRubyObject seconds;
|
||||
if (value instanceof RubyFloat) {
|
||||
seconds = ((RubyFloat) value).truncate(context);
|
||||
} else if (value instanceof RubyRational) {
|
||||
seconds = ((RubyRational) value).to_i(context);
|
||||
} else if (value instanceof RubyBigDecimal) {
|
||||
seconds = ((RubyBigDecimal) value).to_int(context);
|
||||
} else {
|
||||
seconds = ((RubyInteger) value).to_i();
|
||||
}
|
||||
} else if (type == FieldDescriptor.Type.ENUM) {
|
||||
if (! (descriptor instanceof RubyEnumDescriptor)) {
|
||||
throw runtime.newArgumentError("Descriptor has an incorrect type");
|
||||
|
||||
IRubyObject nanos = ((RubyNumeric) value).remainder(context, RubyFixnum.one(runtime));
|
||||
if (nanos instanceof RubyFloat) {
|
||||
nanos = ((RubyFloat) nanos).op_mul(context, 1000000000);
|
||||
} else if (nanos instanceof RubyRational) {
|
||||
nanos = ((RubyRational) nanos).op_mul(context, runtime.newFixnum(1000000000));
|
||||
} else if (nanos instanceof RubyBigDecimal) {
|
||||
nanos = ((RubyBigDecimal) nanos).op_mul(context, runtime.newFixnum(1000000000));
|
||||
} else {
|
||||
nanos = ((RubyInteger) nanos).op_mul(context, 1000000000);
|
||||
}
|
||||
|
||||
RubyHash durationArgs =
|
||||
Helpers.constructHash(
|
||||
runtime,
|
||||
runtime.newString("nanos"),
|
||||
((RubyNumeric) nanos).round(context),
|
||||
false,
|
||||
runtime.newString("seconds"),
|
||||
seconds,
|
||||
false);
|
||||
return ((RubyClass) typeClass).newInstance(context, durationArgs, Block.NULL_BLOCK);
|
||||
}
|
||||
|
||||
// Not able to convert so flag as invalid
|
||||
throw createTypeError(
|
||||
context,
|
||||
"Invalid type "
|
||||
+ value.getMetaClass()
|
||||
+ " to assign to submessage field '"
|
||||
+ fieldName
|
||||
+ "'.");
|
||||
}
|
||||
|
||||
break;
|
||||
case ENUM:
|
||||
boolean isValid =
|
||||
((RubyEnumDescriptor) typeClass.getInstanceVariable(DESCRIPTOR_INSTANCE_VAR))
|
||||
.isValidValue(context, value);
|
||||
if (!isValid) {
|
||||
throw runtime.newRangeError("Unknown symbol value for enum field '" + fieldName + "'.");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
private static IRubyObject validateAndEncodeString(ThreadContext context, String fieldType, String fieldName, IRubyObject value, String encoding) {
|
||||
if (!(value instanceof RubyString))
|
||||
throw createInvalidTypeError(context, fieldType, fieldName, value);
|
||||
public static IRubyObject wrapPrimaryValue(
|
||||
ThreadContext context, FieldDescriptor.Type fieldType, Object value) {
|
||||
return wrapPrimaryValue(context, fieldType, value, false);
|
||||
}
|
||||
|
||||
value = ((RubyString) value).encode(context, context.runtime.evalScriptlet(encoding));
|
||||
value.setFrozen(true);
|
||||
return value;
|
||||
public static IRubyObject wrapPrimaryValue(
|
||||
ThreadContext context, FieldDescriptor.Type fieldType, Object value, boolean encodeBytes) {
|
||||
Ruby runtime = context.runtime;
|
||||
switch (fieldType) {
|
||||
case INT32:
|
||||
case SFIXED32:
|
||||
case SINT32:
|
||||
return runtime.newFixnum((Integer) value);
|
||||
case SFIXED64:
|
||||
case SINT64:
|
||||
case INT64:
|
||||
return runtime.newFixnum((Long) value);
|
||||
case FIXED32:
|
||||
case UINT32:
|
||||
return runtime.newFixnum(((Integer) value) & (-1l >>> 32));
|
||||
case FIXED64:
|
||||
case UINT64:
|
||||
long ret = (Long) value;
|
||||
return ret >= 0
|
||||
? runtime.newFixnum(ret)
|
||||
: RubyBignum.newBignum(runtime, UINT64_COMPLEMENTARY.add(new BigInteger(ret + "")));
|
||||
case FLOAT:
|
||||
return runtime.newFloat((Float) value);
|
||||
case DOUBLE:
|
||||
return runtime.newFloat((Double) value);
|
||||
case BOOL:
|
||||
return (Boolean) value ? runtime.getTrue() : runtime.getFalse();
|
||||
case BYTES:
|
||||
{
|
||||
IRubyObject wrapped =
|
||||
encodeBytes
|
||||
? RubyString.newString(
|
||||
runtime, ((ByteString) value).toStringUtf8(), ASCIIEncoding.INSTANCE)
|
||||
: RubyString.newString(runtime, ((ByteString) value).toByteArray());
|
||||
wrapped.setFrozen(true);
|
||||
return wrapped;
|
||||
}
|
||||
case STRING:
|
||||
{
|
||||
IRubyObject wrapped = runtime.newString(value.toString());
|
||||
wrapped.setFrozen(true);
|
||||
return wrapped;
|
||||
}
|
||||
default:
|
||||
return runtime.getNil();
|
||||
}
|
||||
}
|
||||
|
||||
public static final String DESCRIPTOR_INSTANCE_VAR = "@descriptor";
|
||||
public static int num2uint(IRubyObject value) {
|
||||
long longVal = RubyNumeric.num2long(value);
|
||||
if (longVal > UINT_MAX)
|
||||
throw value
|
||||
.getRuntime()
|
||||
.newRangeError("Integer " + longVal + " too big to convert to 'unsigned int'");
|
||||
long num = longVal;
|
||||
if (num > Integer.MAX_VALUE || num < Integer.MIN_VALUE)
|
||||
// encode to UINT32
|
||||
num = (-longVal ^ (-1l >>> 32)) + 1;
|
||||
RubyNumeric.checkInt(value, num);
|
||||
return (int) num;
|
||||
}
|
||||
|
||||
public static final String EQUAL_SIGN = "=";
|
||||
public static long num2ulong(Ruby runtime, IRubyObject value) {
|
||||
if (value instanceof RubyFloat) {
|
||||
RubyBignum bignum = RubyBignum.newBignum(runtime, ((RubyFloat) value).getDoubleValue());
|
||||
return RubyBignum.big2ulong(bignum);
|
||||
} else if (value instanceof RubyBignum) {
|
||||
return RubyBignum.big2ulong((RubyBignum) value);
|
||||
} else {
|
||||
return RubyNumeric.num2long(value);
|
||||
}
|
||||
}
|
||||
|
||||
private static final BigInteger UINT64_COMPLEMENTARY = new BigInteger("18446744073709551616"); //Math.pow(2, 64)
|
||||
/*
|
||||
* Helper to make it easier to support symbols being passed instead of strings
|
||||
*/
|
||||
public static IRubyObject symToString(IRubyObject sym) {
|
||||
if (sym instanceof RubySymbol) {
|
||||
return ((RubySymbol) sym).id2name();
|
||||
}
|
||||
return sym;
|
||||
}
|
||||
|
||||
private static final String EXPECTED_TYPE_ERROR_FORMAT = "Expected %s type for %s field '%s' (given %s).";
|
||||
private static final String INVALID_TYPE_ERROR_FORMAT = "Invalid argument for %s field '%s' (given %s).";
|
||||
public static void checkNameAvailability(ThreadContext context, String name) {
|
||||
if (context.runtime.getObject().getConstantAt(name) != null)
|
||||
throw context.runtime.newNameError(name + " is already defined", name);
|
||||
}
|
||||
|
||||
private static final long UINT_MAX = 0xffffffffl;
|
||||
public static boolean isMapEntry(FieldDescriptor fieldDescriptor) {
|
||||
return fieldDescriptor.getType() == FieldDescriptor.Type.MESSAGE
|
||||
&& fieldDescriptor.isRepeated()
|
||||
&& fieldDescriptor.getMessageType().getOptions().getMapEntry();
|
||||
}
|
||||
|
||||
private static RubyClass cTypeError;
|
||||
public static RaiseException createTypeError(ThreadContext context, String message) {
|
||||
if (cTypeError == null) {
|
||||
cTypeError = (RubyClass) context.runtime.getClassFromPath("Google::Protobuf::TypeError");
|
||||
}
|
||||
return RaiseException.from(context.runtime, cTypeError, message);
|
||||
}
|
||||
|
||||
public static RaiseException createExpectedTypeError(
|
||||
ThreadContext context, String type, String fieldType, String fieldName, IRubyObject value) {
|
||||
return createTypeError(
|
||||
context,
|
||||
String.format(
|
||||
EXPECTED_TYPE_ERROR_FORMAT, type, fieldType, fieldName, value.getMetaClass()));
|
||||
}
|
||||
|
||||
public static RaiseException createInvalidTypeError(
|
||||
ThreadContext context, String fieldType, String fieldName, IRubyObject value) {
|
||||
return createTypeError(
|
||||
context,
|
||||
String.format(INVALID_TYPE_ERROR_FORMAT, fieldType, fieldName, value.getMetaClass()));
|
||||
}
|
||||
|
||||
protected static boolean isRubyNum(Object value) {
|
||||
return value instanceof RubyFixnum || value instanceof RubyFloat || value instanceof RubyBignum;
|
||||
}
|
||||
|
||||
protected static void validateTypeClass(
|
||||
ThreadContext context, FieldDescriptor.Type type, IRubyObject value) {
|
||||
Ruby runtime = context.runtime;
|
||||
if (!(value instanceof RubyModule)) {
|
||||
throw runtime.newArgumentError("TypeClass has incorrect type");
|
||||
}
|
||||
RubyModule klass = (RubyModule) value;
|
||||
IRubyObject descriptor = klass.getInstanceVariable(DESCRIPTOR_INSTANCE_VAR);
|
||||
if (descriptor.isNil()) {
|
||||
throw runtime.newArgumentError(
|
||||
"Type class has no descriptor. Please pass a "
|
||||
+ "class or enum as returned by the DescriptorPool.");
|
||||
}
|
||||
if (type == FieldDescriptor.Type.MESSAGE) {
|
||||
if (!(descriptor instanceof RubyDescriptor)) {
|
||||
throw runtime.newArgumentError("Descriptor has an incorrect type");
|
||||
}
|
||||
} else if (type == FieldDescriptor.Type.ENUM) {
|
||||
if (!(descriptor instanceof RubyEnumDescriptor)) {
|
||||
throw runtime.newArgumentError("Descriptor has an incorrect type");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static IRubyObject validateAndEncodeString(
|
||||
ThreadContext context,
|
||||
String fieldType,
|
||||
String fieldName,
|
||||
IRubyObject value,
|
||||
String encoding) {
|
||||
if (!(value instanceof RubyString))
|
||||
throw createInvalidTypeError(context, fieldType, fieldName, value);
|
||||
|
||||
value = ((RubyString) value).encode(context, context.runtime.evalScriptlet(encoding));
|
||||
value.setFrozen(true);
|
||||
return value;
|
||||
}
|
||||
|
||||
public static final String DESCRIPTOR_INSTANCE_VAR = "@descriptor";
|
||||
|
||||
public static final String EQUAL_SIGN = "=";
|
||||
|
||||
private static final BigInteger UINT64_COMPLEMENTARY =
|
||||
new BigInteger("18446744073709551616"); // Math.pow(2, 64)
|
||||
|
||||
private static final String EXPECTED_TYPE_ERROR_FORMAT =
|
||||
"Expected %s type for %s field '%s' (given %s).";
|
||||
private static final String INVALID_TYPE_ERROR_FORMAT =
|
||||
"Invalid argument for %s field '%s' (given %s).";
|
||||
|
||||
private static final long UINT_MAX = 0xffffffffl;
|
||||
|
||||
private static RubyClass cTypeError;
|
||||
}
|
||||
|
@ -33,30 +33,29 @@
|
||||
package google;
|
||||
|
||||
import com.google.protobuf.jruby.*;
|
||||
import java.io.IOException;
|
||||
import org.jruby.Ruby;
|
||||
import org.jruby.runtime.load.BasicLibraryService;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class ProtobufJavaService implements BasicLibraryService {
|
||||
@Override
|
||||
public boolean basicLoad(Ruby ruby) throws IOException {
|
||||
ruby.defineModule("Google");
|
||||
@Override
|
||||
public boolean basicLoad(Ruby ruby) throws IOException {
|
||||
ruby.defineModule("Google");
|
||||
|
||||
/*
|
||||
* The order these happen in is important because we
|
||||
* save a static reference to some classes and they
|
||||
* need to exist before we try to save a reference to them
|
||||
*/
|
||||
RubyProtobuf.createProtobuf(ruby);
|
||||
RubyFileDescriptor.createRubyFileDescriptor(ruby);
|
||||
RubyEnumDescriptor.createRubyEnumDescriptor(ruby);
|
||||
RubyRepeatedField.createRubyRepeatedField(ruby);
|
||||
RubyFieldDescriptor.createRubyFieldDescriptor(ruby);
|
||||
RubyMap.createRubyMap(ruby);
|
||||
RubyOneofDescriptor.createRubyOneofDescriptor(ruby);
|
||||
RubyDescriptor.createRubyDescriptor(ruby);
|
||||
RubyDescriptorPool.createRubyDescriptorPool(ruby);
|
||||
return true;
|
||||
}
|
||||
/*
|
||||
* The order these happen in is important because we
|
||||
* save a static reference to some classes and they
|
||||
* need to exist before we try to save a reference to them
|
||||
*/
|
||||
RubyProtobuf.createProtobuf(ruby);
|
||||
RubyFileDescriptor.createRubyFileDescriptor(ruby);
|
||||
RubyEnumDescriptor.createRubyEnumDescriptor(ruby);
|
||||
RubyRepeatedField.createRubyRepeatedField(ruby);
|
||||
RubyFieldDescriptor.createRubyFieldDescriptor(ruby);
|
||||
RubyMap.createRubyMap(ruby);
|
||||
RubyOneofDescriptor.createRubyOneofDescriptor(ruby);
|
||||
RubyDescriptor.createRubyDescriptor(ruby);
|
||||
RubyDescriptorPool.createRubyDescriptorPool(ruby);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user