parent
a5f7bb8ebb
commit
27e2b57830
28 changed files with 4641 additions and 25 deletions
@ -0,0 +1,6 @@ |
||||
*.bundle |
||||
tags |
||||
.idea/ |
||||
lib/google/protobuf_java.jar |
||||
protobuf-jruby.iml |
||||
target/ |
@ -0,0 +1,3 @@ |
||||
source 'https://rubygems.org' |
||||
|
||||
gemspec |
@ -0,0 +1,25 @@ |
||||
PATH |
||||
remote: . |
||||
specs: |
||||
google-protobuf (3.0.0.alpha.2) |
||||
|
||||
GEM |
||||
remote: https://rubygems.org/ |
||||
specs: |
||||
power_assert (0.2.2) |
||||
rake (10.4.2) |
||||
rake-compiler (0.9.5) |
||||
rake |
||||
rubygems-tasks (0.2.4) |
||||
test-unit (3.0.9) |
||||
power_assert |
||||
|
||||
PLATFORMS |
||||
java |
||||
ruby |
||||
|
||||
DEPENDENCIES |
||||
google-protobuf! |
||||
rake-compiler |
||||
rubygems-tasks |
||||
test-unit |
@ -0,0 +1,84 @@ |
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" |
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
||||
<modelVersion>4.0.0</modelVersion> |
||||
<parent> |
||||
<groupId>com.google</groupId> |
||||
<artifactId>google</artifactId> |
||||
<version>1</version> |
||||
</parent> |
||||
|
||||
<groupId>com.google.protobuf.jruby</groupId> |
||||
<artifactId>protobuf-jruby</artifactId> |
||||
<version>1.0-SNAPSHOT</version> |
||||
<name>Protocol Buffer JRuby native extension</name> |
||||
<description> |
||||
Protocol Buffers are a way of encoding structured data in an efficient yet |
||||
extensible format. |
||||
</description> |
||||
<inceptionYear>2014</inceptionYear> |
||||
<url>https://developers.google.com/protocol-buffers/</url> |
||||
<licenses> |
||||
<license> |
||||
<name>New BSD license</name> |
||||
<url>http://www.opensource.org/licenses/bsd-license.php</url> |
||||
<distribution>repo</distribution> |
||||
</license> |
||||
</licenses> |
||||
<scm> |
||||
<url>https://github.com/google/protobuf</url> |
||||
<connection> |
||||
scm:git:https://github.com/google/protobuf.git |
||||
</connection> |
||||
</scm> |
||||
|
||||
<properties> |
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> |
||||
<ruby.sources>lib/google</ruby.sources> |
||||
<jar.finalName>protobuf_java</jar.finalName> |
||||
</properties> |
||||
<build> |
||||
<plugins> |
||||
<plugin> |
||||
<groupId>org.apache.maven.plugins</groupId> |
||||
<artifactId>maven-assembly-plugin</artifactId> |
||||
<configuration> |
||||
<finalName>${jar.finalName}</finalName> |
||||
<outputDirectory>${ruby.sources}</outputDirectory> |
||||
<appendAssemblyId>false</appendAssemblyId> |
||||
<descriptorRefs> |
||||
<descriptorRef>jar-with-dependencies</descriptorRef> |
||||
</descriptorRefs> |
||||
</configuration> |
||||
<executions> |
||||
<execution> |
||||
<id>make-assembly</id> |
||||
<phase>package</phase> |
||||
<goals> |
||||
<goal>single</goal> |
||||
</goals> |
||||
</execution> |
||||
</executions> |
||||
</plugin> |
||||
</plugins> |
||||
</build> |
||||
<dependencies> |
||||
<dependency> |
||||
<groupId>com.fasterxml.jackson.core</groupId> |
||||
<artifactId>jackson-core</artifactId> |
||||
<version>2.4.3</version> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>org.jruby</groupId> |
||||
<artifactId>jruby-complete</artifactId> |
||||
<version>1.7.13</version> |
||||
<scope>provided</scope> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>com.google.protobuf</groupId> |
||||
<artifactId>protobuf-java</artifactId> |
||||
<version>3.0.0-pre</version> |
||||
</dependency> |
||||
</dependencies> |
||||
</project> |
@ -0,0 +1,167 @@ |
||||
/* |
||||
* Protocol Buffers - Google's data interchange format |
||||
* Copyright 2014 Google Inc. All rights reserved. |
||||
* https://developers.google.com/protocol-buffers/
|
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
*/ |
||||
|
||||
package com.google.protobuf.jruby; |
||||
|
||||
import org.jruby.*; |
||||
import org.jruby.anno.JRubyClass; |
||||
import org.jruby.anno.JRubyMethod; |
||||
import org.jruby.runtime.*; |
||||
import org.jruby.runtime.builtin.IRubyObject; |
||||
|
||||
@JRubyClass(name = "Builder") |
||||
public class RubyBuilder extends RubyObject { |
||||
public static void createRubyBuilder(Ruby runtime) { |
||||
RubyModule protobuf = runtime.getClassFromPath("Google::Protobuf"); |
||||
RubyClass cBuilder = protobuf.defineClassUnder("Builder", runtime.getObject(), new ObjectAllocator() { |
||||
@Override |
||||
public IRubyObject allocate(Ruby runtime, RubyClass klazz) { |
||||
return new RubyBuilder(runtime, klazz); |
||||
} |
||||
}); |
||||
cBuilder.defineAnnotatedMethods(RubyBuilder.class); |
||||
} |
||||
|
||||
public RubyBuilder(Ruby runtime, RubyClass metaClass) { |
||||
super(runtime, metaClass); |
||||
this.cDescriptor = (RubyClass) runtime.getClassFromPath("Google::Protobuf::Descriptor"); |
||||
this.cEnumDescriptor = (RubyClass) runtime.getClassFromPath("Google::Protobuf::EnumDescriptor"); |
||||
this.cMessageBuilderContext = (RubyClass) runtime.getClassFromPath("Google::Protobuf::MessageBuilderContext"); |
||||
this.cEnumBuilderContext = (RubyClass) runtime.getClassFromPath("Google::Protobuf::EnumBuilderContext"); |
||||
} |
||||
|
||||
/* |
||||
* call-seq: |
||||
* Builder.new => builder |
||||
* |
||||
* Creates a new Builder. A Builder can accumulate a set of new message and enum |
||||
* descriptors and atomically register them into a pool in a way that allows for |
||||
* (co)recursive type references. |
||||
*/ |
||||
@JRubyMethod |
||||
public IRubyObject initialize(ThreadContext context) { |
||||
Ruby runtime = context.runtime; |
||||
this.pendingList = runtime.newArray(); |
||||
return this; |
||||
} |
||||
|
||||
/* |
||||
* call-seq: |
||||
* Builder.add_message(name, &block) |
||||
* |
||||
* Creates a new, empty descriptor with the given name, and invokes the block in |
||||
* the context of a MessageBuilderContext on that descriptor. The block can then |
||||
* call, e.g., MessageBuilderContext#optional and MessageBuilderContext#repeated |
||||
* methods to define the message fields. |
||||
* |
||||
* This is the recommended, idiomatic way to build message definitions. |
||||
*/ |
||||
@JRubyMethod(name = "add_message") |
||||
public IRubyObject addMessage(ThreadContext context, IRubyObject name, Block block) { |
||||
RubyDescriptor msgdef = (RubyDescriptor) cDescriptor.newInstance(context, Block.NULL_BLOCK); |
||||
IRubyObject ctx = cMessageBuilderContext.newInstance(context, msgdef, this, Block.NULL_BLOCK); |
||||
msgdef.setName(context, name); |
||||
if (block.isGiven()) { |
||||
if (block.arity() == Arity.ONE_ARGUMENT) { |
||||
block.yield(context, ctx); |
||||
} else { |
||||
Binding binding = block.getBinding(); |
||||
binding.setSelf(ctx); |
||||
block.yieldSpecific(context); |
||||
} |
||||
} |
||||
this.pendingList.add(msgdef); |
||||
return context.runtime.getNil(); |
||||
} |
||||
|
||||
/* |
||||
* call-seq: |
||||
* Builder.add_enum(name, &block) |
||||
* |
||||
* Creates a new, empty enum descriptor with the given name, and invokes the block in |
||||
* the context of an EnumBuilderContext on that descriptor. The block can then |
||||
* call EnumBuilderContext#add_value to define the enum values. |
||||
* |
||||
* This is the recommended, idiomatic way to build enum definitions. |
||||
*/ |
||||
@JRubyMethod(name = "add_enum") |
||||
public IRubyObject addEnum(ThreadContext context, IRubyObject name, Block block) { |
||||
RubyEnumDescriptor enumDef = (RubyEnumDescriptor) cEnumDescriptor.newInstance(context, Block.NULL_BLOCK); |
||||
IRubyObject ctx = cEnumBuilderContext.newInstance(context, enumDef, Block.NULL_BLOCK); |
||||
enumDef.setName(context, name); |
||||
|
||||
if (block.isGiven()) { |
||||
if (block.arity() == Arity.ONE_ARGUMENT) { |
||||
block.yield(context, ctx); |
||||
} else { |
||||
Binding binding = block.getBinding(); |
||||
binding.setSelf(ctx); |
||||
block.yieldSpecific(context); |
||||
} |
||||
} |
||||
|
||||
this.pendingList.add(enumDef); |
||||
return context.runtime.getNil(); |
||||
} |
||||
|
||||
/* |
||||
* call-seq: |
||||
* Builder.finalize_to_pool(pool) |
||||
* |
||||
* Adds all accumulated message and enum descriptors created in this builder |
||||
* context to the given pool. The operation occurs atomically, and all |
||||
* descriptors can refer to each other (including in cycles). This is the only |
||||
* way to build (co)recursive message definitions. |
||||
* |
||||
* This method is usually called automatically by DescriptorPool#build after it |
||||
* invokes the given user block in the context of the builder. The user should |
||||
* not normally need to call this manually because a Builder is not normally |
||||
* created manually. |
||||
*/ |
||||
@JRubyMethod(name = "finalize_to_pool") |
||||
public IRubyObject finalizeToPool(ThreadContext context, IRubyObject rbPool) { |
||||
RubyDescriptorPool pool = (RubyDescriptorPool) rbPool; |
||||
for (int i = 0; i < this.pendingList.size(); i++) { |
||||
IRubyObject defRb = this.pendingList.entry(i); |
||||
if (defRb instanceof RubyDescriptor) { |
||||
pool.addToSymtab(context, (RubyDescriptor) defRb); |
||||
} else { |
||||
pool.addToSymtab(context, (RubyEnumDescriptor) defRb); |
||||
} |
||||
} |
||||
this.pendingList = context.runtime.newArray(); |
||||
return context.runtime.getNil(); |
||||
} |
||||
|
||||
protected RubyArray pendingList; |
||||
private RubyClass cDescriptor, cEnumDescriptor, cMessageBuilderContext, cEnumBuilderContext; |
||||
} |
@ -0,0 +1,267 @@ |
||||
/* |
||||
* Protocol Buffers - Google's data interchange format |
||||
* Copyright 2014 Google Inc. All rights reserved. |
||||
* https://developers.google.com/protocol-buffers/
|
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
*/ |
||||
|
||||
package com.google.protobuf.jruby; |
||||
|
||||
import com.google.protobuf.DescriptorProtos; |
||||
import com.google.protobuf.Descriptors; |
||||
import org.jruby.*; |
||||
import org.jruby.anno.JRubyClass; |
||||
import org.jruby.anno.JRubyMethod; |
||||
import org.jruby.runtime.Block; |
||||
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) { |
||||
return new RubyDescriptor(runtime, klazz); |
||||
} |
||||
}); |
||||
cDescriptor.includeModule(runtime.getEnumerable()); |
||||
cDescriptor.defineAnnotatedMethods(RubyDescriptor.class); |
||||
} |
||||
|
||||
public RubyDescriptor(Ruby runtime, RubyClass klazz) { |
||||
super(runtime, klazz); |
||||
} |
||||
|
||||
/* |
||||
* call-seq: |
||||
* Descriptor.new => descriptor |
||||
* |
||||
* Creates a new, empty, message type descriptor. At a minimum, its name must be |
||||
* set before it is added to a pool. It cannot be used to create messages until |
||||
* it is added to a pool, after which it becomes immutable (as part of a |
||||
* finalization process). |
||||
*/ |
||||
@JRubyMethod |
||||
public IRubyObject initialize(ThreadContext context) { |
||||
this.builder = DescriptorProtos.DescriptorProto.newBuilder(); |
||||
this.fieldDefMap = new HashMap<String, RubyFieldDescriptor>(); |
||||
this.oneofDefs = new HashMap<IRubyObject, RubyOneofDescriptor>(); |
||||
return this; |
||||
} |
||||
|
||||
/* |
||||
* call-seq: |
||||
* Descriptor.name => name |
||||
* |
||||
* Returns the name of this message type as a fully-qualfied string (e.g., |
||||
* My.Package.MessageType). |
||||
*/ |
||||
@JRubyMethod(name = "name") |
||||
public IRubyObject getName(ThreadContext context) { |
||||
return this.name; |
||||
} |
||||
|
||||
/* |
||||
* call-seq: |
||||
* Descriptor.name = name |
||||
* |
||||
* Assigns a name to this message type. The descriptor must not have been added |
||||
* to a pool yet. |
||||
*/ |
||||
@JRubyMethod(name = "name=") |
||||
public IRubyObject setName(ThreadContext context, IRubyObject name) { |
||||
this.name = name; |
||||
this.builder.setName(Utils.escapeIdentifier(this.name.asJavaString())); |
||||
return context.runtime.getNil(); |
||||
} |
||||
|
||||
/* |
||||
* call-seq: |
||||
* Descriptor.add_field(field) => nil |
||||
* |
||||
* Adds the given FieldDescriptor to this message type. The descriptor must not |
||||
* have been added to a pool yet. Raises an exception if a field with the same |
||||
* name or number already exists. Sub-type references (e.g. for fields of type |
||||
* message) are not resolved at this point. |
||||
*/ |
||||
@JRubyMethod(name = "add_field") |
||||
public IRubyObject addField(ThreadContext context, IRubyObject obj) { |
||||
RubyFieldDescriptor fieldDef = (RubyFieldDescriptor) obj; |
||||
this.fieldDefMap.put(fieldDef.getName(context).asJavaString(), fieldDef); |
||||
this.builder.addField(fieldDef.build()); |
||||
return context.runtime.getNil(); |
||||
} |
||||
|
||||
/* |
||||
* 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 this.fieldDefMap.get(fieldName.asJavaString()); |
||||
} |
||||
|
||||
/* |
||||
* 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) { |
||||
if (this.klazz == null) { |
||||
this.klazz = buildClassFromDescriptor(context); |
||||
} |
||||
return this.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<String, RubyFieldDescriptor> entry : fieldDefMap.entrySet()) { |
||||
block.yield(context, entry.getValue()); |
||||
} |
||||
return context.runtime.getNil(); |
||||
} |
||||
|
||||
/* |
||||
* call-seq: |
||||
* Descriptor.add_oneof(oneof) => nil |
||||
* |
||||
* Adds the given OneofDescriptor to this message type. This descriptor must not |
||||
* have been added to a pool yet. Raises an exception if a oneof with the same |
||||
* name already exists, or if any of the oneof's fields' names or numbers |
||||
* conflict with an existing field in this message type. All fields in the oneof |
||||
* are added to the message descriptor. Sub-type references (e.g. for fields of |
||||
* type message) are not resolved at this point. |
||||
*/ |
||||
@JRubyMethod(name = "add_oneof") |
||||
public IRubyObject addOneof(ThreadContext context, IRubyObject obj) { |
||||
RubyOneofDescriptor def = (RubyOneofDescriptor) obj; |
||||
builder.addOneofDecl(def.build(builder.getOneofDeclCount())); |
||||
for (RubyFieldDescriptor fieldDescriptor : def.getFields()) { |
||||
addField(context, fieldDescriptor); |
||||
} |
||||
oneofDefs.put(def.getName(context), def); |
||||
return context.runtime.getNil(); |
||||
} |
||||
|
||||
/* |
||||
* 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 : oneofDefs.values()) { |
||||
block.yieldSpecific(context, oneofDescriptor); |
||||
} |
||||
return context.runtime.getNil(); |
||||
} |
||||
|
||||
/* |
||||
* 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) { |
||||
if (name instanceof RubySymbol) { |
||||
name = ((RubySymbol) name).id2name(); |
||||
} |
||||
return oneofDefs.containsKey(name) ? oneofDefs.get(name) : context.runtime.getNil(); |
||||
} |
||||
|
||||
public void setDescriptor(Descriptors.Descriptor descriptor) { |
||||
this.descriptor = descriptor; |
||||
} |
||||
|
||||
public Descriptors.Descriptor getDescriptor() { |
||||
return this.descriptor; |
||||
} |
||||
|
||||
public DescriptorProtos.DescriptorProto.Builder getBuilder() { |
||||
return builder; |
||||
} |
||||
|
||||
public void setMapEntry(boolean isMapEntry) { |
||||
this.builder.setOptions(DescriptorProtos.MessageOptions.newBuilder().setMapEntry(isMapEntry)); |
||||
} |
||||
|
||||
private RubyModule 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); |
||||
} |
||||
}; |
||||
|
||||
// rb_define_class_id
|
||||
RubyClass klass = RubyClass.newClass(runtime, runtime.getObject()); |
||||
klass.setAllocator(allocator); |
||||
klass.makeMetaClass(runtime.getObject().getMetaClass()); |
||||
klass.inherit(runtime.getObject()); |
||||
klass.instance_variable_set(runtime.newString(Utils.DESCRIPTOR_INSTANCE_VAR), this); |
||||
klass.defineAnnotatedMethods(RubyMessage.class); |
||||
return klass; |
||||
} |
||||
|
||||
protected RubyFieldDescriptor lookup(String fieldName) { |
||||
return fieldDefMap.get(Utils.unescapeIdentifier(fieldName)); |
||||
} |
||||
|
||||
private IRubyObject name; |
||||
private RubyModule klazz; |
||||
|
||||
private DescriptorProtos.DescriptorProto.Builder builder; |
||||
private Descriptors.Descriptor descriptor; |
||||
private Map<String, RubyFieldDescriptor> fieldDefMap; |
||||
private Map<IRubyObject, RubyOneofDescriptor> oneofDefs; |
||||
} |
@ -0,0 +1,169 @@ |
||||
/* |
||||
* Protocol Buffers - Google's data interchange format |
||||
* Copyright 2014 Google Inc. All rights reserved. |
||||
* https://developers.google.com/protocol-buffers/
|
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
*/ |
||||
|
||||
package com.google.protobuf.jruby; |
||||
|
||||
import com.google.protobuf.DescriptorProtos; |
||||
import com.google.protobuf.Descriptors; |
||||
import org.jruby.*; |
||||
import org.jruby.anno.JRubyClass; |
||||
import org.jruby.anno.JRubyMethod; |
||||
import org.jruby.runtime.*; |
||||
import org.jruby.runtime.builtin.IRubyObject; |
||||
|
||||
import java.util.HashMap; |
||||
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) { |
||||
return new RubyDescriptorPool(runtime, klazz); |
||||
} |
||||
}); |
||||
|
||||
cDescriptorPool.defineAnnotatedMethods(RubyDescriptorPool.class); |
||||
descriptorPool = (RubyDescriptorPool) cDescriptorPool.newInstance(runtime.getCurrentContext(), Block.NULL_BLOCK); |
||||
} |
||||
|
||||
public RubyDescriptorPool(Ruby ruby, RubyClass klazz) { |
||||
super(ruby, klazz); |
||||
} |
||||
|
||||
@JRubyMethod |
||||
public IRubyObject initialize(ThreadContext context) { |
||||
this.symtab = new HashMap<IRubyObject, IRubyObject>(); |
||||
this.cBuilder = (RubyClass) context.runtime.getClassFromPath("Google::Protobuf::Builder"); |
||||
this.builder = DescriptorProtos.FileDescriptorProto.newBuilder(); |
||||
return this; |
||||
} |
||||
|
||||
@JRubyMethod |
||||
public IRubyObject build(ThreadContext context, Block block) { |
||||
RubyBuilder ctx = (RubyBuilder) cBuilder.newInstance(context, Block.NULL_BLOCK); |
||||
if (block.arity() == Arity.ONE_ARGUMENT) { |
||||
block.yield(context, ctx); |
||||
} else { |
||||
Binding binding = block.getBinding(); |
||||
binding.setSelf(ctx); |
||||
block.yieldSpecific(context); |
||||
} |
||||
ctx.finalizeToPool(context, this); |
||||
buildFileDescriptor(context); |
||||
return context.runtime.getNil(); |
||||
} |
||||
|
||||
@JRubyMethod |
||||
public IRubyObject lookup(ThreadContext context, IRubyObject name) { |
||||
IRubyObject descriptor = this.symtab.get(name); |
||||
if (descriptor == null) { |
||||
return context.runtime.getNil(); |
||||
} |
||||
return descriptor; |
||||
} |
||||
|
||||
/* |
||||
* 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; |
||||
} |
||||
|
||||
protected void addToSymtab(ThreadContext context, RubyDescriptor def) { |
||||
symtab.put(def.getName(context), def); |
||||
this.builder.addMessageType(def.getBuilder()); |
||||
} |
||||
|
||||
protected void addToSymtab(ThreadContext context, RubyEnumDescriptor def) { |
||||
symtab.put(def.getName(context), def); |
||||
this.builder.addEnumType(def.getBuilder()); |
||||
} |
||||
|
||||
private void buildFileDescriptor(ThreadContext context) { |
||||
Ruby runtime = context.runtime; |
||||
try { |
||||
this.builder.setSyntax("proto3"); |
||||
final Descriptors.FileDescriptor fileDescriptor = Descriptors.FileDescriptor.buildFrom( |
||||
this.builder.build(), new Descriptors.FileDescriptor[]{}); |
||||
|
||||
for (Descriptors.EnumDescriptor enumDescriptor : fileDescriptor.getEnumTypes()) { |
||||
String enumName = Utils.unescapeIdentifier(enumDescriptor.getName()); |
||||
if (enumDescriptor.findValueByNumber(0) == null) { |
||||
throw runtime.newTypeError("Enum definition " + enumName |
||||
+ " does not contain a value for '0'"); |
||||
} |
||||
((RubyEnumDescriptor) symtab.get(runtime.newString(enumName))) |
||||
.setDescriptor(enumDescriptor); |
||||
} |
||||
for (Descriptors.Descriptor descriptor : fileDescriptor.getMessageTypes()) { |
||||
RubyDescriptor rubyDescriptor = ((RubyDescriptor) |
||||
symtab.get(runtime.newString(Utils.unescapeIdentifier(descriptor.getName())))); |
||||
for (Descriptors.FieldDescriptor fieldDescriptor : descriptor.getFields()) { |
||||
if (fieldDescriptor.isRequired()) { |
||||
throw runtime.newTypeError("Required fields are unsupported in proto3"); |
||||
} |
||||
RubyFieldDescriptor rubyFieldDescriptor = rubyDescriptor.lookup(fieldDescriptor.getName()); |
||||
rubyFieldDescriptor.setFieldDef(fieldDescriptor); |
||||
if (fieldDescriptor.getType() == Descriptors.FieldDescriptor.Type.MESSAGE) { |
||||
RubyDescriptor subType = (RubyDescriptor) lookup(context, |
||||
runtime.newString(Utils.unescapeIdentifier(fieldDescriptor.getMessageType().getName()))); |
||||
rubyFieldDescriptor.setSubType(subType); |
||||
} |
||||
if (fieldDescriptor.getType() == Descriptors.FieldDescriptor.Type.ENUM) { |
||||
RubyEnumDescriptor subType = (RubyEnumDescriptor) lookup(context, |
||||
runtime.newString(Utils.unescapeIdentifier(fieldDescriptor.getEnumType().getName()))); |
||||
rubyFieldDescriptor.setSubType(subType); |
||||
} |
||||
} |
||||
rubyDescriptor.setDescriptor(descriptor); |
||||
} |
||||
} catch (Descriptors.DescriptorValidationException e) { |
||||
throw runtime.newRuntimeError(e.getMessage()); |
||||
} |
||||
} |
||||
|
||||
private static RubyDescriptorPool descriptorPool; |
||||
|
||||
private RubyClass cBuilder; |
||||
private Map<IRubyObject, IRubyObject> symtab; |
||||
private DescriptorProtos.FileDescriptorProto.Builder builder; |
||||
} |
@ -0,0 +1,86 @@ |
||||
/* |
||||
* Protocol Buffers - Google's data interchange format |
||||
* Copyright 2014 Google Inc. All rights reserved. |
||||
* https://developers.google.com/protocol-buffers/
|
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
*/ |
||||
|
||||
package com.google.protobuf.jruby; |
||||
|
||||
import com.google.protobuf.Descriptors; |
||||
import org.jruby.RubyModule; |
||||
import org.jruby.RubyNumeric; |
||||
import org.jruby.anno.JRubyMethod; |
||||
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 rubyEnumDescriptorescriptor = (RubyEnumDescriptor) getDescriptor(context, recv); |
||||
Descriptors.EnumDescriptor descriptor = rubyEnumDescriptorescriptor.getDescriptor(); |
||||
Descriptors.EnumValueDescriptor value = descriptor.findValueByNumber(RubyNumeric.num2int(number)); |
||||
if (value == null) return context.runtime.getNil(); |
||||
return context.runtime.newSymbol(value.getName()); |
||||
} |
||||
|
||||
/* |
||||
* 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 rubyEnumDescriptorescriptor = (RubyEnumDescriptor) getDescriptor(context, recv); |
||||
Descriptors.EnumDescriptor descriptor = rubyEnumDescriptorescriptor.getDescriptor(); |
||||
Descriptors.EnumValueDescriptor value = descriptor.findValueByName(name.asJavaString()); |
||||
if (value == null) return context.runtime.getNil(); |
||||
return context.runtime.newFixnum(value.getNumber()); |
||||
} |
||||
|
||||
/* |
||||
* 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); |
||||
} |
||||
} |
@ -0,0 +1,82 @@ |
||||
/* |
||||
* Protocol Buffers - Google's data interchange format |
||||
* Copyright 2014 Google Inc. All rights reserved. |
||||
* https://developers.google.com/protocol-buffers/
|
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
*/ |
||||
|
||||
package com.google.protobuf.jruby; |
||||
|
||||
import org.jruby.Ruby; |
||||
import org.jruby.RubyClass; |
||||
import org.jruby.RubyModule; |
||||
import org.jruby.RubyObject; |
||||
import org.jruby.anno.JRubyClass; |
||||
import org.jruby.anno.JRubyMethod; |
||||
import org.jruby.runtime.ObjectAllocator; |
||||
import org.jruby.runtime.ThreadContext; |
||||
import org.jruby.runtime.builtin.IRubyObject; |
||||
|
||||
@JRubyClass(name = "EnumBuilderContext") |
||||
public class RubyEnumBuilderContext extends RubyObject { |
||||
public static void createRubyEnumBuilderContext(Ruby runtime) { |
||||
RubyModule protobuf = runtime.getClassFromPath("Google::Protobuf"); |
||||
RubyClass cMessageBuilderContext = protobuf.defineClassUnder("EnumBuilderContext", runtime.getObject(), new ObjectAllocator() { |
||||
@Override |
||||
public IRubyObject allocate(Ruby runtime, RubyClass klazz) { |
||||
return new RubyEnumBuilderContext(runtime, klazz); |
||||
} |
||||
}); |
||||
cMessageBuilderContext.defineAnnotatedMethods(RubyEnumBuilderContext.class); |
||||
} |
||||
|
||||
public RubyEnumBuilderContext(Ruby ruby, RubyClass klazz) { |
||||
super(ruby, klazz); |
||||
} |
||||
|
||||
@JRubyMethod |
||||
public IRubyObject initialize(ThreadContext context, IRubyObject enumDescriptor) { |
||||
this.enumDescriptor = (RubyEnumDescriptor) enumDescriptor; |
||||
return this; |
||||
} |
||||
|
||||
/* |
||||
* call-seq: |
||||
* EnumBuilder.add_value(name, number) |
||||
* |
||||
* Adds the given name => number mapping to the enum type. Name must be a Ruby |
||||
* symbol. |
||||
*/ |
||||
@JRubyMethod |
||||
public IRubyObject value(ThreadContext context, IRubyObject name, IRubyObject number) { |
||||
this.enumDescriptor.addValue(context, name, number); |
||||
return context.runtime.getNil(); |
||||
} |
||||
|
||||
private RubyEnumDescriptor enumDescriptor; |
||||
} |
@ -0,0 +1,185 @@ |
||||
/* |
||||
* Protocol Buffers - Google's data interchange format |
||||
* Copyright 2014 Google Inc. All rights reserved. |
||||
* https://developers.google.com/protocol-buffers/
|
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
*/ |
||||
|
||||
package com.google.protobuf.jruby; |
||||
|
||||
import com.google.protobuf.DescriptorProtos; |
||||
import com.google.protobuf.Descriptors; |
||||
import org.jruby.Ruby; |
||||
import org.jruby.RubyClass; |
||||
import org.jruby.RubyModule; |
||||
import org.jruby.RubyObject; |
||||
import org.jruby.RubyNumeric; |
||||
import org.jruby.anno.JRubyClass; |
||||
import org.jruby.anno.JRubyMethod; |
||||
import org.jruby.runtime.Block; |
||||
import org.jruby.runtime.ObjectAllocator; |
||||
import org.jruby.runtime.ThreadContext; |
||||
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) { |
||||
return new RubyEnumDescriptor(runtime, klazz); |
||||
} |
||||
}); |
||||
cEnumDescriptor.includeModule(runtime.getEnumerable()); |
||||
cEnumDescriptor.defineAnnotatedMethods(RubyEnumDescriptor.class); |
||||
} |
||||
|
||||
public RubyEnumDescriptor(Ruby runtime, RubyClass klazz) { |
||||
super(runtime, klazz); |
||||
} |
||||
|
||||
/* |
||||
* call-seq: |
||||
* EnumDescriptor.new => enum_descriptor |
||||
* |
||||
* Creates a new, empty, enum descriptor. Must be added to a pool before the |
||||
* enum type can be used. The enum type may only be modified prior to adding to |
||||
* a pool. |
||||
*/ |
||||
@JRubyMethod |
||||
public IRubyObject initialize(ThreadContext context) { |
||||
this.builder = DescriptorProtos.EnumDescriptorProto.newBuilder(); |
||||
return this; |
||||
} |
||||
|
||||
/* |
||||
* 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.name = name |
||||
* |
||||
* Sets the name of this enum type. Cannot be called if the enum type has |
||||
* already been added to a pool. |
||||
*/ |
||||
@JRubyMethod(name = "name=") |
||||
public IRubyObject setName(ThreadContext context, IRubyObject name) { |
||||
this.name = name; |
||||
this.builder.setName(Utils.escapeIdentifier(name.asJavaString())); |
||||
return context.runtime.getNil(); |
||||
} |
||||
|
||||
/* |
||||
* call-seq: |
||||
* EnumDescriptor.add_value(key, value) |
||||
* |
||||
* Adds a new key => value mapping to this enum type. Key must be given as a |
||||
* Ruby symbol. Cannot be called if the enum type has already been added to a |
||||
* pool. Will raise an exception if the key or value is already in use. |
||||
*/ |
||||
@JRubyMethod(name = "add_value") |
||||
public IRubyObject addValue(ThreadContext context, IRubyObject name, IRubyObject number) { |
||||
DescriptorProtos.EnumValueDescriptorProto.Builder valueBuilder = DescriptorProtos.EnumValueDescriptorProto.newBuilder(); |
||||
valueBuilder.setName(name.asJavaString()); |
||||
valueBuilder.setNumber(RubyNumeric.num2int(number)); |
||||
this.builder.addValue(valueBuilder); |
||||
return context.runtime.getNil(); |
||||
} |
||||
|
||||
/* |
||||
* 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 (Descriptors.EnumValueDescriptor enumValueDescriptor : descriptor.getValues()) { |
||||
block.yield(context, runtime.newArray(runtime.newSymbol(enumValueDescriptor.getName()), |
||||
runtime.newFixnum(enumValueDescriptor.getNumber()))); |
||||
} |
||||
return runtime.getNil(); |
||||
} |
||||
|
||||
/* |
||||
* 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) { |
||||
if (this.klazz == null) { |
||||
this.klazz = buildModuleFromDescriptor(context); |
||||
} |
||||
return this.klazz; |
||||
} |
||||
|
||||
public void setDescriptor(Descriptors.EnumDescriptor descriptor) { |
||||
this.descriptor = descriptor; |
||||
} |
||||
|
||||
public Descriptors.EnumDescriptor getDescriptor() { |
||||
return this.descriptor; |
||||
} |
||||
|
||||
public DescriptorProtos.EnumDescriptorProto.Builder getBuilder() { |
||||
return this.builder; |
||||
} |
||||
|
||||
private RubyModule buildModuleFromDescriptor(ThreadContext context) { |
||||
Ruby runtime = context.runtime; |
||||
Utils.checkNameAvailability(context, name.asJavaString()); |
||||
|
||||
RubyModule enumModule = RubyModule.newModule(runtime); |
||||
for (Descriptors.EnumValueDescriptor value : descriptor.getValues()) { |
||||
enumModule.defineConstant(value.getName(), runtime.newFixnum(value.getNumber())); |
||||
} |
||||
|
||||
enumModule.instance_variable_set(runtime.newString(Utils.DESCRIPTOR_INSTANCE_VAR), this); |
||||
enumModule.defineAnnotatedMethods(RubyEnum.class); |
||||
return enumModule; |
||||
} |
||||
|
||||
private IRubyObject name; |
||||
private RubyModule klazz; |
||||
private Descriptors.EnumDescriptor descriptor; |
||||
private DescriptorProtos.EnumDescriptorProto.Builder builder; |
||||
} |
@ -0,0 +1,248 @@ |
||||
/* |
||||
* Protocol Buffers - Google's data interchange format |
||||
* Copyright 2014 Google Inc. All rights reserved. |
||||
* https://developers.google.com/protocol-buffers/
|
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
*/ |
||||
|
||||
package com.google.protobuf.jruby; |
||||
|
||||
import com.google.protobuf.DescriptorProtos; |
||||
import com.google.protobuf.Descriptors; |
||||
import org.jruby.*; |
||||
import org.jruby.anno.JRubyClass; |
||||
import org.jruby.anno.JRubyMethod; |
||||
import org.jruby.runtime.ObjectAllocator; |
||||
import org.jruby.runtime.ThreadContext; |
||||
import org.jruby.runtime.builtin.IRubyObject; |
||||
|
||||
@JRubyClass(name = "FieldDescriptor") |
||||
public class RubyFieldDescriptor extends RubyObject { |
||||
public static void createRubyFileDescriptor(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); |
||||
} |
||||
|
||||
public RubyFieldDescriptor(Ruby runtime, RubyClass klazz) { |
||||
super(runtime, klazz); |
||||
} |
||||
|
||||
/* |
||||
* call-seq: |
||||
* FieldDescriptor.new => field |
||||
* |
||||
* Returns a new field descriptor. Its name, type, etc. must be set before it is |
||||
* added to a message type. |
||||
*/ |
||||
@JRubyMethod |
||||
public IRubyObject initialize(ThreadContext context) { |
||||
builder = DescriptorProtos.FieldDescriptorProto.newBuilder(); |
||||
return this; |
||||
} |
||||
|
||||
/* |
||||
* call-seq: |
||||
* FieldDescriptor.label = label |
||||
* |
||||
* Sets the label on this field. Cannot be called if field is part of a message |
||||
* type already in a pool. |
||||
*/ |
||||
@JRubyMethod(name = "label=") |
||||
public IRubyObject setLabel(ThreadContext context, IRubyObject value) { |
||||
this.builder.setLabel( |
||||
DescriptorProtos.FieldDescriptorProto.Label.valueOf("LABEL_" + value.asJavaString().toUpperCase())); |
||||
return context.runtime.getNil(); |
||||
} |
||||
|
||||
/* |
||||
* call-seq: |
||||
* FieldDescriptor.name => name |
||||
* |
||||
* Returns the name of this field. |
||||
*/ |
||||
@JRubyMethod(name = "name") |
||||
public IRubyObject getName(ThreadContext context) { |
||||
return this.name; |
||||
} |
||||
|
||||
@JRubyMethod(name = "subtype") |
||||
public IRubyObject getSubType(ThreadContext context) { |
||||
return subType; |
||||
} |
||||
|
||||
/* |
||||
* call-seq: |
||||
* FieldDescriptor.name = name |
||||
* |
||||
* Sets the name of this field. Cannot be called once the containing message |
||||
* type, if any, is added to a pool. |
||||
*/ |
||||
@JRubyMethod(name = "name=") |
||||
public IRubyObject setName(ThreadContext context, IRubyObject value) { |
||||
String nameStr = value.asJavaString(); |
||||
this.name = context.runtime.newString(nameStr); |
||||
this.builder.setName(Utils.escapeIdentifier(nameStr)); |
||||
return context.runtime.getNil(); |
||||
} |
||||
|
||||
/* |
||||
* 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, this.builder.getType()); |
||||
} |
||||
|
||||
/* |
||||
* call-seq: |
||||
* FieldDescriptor.type = type |
||||
* |
||||
* Sets this field's type. Cannot be called if field is part of a message type |
||||
* already in a pool. |
||||
*/ |
||||
@JRubyMethod(name = "type=") |
||||
public IRubyObject setType(ThreadContext context, IRubyObject value) { |
||||
this.builder.setType(DescriptorProtos.FieldDescriptorProto.Type.valueOf("TYPE_" + value.asJavaString().toUpperCase())); |
||||
return context.runtime.getNil(); |
||||
} |
||||
|
||||
/* |
||||
* call-seq: |
||||
* FieldDescriptor.number = number |
||||
* |
||||
* Sets the tag number for this field. Cannot be called if field is part of a |
||||
* message type already in a pool. |
||||
*/ |
||||
@JRubyMethod(name = "number=") |
||||
public IRubyObject setNumber(ThreadContext context, IRubyObject value) { |
||||
this.builder.setNumber(RubyNumeric.num2int(value)); |
||||
return context.runtime.getNil(); |
||||
} |
||||
|
||||
/* |
||||
* 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.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 msgRb) { |
||||
RubyMessage message = (RubyMessage) msgRb; |
||||
if (message.getDescriptor() != fieldDef.getContainingType()) { |
||||
throw context.runtime.newTypeError("set method called on wrong message type"); |
||||
} |
||||
return message.getField(context, fieldDef); |
||||
} |
||||
|
||||
/* |
||||
* 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 msgRb, IRubyObject value) { |
||||
RubyMessage message = (RubyMessage) msgRb; |
||||
if (message.getDescriptor() != fieldDef.getContainingType()) { |
||||
throw context.runtime.newTypeError("set method called on wrong message type"); |
||||
} |
||||
message.setField(context, fieldDef, value); |
||||
return context.runtime.getNil(); |
||||
} |
||||
|
||||
protected void setSubType(IRubyObject rubyDescriptor) { |
||||
this.subType = rubyDescriptor; |
||||
} |
||||
|
||||
protected void setFieldDef(Descriptors.FieldDescriptor fieldDescriptor) { |
||||
this.fieldDef = fieldDescriptor; |
||||
} |
||||
|
||||
protected void setOneofName(IRubyObject name) { |
||||
oneofName = name; |
||||
} |
||||
|
||||
protected void setOneofIndex(int index) { |
||||
hasOneofIndex = true; |
||||
oneofIndex = index; |
||||
} |
||||
|
||||
protected IRubyObject getOneofName() { |
||||
return oneofName; |
||||
} |
||||
|
||||
protected Descriptors.FieldDescriptor getFieldDef() { |
||||
return fieldDef; |
||||
} |
||||
|
||||
protected DescriptorProtos.FieldDescriptorProto build() { |
||||
if (hasOneofIndex) |
||||
builder.setOneofIndex(oneofIndex); |
||||
return this.builder.build(); |
||||
} |
||||
|
||||
private DescriptorProtos.FieldDescriptorProto.Builder builder; |
||||
private IRubyObject name; |
||||
private IRubyObject subType; |
||||
private IRubyObject oneofName; |
||||
private Descriptors.FieldDescriptor fieldDef; |
||||
private int oneofIndex; |
||||
private boolean hasOneofIndex = false; |
||||
} |
@ -0,0 +1,434 @@ |
||||
/* |
||||
* Protocol Buffers - Google's data interchange format |
||||
* Copyright 2014 Google Inc. All rights reserved. |
||||
* https://developers.google.com/protocol-buffers/
|
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
*/ |
||||
|
||||
package com.google.protobuf.jruby; |
||||
|
||||
import com.google.protobuf.Descriptors; |
||||
import com.google.protobuf.DynamicMessage; |
||||
import com.google.protobuf.MapEntry; |
||||
import org.jruby.*; |
||||
import org.jruby.anno.JRubyClass; |
||||
import org.jruby.anno.JRubyMethod; |
||||
import org.jruby.internal.runtime.methods.DynamicMethod; |
||||
import org.jruby.runtime.Block; |
||||
import org.jruby.runtime.ObjectAllocator; |
||||
import org.jruby.runtime.ThreadContext; |
||||
import org.jruby.runtime.builtin.IRubyObject; |
||||
import org.jruby.util.ByteList; |
||||
|
||||
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) { |
||||
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, :bool, |
||||
* :string, :bytes. |
||||
* |
||||
* The supported value types are: :int32, :int64, :uint32, :uint64, :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 INT32: |
||||
case INT64: |
||||
case UINT32: |
||||
case UINT64: |
||||
case BOOL: |
||||
case STRING: |
||||
case BYTES: |
||||
// 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(); |
||||
} |
||||
|
||||
// Table value type is always UINT64: this ensures enough space to store the
|
||||
// native_slot value.
|
||||
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) { |
||||
Utils.checkType(context, keyType, key, (RubyModule) valueTypeClass); |
||||
Utils.checkType(context, valueType, value, (RubyModule) valueTypeClass); |
||||
IRubyObject symbol; |
||||
if (valueType == Descriptors.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) { |
||||
if (table.containsKey(key)) |
||||
return this.table.get(key); |
||||
return context.runtime.getNil(); |
||||
} |
||||
|
||||
/* |
||||
* 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 toHash(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 toHash(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.newString(new ByteList(digest.digest())); |
||||
} 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) { |
||||
table.clear(); |
||||
return context.runtime.getNil(); |
||||
} |
||||
|
||||
/* |
||||
* 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.runtime.getNil(); |
||||
} |
||||
|
||||
/* |
||||
* 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) { |
||||
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 |
||||
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) { |
||||
return RubyHash.newHash(context.runtime, table, context.runtime.getNil()); |
||||
} |
||||
|
||||
// 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) { |
||||
List<DynamicMessage> list = new ArrayList<DynamicMessage>(); |
||||
RubyClass rubyClass = (RubyClass) descriptor.msgclass(context); |
||||
Descriptors.FieldDescriptor keyField = descriptor.lookup("key").getFieldDef(); |
||||
Descriptors.FieldDescriptor valueField = descriptor.lookup("value").getFieldDef(); |
||||
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)); |
||||
} |
||||
return list; |
||||
} |
||||
|
||||
protected RubyMap mergeIntoSelf(final ThreadContext context, IRubyObject hashmap) { |
||||
if (hashmap instanceof RubyHash) { |
||||
((RubyHash) hashmap).visitAll(new RubyHash.Visitor() { |
||||
@Override |
||||
public void visit(IRubyObject key, IRubyObject val) { |
||||
indexSet(context, key, val); |
||||
} |
||||
}); |
||||
} else if (hashmap instanceof RubyMap) { |
||||
RubyMap other = (RubyMap) hashmap; |
||||
if (!typeCompatible(other)) { |
||||
throw context.runtime.newTypeError("Attempt to merge Map with mismatching types"); |
||||
} |
||||
} else { |
||||
throw context.runtime.newTypeError("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; |
||||
} |
||||
|
||||
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 boolean needTypeclass(Descriptors.FieldDescriptor.Type type) { |
||||
switch(type) { |
||||
case MESSAGE: |
||||
case ENUM: |
||||
return true; |
||||
default: |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
private Descriptors.FieldDescriptor.Type keyType; |
||||
private Descriptors.FieldDescriptor.Type valueType; |
||||
private IRubyObject valueTypeClass; |
||||
private Map<IRubyObject, IRubyObject> table; |
||||
} |
@ -0,0 +1,744 @@ |
||||
/* |
||||
* Protocol Buffers - Google's data interchange format |
||||
* Copyright 2014 Google Inc. All rights reserved. |
||||
* https://developers.google.com/protocol-buffers/
|
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
*/ |
||||
|
||||
package com.google.protobuf.jruby; |
||||
|
||||
import com.google.protobuf.*; |
||||
import org.jruby.*; |
||||
import org.jruby.anno.JRubyMethod; |
||||
import org.jruby.runtime.Block; |
||||
import org.jruby.runtime.Helpers; |
||||
import org.jruby.runtime.ThreadContext; |
||||
import org.jruby.runtime.builtin.IRubyObject; |
||||
import org.jruby.util.ByteList; |
||||
|
||||
import java.util.HashMap; |
||||
import java.util.Map; |
||||
|
||||
public class RubyMessage extends RubyObject { |
||||
public RubyMessage(Ruby ruby, RubyClass klazz, Descriptors.Descriptor descriptor) { |
||||
super(ruby, klazz); |
||||
this.descriptor = descriptor; |
||||
} |
||||
|
||||
/* |
||||
* call-seq: |
||||
* Message.new(kwargs) => new_message |
||||
* |
||||
* Creates a new instance of the given message class. Keyword arguments may be |
||||
* provided with keywords corresponding to field names. |
||||
* |
||||
* Note that no literal Message class exists. Only concrete classes per message |
||||
* type exist, as provided by the #msgclass method on Descriptors after they |
||||
* have been added to a pool. The method definitions described here on the |
||||
* Message class are provided on each concrete message class. |
||||
*/ |
||||
@JRubyMethod(optional = 1) |
||||
public IRubyObject initialize(final ThreadContext context, IRubyObject[] args) { |
||||
final Ruby runtime = context.runtime; |
||||
this.cRepeatedField = (RubyClass) runtime.getClassFromPath("Google::Protobuf::RepeatedField"); |
||||
this.cMap = (RubyClass) runtime.getClassFromPath("Google::Protobuf::Map"); |
||||
this.builder = DynamicMessage.newBuilder(this.descriptor); |
||||
this.repeatedFields = new HashMap<Descriptors.FieldDescriptor, RubyRepeatedField>(); |
||||
this.maps = new HashMap<Descriptors.FieldDescriptor, RubyMap>(); |
||||
this.fields = new HashMap<Descriptors.FieldDescriptor, IRubyObject>(); |
||||
this.oneofCases = new HashMap<Descriptors.OneofDescriptor, Descriptors.FieldDescriptor>(); |
||||
if (args.length == 1) { |
||||
if (!(args[0] instanceof RubyHash)) { |
||||
throw runtime.newArgumentError("expected Hash arguments."); |
||||
} |
||||
RubyHash hash = args[0].convertToHash(); |
||||
hash.visitAll(new RubyHash.Visitor() { |
||||
@Override |
||||
public void visit(IRubyObject key, IRubyObject value) { |
||||
if (!(key instanceof RubySymbol)) |
||||
throw runtime.newTypeError("Expected symbols as hash keys in initialization map."); |
||||
final Descriptors.FieldDescriptor fieldDescriptor = findField(context, key); |
||||
|
||||
if (Utils.isMapEntry(fieldDescriptor)) { |
||||
if (!(value instanceof RubyHash)) |
||||
throw runtime.newArgumentError("Expected Hash object as initializer value for map field."); |
||||
|
||||
final RubyMap map = newMapForField(context, fieldDescriptor); |
||||
map.mergeIntoSelf(context, value); |
||||
maps.put(fieldDescriptor, map); |
||||
} else if (fieldDescriptor.isRepeated()) { |
||||
if (!(value instanceof RubyArray)) |
||||
throw runtime.newTypeError("Expected array as initializer var for repeated field."); |
||||
RubyRepeatedField repeatedField = rubyToRepeatedField(context, fieldDescriptor, value); |
||||
addRepeatedField(fieldDescriptor, repeatedField); |
||||
} else { |
||||
Descriptors.OneofDescriptor oneof = fieldDescriptor.getContainingOneof(); |
||||
if (oneof != null) { |
||||
oneofCases.put(oneof, fieldDescriptor); |
||||
} |
||||
fields.put(fieldDescriptor, value); |
||||
} |
||||
|
||||
} |
||||
}); |
||||
} |
||||
return this; |
||||
} |
||||
|
||||
/* |
||||
* call-seq: |
||||
* Message.[]=(index, value) |
||||
* |
||||
* Sets a field's value by field name. The provided field name should be a |
||||
* string. |
||||
*/ |
||||
@JRubyMethod(name = "[]=") |
||||
public IRubyObject indexSet(ThreadContext context, IRubyObject fieldName, IRubyObject value) { |
||||
Descriptors.FieldDescriptor fieldDescriptor = findField(context, fieldName); |
||||
return setField(context, fieldDescriptor, value); |
||||
} |
||||
|
||||
/* |
||||
* call-seq: |
||||
* Message.[](index) => value |
||||
* |
||||
* Accesses a field's value by field name. The provided field name should be a |
||||
* string. |
||||
*/ |
||||
@JRubyMethod(name = "[]") |
||||
public IRubyObject index(ThreadContext context, IRubyObject fieldName) { |
||||
Descriptors.FieldDescriptor fieldDescriptor = findField(context, fieldName); |
||||
return getField(context, fieldDescriptor); |
||||
} |
||||
|
||||
/* |
||||
* call-seq: |
||||
* Message.inspect => string |
||||
* |
||||
* Returns a human-readable string representing this message. It will be |
||||
* formatted as "<MessageType: field1: value1, field2: value2, ...>". Each |
||||
* field's value is represented according to its own #inspect method. |
||||
*/ |
||||
@JRubyMethod |
||||
public IRubyObject inspect() { |
||||
String cname = metaClass.getName(); |
||||
StringBuilder sb = new StringBuilder("<"); |
||||
sb.append(cname); |
||||
sb.append(": "); |
||||
sb.append(this.layoutInspect()); |
||||
sb.append(">"); |
||||
|
||||
return getRuntime().newString(sb.toString()); |
||||
} |
||||
|
||||
/* |
||||
* call-seq: |
||||
* Message.hash => hash_value |
||||
* |
||||
* Returns a hash value that represents this message's field values. |
||||
*/ |
||||
@JRubyMethod |
||||
public IRubyObject hash(ThreadContext context) { |
||||
int hashCode = System.identityHashCode(this); |
||||
return context.runtime.newFixnum(hashCode); |
||||
} |
||||
|
||||
/* |
||||
* call-seq: |
||||
* Message.==(other) => boolean |
||||
* |
||||
* Performs a deep comparison of this message with another. Messages are equal |
||||
* if they have the same type and if each field is equal according to the :== |
||||
* method's semantics (a more efficient comparison may actually be done if the |
||||
* field is of a primitive type). |
||||
*/ |
||||
@JRubyMethod(name = "==") |
||||
public IRubyObject eq(ThreadContext context, IRubyObject other) { |
||||
Ruby runtime = context.runtime; |
||||
if (!(other instanceof RubyMessage)) |
||||
return runtime.getFalse(); |
||||
RubyMessage message = (RubyMessage) other; |
||||
if (descriptor != message.descriptor) { |
||||
return runtime.getFalse(); |
||||
} |
||||
|
||||
for (Descriptors.FieldDescriptor fdef : descriptor.getFields()) { |
||||
IRubyObject thisVal = getField(context, fdef); |
||||
IRubyObject thatVal = message.getField(context, fdef); |
||||
IRubyObject ret = thisVal.callMethod(context, "==", thatVal); |
||||
if (!ret.isTrue()) { |
||||
return runtime.getFalse(); |
||||
} |
||||
} |
||||
return runtime.getTrue(); |
||||
} |
||||
|
||||
/* |
||||
* call-seq: |
||||
* Message.method_missing(*args) |
||||
* |
||||
* Provides accessors and setters for message fields according to their field |
||||
* names. For any field whose name does not conflict with a built-in method, an |
||||
* accessor is provided with the same name as the field, and a setter is |
||||
* provided with the name of the field plus the '=' suffix. Thus, given a |
||||
* message instance 'msg' with field 'foo', the following code is valid: |
||||
* |
||||
* msg.foo = 42 |
||||
* puts msg.foo |
||||
*/ |
||||
@JRubyMethod(name = "method_missing", rest = true) |
||||
public IRubyObject methodMissing(ThreadContext context, IRubyObject[] args) { |
||||
if (args.length == 1) { |
||||
RubyDescriptor rubyDescriptor = (RubyDescriptor) getDescriptor(context, metaClass); |
||||
IRubyObject oneofDescriptor = rubyDescriptor.lookupOneof(context, args[0]); |
||||
if (oneofDescriptor.isNil()) { |
||||
return index(context, args[0]); |
||||
} |
||||
RubyOneofDescriptor rubyOneofDescriptor = (RubyOneofDescriptor) oneofDescriptor; |
||||
Descriptors.FieldDescriptor fieldDescriptor = |
||||
oneofCases.get(rubyOneofDescriptor.getOneofDescriptor()); |
||||
if (fieldDescriptor == null) |
||||
return context.runtime.getNil(); |
||||
|
||||
return context.runtime.newSymbol(fieldDescriptor.getName()); |
||||
} else { |
||||
// fieldName is RubySymbol
|
||||
RubyString field = args[0].asString(); |
||||
RubyString equalSign = context.runtime.newString(Utils.EQUAL_SIGN); |
||||
if (field.end_with_p(context, equalSign).isTrue()) { |
||||
field.chomp_bang(context, equalSign); |
||||
} |
||||
return indexSet(context, field, args[1]); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* call-seq: |
||||
* Message.dup => new_message |
||||
* Performs a shallow copy of this message and returns the new copy. |
||||
*/ |
||||
@JRubyMethod |
||||
public IRubyObject dup(ThreadContext context) { |
||||
RubyMessage dup = (RubyMessage) metaClass.newInstance(context, Block.NULL_BLOCK); |
||||
IRubyObject value; |
||||
for (Descriptors.FieldDescriptor fieldDescriptor : builder.getAllFields().keySet()) { |
||||
if (fieldDescriptor.isRepeated()) { |
||||
dup.repeatedFields.put(fieldDescriptor, getRepeatedField(context, fieldDescriptor)); |
||||
} else if (builder.hasField(fieldDescriptor)) { |
||||
dup.fields.put(fieldDescriptor, wrapField(context, fieldDescriptor, builder.getField(fieldDescriptor))); |
||||
} |
||||
} |
||||
for (Descriptors.FieldDescriptor fieldDescriptor : fields.keySet()) { |
||||
dup.fields.put(fieldDescriptor, fields.get(fieldDescriptor)); |
||||
} |
||||
for (Descriptors.FieldDescriptor fieldDescriptor : maps.keySet()) { |
||||
dup.maps.put(fieldDescriptor, maps.get(fieldDescriptor)); |
||||
} |
||||
return dup; |
||||
} |
||||
|
||||
/* |
||||
* call-seq: |
||||
* Message.descriptor => descriptor |
||||
* |
||||
* Class method that returns the Descriptor instance corresponding to this |
||||
* message class's type. |
||||
*/ |
||||
@JRubyMethod(name = "descriptor", meta = true) |
||||
public static IRubyObject getDescriptor(ThreadContext context, IRubyObject recv) { |
||||
return ((RubyClass) recv).getInstanceVariable(Utils.DESCRIPTOR_INSTANCE_VAR); |
||||
} |
||||
|
||||
/* |
||||
* call-seq: |
||||
* MessageClass.encode(msg) => bytes |
||||
* |
||||
* Encodes the given message object to its serialized form in protocol buffers |
||||
* wire format. |
||||
*/ |
||||
@JRubyMethod(meta = true) |
||||
public static IRubyObject encode(ThreadContext context, IRubyObject recv, IRubyObject value) { |
||||
RubyMessage message = (RubyMessage) value; |
||||
return context.runtime.newString(new ByteList(message.build(context).toByteArray())); |
||||
} |
||||
|
||||
/* |
||||
* call-seq: |
||||
* MessageClass.decode(data) => message |
||||
* |
||||
* Decodes the given data (as a string containing bytes in protocol buffers wire |
||||
* format) under the interpretration given by this message class's definition |
||||
* and returns a message object with the corresponding field values. |
||||
*/ |
||||
@JRubyMethod(meta = true) |
||||
public static IRubyObject decode(ThreadContext context, IRubyObject recv, IRubyObject data) { |
||||
byte[] bin = data.convertToString().getBytes(); |
||||
RubyMessage ret = (RubyMessage) ((RubyClass) recv).newInstance(context, Block.NULL_BLOCK); |
||||
try { |
||||
ret.builder.mergeFrom(bin); |
||||
} catch (InvalidProtocolBufferException e) { |
||||
throw context.runtime.newRuntimeError(e.getMessage()); |
||||
} |
||||
return ret; |
||||
} |
||||
|
||||
/* |
||||
* call-seq: |
||||
* MessageClass.encode_json(msg) => json_string |
||||
* |
||||
* Encodes the given message object into its serialized JSON representation. |
||||
*/ |
||||
@JRubyMethod(name = "encode_json", meta = true) |
||||
public static IRubyObject encodeJson(ThreadContext context, IRubyObject recv, IRubyObject msgRb) { |
||||
RubyMessage message = (RubyMessage) msgRb; |
||||
return Helpers.invoke(context, message.toHash(context), "to_json"); |
||||
} |
||||
|
||||
/* |
||||
* call-seq: |
||||
* MessageClass.decode_json(data) => message |
||||
* |
||||
* Decodes the given data (as a string containing bytes in protocol buffers wire |
||||
* format) under the interpretration given by this message class's definition |
||||
* and returns a message object with the corresponding field values. |
||||
*/ |
||||
@JRubyMethod(name = "decode_json", meta = true) |
||||
public static IRubyObject decodeJson(ThreadContext context, IRubyObject recv, IRubyObject json) { |
||||
Ruby runtime = context.runtime; |
||||
RubyMessage ret = (RubyMessage) ((RubyClass) recv).newInstance(context, Block.NULL_BLOCK); |
||||
RubyModule jsonModule = runtime.getClassFromPath("JSON"); |
||||
RubyHash opts = RubyHash.newHash(runtime); |
||||
opts.fastASet(runtime.newSymbol("symbolize_names"), runtime.getTrue()); |
||||
IRubyObject[] args = new IRubyObject[] { Helpers.invoke(context, jsonModule, "parse", json, opts) }; |
||||
ret.initialize(context, args); |
||||
return ret; |
||||
} |
||||
|
||||
@JRubyMethod(name = "to_h") |
||||
public IRubyObject toHash(ThreadContext context) { |
||||
Ruby runtime = context.runtime; |
||||
RubyHash ret = RubyHash.newHash(runtime); |
||||
for (Descriptors.FieldDescriptor fdef : this.descriptor.getFields()) { |
||||
IRubyObject value = getField(context, fdef); |
||||
if (value.respondsTo("to_h")) { |
||||
value = Helpers.invoke(context, value, "to_h"); |
||||
} |
||||
ret.fastASet(runtime.newString(fdef.getName()), value); |
||||
} |
||||
return ret; |
||||
} |
||||
|
||||
protected DynamicMessage build(ThreadContext context) { |
||||
return build(context, 0); |
||||
} |
||||
|
||||
protected DynamicMessage build(ThreadContext context, int depth) { |
||||
if (depth > SINK_MAXIMUM_NESTING) { |
||||
throw context.runtime.newRuntimeError("Maximum recursion depth exceeded during encoding."); |
||||
} |
||||
for (Descriptors.FieldDescriptor fieldDescriptor : maps.keySet()) { |
||||
this.builder.clearField(fieldDescriptor); |
||||
RubyDescriptor mapDescriptor = (RubyDescriptor) getDescriptorForField(context, fieldDescriptor); |
||||
for (DynamicMessage kv : maps.get(fieldDescriptor).build(context, mapDescriptor)) { |
||||
this.builder.addRepeatedField(fieldDescriptor, kv); |
||||
} |
||||
} |
||||
for (Descriptors.FieldDescriptor fieldDescriptor : repeatedFields.keySet()) { |
||||
RubyRepeatedField repeatedField = repeatedFields.get(fieldDescriptor); |
||||
this.builder.clearField(fieldDescriptor); |
||||
for (int i = 0; i < repeatedField.size(); i++) { |
||||
Object item = convert(context, fieldDescriptor, repeatedField.get(i), depth); |
||||
this.builder.addRepeatedField(fieldDescriptor, item); |
||||
} |
||||
} |
||||
for (Descriptors.FieldDescriptor fieldDescriptor : fields.keySet()) { |
||||
IRubyObject value = fields.get(fieldDescriptor); |
||||
this.builder.setField(fieldDescriptor, convert(context, fieldDescriptor, value, depth)); |
||||
} |
||||
return this.builder.build(); |
||||
} |
||||
|
||||
protected Descriptors.Descriptor getDescriptor() { |
||||
return this.descriptor; |
||||
} |
||||
|
||||
// Internal use only, called by Google::Protobuf.deep_copy
|
||||
protected IRubyObject deepCopy(ThreadContext context) { |
||||
RubyMessage copy = (RubyMessage) metaClass.newInstance(context, Block.NULL_BLOCK); |
||||
for (Descriptors.FieldDescriptor fdef : this.descriptor.getFields()) { |
||||
if (fdef.isRepeated()) { |
||||
copy.addRepeatedField(fdef, this.getRepeatedField(context, fdef).deepCopy(context)); |
||||
} else if (fields.containsKey(fdef)) { |
||||
copy.fields.put(fdef, fields.get(fdef)); |
||||
} else if (this.builder.hasField(fdef)) { |
||||
copy.fields.put(fdef, wrapField(context, fdef, this.builder.getField(fdef))); |
||||
} |
||||
} |
||||
return copy; |
||||
} |
||||
|
||||
private RubyRepeatedField getRepeatedField(ThreadContext context, Descriptors.FieldDescriptor fieldDescriptor) { |
||||
if (this.repeatedFields.containsKey(fieldDescriptor)) { |
||||
return this.repeatedFields.get(fieldDescriptor); |
||||
} |
||||
int count = this.builder.getRepeatedFieldCount(fieldDescriptor); |
||||
RubyRepeatedField ret = repeatedFieldForFieldDescriptor(context, fieldDescriptor); |
||||
for (int i = 0; i < count; i++) { |
||||
ret.push(context, wrapField(context, fieldDescriptor, this.builder.getRepeatedField(fieldDescriptor, i))); |
||||
} |
||||
return ret; |
||||
} |
||||
|
||||
private void addRepeatedField(Descriptors.FieldDescriptor fieldDescriptor, RubyRepeatedField repeatedField) { |
||||
this.repeatedFields.put(fieldDescriptor, repeatedField); |
||||
} |
||||
|
||||
private IRubyObject buildFrom(ThreadContext context, DynamicMessage dynamicMessage) { |
||||
this.builder.mergeFrom(dynamicMessage); |
||||
return this; |
||||
} |
||||
|
||||
private Descriptors.FieldDescriptor findField(ThreadContext context, IRubyObject fieldName) { |
||||
String nameStr = fieldName.asJavaString(); |
||||
Descriptors.FieldDescriptor ret = this.descriptor.findFieldByName(Utils.escapeIdentifier(nameStr)); |
||||
if (ret == null) |
||||
throw context.runtime.newArgumentError("field " + fieldName.asJavaString() + " is not found"); |
||||
return ret; |
||||
} |
||||
|
||||
private void checkRepeatedFieldType(ThreadContext context, IRubyObject value, |
||||
Descriptors.FieldDescriptor fieldDescriptor) { |
||||
Ruby runtime = context.runtime; |
||||
if (!(value instanceof RubyRepeatedField)) { |
||||
throw runtime.newTypeError("Expected repeated field array"); |
||||
} |
||||
} |
||||
|
||||
// convert a ruby object to protobuf type, with type check
|
||||
private Object convert(ThreadContext context, |
||||
Descriptors.FieldDescriptor fieldDescriptor, |
||||
IRubyObject value, int depth) { |
||||
Ruby runtime = context.runtime; |
||||
Object val = null; |
||||
switch (fieldDescriptor.getType()) { |
||||
case INT32: |
||||
case INT64: |
||||
case UINT32: |
||||
case UINT64: |
||||
if (!Utils.isRubyNum(value)) { |
||||
throw runtime.newTypeError("Expected number type for integral field."); |
||||
} |
||||
Utils.checkIntTypePrecision(context, fieldDescriptor.getType(), value); |
||||
switch (fieldDescriptor.getType()) { |
||||
case INT32: |
||||
val = RubyNumeric.num2int(value); |
||||
break; |
||||
case INT64: |
||||
val = RubyNumeric.num2long(value); |
||||
break; |
||||
case UINT32: |
||||
val = Utils.num2uint(value); |
||||
break; |
||||
case UINT64: |
||||
val = Utils.num2ulong(context.runtime, value); |
||||
break; |
||||
default: |
||||
break; |
||||
} |
||||
break; |
||||
case FLOAT: |
||||
if (!Utils.isRubyNum(value)) |
||||
throw runtime.newTypeError("Expected number type for float field."); |
||||
val = (float) RubyNumeric.num2dbl(value); |
||||
break; |
||||
case DOUBLE: |
||||
if (!Utils.isRubyNum(value)) |
||||
throw runtime.newTypeError("Expected number type for double field."); |
||||
val = RubyNumeric.num2dbl(value); |
||||
break; |
||||
case BOOL: |
||||
if (!(value instanceof RubyBoolean)) |
||||
throw runtime.newTypeError("Invalid argument for boolean field."); |
||||
val = value.isTrue(); |
||||
break; |
||||
case BYTES: |
||||
case STRING: |
||||
Utils.validateStringEncoding(context.runtime, fieldDescriptor.getType(), value); |
||||
RubyString str = (RubyString) value; |
||||
switch (fieldDescriptor.getType()) { |
||||
case BYTES: |
||||
val = ByteString.copyFrom(str.getBytes()); |
||||
break; |
||||
case STRING: |
||||
val = str.asJavaString(); |
||||
break; |
||||
default: |
||||
break; |
||||
} |
||||
break; |
||||
case MESSAGE: |
||||
RubyClass typeClass = (RubyClass) ((RubyDescriptor) getDescriptorForField(context, fieldDescriptor)).msgclass(context); |
||||
if (!value.getMetaClass().equals(typeClass)) |
||||
throw runtime.newTypeError(value, "Invalid type to assign to submessage field."); |
||||
val = ((RubyMessage) value).build(context, depth + 1); |
||||
break; |
||||
case ENUM: |
||||
Descriptors.EnumDescriptor enumDescriptor = fieldDescriptor.getEnumType(); |
||||
|
||||
if (Utils.isRubyNum(value)) { |
||||
val = enumDescriptor.findValueByNumberCreatingIfUnknown(RubyNumeric.num2int(value)); |
||||
} else if (value instanceof RubySymbol) { |
||||
val = enumDescriptor.findValueByName(value.asJavaString()); |
||||
} else { |
||||
throw runtime.newTypeError("Expected number or symbol type for enum field."); |
||||
} |
||||
if (val == null) { |
||||
throw runtime.newRangeError("Enum value " + value + " is not found."); |
||||
} |
||||
break; |
||||
default: |
||||
break; |
||||
} |
||||
return val; |
||||
} |
||||
|
||||
private IRubyObject wrapField(ThreadContext context, Descriptors.FieldDescriptor fieldDescriptor, Object value) { |
||||
if (value == null) { |
||||
return context.runtime.getNil(); |
||||
} |
||||
Ruby runtime = context.runtime; |
||||
switch (fieldDescriptor.getType()) { |
||||
case INT32: |
||||
case INT64: |
||||
case UINT32: |
||||
case UINT64: |
||||
case FLOAT: |
||||
case DOUBLE: |
||||
case BOOL: |
||||
case BYTES: |
||||
case STRING: |
||||
return Utils.wrapPrimaryValue(context, fieldDescriptor.getType(), value); |
||||
case MESSAGE: |
||||
RubyClass typeClass = (RubyClass) ((RubyDescriptor) getDescriptorForField(context, fieldDescriptor)).msgclass(context); |
||||
RubyMessage msg = (RubyMessage) typeClass.newInstance(context, Block.NULL_BLOCK); |
||||
return msg.buildFrom(context, (DynamicMessage) value); |
||||
case ENUM: |
||||
Descriptors.EnumValueDescriptor enumValueDescriptor = (Descriptors.EnumValueDescriptor) value; |
||||
if (enumValueDescriptor.getIndex() == -1) { // UNKNOWN ENUM VALUE
|
||||
return runtime.newFixnum(enumValueDescriptor.getNumber()); |
||||
} |
||||
return runtime.newSymbol(enumValueDescriptor.getName()); |
||||
default: |
||||
return runtime.newString(value.toString()); |
||||
} |
||||
} |
||||
|
||||
private RubyRepeatedField repeatedFieldForFieldDescriptor(ThreadContext context, |
||||
Descriptors.FieldDescriptor fieldDescriptor) { |
||||
IRubyObject typeClass = context.runtime.getNilClass(); |
||||
|
||||
IRubyObject descriptor = getDescriptorForField(context, fieldDescriptor); |
||||
Descriptors.FieldDescriptor.Type type = fieldDescriptor.getType(); |
||||
if (type == Descriptors.FieldDescriptor.Type.MESSAGE) { |
||||
typeClass = ((RubyDescriptor) descriptor).msgclass(context); |
||||
|
||||
} else if (type == Descriptors.FieldDescriptor.Type.ENUM) { |
||||
typeClass = ((RubyEnumDescriptor) descriptor).enummodule(context); |
||||
} |
||||
return new RubyRepeatedField(context.runtime, cRepeatedField, type, typeClass); |
||||
} |
||||
|
||||
protected IRubyObject getField(ThreadContext context, Descriptors.FieldDescriptor fieldDescriptor) { |
||||
Descriptors.OneofDescriptor oneofDescriptor = fieldDescriptor.getContainingOneof(); |
||||
if (oneofDescriptor != null) { |
||||
if (oneofCases.containsKey(oneofDescriptor)) { |
||||
if (oneofCases.get(oneofDescriptor) != fieldDescriptor) |
||||
return context.runtime.getNil(); |
||||
return fields.get(fieldDescriptor); |
||||
} else { |
||||
Descriptors.FieldDescriptor oneofCase = builder.getOneofFieldDescriptor(oneofDescriptor); |
||||
if (oneofCase != fieldDescriptor) return context.runtime.getNil(); |
||||
IRubyObject value = wrapField(context, oneofCase, builder.getField(oneofCase)); |
||||
fields.put(fieldDescriptor, value); |
||||
return value; |
||||
} |
||||
} |
||||
|
||||
if (Utils.isMapEntry(fieldDescriptor)) { |
||||
RubyMap map = maps.get(fieldDescriptor); |
||||
if (map == null) { |
||||
map = newMapForField(context, fieldDescriptor); |
||||
int mapSize = this.builder.getRepeatedFieldCount(fieldDescriptor); |
||||
Descriptors.FieldDescriptor keyField = fieldDescriptor.getMessageType().findFieldByNumber(1); |
||||
Descriptors.FieldDescriptor valueField = fieldDescriptor.getMessageType().findFieldByNumber(2); |
||||
RubyDescriptor kvDescriptor = (RubyDescriptor) getDescriptorForField(context, fieldDescriptor); |
||||
RubyClass kvClass = (RubyClass) kvDescriptor.msgclass(context); |
||||
for (int i = 0; i < mapSize; i++) { |
||||
RubyMessage kvMessage = (RubyMessage) kvClass.newInstance(context, Block.NULL_BLOCK); |
||||
DynamicMessage message = (DynamicMessage) this.builder.getRepeatedField(fieldDescriptor, i); |
||||
kvMessage.buildFrom(context, message); |
||||
map.indexSet(context, kvMessage.getField(context, keyField), kvMessage.getField(context, valueField)); |
||||
} |
||||
maps.put(fieldDescriptor, map); |
||||
} |
||||
return map; |
||||
} |
||||
if (fieldDescriptor.isRepeated()) { |
||||
return getRepeatedField(context, fieldDescriptor); |
||||
} |
||||
if (fieldDescriptor.getType() != Descriptors.FieldDescriptor.Type.MESSAGE || |
||||
this.builder.hasField(fieldDescriptor) || fields.containsKey(fieldDescriptor)) { |
||||
if (fields.containsKey(fieldDescriptor)) { |
||||
return fields.get(fieldDescriptor); |
||||
} else { |
||||
IRubyObject value = wrapField(context, fieldDescriptor, this.builder.getField(fieldDescriptor)); |
||||
if (this.builder.hasField(fieldDescriptor)) { |
||||
fields.put(fieldDescriptor, value); |
||||
} |
||||
return value; |
||||
} |
||||
} |
||||
return context.runtime.getNil(); |
||||
} |
||||
|
||||
protected IRubyObject setField(ThreadContext context, Descriptors.FieldDescriptor fieldDescriptor, IRubyObject value) { |
||||
if (Utils.isMapEntry(fieldDescriptor)) { |
||||
if (!(value instanceof RubyMap)) { |
||||
throw context.runtime.newTypeError("Expected Map instance"); |
||||
} |
||||
RubyMap thisMap = (RubyMap) getField(context, fieldDescriptor); |
||||
thisMap.mergeIntoSelf(context, value); |
||||
} else if (fieldDescriptor.isRepeated()) { |
||||
checkRepeatedFieldType(context, value, fieldDescriptor); |
||||
if (value instanceof RubyRepeatedField) { |
||||
addRepeatedField(fieldDescriptor, (RubyRepeatedField) value); |
||||
} else { |
||||
RubyArray ary = value.convertToArray(); |
||||
RubyRepeatedField repeatedField = rubyToRepeatedField(context, fieldDescriptor, ary); |
||||
addRepeatedField(fieldDescriptor, repeatedField); |
||||
} |
||||
} else { |
||||
Descriptors.OneofDescriptor oneofDescriptor = fieldDescriptor.getContainingOneof(); |
||||
if (oneofDescriptor != null) { |
||||
Descriptors.FieldDescriptor oneofCase = oneofCases.get(oneofDescriptor); |
||||
if (oneofCase != null && oneofCase != fieldDescriptor) { |
||||
fields.remove(oneofCase); |
||||
} |
||||
if (value.isNil()) { |
||||
oneofCases.remove(oneofDescriptor); |
||||
fields.remove(fieldDescriptor); |
||||
} else { |
||||
oneofCases.put(oneofDescriptor, fieldDescriptor); |
||||
fields.put(fieldDescriptor, value); |
||||
} |
||||
} else { |
||||
Descriptors.FieldDescriptor.Type fieldType = fieldDescriptor.getType(); |
||||
IRubyObject typeClass = context.runtime.getObject(); |
||||
if (fieldType == Descriptors.FieldDescriptor.Type.MESSAGE) { |
||||
typeClass = ((RubyDescriptor) getDescriptorForField(context, fieldDescriptor)).msgclass(context); |
||||
} else if (fieldType == Descriptors.FieldDescriptor.Type.ENUM) { |
||||
typeClass = ((RubyEnumDescriptor) getDescriptorForField(context, fieldDescriptor)).enummodule(context); |
||||
} |
||||
Utils.checkType(context, fieldType, value, (RubyModule) typeClass); |
||||
// Convert integer enum to symbol
|
||||
if (fieldType == Descriptors.FieldDescriptor.Type.ENUM) { |
||||
Descriptors.EnumDescriptor enumDescriptor = fieldDescriptor.getEnumType(); |
||||
if (Utils.isRubyNum(value)) { |
||||
Descriptors.EnumValueDescriptor val = |
||||
enumDescriptor.findValueByNumberCreatingIfUnknown(RubyNumeric.num2int(value)); |
||||
if (val.getIndex() != -1) value = context.runtime.newSymbol(val.getName()); |
||||
} |
||||
} |
||||
this.fields.put(fieldDescriptor, value); |
||||
} |
||||
} |
||||
return context.runtime.getNil(); |
||||
} |
||||
|
||||
private String layoutInspect() { |
||||
ThreadContext context = getRuntime().getCurrentContext(); |
||||
StringBuilder sb = new StringBuilder(); |
||||
for (Descriptors.FieldDescriptor fdef : descriptor.getFields()) { |
||||
sb.append(Utils.unescapeIdentifier(fdef.getName())); |
||||
sb.append(": "); |
||||
sb.append(getField(context, fdef).inspect()); |
||||
sb.append(", "); |
||||
} |
||||
return sb.substring(0, sb.length() - 2); |
||||
} |
||||
|
||||
private IRubyObject getDescriptorForField(ThreadContext context, Descriptors.FieldDescriptor fieldDescriptor) { |
||||
RubyDescriptor thisRbDescriptor = (RubyDescriptor) getDescriptor(context, metaClass); |
||||
return thisRbDescriptor.lookup(fieldDescriptor.getName()).getSubType(context); |
||||
} |
||||
|
||||
private RubyRepeatedField rubyToRepeatedField(ThreadContext context, |
||||
Descriptors.FieldDescriptor fieldDescriptor, IRubyObject value) { |
||||
RubyArray arr = value.convertToArray(); |
||||
RubyRepeatedField repeatedField = repeatedFieldForFieldDescriptor(context, fieldDescriptor); |
||||
for (int i = 0; i < arr.size(); i++) { |
||||
repeatedField.push(context, arr.eltInternal(i)); |
||||
} |
||||
return repeatedField; |
||||
} |
||||
|
||||
private RubyMap newMapForField(ThreadContext context, Descriptors.FieldDescriptor fieldDescriptor) { |
||||
RubyDescriptor mapDescriptor = (RubyDescriptor) getDescriptorForField(context, fieldDescriptor); |
||||
Descriptors.FieldDescriptor keyField = fieldDescriptor.getMessageType().findFieldByNumber(1); |
||||
Descriptors.FieldDescriptor valueField = fieldDescriptor.getMessageType().findFieldByNumber(2); |
||||
IRubyObject keyType = RubySymbol.newSymbol(context.runtime, keyField.getType().name()); |
||||
IRubyObject valueType = RubySymbol.newSymbol(context.runtime, valueField.getType().name()); |
||||
if (valueField.getType() == Descriptors.FieldDescriptor.Type.MESSAGE) { |
||||
RubyFieldDescriptor rubyFieldDescriptor = (RubyFieldDescriptor) mapDescriptor.lookup(context, |
||||
context.runtime.newString("value")); |
||||
RubyDescriptor rubyDescriptor = (RubyDescriptor) rubyFieldDescriptor.getSubType(context); |
||||
return (RubyMap) cMap.newInstance(context, keyType, valueType, |
||||
rubyDescriptor.msgclass(context), Block.NULL_BLOCK); |
||||
} else { |
||||
return (RubyMap) cMap.newInstance(context, keyType, valueType, Block.NULL_BLOCK); |
||||
} |
||||
} |
||||
|
||||
private Descriptors.FieldDescriptor getOneofCase(Descriptors.OneofDescriptor oneof) { |
||||
if (oneofCases.containsKey(oneof)) { |
||||
return oneofCases.get(oneof); |
||||
} |
||||
return builder.getOneofFieldDescriptor(oneof); |
||||
} |
||||
|
||||
private Descriptors.Descriptor descriptor; |
||||
private DynamicMessage.Builder builder; |
||||
private RubyClass cRepeatedField; |
||||
private RubyClass cMap; |
||||
private Map<Descriptors.FieldDescriptor, RubyRepeatedField> repeatedFields; |
||||
private Map<Descriptors.FieldDescriptor, RubyMap> maps; |
||||
private Map<Descriptors.FieldDescriptor, IRubyObject> fields; |
||||
private Map<Descriptors.OneofDescriptor, Descriptors.FieldDescriptor> oneofCases; |
||||
|
||||
private static final int SINK_MAXIMUM_NESTING = 64; |
||||
} |
@ -0,0 +1,217 @@ |
||||
/* |
||||
* Protocol Buffers - Google's data interchange format |
||||
* Copyright 2014 Google Inc. All rights reserved. |
||||
* https://developers.google.com/protocol-buffers/
|
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
*/ |
||||
|
||||
package com.google.protobuf.jruby; |
||||
|
||||
import com.google.protobuf.Descriptors; |
||||
import org.jruby.*; |
||||
import org.jruby.anno.JRubyClass; |
||||
import org.jruby.anno.JRubyMethod; |
||||
import org.jruby.runtime.Binding; |
||||
import org.jruby.runtime.Block; |
||||
import org.jruby.runtime.ObjectAllocator; |
||||
import org.jruby.runtime.ThreadContext; |
||||
import org.jruby.runtime.builtin.IRubyObject; |
||||
|
||||
@JRubyClass(name = "MessageBuilderContext") |
||||
public class RubyMessageBuilderContext extends RubyObject { |
||||
public static void createRubyMessageBuilderContext(Ruby runtime) { |
||||
RubyModule protobuf = runtime.getClassFromPath("Google::Protobuf"); |
||||
RubyClass cMessageBuilderContext = protobuf.defineClassUnder("MessageBuilderContext", runtime.getObject(), new ObjectAllocator() { |
||||
@Override |
||||
public IRubyObject allocate(Ruby runtime, RubyClass klazz) { |
||||
return new RubyMessageBuilderContext(runtime, klazz); |
||||
} |
||||
}); |
||||
cMessageBuilderContext.defineAnnotatedMethods(RubyMessageBuilderContext.class); |
||||
} |
||||
|
||||
public RubyMessageBuilderContext(Ruby ruby, RubyClass klazz) { |
||||
super(ruby, klazz); |
||||
} |
||||
|
||||
@JRubyMethod |
||||
public IRubyObject initialize(ThreadContext context, IRubyObject descriptor, IRubyObject rubyBuilder) { |
||||
this.cFieldDescriptor = (RubyClass) context.runtime.getClassFromPath("Google::Protobuf::FieldDescriptor"); |
||||
this.cDescriptor = (RubyClass) context.runtime.getClassFromPath("Google::Protobuf::Descriptor"); |
||||
this.cOneofDescriptor = (RubyClass) context.runtime.getClassFromPath("Google::Protobuf::OneofDescriptor"); |
||||
this.cOneofBuilderContext = (RubyClass) context.runtime.getClassFromPath("Google::Protobuf::Internal::OneofBuilderContext"); |
||||
this.descriptor = (RubyDescriptor) descriptor; |
||||
this.builder = (RubyBuilder) rubyBuilder; |
||||
return this; |
||||
} |
||||
|
||||
/* |
||||
* call-seq: |
||||
* MessageBuilderContext.optional(name, type, number, type_class = nil) |
||||
* |
||||
* Defines a new optional field on this message type with the given type, tag |
||||
* number, and type class (for message and enum fields). The type must be a Ruby |
||||
* symbol (as accepted by FieldDescriptor#type=) and the type_class must be a |
||||
* string, if present (as accepted by FieldDescriptor#submsg_name=). |
||||
*/ |
||||
@JRubyMethod(required = 3, optional = 1) |
||||
public IRubyObject optional(ThreadContext context, IRubyObject[] args) { |
||||
Ruby runtime = context.runtime; |
||||
IRubyObject typeClass = runtime.getNil(); |
||||
if (args.length > 3) typeClass = args[3]; |
||||
msgdefAddField(context, "optional", args[0], args[1], args[2], typeClass); |
||||
return context.runtime.getNil(); |
||||
} |
||||
|
||||
/* |
||||
* call-seq: |
||||
* MessageBuilderContext.required(name, type, number, type_class = nil) |
||||
* |
||||
* Defines a new required field on this message type with the given type, tag |
||||
* number, and type class (for message and enum fields). The type must be a Ruby |
||||
* symbol (as accepted by FieldDescriptor#type=) and the type_class must be a |
||||
* string, if present (as accepted by FieldDescriptor#submsg_name=). |
||||
* |
||||
* Proto3 does not have required fields, but this method exists for |
||||
* completeness. Any attempt to add a message type with required fields to a |
||||
* pool will currently result in an error. |
||||
*/ |
||||
@JRubyMethod(required = 3, optional = 1) |
||||
public IRubyObject required(ThreadContext context, IRubyObject[] args) { |
||||
IRubyObject typeClass = context.runtime.getNil(); |
||||
if (args.length > 3) typeClass = args[3]; |
||||
msgdefAddField(context, "required", args[0], args[1], args[2], typeClass); |
||||
return context.runtime.getNil(); |
||||
} |
||||
|
||||
/* |
||||
* call-seq: |
||||
* MessageBuilderContext.repeated(name, type, number, type_class = nil) |
||||
* |
||||
* Defines a new repeated field on this message type with the given type, tag |
||||
* number, and type class (for message and enum fields). The type must be a Ruby |
||||
* symbol (as accepted by FieldDescriptor#type=) and the type_class must be a |
||||
* string, if present (as accepted by FieldDescriptor#submsg_name=). |
||||
*/ |
||||
@JRubyMethod(required = 3, optional = 1) |
||||
public IRubyObject repeated(ThreadContext context, IRubyObject[] args) { |
||||
IRubyObject typeClass = context.runtime.getNil(); |
||||
if (args.length > 3) typeClass = args[3]; |
||||
msgdefAddField(context, "repeated", args[0], args[1], args[2], typeClass); |
||||
return context.runtime.getNil(); |
||||
} |
||||
|
||||
/* |
||||
* call-seq: |
||||
* MessageBuilderContext.map(name, key_type, value_type, number, |
||||
* value_type_class = nil) |
||||
* |
||||
* Defines a new map field on this message type with the given key and value |
||||
* types, tag number, and type class (for message and enum value types). The key |
||||
* type must be :int32/:uint32/:int64/:uint64, :bool, or :string. The value type |
||||
* type must be a Ruby symbol (as accepted by FieldDescriptor#type=) and the |
||||
* type_class must be a string, if present (as accepted by |
||||
* FieldDescriptor#submsg_name=). |
||||
*/ |
||||
@JRubyMethod(required = 4, optional = 1) |
||||
public IRubyObject map(ThreadContext context, IRubyObject[] args) { |
||||
Ruby runtime = context.runtime; |
||||
IRubyObject name = args[0]; |
||||
IRubyObject keyType = args[1]; |
||||
IRubyObject valueType = args[2]; |
||||
IRubyObject number = args[3]; |
||||
IRubyObject typeClass = args.length > 4 ? args[4] : context.runtime.getNil(); |
||||
|
||||
// Validate the key type. We can't accept enums, messages, or floats/doubles
|
||||
// as map keys. (We exclude these explicitly, and the field-descriptor setter
|
||||
// below then ensures that the type is one of the remaining valid options.)
|
||||
if (keyType.equals(RubySymbol.newSymbol(runtime, "float")) || |
||||
keyType.equals(RubySymbol.newSymbol(runtime, "double")) || |
||||
keyType.equals(RubySymbol.newSymbol(runtime, "enum")) || |
||||
keyType.equals(RubySymbol.newSymbol(runtime, "message"))) |
||||
throw runtime.newArgumentError("Cannot add a map field with a float, double, enum, or message type."); |
||||
|
||||
// Create a new message descriptor for the map entry message, and create a
|
||||
// repeated submessage field here with that type.
|
||||
RubyDescriptor mapentryDesc = (RubyDescriptor) cDescriptor.newInstance(context, Block.NULL_BLOCK); |
||||
IRubyObject mapentryDescName = RubySymbol.newSymbol(runtime, name).id2name(context); |
||||
mapentryDesc.setName(context, mapentryDescName); |
||||
mapentryDesc.setMapEntry(true); |
||||
|
||||
//optional <type> key = 1;
|
||||
RubyFieldDescriptor keyField = (RubyFieldDescriptor) cFieldDescriptor.newInstance(context, Block.NULL_BLOCK); |
||||
keyField.setName(context, runtime.newString("key")); |
||||
keyField.setLabel(context, RubySymbol.newSymbol(runtime, "optional")); |
||||
keyField.setNumber(context, runtime.newFixnum(1)); |
||||
keyField.setType(context, keyType); |
||||
mapentryDesc.addField(context, keyField); |
||||
|
||||
//optional <type> value = 2;
|
||||
RubyFieldDescriptor valueField = (RubyFieldDescriptor) cFieldDescriptor.newInstance(context, Block.NULL_BLOCK); |
||||
valueField.setName(context, runtime.newString("value")); |
||||
valueField.setLabel(context, RubySymbol.newSymbol(runtime, "optional")); |
||||
valueField.setNumber(context, runtime.newFixnum(2)); |
||||
valueField.setType(context, valueType); |
||||
if (! typeClass.isNil()) valueField.setSubmsgName(context, typeClass); |
||||
mapentryDesc.addField(context, valueField); |
||||
|
||||
// Add the map-entry message type to the current builder, and use the type to
|
||||
// create the map field itself.
|
||||
this.builder.pendingList.add(mapentryDesc); |
||||
|
||||
msgdefAddField(context, "repeated", name, runtime.newSymbol("message"), number, mapentryDescName); |
||||
return runtime.getNil(); |
||||
} |
||||
|
||||
@JRubyMethod |
||||
public IRubyObject oneof(ThreadContext context, IRubyObject name, Block block) { |
||||
RubyOneofDescriptor oneofdef = (RubyOneofDescriptor) |
||||
cOneofDescriptor.newInstance(context, Block.NULL_BLOCK); |
||||
RubyOneofBuilderContext ctx = (RubyOneofBuilderContext) |
||||
cOneofBuilderContext.newInstance(context, oneofdef, Block.NULL_BLOCK); |
||||
oneofdef.setName(context, name); |
||||
Binding binding = block.getBinding(); |
||||
binding.setSelf(ctx); |
||||
block.yieldSpecific(context); |
||||
descriptor.addOneof(context, oneofdef); |
||||
return context.runtime.getNil(); |
||||
} |
||||
|
||||
private void msgdefAddField(ThreadContext context, String label, IRubyObject name, |
||||
IRubyObject type, IRubyObject number, IRubyObject typeClass) { |
||||
descriptor.addField(context, |
||||
Utils.msgdefCreateField(context, label, name, type, number, typeClass, cFieldDescriptor)); |
||||
} |
||||
|
||||
private RubyDescriptor descriptor; |
||||
private RubyBuilder builder; |
||||
private RubyClass cFieldDescriptor; |
||||
private RubyClass cOneofDescriptor; |
||||
private RubyClass cOneofBuilderContext; |
||||
private RubyClass cDescriptor; |
||||
} |
@ -0,0 +1,84 @@ |
||||
/* |
||||
* Protocol Buffers - Google's data interchange format |
||||
* Copyright 2014 Google Inc. All rights reserved. |
||||
* https://developers.google.com/protocol-buffers/
|
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
*/ |
||||
|
||||
package com.google.protobuf.jruby; |
||||
|
||||
import org.jruby.Ruby; |
||||
import org.jruby.RubyClass; |
||||
import org.jruby.RubyModule; |
||||
import org.jruby.RubyObject; |
||||
import org.jruby.anno.JRubyClass; |
||||
import org.jruby.anno.JRubyMethod; |
||||
import org.jruby.runtime.ObjectAllocator; |
||||
import org.jruby.runtime.ThreadContext; |
||||
import org.jruby.runtime.builtin.IRubyObject; |
||||
|
||||
@JRubyClass(name = "OneofBuilderContext") |
||||
public class RubyOneofBuilderContext extends RubyObject { |
||||
public static void createRubyOneofBuilderContext(Ruby runtime) { |
||||
RubyModule protobuf = runtime.getClassFromPath("Google::Protobuf"); |
||||
RubyModule internal = protobuf.defineModuleUnder("Internal"); |
||||
RubyClass cRubyOneofBuidlerContext = internal.defineClassUnder("OneofBuilderContext", runtime.getObject(), new ObjectAllocator() { |
||||
@Override |
||||
public IRubyObject allocate(Ruby ruby, RubyClass rubyClass) { |
||||
return new RubyOneofBuilderContext(ruby, rubyClass); |
||||
} |
||||
}); |
||||
cRubyOneofBuidlerContext.defineAnnotatedMethods(RubyOneofBuilderContext.class); |
||||
} |
||||
|
||||
public RubyOneofBuilderContext(Ruby ruby, RubyClass rubyClass) { |
||||
super(ruby, rubyClass); |
||||
} |
||||
|
||||
@JRubyMethod |
||||
public IRubyObject initialize(ThreadContext context, IRubyObject oneofdef) { |
||||
this.descriptor = (RubyOneofDescriptor) oneofdef; |
||||
this.cFieldDescriptor = (RubyClass) context.runtime.getClassFromPath("Google::Protobuf::FieldDescriptor"); |
||||
return this; |
||||
} |
||||
|
||||
@JRubyMethod(required = 3, optional = 1) |
||||
public IRubyObject optional(ThreadContext context, IRubyObject[] args) { |
||||
IRubyObject name = args[0]; |
||||
IRubyObject type = args[1]; |
||||
IRubyObject number = args[2]; |
||||
IRubyObject typeClass = args.length > 3 ? args[3] : context.runtime.getNil(); |
||||
RubyFieldDescriptor fieldDescriptor = Utils.msgdefCreateField(context, "optional", |
||||
name, type, number, typeClass, cFieldDescriptor); |
||||
descriptor.addField(context, fieldDescriptor); |
||||
return this; |
||||
} |
||||
|
||||
private RubyOneofDescriptor descriptor; |
||||
private RubyClass cFieldDescriptor; |
||||
} |
@ -0,0 +1,124 @@ |
||||
package com.google.protobuf.jruby; |
||||
|
||||
import com.google.protobuf.DescriptorProtos; |
||||
import com.google.protobuf.Descriptors; |
||||
import org.jruby.Ruby; |
||||
import org.jruby.RubyClass; |
||||
import org.jruby.RubyModule; |
||||
import org.jruby.RubyObject; |
||||
import org.jruby.anno.JRubyClass; |
||||
import org.jruby.anno.JRubyMethod; |
||||
import org.jruby.runtime.Block; |
||||
import org.jruby.runtime.ObjectAllocator; |
||||
import org.jruby.runtime.ThreadContext; |
||||
import org.jruby.runtime.builtin.IRubyObject; |
||||
|
||||
import java.util.*; |
||||
|
||||
@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) { |
||||
return new RubyOneofDescriptor(ruby, rubyClass); |
||||
} |
||||
}); |
||||
cRubyOneofDescriptor.defineAnnotatedMethods(RubyOneofDescriptor.class); |
||||
cRubyOneofDescriptor.includeModule(runtime.getEnumerable()); |
||||
} |
||||
|
||||
public RubyOneofDescriptor(Ruby ruby, RubyClass rubyClass) { |
||||
super(ruby, rubyClass); |
||||
} |
||||
|
||||
@JRubyMethod |
||||
public IRubyObject initialize(ThreadContext context) { |
||||
builder = DescriptorProtos.OneofDescriptorProto.newBuilder(); |
||||
fields = new ArrayList<RubyFieldDescriptor>(); |
||||
return this; |
||||
} |
||||
|
||||
/* |
||||
* call-seq: |
||||
* OneofDescriptor.name => name |
||||
* |
||||
* Returns the name of this oneof. |
||||
*/ |
||||
@JRubyMethod(name = "name") |
||||
public IRubyObject getName(ThreadContext context) { |
||||
return name; |
||||
} |
||||
|
||||
/* |
||||
* call-seq: |
||||
* OneofDescriptor.name = name |
||||
* |
||||
* Sets a new name for this oneof. The oneof must not have been added to a |
||||
* message descriptor yet. |
||||
*/ |
||||
@JRubyMethod(name = "name=") |
||||
public IRubyObject setName(ThreadContext context, IRubyObject name) { |
||||
this.name = context.runtime.newString(name.asJavaString()); |
||||
this.builder.setName(name.asJavaString()); |
||||
return context.runtime.getNil(); |
||||
} |
||||
|
||||
/* |
||||
* call-seq: |
||||
* OneofDescriptor.add_field(field) => nil |
||||
* |
||||
* Adds a field to this oneof. The field may have been added to this oneof in |
||||
* the past, or the message to which this oneof belongs (if any), but may not |
||||
* have already been added to any other oneof or message. Otherwise, an |
||||
* exception is raised. |
||||
* |
||||
* All fields added to the oneof via this method will be automatically added to |
||||
* the message to which this oneof belongs, if it belongs to one currently, or |
||||
* else will be added to any message to which the oneof is later added at the |
||||
* time that it is added. |
||||
*/ |
||||
@JRubyMethod(name = "add_field") |
||||
public IRubyObject addField(ThreadContext context, IRubyObject obj) { |
||||
RubyFieldDescriptor fieldDescriptor = (RubyFieldDescriptor) obj; |
||||
fieldDescriptor.setOneofName(this.name); |
||||
fields.add(fieldDescriptor); |
||||
return context.runtime.getNil(); |
||||
} |
||||
|
||||
/* |
||||
* 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.runtime.getNil(); |
||||
} |
||||
|
||||
public DescriptorProtos.OneofDescriptorProto build(int index) { |
||||
for (RubyFieldDescriptor field: fields) { |
||||
field.setOneofIndex(index); |
||||
} |
||||
return this.builder.build(); |
||||
} |
||||
|
||||
protected Collection<RubyFieldDescriptor> getFields() { |
||||
return fields; |
||||
} |
||||
|
||||
protected Descriptors.OneofDescriptor getOneofDescriptor() { |
||||
RubyFieldDescriptor fieldDescriptor = fields.get(0); |
||||
return fieldDescriptor.getFieldDef().getContainingOneof(); |
||||
} |
||||
|
||||
private IRubyObject name; |
||||
private DescriptorProtos.OneofDescriptorProto.Builder builder; |
||||
private List<RubyFieldDescriptor> fields; |
||||
} |
@ -0,0 +1,118 @@ |
||||
/* |
||||
* Protocol Buffers - Google's data interchange format |
||||
* Copyright 2014 Google Inc. All rights reserved. |
||||
* https://developers.google.com/protocol-buffers/
|
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
*/ |
||||
|
||||
package com.google.protobuf.jruby; |
||||
|
||||
import org.jruby.Ruby; |
||||
import org.jruby.RubyModule; |
||||
import org.jruby.anno.JRubyMethod; |
||||
import org.jruby.anno.JRubyModule; |
||||
import org.jruby.runtime.ThreadContext; |
||||
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); |
||||
} |
||||
|
||||
/* |
||||
* call-seq: |
||||
* Google::Protobuf.encode(msg) => bytes |
||||
* |
||||
* Encodes the given message object to protocol buffers wire format. This is an |
||||
* alternative to the #encode method on msg's class. |
||||
*/ |
||||
@JRubyMethod(meta = true) |
||||
public static IRubyObject encode(ThreadContext context, IRubyObject self, IRubyObject message) { |
||||
return RubyMessage.encode(context, message.getMetaClass(), message); |
||||
} |
||||
|
||||
/* |
||||
* call-seq: |
||||
* Google::Protobuf.decode(class, bytes) => msg |
||||
* |
||||
* Decodes the given bytes as protocol buffers wire format under the |
||||
* interpretation given by the given class's message definition. This is an |
||||
* alternative to the #decode method on the given class. |
||||
*/ |
||||
@JRubyMethod(meta = true) |
||||
public static IRubyObject decode(ThreadContext context, IRubyObject self, IRubyObject klazz, IRubyObject message) { |
||||
return RubyMessage.decode(context, klazz, message); |
||||
} |
||||
|
||||
/* |
||||
* call-seq: |
||||
* Google::Protobuf.encode_json(msg) => json_string |
||||
* |
||||
* Encodes the given message object to its JSON representation. This is an |
||||
* alternative to the #encode_json method on msg's class. |
||||
*/ |
||||
@JRubyMethod(name = "encode_json", meta = true) |
||||
public static IRubyObject encodeJson(ThreadContext context, IRubyObject self, IRubyObject message) { |
||||
return RubyMessage.encodeJson(context, message.getMetaClass(), message); |
||||
} |
||||
|
||||
/* |
||||
* call-seq: |
||||
* Google::Protobuf.decode_json(class, json_string) => msg |
||||
* |
||||
* Decodes the given JSON string under the interpretation given by the given |
||||
* class's message definition. This is an alternative to the #decode_json method |
||||
* on the given class. |
||||
*/ |
||||
@JRubyMethod(name = "decode_json", meta = true) |
||||
public static IRubyObject decodeJson(ThreadContext context, IRubyObject self, IRubyObject klazz, IRubyObject message) { |
||||
return RubyMessage.decodeJson(context, klazz, message); |
||||
} |
||||
|
||||
/* |
||||
* 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); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,391 @@ |
||||
/* |
||||
* Protocol Buffers - Google's data interchange format |
||||
* Copyright 2014 Google Inc. All rights reserved. |
||||
* https://developers.google.com/protocol-buffers/
|
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
*/ |
||||
|
||||
package com.google.protobuf.jruby; |
||||
|
||||
import com.google.protobuf.Descriptors; |
||||
import org.jruby.*; |
||||
import org.jruby.anno.JRubyClass; |
||||
import org.jruby.anno.JRubyMethod; |
||||
import org.jruby.runtime.Block; |
||||
import org.jruby.runtime.ObjectAllocator; |
||||
import org.jruby.runtime.ThreadContext; |
||||
import org.jruby.runtime.builtin.IRubyObject; |
||||
|
||||
@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 RubyRepeatedField(Ruby runtime, RubyClass klazz) { |
||||
super(runtime, klazz); |
||||
} |
||||
|
||||
public RubyRepeatedField(Ruby runtime, RubyClass klazz, Descriptors.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 == Descriptors.FieldDescriptor.Type.MESSAGE |
||||
|| fieldType == Descriptors.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) { |
||||
Utils.checkType(context, fieldType, value, (RubyModule) typeClass); |
||||
this.storage.set(RubyNumeric.num2int(index), value); |
||||
return context.runtime.getNil(); |
||||
} |
||||
|
||||
/* |
||||
* call-seq: |
||||
* RepeatedField.[](index) => value |
||||
* |
||||
* Accesses the element at the given index. Throws an exception on out-of-bounds |
||||
* errors. |
||||
*/ |
||||
@JRubyMethod(name = "[]") |
||||
public IRubyObject index(ThreadContext context, IRubyObject index) { |
||||
return this.storage.eltInternal(RubyNumeric.num2int(index)); |
||||
} |
||||
|
||||
/* |
||||
* call-seq: |
||||
* RepeatedField.insert(*args) |
||||
* |
||||
* Pushes each arg in turn onto the end of the repeated field. |
||||
*/ |
||||
@JRubyMethod(rest = true) |
||||
public IRubyObject insert(ThreadContext context, IRubyObject[] args) { |
||||
for (int i = 0; i < args.length; i++) { |
||||
Utils.checkType(context, fieldType, args[i], (RubyModule) typeClass); |
||||
this.storage.add(args[i]); |
||||
} |
||||
return context.runtime.getNil(); |
||||
} |
||||
|
||||
/* |
||||
* call-seq: |
||||
* RepeatedField.push(value) |
||||
* |
||||
* Adds a new element to the repeated field. |
||||
*/ |
||||
@JRubyMethod(name = {"push", "<<"}) |
||||
public IRubyObject push(ThreadContext context, IRubyObject value) { |
||||
Utils.checkType(context, fieldType, value, (RubyModule) typeClass); |
||||
this.storage.add(value); |
||||
return this; |
||||
} |
||||
|
||||
/* |
||||
* call-seq: |
||||
* RepeatedField.pop => value |
||||
* |
||||
* Removes the last element and returns it. Throws an exception if the repeated |
||||
* field is empty. |
||||
*/ |
||||
@JRubyMethod |
||||
public IRubyObject pop(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 context.runtime.getNil(); |
||||
} |
||||
|
||||
/* |
||||
* call-seq: |
||||
* RepeatedField.clear |
||||
* |
||||
* Clears (removes all elements from) this repeated field. |
||||
*/ |
||||
@JRubyMethod |
||||
public IRubyObject clear(ThreadContext context) { |
||||
this.storage.clear(); |
||||
return context.runtime.getNil(); |
||||
} |
||||
|
||||
/* |
||||
* call-seq: |
||||
* RepeatedField.length |
||||
* |
||||
* Returns the length of this repeated field. |
||||
*/ |
||||
@JRubyMethod(name = {"count", "length"}) |
||||
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.hash => hash_value |
||||
* |
||||
* Returns a hash value computed from this repeated field's elements. |
||||
*/ |
||||
@JRubyMethod |
||||
public IRubyObject hash(ThreadContext context) { |
||||
int hashCode = System.identityHashCode(this.storage); |
||||
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 context.runtime.getNil(); |
||||
} |
||||
|
||||
@JRubyMethod(name = {"to_ary", "to_a"}) |
||||
public IRubyObject toArray(ThreadContext context) { |
||||
for (int i = 0; i < this.storage.size(); i++) { |
||||
IRubyObject defaultValue = defaultValue(context); |
||||
if (storage.eltInternal(i).isNil()) { |
||||
storage.set(i, defaultValue); |
||||
} |
||||
} |
||||
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); |
||||
for (int i = 0; i < this.storage.size(); i++) { |
||||
dup.push(context, this.storage.eltInternal(i)); |
||||
} |
||||
return dup; |
||||
} |
||||
|
||||
/* |
||||
* call-seq: |
||||
* RepeatedField.inspect => string |
||||
* |
||||
* Returns a string representing this repeated field's elements. It will be |
||||
* formated as "[<element>, <element>, ...]", with each element's string |
||||
* representation computed by its own #inspect method. |
||||
*/ |
||||
@JRubyMethod |
||||
public IRubyObject inspect() { |
||||
StringBuilder str = new StringBuilder("["); |
||||
for (int i = 0; i < this.storage.size(); i++) { |
||||
str.append(storage.eltInternal(i).inspect()); |
||||
str.append(", "); |
||||
} |
||||
|
||||
if (str.length() > 1) { |
||||
str.replace(str.length() - 2, str.length(), "]"); |
||||
} else { |
||||
str.append("]"); |
||||
} |
||||
|
||||
return getRuntime().newString(str.toString()); |
||||
} |
||||
|
||||
// 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 == Descriptors.FieldDescriptor.Type.MESSAGE) { |
||||
copy.storage.add(((RubyMessage) value).deepCopy(context)); |
||||
} else { |
||||
copy.storage.add(value); |
||||
} |
||||
} |
||||
return copy; |
||||
} |
||||
|
||||
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; |
||||
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, arr.eltInternal(i), (RubyModule) typeClass); |
||||
} |
||||
} |
||||
|
||||
private RubyArray storage; |
||||
private Descriptors.FieldDescriptor.Type fieldType; |
||||
private IRubyObject typeClass; |
||||
} |
@ -0,0 +1,776 @@ |
||||
/* |
||||
* Protocol Buffers - Google's data interchange format |
||||
* Copyright 2014 Google Inc. All rights reserved. |
||||
* https://developers.google.com/protocol-buffers/
|
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
*/ |
||||
|
||||
// Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
// source: sentinel.proto
|
||||
|
||||
package com.google.protobuf.jruby; |
||||
|
||||
public final class SentinelOuterClass { |
||||
private SentinelOuterClass() {} |
||||
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> |
||||
*/ |
||||
int getDefaultInt32(); |
||||
|
||||
/** |
||||
* <code>optional int64 default_int64 = 2;</code> |
||||
*/ |
||||
long getDefaultInt64(); |
||||
|
||||
/** |
||||
* <code>optional uint32 default_unit32 = 3;</code> |
||||
*/ |
||||
int getDefaultUnit32(); |
||||
|
||||
/** |
||||
* <code>optional uint64 default_uint64 = 4;</code> |
||||
*/ |
||||
long getDefaultUint64(); |
||||
|
||||
/** |
||||
* <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 bool default_bool = 6;</code> |
||||
*/ |
||||
boolean getDefaultBool(); |
||||
|
||||
/** |
||||
* <code>optional float default_float = 7;</code> |
||||
*/ |
||||
float getDefaultFloat(); |
||||
|
||||
/** |
||||
* <code>optional double default_double = 8;</code> |
||||
*/ |
||||
double getDefaultDouble(); |
||||
|
||||
/** |
||||
* <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 |
||||
// @@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; |
||||
defaultUnit32_ = 0; |
||||
defaultUint64_ = 0L; |
||||
defaultString_ = ""; |
||||
defaultBool_ = false; |
||||
defaultFloat_ = 0F; |
||||
defaultDouble_ = 0D; |
||||
defaultBytes_ = com.google.protobuf.ByteString.EMPTY; |
||||
} |
||||
|
||||
@java.lang.Override |
||||
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; |
||||
} |
||||
|
||||
protected com.google.protobuf.GeneratedMessage.FieldAccessorTable |
||||
internalGetFieldAccessorTable() { |
||||
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); |
||||
} |
||||
|
||||
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(); |
||||
} |
||||
}; |
||||
|
||||
@java.lang.Override |
||||
public com.google.protobuf.Parser<Sentinel> getParserForType() { |
||||
return PARSER; |
||||
} |
||||
|
||||
public static final int DEFAULT_INT32_FIELD_NUMBER = 1; |
||||
private int defaultInt32_; |
||||
/** |
||||
* <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> |
||||
*/ |
||||
public long getDefaultInt64() { |
||||
return defaultInt64_; |
||||
} |
||||
|
||||
public static final int DEFAULT_UNIT32_FIELD_NUMBER = 3; |
||||
private int defaultUnit32_; |
||||
/** |
||||
* <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> |
||||
*/ |
||||
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> |
||||
*/ |
||||
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; |
||||
java.lang.String s = bs.toStringUtf8(); |
||||
if (bs.isValidUtf8()) { |
||||
defaultString_ = s; |
||||
} |
||||
return s; |
||||
} |
||||
} |
||||
/** |
||||
* <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); |
||||
defaultString_ = b; |
||||
return b; |
||||
} else { |
||||
return (com.google.protobuf.ByteString) ref; |
||||
} |
||||
} |
||||
|
||||
public static final int DEFAULT_BOOL_FIELD_NUMBER = 6; |
||||
private boolean defaultBool_; |
||||
/** |
||||
* <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> |
||||
*/ |
||||
public float getDefaultFloat() { |
||||
return defaultFloat_; |
||||
} |
||||
|
||||
public static final int DEFAULT_DOUBLE_FIELD_NUMBER = 8; |
||||
private double defaultDouble_; |
||||
/** |
||||
* <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> |
||||
*/ |
||||
public com.google.protobuf.ByteString getDefaultBytes() { |
||||
return defaultBytes_; |
||||
} |
||||
|
||||
public static com.google.protobuf.jruby.SentinelOuterClass.Sentinel parseFrom( |
||||
com.google.protobuf.ByteString data) |
||||
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) |
||||
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 { |
||||
return PARSER.parseFrom(input); |
||||
} |
||||
public static com.google.protobuf.jruby.SentinelOuterClass.Sentinel parseFrom( |
||||
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 { |
||||
return PARSER.parseDelimitedFrom(input); |
||||
} |
||||
public static com.google.protobuf.jruby.SentinelOuterClass.Sentinel parseDelimitedFrom( |
||||
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 { |
||||
return PARSER.parseFrom(input); |
||||
} |
||||
public static com.google.protobuf.jruby.SentinelOuterClass.Sentinel parseFrom( |
||||
com.google.protobuf.CodedInputStream input, |
||||
com.google.protobuf.ExtensionRegistryLite extensionRegistry) |
||||
throws java.io.IOException { |
||||
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) { |
||||
return newBuilder().mergeFrom(prototype); |
||||
} |
||||
public Builder toBuilder() { return newBuilder(this); } |
||||
|
||||
@java.lang.Override |
||||
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 |
||||
// @@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; |
||||
} |
||||
|
||||
protected com.google.protobuf.GeneratedMessage.FieldAccessorTable |
||||
internalGetFieldAccessorTable() { |
||||
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); |
||||
} |
||||
|
||||
// Construct using com.google.protobuf.jruby.SentinelOuterClass.Sentinel.newBuilder()
|
||||
private Builder() { |
||||
maybeForceBuilderInitialization(); |
||||
} |
||||
|
||||
private Builder( |
||||
com.google.protobuf.GeneratedMessage.BuilderParent parent) { |
||||
super(parent); |
||||
maybeForceBuilderInitialization(); |
||||
} |
||||
private void maybeForceBuilderInitialization() { |
||||
if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) { |
||||
} |
||||
} |
||||
public Builder clear() { |
||||
super.clear(); |
||||
defaultInt32_ = 0; |
||||
|
||||
defaultInt64_ = 0L; |
||||
|
||||
defaultUnit32_ = 0; |
||||
|
||||
defaultUint64_ = 0L; |
||||
|
||||
defaultString_ = ""; |
||||
|
||||
defaultBool_ = false; |
||||
|
||||
defaultFloat_ = 0F; |
||||
|
||||
defaultDouble_ = 0D; |
||||
|
||||
defaultBytes_ = com.google.protobuf.ByteString.EMPTY; |
||||
|
||||
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.jruby.SentinelOuterClass.Sentinel getDefaultInstanceForType() { |
||||
return com.google.protobuf.jruby.SentinelOuterClass.Sentinel.getDefaultInstance(); |
||||
} |
||||
|
||||
public com.google.protobuf.jruby.SentinelOuterClass.Sentinel build() { |
||||
com.google.protobuf.jruby.SentinelOuterClass.Sentinel result = buildPartial(); |
||||
if (!result.isInitialized()) { |
||||
throw newUninitializedMessageException(result); |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
public com.google.protobuf.jruby.SentinelOuterClass.Sentinel buildPartial() { |
||||
com.google.protobuf.jruby.SentinelOuterClass.Sentinel result = new com.google.protobuf.jruby.SentinelOuterClass.Sentinel(this); |
||||
result.defaultInt32_ = defaultInt32_; |
||||
result.defaultInt64_ = defaultInt64_; |
||||
result.defaultUnit32_ = defaultUnit32_; |
||||
result.defaultUint64_ = defaultUint64_; |
||||
result.defaultString_ = defaultString_; |
||||
result.defaultBool_ = defaultBool_; |
||||
result.defaultFloat_ = defaultFloat_; |
||||
result.defaultDouble_ = defaultDouble_; |
||||
result.defaultBytes_ = defaultBytes_; |
||||
onBuilt(); |
||||
return result; |
||||
} |
||||
|
||||
|
||||
private int defaultInt32_ ; |
||||
/** |
||||
* <code>optional int32 default_int32 = 1;</code> |
||||
*/ |
||||
public int getDefaultInt32() { |
||||
return defaultInt32_; |
||||
} |
||||
/** |
||||
* <code>optional int32 default_int32 = 1;</code> |
||||
*/ |
||||
public Builder setDefaultInt32(int value) { |
||||
|
||||
defaultInt32_ = value; |
||||
onChanged(); |
||||
return this; |
||||
} |
||||
/** |
||||
* <code>optional int32 default_int32 = 1;</code> |
||||
*/ |
||||
public Builder clearDefaultInt32() { |
||||
|
||||
defaultInt32_ = 0; |
||||
onChanged(); |
||||
return this; |
||||
} |
||||
|
||||
private long defaultInt64_ ; |
||||
/** |
||||
* <code>optional int64 default_int64 = 2;</code> |
||||
*/ |
||||
public long getDefaultInt64() { |
||||
return defaultInt64_; |
||||
} |
||||
/** |
||||
* <code>optional int64 default_int64 = 2;</code> |
||||
*/ |
||||
public Builder setDefaultInt64(long value) { |
||||
|
||||
defaultInt64_ = value; |
||||
onChanged(); |
||||
return this; |
||||
} |
||||
/** |
||||
* <code>optional int64 default_int64 = 2;</code> |
||||
*/ |
||||
public Builder clearDefaultInt64() { |
||||
|
||||
defaultInt64_ = 0L; |
||||
onChanged(); |
||||
return this; |
||||
} |
||||
|
||||
private int defaultUnit32_ ; |
||||
/** |
||||
* <code>optional uint32 default_unit32 = 3;</code> |
||||
*/ |
||||
public int getDefaultUnit32() { |
||||
return defaultUnit32_; |
||||
} |
||||
/** |
||||
* <code>optional uint32 default_unit32 = 3;</code> |
||||
*/ |
||||
public Builder setDefaultUnit32(int value) { |
||||
|
||||
defaultUnit32_ = value; |
||||
onChanged(); |
||||
return this; |
||||
} |
||||
/** |
||||
* <code>optional uint32 default_unit32 = 3;</code> |
||||
*/ |
||||
public Builder clearDefaultUnit32() { |
||||
|
||||
defaultUnit32_ = 0; |
||||
onChanged(); |
||||
return this; |
||||
} |
||||
|
||||
private long defaultUint64_ ; |
||||
/** |
||||
* <code>optional uint64 default_uint64 = 4;</code> |
||||
*/ |
||||
public long getDefaultUint64() { |
||||
return defaultUint64_; |
||||
} |
||||
/** |
||||
* <code>optional uint64 default_uint64 = 4;</code> |
||||
*/ |
||||
public Builder setDefaultUint64(long value) { |
||||
|
||||
defaultUint64_ = value; |
||||
onChanged(); |
||||
return this; |
||||
} |
||||
/** |
||||
* <code>optional uint64 default_uint64 = 4;</code> |
||||
*/ |
||||
public Builder clearDefaultUint64() { |
||||
|
||||
defaultUint64_ = 0L; |
||||
onChanged(); |
||||
return this; |
||||
} |
||||
|
||||
private java.lang.Object defaultString_ = ""; |
||||
/** |
||||
* <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; |
||||
java.lang.String s = bs.toStringUtf8(); |
||||
if (bs.isValidUtf8()) { |
||||
defaultString_ = s; |
||||
} |
||||
return s; |
||||
} else { |
||||
return (java.lang.String) ref; |
||||
} |
||||
} |
||||
/** |
||||
* <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); |
||||
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) { |
||||
if (value == null) { |
||||
throw new NullPointerException(); |
||||
} |
||||
|
||||
defaultString_ = value; |
||||
onChanged(); |
||||
return this; |
||||
} |
||||
/** |
||||
* <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) { |
||||
if (value == null) { |
||||
throw new NullPointerException(); |
||||
} |
||||
|
||||
defaultString_ = value; |
||||
onChanged(); |
||||
return this; |
||||
} |
||||
|
||||
private boolean defaultBool_ ; |
||||
/** |
||||
* <code>optional bool default_bool = 6;</code> |
||||
*/ |
||||
public boolean getDefaultBool() { |
||||
return defaultBool_; |
||||
} |
||||
/** |
||||
* <code>optional bool default_bool = 6;</code> |
||||
*/ |
||||
public Builder setDefaultBool(boolean value) { |
||||
|
||||
defaultBool_ = value; |
||||
onChanged(); |
||||
return this; |
||||
} |
||||
/** |
||||
* <code>optional bool default_bool = 6;</code> |
||||
*/ |
||||
public Builder clearDefaultBool() { |
||||
|
||||
defaultBool_ = false; |
||||
onChanged(); |
||||
return this; |
||||
} |
||||
|
||||
private float defaultFloat_ ; |
||||
/** |
||||
* <code>optional float default_float = 7;</code> |
||||
*/ |
||||
public float getDefaultFloat() { |
||||
return defaultFloat_; |
||||
} |
||||
/** |
||||
* <code>optional float default_float = 7;</code> |
||||
*/ |
||||
public Builder setDefaultFloat(float value) { |
||||
|
||||
defaultFloat_ = value; |
||||
onChanged(); |
||||
return this; |
||||
} |
||||
/** |
||||
* <code>optional float default_float = 7;</code> |
||||
*/ |
||||
public Builder clearDefaultFloat() { |
||||
|
||||
defaultFloat_ = 0F; |
||||
onChanged(); |
||||
return this; |
||||
} |
||||
|
||||
private double defaultDouble_ ; |
||||
/** |
||||
* <code>optional double default_double = 8;</code> |
||||
*/ |
||||
public double getDefaultDouble() { |
||||
return defaultDouble_; |
||||
} |
||||
/** |
||||
* <code>optional double default_double = 8;</code> |
||||
*/ |
||||
public Builder setDefaultDouble(double value) { |
||||
|
||||
defaultDouble_ = value; |
||||
onChanged(); |
||||
return this; |
||||
} |
||||
/** |
||||
* <code>optional double default_double = 8;</code> |
||||
*/ |
||||
public Builder clearDefaultDouble() { |
||||
|
||||
defaultDouble_ = 0D; |
||||
onChanged(); |
||||
return this; |
||||
} |
||||
|
||||
private com.google.protobuf.ByteString defaultBytes_ = com.google.protobuf.ByteString.EMPTY; |
||||
/** |
||||
* <code>optional bytes default_bytes = 9;</code> |
||||
*/ |
||||
public com.google.protobuf.ByteString getDefaultBytes() { |
||||
return defaultBytes_; |
||||
} |
||||
/** |
||||
* <code>optional bytes default_bytes = 9;</code> |
||||
*/ |
||||
public Builder setDefaultBytes(com.google.protobuf.ByteString value) { |
||||
if (value == null) { |
||||
throw new NullPointerException(); |
||||
} |
||||
|
||||
defaultBytes_ = value; |
||||
onChanged(); |
||||
return this; |
||||
} |
||||
/** |
||||
* <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; |
||||
} |
||||
|
||||
public final Builder mergeUnknownFields( |
||||
final com.google.protobuf.UnknownFieldSet unknownFields) { |
||||
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 { |
||||
defaultInstance = new com.google.protobuf.jruby.SentinelOuterClass.Sentinel(); |
||||
} |
||||
|
||||
public static com.google.protobuf.jruby.SentinelOuterClass.Sentinel getDefaultInstance() { |
||||
return defaultInstance; |
||||
} |
||||
|
||||
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_fieldAccessorTable; |
||||
|
||||
public static com.google.protobuf.Descriptors.FileDescriptor |
||||
getDescriptor() { |
||||
return 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" |
||||
}; |
||||
com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner = |
||||
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); |
||||
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", }); |
||||
} |
||||
|
||||
// @@protoc_insertion_point(outer_class_scope)
|
||||
} |
@ -0,0 +1,300 @@ |
||||
/* |
||||
* Protocol Buffers - Google's data interchange format |
||||
* Copyright 2014 Google Inc. All rights reserved. |
||||
* https://developers.google.com/protocol-buffers/
|
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
*/ |
||||
|
||||
package com.google.protobuf.jruby; |
||||
|
||||
import com.google.protobuf.ByteString; |
||||
import com.google.protobuf.DescriptorProtos; |
||||
import com.google.protobuf.Descriptors; |
||||
import org.jcodings.Encoding; |
||||
import org.jcodings.specific.ASCIIEncoding; |
||||
import org.jcodings.specific.USASCIIEncoding; |
||||
import org.jcodings.specific.UTF8Encoding; |
||||
import org.jruby.*; |
||||
import org.jruby.runtime.Block; |
||||
import org.jruby.runtime.ThreadContext; |
||||
import org.jruby.runtime.builtin.IRubyObject; |
||||
|
||||
import java.math.BigInteger; |
||||
|
||||
public class Utils { |
||||
public static Descriptors.FieldDescriptor.Type rubyToFieldType(IRubyObject typeClass) { |
||||
return Descriptors.FieldDescriptor.Type.valueOf(typeClass.asJavaString().toUpperCase()); |
||||
} |
||||
|
||||
public static IRubyObject fieldTypeToRuby(ThreadContext context, Descriptors.FieldDescriptor.Type type) { |
||||
return fieldTypeToRuby(context, type.name()); |
||||
} |
||||
|
||||
public static IRubyObject fieldTypeToRuby(ThreadContext context, DescriptorProtos.FieldDescriptorProto.Type type) { |
||||
return fieldTypeToRuby(context, type.name()); |
||||
} |
||||
|
||||
private static IRubyObject fieldTypeToRuby(ThreadContext context, String typeName) { |
||||
|
||||
return context.runtime.newSymbol(typeName.replace("TYPE_", "").toLowerCase()); |
||||
} |
||||
|
||||
public static void checkType(ThreadContext context, Descriptors.FieldDescriptor.Type fieldType, |
||||
IRubyObject value, RubyModule typeClass) { |
||||
Ruby runtime = context.runtime; |
||||
Object val; |
||||
switch(fieldType) { |
||||
case INT32: |
||||
case INT64: |
||||
case UINT32: |
||||
case UINT64: |
||||
if (!isRubyNum(value)) { |
||||
throw runtime.newTypeError("Expected number type for integral field."); |
||||
} |
||||
switch(fieldType) { |
||||
case INT32: |
||||
RubyNumeric.num2int(value); |
||||
break; |
||||
case INT64: |
||||
RubyNumeric.num2long(value); |
||||
break; |
||||
case UINT32: |
||||
num2uint(value); |
||||
break; |
||||
default: |
||||
num2ulong(context.runtime, value); |
||||
break; |
||||
} |
||||
checkIntTypePrecision(context, fieldType, value); |
||||
break; |
||||
case FLOAT: |
||||
if (!isRubyNum(value)) |
||||
throw runtime.newTypeError("Expected number type for float field."); |
||||
break; |
||||
case DOUBLE: |
||||
if (!isRubyNum(value)) |
||||
throw runtime.newTypeError("Expected number type for double field."); |
||||
break; |
||||
case BOOL: |
||||
if (!(value instanceof RubyBoolean)) |
||||
throw runtime.newTypeError("Invalid argument for boolean field."); |
||||
break; |
||||
case BYTES: |
||||
case STRING: |
||||
validateStringEncoding(context.runtime, fieldType, value); |
||||
break; |
||||
case MESSAGE: |
||||
if (value.getMetaClass() != typeClass) { |
||||
throw runtime.newTypeError(value, typeClass); |
||||
} |
||||
break; |
||||
case ENUM: |
||||
if (value instanceof RubySymbol) { |
||||
Descriptors.EnumDescriptor enumDescriptor = |
||||
((RubyEnumDescriptor) typeClass.getInstanceVariable(DESCRIPTOR_INSTANCE_VAR)).getDescriptor(); |
||||
val = enumDescriptor.findValueByName(value.asJavaString()); |
||||
if (val == null) |
||||
throw runtime.newRangeError("Enum value " + value + " is not found."); |
||||
} else if(!isRubyNum(value)) { |
||||
throw runtime.newTypeError("Expected number or symbol type for enum field."); |
||||
} |
||||
break; |
||||
default: |
||||
break; |
||||
} |
||||
} |
||||
|
||||
public static IRubyObject wrapPrimaryValue(ThreadContext context, Descriptors.FieldDescriptor.Type fieldType, Object value) { |
||||
Ruby runtime = context.runtime; |
||||
switch (fieldType) { |
||||
case INT32: |
||||
return runtime.newFixnum((Integer) value); |
||||
case INT64: |
||||
return runtime.newFixnum((Long) value); |
||||
case UINT32: |
||||
return runtime.newFixnum(((Integer) value) & (-1l >>> 32)); |
||||
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: |
||||
return runtime.newString(((ByteString) value).toStringUtf8()); |
||||
case STRING: |
||||
return runtime.newString(value.toString()); |
||||
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); |
||||
} |
||||
} |
||||
|
||||
public static void validateStringEncoding(Ruby runtime, Descriptors.FieldDescriptor.Type type, IRubyObject value) { |
||||
if (!(value instanceof RubyString)) |
||||
throw runtime.newTypeError("Invalid argument for string field."); |
||||
Encoding encoding = ((RubyString) value).getEncoding(); |
||||
switch(type) { |
||||
case BYTES: |
||||
if (encoding != ASCIIEncoding.INSTANCE) |
||||
throw runtime.newTypeError("Encoding for bytes fields" + |
||||
" must be \"ASCII-8BIT\", but was " + encoding); |
||||
break; |
||||
case STRING: |
||||
if (encoding != UTF8Encoding.INSTANCE |
||||
&& encoding != USASCIIEncoding.INSTANCE) |
||||
throw runtime.newTypeError("Encoding for string fields" + |
||||
" must be \"UTF-8\" or \"ASCII\", but was " + encoding); |
||||
break; |
||||
default: |
||||
break; |
||||
} |
||||
} |
||||
|
||||
public static void checkNameAvailability(ThreadContext context, String name) { |
||||
if (context.runtime.getObject().getConstantAt(name) != null) |
||||
throw context.runtime.newNameError(name + " is already defined", name); |
||||
} |
||||
|
||||
/** |
||||
* Replace invalid "." in descriptor with __DOT__ |
||||
* @param name |
||||
* @return |
||||
*/ |
||||
public static String escapeIdentifier(String name) { |
||||
return name.replace(".", BADNAME_REPLACEMENT); |
||||
} |
||||
|
||||
/** |
||||
* Replace __DOT__ in descriptor name with "." |
||||
* @param name |
||||
* @return |
||||
*/ |
||||
public static String unescapeIdentifier(String name) { |
||||
return name.replace(BADNAME_REPLACEMENT, "."); |
||||
} |
||||
|
||||
public static boolean isMapEntry(Descriptors.FieldDescriptor fieldDescriptor) { |
||||
return fieldDescriptor.getType() == Descriptors.FieldDescriptor.Type.MESSAGE && |
||||
fieldDescriptor.isRepeated() && |
||||
fieldDescriptor.getMessageType().getOptions().getMapEntry(); |
||||
} |
||||
|
||||
public static RubyFieldDescriptor msgdefCreateField(ThreadContext context, String label, IRubyObject name, |
||||
IRubyObject type, IRubyObject number, IRubyObject typeClass, RubyClass cFieldDescriptor) { |
||||
Ruby runtime = context.runtime; |
||||
RubyFieldDescriptor fieldDef = (RubyFieldDescriptor) cFieldDescriptor.newInstance(context, Block.NULL_BLOCK); |
||||
fieldDef.setLabel(context, runtime.newString(label)); |
||||
fieldDef.setName(context, name); |
||||
fieldDef.setType(context, type); |
||||
fieldDef.setNumber(context, number); |
||||
|
||||
if (!typeClass.isNil()) { |
||||
if (!(typeClass instanceof RubyString)) { |
||||
throw runtime.newArgumentError("expected string for type class"); |
||||
} |
||||
fieldDef.setSubmsgName(context, typeClass); |
||||
} |
||||
return fieldDef; |
||||
} |
||||
|
||||
protected static void checkIntTypePrecision(ThreadContext context, Descriptors.FieldDescriptor.Type type, IRubyObject value) { |
||||
if (value instanceof RubyFloat) { |
||||
double doubleVal = RubyNumeric.num2dbl(value); |
||||
if (Math.floor(doubleVal) != doubleVal) { |
||||
throw context.runtime.newRangeError("Non-integral floating point value assigned to integer field."); |
||||
} |
||||
} |
||||
if (type == Descriptors.FieldDescriptor.Type.UINT32 || type == Descriptors.FieldDescriptor.Type.UINT64) { |
||||
if (RubyNumeric.num2dbl(value) < 0) { |
||||
throw context.runtime.newRangeError("Assigning negative value to unsigned integer field."); |
||||
} |
||||
} |
||||
} |
||||
|
||||
protected static boolean isRubyNum(Object value) { |
||||
return value instanceof RubyFixnum || value instanceof RubyFloat || value instanceof RubyBignum; |
||||
} |
||||
|
||||
protected static void validateTypeClass(ThreadContext context, Descriptors.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 == Descriptors.FieldDescriptor.Type.MESSAGE) { |
||||
if (! (descriptor instanceof RubyDescriptor)) { |
||||
throw runtime.newArgumentError("Descriptor has an incorrect type"); |
||||
} |
||||
} else if (type == Descriptors.FieldDescriptor.Type.ENUM) { |
||||
if (! (descriptor instanceof RubyEnumDescriptor)) { |
||||
throw runtime.newArgumentError("Descriptor has an incorrect type"); |
||||
} |
||||
} |
||||
} |
||||
|
||||
public static String BADNAME_REPLACEMENT = "__DOT__"; |
||||
|
||||
public static String DESCRIPTOR_INSTANCE_VAR = "@descriptor"; |
||||
|
||||
public static String EQUAL_SIGN = "="; |
||||
|
||||
private static BigInteger UINT64_COMPLEMENTARY = new BigInteger("18446744073709551616"); //Math.pow(2, 64)
|
||||
|
||||
private static long UINT_MAX = 0xffffffffl; |
||||
} |
@ -0,0 +1,60 @@ |
||||
/* |
||||
* Protocol Buffers - Google's data interchange format |
||||
* Copyright 2014 Google Inc. All rights reserved. |
||||
* https://developers.google.com/protocol-buffers/
|
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
*/ |
||||
|
||||
package google; |
||||
|
||||
import com.google.protobuf.jruby.*; |
||||
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"); |
||||
RubyProtobuf.createProtobuf(ruby); |
||||
RubyDescriptor.createRubyDescriptor(ruby); |
||||
RubyBuilder.createRubyBuilder(ruby); |
||||
RubyFieldDescriptor.createRubyFileDescriptor(ruby); |
||||
RubyMessageBuilderContext.createRubyMessageBuilderContext(ruby); |
||||
RubyEnumDescriptor.createRubyEnumDescriptor(ruby); |
||||
RubyEnumBuilderContext.createRubyEnumBuilderContext(ruby); |
||||
RubyDescriptorPool.createRubyDescriptorPool(ruby); |
||||
RubyRepeatedField.createRubyRepeatedField(ruby); |
||||
RubyFieldDescriptor.createRubyFileDescriptor(ruby); |
||||
RubyMap.createRubyMap(ruby); |
||||
RubyOneofDescriptor.createRubyOneofDescriptor(ruby); |
||||
RubyOneofBuilderContext.createRubyOneofBuilderContext(ruby); |
||||
return true; |
||||
} |
||||
} |
@ -0,0 +1,15 @@ |
||||
syntax = "proto3"; |
||||
package com.google.protobuf.jruby; |
||||
option optimize_for = CODE_SIZE; |
||||
|
||||
message Sentinel { |
||||
optional int32 default_int32 = 1; |
||||
optional int64 default_int64 = 2; |
||||
optional uint32 default_unit32 = 3; |
||||
optional uint64 default_uint64 = 4; |
||||
optional string default_string = 5; |
||||
optional bool default_bool = 6; |
||||
optional float default_float = 7; |
||||
optional double default_double = 8; |
||||
optional bytes default_bytes = 9; |
||||
} |
Loading…
Reference in new issue