diff options
Diffstat (limited to 'third_party/protobuf/3.2.0/ruby/src/main/java/com/google/protobuf/jruby/RubyMessage.java')
-rw-r--r-- | third_party/protobuf/3.2.0/ruby/src/main/java/com/google/protobuf/jruby/RubyMessage.java | 784 |
1 files changed, 0 insertions, 784 deletions
diff --git a/third_party/protobuf/3.2.0/ruby/src/main/java/com/google/protobuf/jruby/RubyMessage.java b/third_party/protobuf/3.2.0/ruby/src/main/java/com/google/protobuf/jruby/RubyMessage.java deleted file mode 100644 index 733ccfbc7d..0000000000 --- a/third_party/protobuf/3.2.0/ruby/src/main/java/com/google/protobuf/jruby/RubyMessage.java +++ /dev/null @@ -1,784 +0,0 @@ -/* - * 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.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -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 '" + key.asJavaString() + "'."); - - final RubyMap map = newMapForField(context, fieldDescriptor); - map.mergeIntoSelf(context, value); - maps.put(fieldDescriptor, map); - } else if (fieldDescriptor.isRepeated()) { - if (!(value instanceof RubyArray)) - throw runtime.newArgumentError("Expected array as initializer value for repeated field '" + key.asJavaString() + "'."); - 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) { - try { - MessageDigest digest = MessageDigest.getInstance("SHA-256"); - for (RubyMap map : maps.values()) { - digest.update((byte) map.hashCode()); - } - for (RubyRepeatedField repeatedField : repeatedFields.values()) { - digest.update((byte) repeatedFields.hashCode()); - } - for (IRubyObject field : fields.values()) { - digest.update((byte) field.hashCode()); - } - return context.runtime.newString(new ByteList(digest.digest())); - } catch (NoSuchAlgorithmException ignore) { - return context.runtime.newFixnum(System.identityHashCode(this)); - } - } - - /* - * 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()) { - if (!hasField(args[0])) { - return Helpers.invokeSuper(context, this, metaClass, "method_missing", args, Block.NULL_BLOCK); - } - 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); - } - - if (!hasField(field)) { - return Helpers.invokeSuper(context, this, metaClass, "method_missing", args, Block.NULL_BLOCK); - } - 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 : this.descriptor.getFields()) { - if (fieldDescriptor.isRepeated()) { - dup.addRepeatedField(fieldDescriptor, this.getRepeatedField(context, fieldDescriptor)); - } else if (fields.containsKey(fieldDescriptor)) { - dup.fields.put(fieldDescriptor, fields.get(fieldDescriptor)); - } else if (this.builder.hasField(fieldDescriptor)) { - dup.fields.put(fieldDescriptor, wrapField(context, fieldDescriptor, this.builder.getField(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", "to_hash"}) - 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.isNil()) { - if (value.respondsTo("to_h")) { - value = Helpers.invoke(context, value, "to_h"); - } else if (value.respondsTo("to_a")) { - value = Helpers.invoke(context, value, "to_a"); - } - } - ret.fastASet(runtime.newSymbol(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))); - } - addRepeatedField(fieldDescriptor, ret); - 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 boolean hasField(IRubyObject fieldName) { - String nameStr = fieldName.asJavaString(); - return this.descriptor.findFieldByName(Utils.escapeIdentifier(nameStr)) != null; - } - - 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, 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.get(oneofDescriptor) == fieldDescriptor) { - return fields.get(fieldDescriptor); - } else { - Descriptors.FieldDescriptor oneofCase = builder.getOneofFieldDescriptor(oneofDescriptor); - if (oneofCase != fieldDescriptor) { - if (fieldDescriptor.getType() == Descriptors.FieldDescriptor.Type.MESSAGE) { - return context.runtime.getNil(); - } else { - return wrapField(context, fieldDescriptor, fieldDescriptor.getDefaultValue()); - } - } - 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(); - boolean addValue = true; - if (fieldType == Descriptors.FieldDescriptor.Type.MESSAGE) { - typeClass = ((RubyDescriptor) getDescriptorForField(context, fieldDescriptor)).msgclass(context); - if (value.isNil()){ - addValue = false; - } - } else if (fieldType == Descriptors.FieldDescriptor.Type.ENUM) { - typeClass = ((RubyEnumDescriptor) getDescriptorForField(context, fieldDescriptor)).enummodule(context); - 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()); - } - } - if (addValue) { - value = Utils.checkType(context, fieldType, value, (RubyModule) typeClass); - this.fields.put(fieldDescriptor, value); - } else { - this.fields.remove(fieldDescriptor); - } - } - } - 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; -} |