1b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer/*
2b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * Protocol Buffers - Google's data interchange format
3b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * Copyright 2014 Google Inc.  All rights reserved.
4b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * https://developers.google.com/protocol-buffers/
5b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer *
6b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * Redistribution and use in source and binary forms, with or without
7b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * modification, are permitted provided that the following conditions are
8b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * met:
9b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer *
10b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer *     * Redistributions of source code must retain the above copyright
11b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * notice, this list of conditions and the following disclaimer.
12b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer *     * Redistributions in binary form must reproduce the above
13b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * copyright notice, this list of conditions and the following disclaimer
14b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * in the documentation and/or other materials provided with the
15b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * distribution.
16b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer *     * Neither the name of Google Inc. nor the names of its
17b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * contributors may be used to endorse or promote products derived from
18b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * this software without specific prior written permission.
19b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer *
20b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer */
32b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
33b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerpackage com.google.protobuf.jruby;
34b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
35b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerimport com.google.protobuf.*;
36b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerimport org.jruby.*;
37b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerimport org.jruby.anno.JRubyMethod;
38b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerimport org.jruby.runtime.Block;
39b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerimport org.jruby.runtime.Helpers;
40b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerimport org.jruby.runtime.ThreadContext;
41b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerimport org.jruby.runtime.builtin.IRubyObject;
42b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerimport org.jruby.util.ByteList;
43b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
44b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerimport java.util.HashMap;
45b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerimport java.util.Map;
46b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
47b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerpublic class RubyMessage extends RubyObject {
48b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public RubyMessage(Ruby ruby, RubyClass klazz, Descriptors.Descriptor descriptor) {
49b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        super(ruby, klazz);
50b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        this.descriptor = descriptor;
51b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
52b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
53b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    /*
54b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     * call-seq:
55b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     *     Message.new(kwargs) => new_message
56b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     *
57b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     * Creates a new instance of the given message class. Keyword arguments may be
58b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     * provided with keywords corresponding to field names.
59b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     *
60b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     * Note that no literal Message class exists. Only concrete classes per message
61b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     * type exist, as provided by the #msgclass method on Descriptors after they
62b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     * have been added to a pool. The method definitions described here on the
63b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     * Message class are provided on each concrete message class.
64b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     */
65b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @JRubyMethod(optional = 1)
66b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public IRubyObject initialize(final ThreadContext context, IRubyObject[] args) {
67b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        final Ruby runtime = context.runtime;
68b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        this.cRepeatedField = (RubyClass) runtime.getClassFromPath("Google::Protobuf::RepeatedField");
69b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        this.cMap = (RubyClass) runtime.getClassFromPath("Google::Protobuf::Map");
70b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        this.builder = DynamicMessage.newBuilder(this.descriptor);
71b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        this.repeatedFields = new HashMap<Descriptors.FieldDescriptor, RubyRepeatedField>();
72b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        this.maps = new HashMap<Descriptors.FieldDescriptor, RubyMap>();
73b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        this.fields = new HashMap<Descriptors.FieldDescriptor, IRubyObject>();
74b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        this.oneofCases = new HashMap<Descriptors.OneofDescriptor, Descriptors.FieldDescriptor>();
75b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        if (args.length == 1) {
76b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            if (!(args[0] instanceof RubyHash)) {
77b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                throw runtime.newArgumentError("expected Hash arguments.");
78b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            }
79b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            RubyHash hash = args[0].convertToHash();
80b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            hash.visitAll(new RubyHash.Visitor() {
81b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                @Override
82b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                public void visit(IRubyObject key, IRubyObject value) {
83b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                    if (!(key instanceof RubySymbol))
84b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                        throw runtime.newTypeError("Expected symbols as hash keys in initialization map.");
85b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                    final Descriptors.FieldDescriptor fieldDescriptor = findField(context, key);
86b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
87b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                    if (Utils.isMapEntry(fieldDescriptor)) {
88b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                        if (!(value instanceof RubyHash))
89b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                            throw runtime.newArgumentError("Expected Hash object as initializer value for map field '" +  key.asJavaString() + "'.");
90b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
91b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                        final RubyMap map = newMapForField(context, fieldDescriptor);
92b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                        map.mergeIntoSelf(context, value);
93b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                        maps.put(fieldDescriptor, map);
94b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                    } else if (fieldDescriptor.isRepeated()) {
95b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                        if (!(value instanceof RubyArray))
96b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                            throw runtime.newArgumentError("Expected array as initializer value for repeated field '" +  key.asJavaString() + "'.");
97b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                        RubyRepeatedField repeatedField = rubyToRepeatedField(context, fieldDescriptor, value);
98b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                        addRepeatedField(fieldDescriptor, repeatedField);
99b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                    } else {
100b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                        Descriptors.OneofDescriptor oneof = fieldDescriptor.getContainingOneof();
101b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                        if (oneof != null) {
102b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                            oneofCases.put(oneof, fieldDescriptor);
103b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                        }
104b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                        fields.put(fieldDescriptor, value);
105b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                    }
106b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
107b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                }
108b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            });
109b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        }
110b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        return this;
111b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
112b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
113b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    /*
114b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     * call-seq:
115b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     *     Message.[]=(index, value)
116b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     *
117b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     * Sets a field's value by field name. The provided field name should be a
118b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     * string.
119b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     */
120b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @JRubyMethod(name = "[]=")
121b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public IRubyObject indexSet(ThreadContext context, IRubyObject fieldName, IRubyObject value) {
122b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        Descriptors.FieldDescriptor fieldDescriptor = findField(context, fieldName);
123b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        return setField(context, fieldDescriptor, value);
124b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
125b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
126b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    /*
127b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     * call-seq:
128b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     *     Message.[](index) => value
129b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     *
130b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     * Accesses a field's value by field name. The provided field name should be a
131b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     * string.
132b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     */
133b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @JRubyMethod(name = "[]")
134b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public IRubyObject index(ThreadContext context, IRubyObject fieldName) {
135b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        Descriptors.FieldDescriptor fieldDescriptor = findField(context, fieldName);
136b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        return getField(context, fieldDescriptor);
137b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
138b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
139b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    /*
140b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     * call-seq:
141b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     *     Message.inspect => string
142b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     *
143b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     * Returns a human-readable string representing this message. It will be
144b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     * formatted as "<MessageType: field1: value1, field2: value2, ...>". Each
145b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     * field's value is represented according to its own #inspect method.
146b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     */
147b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @JRubyMethod
148b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public IRubyObject inspect() {
149b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        String cname = metaClass.getName();
150b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        StringBuilder sb = new StringBuilder("<");
151b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        sb.append(cname);
152b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        sb.append(": ");
153b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        sb.append(this.layoutInspect());
154b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        sb.append(">");
155b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
156b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        return getRuntime().newString(sb.toString());
157b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
158b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
159b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    /*
160b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     * call-seq:
161b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     *     Message.hash => hash_value
162b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     *
163b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     * Returns a hash value that represents this message's field values.
164b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     */
165b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @JRubyMethod
166b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public IRubyObject hash(ThreadContext context) {
167b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        int hashCode = System.identityHashCode(this);
168b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        return context.runtime.newFixnum(hashCode);
169b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
170b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
171b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    /*
172b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     * call-seq:
173b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     *     Message.==(other) => boolean
174b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     *
175b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     * Performs a deep comparison of this message with another. Messages are equal
176b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     * if they have the same type and if each field is equal according to the :==
177b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     * method's semantics (a more efficient comparison may actually be done if the
178b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     * field is of a primitive type).
179b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     */
180b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @JRubyMethod(name = "==")
181b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public IRubyObject eq(ThreadContext context, IRubyObject other) {
182b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        Ruby runtime = context.runtime;
183b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        if (!(other instanceof RubyMessage))
184b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            return runtime.getFalse();
185b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        RubyMessage message = (RubyMessage) other;
186b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        if (descriptor != message.descriptor) {
187b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            return runtime.getFalse();
188b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        }
189b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
190b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        for (Descriptors.FieldDescriptor fdef : descriptor.getFields()) {
191b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            IRubyObject thisVal = getField(context, fdef);
192b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            IRubyObject thatVal = message.getField(context, fdef);
193b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            IRubyObject ret = thisVal.callMethod(context, "==", thatVal);
194b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            if (!ret.isTrue()) {
195b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                return runtime.getFalse();
196b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            }
197b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        }
198b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        return runtime.getTrue();
199b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
200b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
201b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    /*
202b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     * call-seq:
203b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     *     Message.method_missing(*args)
204b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     *
205b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     * Provides accessors and setters for message fields according to their field
206b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     * names. For any field whose name does not conflict with a built-in method, an
207b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     * accessor is provided with the same name as the field, and a setter is
208b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     * provided with the name of the field plus the '=' suffix. Thus, given a
209b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     * message instance 'msg' with field 'foo', the following code is valid:
210b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     *
211b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     *     msg.foo = 42
212b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     *     puts msg.foo
213b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     */
214b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @JRubyMethod(name = "method_missing", rest = true)
215b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public IRubyObject methodMissing(ThreadContext context, IRubyObject[] args) {
216b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        if (args.length == 1) {
217b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            RubyDescriptor rubyDescriptor = (RubyDescriptor) getDescriptor(context, metaClass);
218b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            IRubyObject oneofDescriptor = rubyDescriptor.lookupOneof(context, args[0]);
219b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            if (oneofDescriptor.isNil()) {
220b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                if (!hasField(args[0])) {
221b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                    return Helpers.invokeSuper(context, this, metaClass, "method_missing", args, Block.NULL_BLOCK);
222b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                }
223b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                return index(context, args[0]);
224b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            }
225b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            RubyOneofDescriptor rubyOneofDescriptor = (RubyOneofDescriptor) oneofDescriptor;
226b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            Descriptors.FieldDescriptor fieldDescriptor =
227b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                    oneofCases.get(rubyOneofDescriptor.getOneofDescriptor());
228b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            if (fieldDescriptor == null)
229b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                return context.runtime.getNil();
230b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
231b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            return context.runtime.newSymbol(fieldDescriptor.getName());
232b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        } else {
233b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            // fieldName is RubySymbol
234b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            RubyString field = args[0].asString();
235b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            RubyString equalSign = context.runtime.newString(Utils.EQUAL_SIGN);
236b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            if (field.end_with_p(context, equalSign).isTrue()) {
237b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                field.chomp_bang(context, equalSign);
238b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            }
239b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
240b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            if (!hasField(field)) {
241b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                return Helpers.invokeSuper(context, this, metaClass, "method_missing", args, Block.NULL_BLOCK);
242b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            }
243b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            return indexSet(context, field, args[1]);
244b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        }
245b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
246b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
247b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    /**
248b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     * call-seq:
249b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     * Message.dup => new_message
250b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     * Performs a shallow copy of this message and returns the new copy.
251b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     */
252b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @JRubyMethod
253b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public IRubyObject dup(ThreadContext context) {
254b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        RubyMessage dup = (RubyMessage) metaClass.newInstance(context, Block.NULL_BLOCK);
255b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        IRubyObject value;
256b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        for (Descriptors.FieldDescriptor fieldDescriptor : this.descriptor.getFields()) {
257b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            if (fieldDescriptor.isRepeated()) {
258b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                dup.addRepeatedField(fieldDescriptor, this.getRepeatedField(context, fieldDescriptor));
259b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            } else if (fields.containsKey(fieldDescriptor)) {
260b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                dup.fields.put(fieldDescriptor, fields.get(fieldDescriptor));
261b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            } else if (this.builder.hasField(fieldDescriptor)) {
262b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                dup.fields.put(fieldDescriptor, wrapField(context, fieldDescriptor, this.builder.getField(fieldDescriptor)));
263b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            }
264b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        }
265b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        for (Descriptors.FieldDescriptor fieldDescriptor : maps.keySet()) {
266b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            dup.maps.put(fieldDescriptor, maps.get(fieldDescriptor));
267b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        }
268b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        return dup;
269b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
270b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
271b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    /*
272b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     * call-seq:
273b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     *     Message.descriptor => descriptor
274b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     *
275b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     * Class method that returns the Descriptor instance corresponding to this
276b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     * message class's type.
277b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     */
278b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @JRubyMethod(name = "descriptor", meta = true)
279b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public static IRubyObject getDescriptor(ThreadContext context, IRubyObject recv) {
280b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        return ((RubyClass) recv).getInstanceVariable(Utils.DESCRIPTOR_INSTANCE_VAR);
281b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
282b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
283b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    /*
284b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     * call-seq:
285b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     *     MessageClass.encode(msg) => bytes
286b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     *
287b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     * Encodes the given message object to its serialized form in protocol buffers
288b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     * wire format.
289b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     */
290b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @JRubyMethod(meta = true)
291b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public static IRubyObject encode(ThreadContext context, IRubyObject recv, IRubyObject value) {
292b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        RubyMessage message = (RubyMessage) value;
293b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        return context.runtime.newString(new ByteList(message.build(context).toByteArray()));
294b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
295b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
296b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    /*
297b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     * call-seq:
298b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     *     MessageClass.decode(data) => message
299b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     *
300b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     * Decodes the given data (as a string containing bytes in protocol buffers wire
301b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     * format) under the interpretration given by this message class's definition
302b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     * and returns a message object with the corresponding field values.
303b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     */
304b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @JRubyMethod(meta = true)
305b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public static IRubyObject decode(ThreadContext context, IRubyObject recv, IRubyObject data) {
306b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        byte[] bin = data.convertToString().getBytes();
307b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        RubyMessage ret = (RubyMessage) ((RubyClass) recv).newInstance(context, Block.NULL_BLOCK);
308b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        try {
309b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            ret.builder.mergeFrom(bin);
310b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        } catch (InvalidProtocolBufferException e) {
311b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            throw context.runtime.newRuntimeError(e.getMessage());
312b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        }
313b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        return ret;
314b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
315b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
316b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    /*
317b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     * call-seq:
318b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     *     MessageClass.encode_json(msg) => json_string
319b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     *
320b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     * Encodes the given message object into its serialized JSON representation.
321b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     */
322b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @JRubyMethod(name = "encode_json", meta = true)
323b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public static IRubyObject encodeJson(ThreadContext context, IRubyObject recv, IRubyObject msgRb) {
324b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        RubyMessage message = (RubyMessage) msgRb;
325b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        return Helpers.invoke(context, message.toHash(context), "to_json");
326b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
327b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
328b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    /*
329b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     * call-seq:
330b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     *     MessageClass.decode_json(data) => message
331b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     *
332b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     * Decodes the given data (as a string containing bytes in protocol buffers wire
333b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     * format) under the interpretration given by this message class's definition
334b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     * and returns a message object with the corresponding field values.
335b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer     */
336b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @JRubyMethod(name = "decode_json", meta = true)
337b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public static IRubyObject decodeJson(ThreadContext context, IRubyObject recv, IRubyObject json) {
338b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        Ruby runtime = context.runtime;
339b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        RubyMessage ret = (RubyMessage) ((RubyClass) recv).newInstance(context, Block.NULL_BLOCK);
340b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        RubyModule jsonModule = runtime.getClassFromPath("JSON");
341b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        RubyHash opts = RubyHash.newHash(runtime);
342b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        opts.fastASet(runtime.newSymbol("symbolize_names"), runtime.getTrue());
343b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        IRubyObject[] args = new IRubyObject[] { Helpers.invoke(context, jsonModule, "parse", json, opts) };
344b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        ret.initialize(context, args);
345b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        return ret;
346b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
347b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
348b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    @JRubyMethod(name = {"to_h", "to_hash"})
349b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    public IRubyObject toHash(ThreadContext context) {
350b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        Ruby runtime = context.runtime;
351b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        RubyHash ret = RubyHash.newHash(runtime);
352b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        for (Descriptors.FieldDescriptor fdef : this.descriptor.getFields()) {
353b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            IRubyObject value = getField(context, fdef);
354b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            if (!value.isNil()) {
355b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                if (value.respondsTo("to_h")) {
356b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                    value = Helpers.invoke(context, value, "to_h");
357b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                } else if (value.respondsTo("to_a")) {
358b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                    value = Helpers.invoke(context, value, "to_a");
359b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                }
360b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            }
361b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            ret.fastASet(runtime.newSymbol(fdef.getName()), value);
362b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        }
363b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        return ret;
364b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
365b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
366b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    protected DynamicMessage build(ThreadContext context) {
367b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        return build(context, 0);
368b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
369b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
370b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    protected DynamicMessage build(ThreadContext context, int depth) {
371b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        if (depth > SINK_MAXIMUM_NESTING) {
372b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            throw context.runtime.newRuntimeError("Maximum recursion depth exceeded during encoding.");
373b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        }
374b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        for (Descriptors.FieldDescriptor fieldDescriptor : maps.keySet()) {
375b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            this.builder.clearField(fieldDescriptor);
376b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            RubyDescriptor mapDescriptor = (RubyDescriptor) getDescriptorForField(context, fieldDescriptor);
377b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            for (DynamicMessage kv : maps.get(fieldDescriptor).build(context, mapDescriptor)) {
378b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                this.builder.addRepeatedField(fieldDescriptor, kv);
379b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            }
380b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        }
381b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        for (Descriptors.FieldDescriptor fieldDescriptor : repeatedFields.keySet()) {
382b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            RubyRepeatedField repeatedField = repeatedFields.get(fieldDescriptor);
383b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            this.builder.clearField(fieldDescriptor);
384b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            for (int i = 0; i < repeatedField.size(); i++) {
385b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                Object item = convert(context, fieldDescriptor, repeatedField.get(i), depth);
386b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                this.builder.addRepeatedField(fieldDescriptor, item);
387b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            }
388b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        }
389b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        for (Descriptors.FieldDescriptor fieldDescriptor : fields.keySet()) {
390b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            IRubyObject value = fields.get(fieldDescriptor);
391b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            this.builder.setField(fieldDescriptor, convert(context, fieldDescriptor, value, depth));
392b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        }
393b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        return this.builder.build();
394b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
395b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
396b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    protected Descriptors.Descriptor getDescriptor() {
397b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        return this.descriptor;
398b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
399b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
400b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // Internal use only, called by Google::Protobuf.deep_copy
401b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    protected IRubyObject deepCopy(ThreadContext context) {
402b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        RubyMessage copy = (RubyMessage) metaClass.newInstance(context, Block.NULL_BLOCK);
403b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        for (Descriptors.FieldDescriptor fdef : this.descriptor.getFields()) {
404b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            if (fdef.isRepeated()) {
405b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                copy.addRepeatedField(fdef, this.getRepeatedField(context, fdef).deepCopy(context));
406b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            } else if (fields.containsKey(fdef)) {
407b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                copy.fields.put(fdef, fields.get(fdef));
408b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            } else if (this.builder.hasField(fdef)) {
409b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                copy.fields.put(fdef, wrapField(context, fdef, this.builder.getField(fdef)));
410b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            }
411b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        }
412b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        return copy;
413b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
414b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
415b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    private RubyRepeatedField getRepeatedField(ThreadContext context, Descriptors.FieldDescriptor fieldDescriptor) {
416b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        if (this.repeatedFields.containsKey(fieldDescriptor)) {
417b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            return this.repeatedFields.get(fieldDescriptor);
418b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        }
419b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        int count = this.builder.getRepeatedFieldCount(fieldDescriptor);
420b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        RubyRepeatedField ret = repeatedFieldForFieldDescriptor(context, fieldDescriptor);
421b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        for (int i = 0; i < count; i++) {
422b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            ret.push(context, wrapField(context, fieldDescriptor, this.builder.getRepeatedField(fieldDescriptor, i)));
423b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        }
424b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        addRepeatedField(fieldDescriptor, ret);
425b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        return ret;
426b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
427b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
428b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    private void addRepeatedField(Descriptors.FieldDescriptor fieldDescriptor, RubyRepeatedField repeatedField) {
429b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        this.repeatedFields.put(fieldDescriptor, repeatedField);
430b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
431b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
432b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    private IRubyObject buildFrom(ThreadContext context, DynamicMessage dynamicMessage) {
433b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        this.builder.mergeFrom(dynamicMessage);
434b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        return this;
435b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
436b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
437b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    private Descriptors.FieldDescriptor findField(ThreadContext context, IRubyObject fieldName) {
438b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        String nameStr = fieldName.asJavaString();
439b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        Descriptors.FieldDescriptor ret = this.descriptor.findFieldByName(Utils.escapeIdentifier(nameStr));
440b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        if (ret == null)
441b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            throw context.runtime.newArgumentError("field " + fieldName.asJavaString() + " is not found");
442b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        return ret;
443b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
444b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
445b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    private boolean hasField(IRubyObject fieldName) {
446b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        String nameStr = fieldName.asJavaString();
447b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        return this.descriptor.findFieldByName(Utils.escapeIdentifier(nameStr)) != null;
448b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
449b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
450b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    private void checkRepeatedFieldType(ThreadContext context, IRubyObject value,
451b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                                        Descriptors.FieldDescriptor fieldDescriptor) {
452b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        Ruby runtime = context.runtime;
453b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        if (!(value instanceof RubyRepeatedField)) {
454b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            throw runtime.newTypeError("Expected repeated field array");
455b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        }
456b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
457b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
458b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // convert a ruby object to protobuf type, with type check
459b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    private Object convert(ThreadContext context,
460b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                           Descriptors.FieldDescriptor fieldDescriptor,
461b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                           IRubyObject value, int depth) {
462b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        Ruby runtime = context.runtime;
463b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        Object val = null;
464b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        switch (fieldDescriptor.getType()) {
465b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            case INT32:
466b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            case INT64:
467b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            case UINT32:
468b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            case UINT64:
469b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                if (!Utils.isRubyNum(value)) {
470b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                    throw runtime.newTypeError("Expected number type for integral field.");
471b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                }
472b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                Utils.checkIntTypePrecision(context, fieldDescriptor.getType(), value);
473b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                switch (fieldDescriptor.getType()) {
474b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                    case INT32:
475b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                        val = RubyNumeric.num2int(value);
476b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                        break;
477b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                    case INT64:
478b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                        val = RubyNumeric.num2long(value);
479b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                        break;
480b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                    case UINT32:
481b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                        val = Utils.num2uint(value);
482b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                        break;
483b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                    case UINT64:
484b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                        val = Utils.num2ulong(context.runtime, value);
485b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                        break;
486b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                    default:
487b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                        break;
488b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                }
489b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                break;
490b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            case FLOAT:
491b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                if (!Utils.isRubyNum(value))
492b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                    throw runtime.newTypeError("Expected number type for float field.");
493b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                val = (float) RubyNumeric.num2dbl(value);
494b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                break;
495b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            case DOUBLE:
496b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                if (!Utils.isRubyNum(value))
497b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                    throw runtime.newTypeError("Expected number type for double field.");
498b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                val = RubyNumeric.num2dbl(value);
499b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                break;
500b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            case BOOL:
501b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                if (!(value instanceof RubyBoolean))
502b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                    throw runtime.newTypeError("Invalid argument for boolean field.");
503b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                val = value.isTrue();
504b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                break;
505b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            case BYTES:
506b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            case STRING:
507b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                Utils.validateStringEncoding(context.runtime, fieldDescriptor.getType(), value);
508b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                RubyString str = (RubyString) value;
509b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                switch (fieldDescriptor.getType()) {
510b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                    case BYTES:
511b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                        val = ByteString.copyFrom(str.getBytes());
512b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                        break;
513b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                    case STRING:
514b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                        val = str.asJavaString();
515b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                        break;
516b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                    default:
517b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                        break;
518b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                }
519b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                break;
520b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            case MESSAGE:
521b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                RubyClass typeClass = (RubyClass) ((RubyDescriptor) getDescriptorForField(context, fieldDescriptor)).msgclass(context);
522b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                if (!value.getMetaClass().equals(typeClass))
523b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                    throw runtime.newTypeError(value, "Invalid type to assign to submessage field.");
524b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                val = ((RubyMessage) value).build(context, depth + 1);
525b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                break;
526b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            case ENUM:
527b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                Descriptors.EnumDescriptor enumDescriptor = fieldDescriptor.getEnumType();
528b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
529b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                if (Utils.isRubyNum(value)) {
530b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                    val = enumDescriptor.findValueByNumberCreatingIfUnknown(RubyNumeric.num2int(value));
531b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                } else if (value instanceof RubySymbol) {
532b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                    val = enumDescriptor.findValueByName(value.asJavaString());
533b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                } else {
534b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                    throw runtime.newTypeError("Expected number or symbol type for enum field.");
535b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                }
536b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                if (val == null) {
537b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                    throw runtime.newRangeError("Enum value " + value + " is not found.");
538b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                }
539b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                break;
540b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            default:
541b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                break;
542b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        }
543b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        return val;
544b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
545b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
546b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    private IRubyObject wrapField(ThreadContext context, Descriptors.FieldDescriptor fieldDescriptor, Object value) {
547b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        if (value == null) {
548b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            return context.runtime.getNil();
549b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        }
550b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        Ruby runtime = context.runtime;
551b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        switch (fieldDescriptor.getType()) {
552b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            case INT32:
553b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            case INT64:
554b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            case UINT32:
555b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            case UINT64:
556b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            case FLOAT:
557b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            case DOUBLE:
558b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            case BOOL:
559b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            case BYTES:
560b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            case STRING:
561b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                return Utils.wrapPrimaryValue(context, fieldDescriptor.getType(), value);
562b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            case MESSAGE:
563b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                RubyClass typeClass = (RubyClass) ((RubyDescriptor) getDescriptorForField(context, fieldDescriptor)).msgclass(context);
564b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                RubyMessage msg = (RubyMessage) typeClass.newInstance(context, Block.NULL_BLOCK);
565b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                return msg.buildFrom(context, (DynamicMessage) value);
566b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            case ENUM:
567b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                Descriptors.EnumValueDescriptor enumValueDescriptor = (Descriptors.EnumValueDescriptor) value;
568b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                if (enumValueDescriptor.getIndex() == -1) { // UNKNOWN ENUM VALUE
569b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                    return runtime.newFixnum(enumValueDescriptor.getNumber());
570b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                }
571b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                return runtime.newSymbol(enumValueDescriptor.getName());
572b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            default:
573b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                return runtime.newString(value.toString());
574b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        }
575b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
576b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
577b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    private RubyRepeatedField repeatedFieldForFieldDescriptor(ThreadContext context,
578b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                                                              Descriptors.FieldDescriptor fieldDescriptor) {
579b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        IRubyObject typeClass = context.runtime.getNilClass();
580b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
581b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        IRubyObject descriptor = getDescriptorForField(context, fieldDescriptor);
582b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        Descriptors.FieldDescriptor.Type type = fieldDescriptor.getType();
583b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        if (type == Descriptors.FieldDescriptor.Type.MESSAGE) {
584b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            typeClass = ((RubyDescriptor) descriptor).msgclass(context);
585b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
586b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        } else if (type == Descriptors.FieldDescriptor.Type.ENUM) {
587b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            typeClass = ((RubyEnumDescriptor) descriptor).enummodule(context);
588b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        }
589b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        return new RubyRepeatedField(context.runtime, cRepeatedField, type, typeClass);
590b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
591b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
592b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    protected IRubyObject getField(ThreadContext context, Descriptors.FieldDescriptor fieldDescriptor) {
593b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        Descriptors.OneofDescriptor oneofDescriptor = fieldDescriptor.getContainingOneof();
594b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        if (oneofDescriptor != null) {
595b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            if (oneofCases.containsKey(oneofDescriptor)) {
596b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                if (oneofCases.get(oneofDescriptor) != fieldDescriptor)
597b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                    return context.runtime.getNil();
598b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                return fields.get(fieldDescriptor);
599b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            } else {
600b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                Descriptors.FieldDescriptor oneofCase = builder.getOneofFieldDescriptor(oneofDescriptor);
601b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                if (oneofCase != fieldDescriptor) return context.runtime.getNil();
602b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                IRubyObject value = wrapField(context, oneofCase, builder.getField(oneofCase));
603b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                fields.put(fieldDescriptor, value);
604b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                return value;
605b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            }
606b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        }
607b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
608b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        if (Utils.isMapEntry(fieldDescriptor)) {
609b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            RubyMap map = maps.get(fieldDescriptor);
610b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            if (map == null) {
611b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                map = newMapForField(context, fieldDescriptor);
612b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                int mapSize = this.builder.getRepeatedFieldCount(fieldDescriptor);
613b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                Descriptors.FieldDescriptor keyField = fieldDescriptor.getMessageType().findFieldByNumber(1);
614b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                Descriptors.FieldDescriptor valueField = fieldDescriptor.getMessageType().findFieldByNumber(2);
615b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                RubyDescriptor kvDescriptor = (RubyDescriptor) getDescriptorForField(context, fieldDescriptor);
616b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                RubyClass kvClass = (RubyClass) kvDescriptor.msgclass(context);
617b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                for (int i = 0; i < mapSize; i++) {
618b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                    RubyMessage kvMessage = (RubyMessage) kvClass.newInstance(context, Block.NULL_BLOCK);
619b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                    DynamicMessage message = (DynamicMessage) this.builder.getRepeatedField(fieldDescriptor, i);
620b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                    kvMessage.buildFrom(context, message);
621b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                    map.indexSet(context, kvMessage.getField(context, keyField), kvMessage.getField(context, valueField));
622b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                }
623b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                maps.put(fieldDescriptor, map);
624b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            }
625b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            return map;
626b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        }
627b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        if (fieldDescriptor.isRepeated()) {
628b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            return getRepeatedField(context, fieldDescriptor);
629b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        }
630b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        if (fieldDescriptor.getType() != Descriptors.FieldDescriptor.Type.MESSAGE ||
631b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                this.builder.hasField(fieldDescriptor) || fields.containsKey(fieldDescriptor)) {
632b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            if (fields.containsKey(fieldDescriptor)) {
633b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                return fields.get(fieldDescriptor);
634b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            } else {
635b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                IRubyObject value = wrapField(context, fieldDescriptor, this.builder.getField(fieldDescriptor));
636b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                if (this.builder.hasField(fieldDescriptor)) {
637b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                    fields.put(fieldDescriptor, value);
638b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                }
639b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                return value;
640b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            }
641b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        }
642b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        return context.runtime.getNil();
643b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
644b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
645b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    protected IRubyObject setField(ThreadContext context, Descriptors.FieldDescriptor fieldDescriptor, IRubyObject value) {
646b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        if (Utils.isMapEntry(fieldDescriptor)) {
647b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            if (!(value instanceof RubyMap)) {
648b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                throw context.runtime.newTypeError("Expected Map instance");
649b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            }
650b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            RubyMap thisMap = (RubyMap) getField(context, fieldDescriptor);
651b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            thisMap.mergeIntoSelf(context, value);
652b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        } else if (fieldDescriptor.isRepeated()) {
653b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            checkRepeatedFieldType(context, value, fieldDescriptor);
654b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            if (value instanceof RubyRepeatedField) {
655b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                addRepeatedField(fieldDescriptor, (RubyRepeatedField) value);
656b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            } else {
657b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                RubyArray ary = value.convertToArray();
658b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                RubyRepeatedField repeatedField = rubyToRepeatedField(context, fieldDescriptor, ary);
659b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                addRepeatedField(fieldDescriptor, repeatedField);
660b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            }
661b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        } else {
662b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            Descriptors.OneofDescriptor oneofDescriptor = fieldDescriptor.getContainingOneof();
663b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            if (oneofDescriptor != null) {
664b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                Descriptors.FieldDescriptor oneofCase = oneofCases.get(oneofDescriptor);
665b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                if (oneofCase != null && oneofCase != fieldDescriptor) {
666b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                    fields.remove(oneofCase);
667b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                }
668b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                if (value.isNil()) {
669b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                    oneofCases.remove(oneofDescriptor);
670b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                    fields.remove(fieldDescriptor);
671b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                } else {
672b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                    oneofCases.put(oneofDescriptor, fieldDescriptor);
673b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                    fields.put(fieldDescriptor, value);
674b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                }
675b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            } else {
676b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                Descriptors.FieldDescriptor.Type fieldType = fieldDescriptor.getType();
677b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                IRubyObject typeClass = context.runtime.getObject();
678b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                boolean addValue = true;
679b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                if (fieldType == Descriptors.FieldDescriptor.Type.MESSAGE) {
680b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                    typeClass = ((RubyDescriptor) getDescriptorForField(context, fieldDescriptor)).msgclass(context);
681b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                    if (value.isNil()){
682b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                        addValue = false;
683b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                    }
684b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                } else if (fieldType == Descriptors.FieldDescriptor.Type.ENUM) {
685b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                    typeClass = ((RubyEnumDescriptor) getDescriptorForField(context, fieldDescriptor)).enummodule(context);
686b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                    Descriptors.EnumDescriptor enumDescriptor = fieldDescriptor.getEnumType();
687b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                    if (Utils.isRubyNum(value)) {
688b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                        Descriptors.EnumValueDescriptor val =
689b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                                enumDescriptor.findValueByNumberCreatingIfUnknown(RubyNumeric.num2int(value));
690b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                        if (val.getIndex() != -1) value = context.runtime.newSymbol(val.getName());
691b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                    }
692b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                }
693b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                if (addValue) {
694b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                    Utils.checkType(context, fieldType, value, (RubyModule) typeClass);
695b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                    this.fields.put(fieldDescriptor, value);
696b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                } else {
697b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                    this.fields.remove(fieldDescriptor);
698b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                }
699b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            }
700b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        }
701b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        return context.runtime.getNil();
702b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
703b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
704b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    private String layoutInspect() {
705b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        ThreadContext context = getRuntime().getCurrentContext();
706b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        StringBuilder sb = new StringBuilder();
707b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        for (Descriptors.FieldDescriptor fdef : descriptor.getFields()) {
708b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            sb.append(Utils.unescapeIdentifier(fdef.getName()));
709b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            sb.append(": ");
710b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            sb.append(getField(context, fdef).inspect());
711b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            sb.append(", ");
712b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        }
713b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        return sb.substring(0, sb.length() - 2);
714b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
715b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
716b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    private IRubyObject getDescriptorForField(ThreadContext context, Descriptors.FieldDescriptor fieldDescriptor) {
717b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        RubyDescriptor thisRbDescriptor = (RubyDescriptor) getDescriptor(context, metaClass);
718b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        return thisRbDescriptor.lookup(fieldDescriptor.getName()).getSubType(context);
719b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
720b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
721b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    private RubyRepeatedField rubyToRepeatedField(ThreadContext context,
722b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                                                  Descriptors.FieldDescriptor fieldDescriptor, IRubyObject value) {
723b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        RubyArray arr = value.convertToArray();
724b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        RubyRepeatedField repeatedField = repeatedFieldForFieldDescriptor(context, fieldDescriptor);
725b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        for (int i = 0; i < arr.size(); i++) {
726b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            repeatedField.push(context, arr.eltInternal(i));
727b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        }
728b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        return repeatedField;
729b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
730b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
731b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    private RubyMap newMapForField(ThreadContext context, Descriptors.FieldDescriptor fieldDescriptor) {
732b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        RubyDescriptor mapDescriptor = (RubyDescriptor) getDescriptorForField(context, fieldDescriptor);
733b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        Descriptors.FieldDescriptor keyField = fieldDescriptor.getMessageType().findFieldByNumber(1);
734b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        Descriptors.FieldDescriptor valueField = fieldDescriptor.getMessageType().findFieldByNumber(2);
735b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        IRubyObject keyType = RubySymbol.newSymbol(context.runtime, keyField.getType().name());
736b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        IRubyObject valueType = RubySymbol.newSymbol(context.runtime, valueField.getType().name());
737b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        if (valueField.getType() == Descriptors.FieldDescriptor.Type.MESSAGE) {
738b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            RubyFieldDescriptor rubyFieldDescriptor = (RubyFieldDescriptor) mapDescriptor.lookup(context,
739b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                    context.runtime.newString("value"));
740b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            RubyDescriptor rubyDescriptor = (RubyDescriptor) rubyFieldDescriptor.getSubType(context);
741b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            return (RubyMap) cMap.newInstance(context, keyType, valueType,
742b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                    rubyDescriptor.msgclass(context), Block.NULL_BLOCK);
743b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        } else {
744b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            return (RubyMap) cMap.newInstance(context, keyType, valueType, Block.NULL_BLOCK);
745b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        }
746b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
747b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
748b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    private Descriptors.FieldDescriptor getOneofCase(Descriptors.OneofDescriptor oneof) {
749b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        if (oneofCases.containsKey(oneof)) {
750b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            return oneofCases.get(oneof);
751b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        }
752b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        return builder.getOneofFieldDescriptor(oneof);
753b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
754b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
755b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    private Descriptors.Descriptor descriptor;
756b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    private DynamicMessage.Builder builder;
757b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    private RubyClass cRepeatedField;
758b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    private RubyClass cMap;
759b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    private Map<Descriptors.FieldDescriptor, RubyRepeatedField> repeatedFields;
760b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    private Map<Descriptors.FieldDescriptor, RubyMap> maps;
761b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    private Map<Descriptors.FieldDescriptor, IRubyObject> fields;
762b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    private Map<Descriptors.OneofDescriptor, Descriptors.FieldDescriptor> oneofCases;
763b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
764b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    private static final int SINK_MAXIMUM_NESTING = 64;
765b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
766