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