• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Protocol Buffers - Google's data interchange format
3  * Copyright 2014 Google Inc.  All rights reserved.
4  * https://developers.google.com/protocol-buffers/
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are
8  * met:
9  *
10  *     * Redistributions of source code must retain the above copyright
11  * notice, this list of conditions and the following disclaimer.
12  *     * Redistributions in binary form must reproduce the above
13  * copyright notice, this list of conditions and the following disclaimer
14  * in the documentation and/or other materials provided with the
15  * distribution.
16  *     * Neither the name of Google Inc. nor the names of its
17  * contributors may be used to endorse or promote products derived from
18  * this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 package com.google.protobuf.jruby;
34 
35 import com.google.protobuf.DescriptorProtos;
36 import com.google.protobuf.Descriptors;
37 import org.jruby.*;
38 import org.jruby.anno.JRubyClass;
39 import org.jruby.anno.JRubyMethod;
40 import org.jruby.runtime.ObjectAllocator;
41 import org.jruby.runtime.ThreadContext;
42 import org.jruby.runtime.builtin.IRubyObject;
43 
44 @JRubyClass(name = "FieldDescriptor")
45 public class RubyFieldDescriptor extends RubyObject {
createRubyFileDescriptor(Ruby runtime)46     public static void createRubyFileDescriptor(Ruby runtime) {
47         RubyModule mProtobuf = runtime.getClassFromPath("Google::Protobuf");
48         RubyClass cFieldDescriptor = mProtobuf.defineClassUnder("FieldDescriptor", runtime.getObject(), new ObjectAllocator() {
49             @Override
50             public IRubyObject allocate(Ruby runtime, RubyClass klazz) {
51                 return new RubyFieldDescriptor(runtime, klazz);
52             }
53         });
54         cFieldDescriptor.defineAnnotatedMethods(RubyFieldDescriptor.class);
55     }
56 
RubyFieldDescriptor(Ruby runtime, RubyClass klazz)57     public RubyFieldDescriptor(Ruby runtime, RubyClass klazz) {
58         super(runtime, klazz);
59     }
60 
61     /*
62      * call-seq:
63      *     FieldDescriptor.new => field
64      *
65      * Returns a new field descriptor. Its name, type, etc. must be set before it is
66      * added to a message type.
67      */
68     @JRubyMethod
initialize(ThreadContext context)69     public IRubyObject initialize(ThreadContext context) {
70         builder = DescriptorProtos.FieldDescriptorProto.newBuilder();
71         return this;
72     }
73 
74     /*
75      * call-seq:
76      *     FieldDescriptor.label
77      *
78      * Return the label of this field.
79      */
80     @JRubyMethod(name = "label")
getLabel(ThreadContext context)81     public IRubyObject getLabel(ThreadContext context) {
82         return this.label;
83     }
84 
85     /*
86      * call-seq:
87      *     FieldDescriptor.label = label
88      *
89      * Sets the label on this field. Cannot be called if field is part of a message
90      * type already in a pool.
91      */
92     @JRubyMethod(name = "label=")
setLabel(ThreadContext context, IRubyObject value)93     public IRubyObject setLabel(ThreadContext context, IRubyObject value) {
94         String labelName = value.asJavaString();
95         this.label = context.runtime.newSymbol(labelName.toLowerCase());
96         this.builder.setLabel(
97                 DescriptorProtos.FieldDescriptorProto.Label.valueOf("LABEL_" + labelName.toUpperCase()));
98         return context.runtime.getNil();
99     }
100 
101     /*
102      * call-seq:
103      *     FieldDescriptor.name => name
104      *
105      * Returns the name of this field as a Ruby String, or nil if it is not set.
106      */
107     @JRubyMethod(name = "name")
getName(ThreadContext context)108     public IRubyObject getName(ThreadContext context) {
109         return this.name;
110     }
111 
112     /*
113      * call-seq:
114      *     FieldDescriptor.name = name
115      *
116      * Sets the name of this field. Cannot be called once the containing message
117      * type, if any, is added to a pool.
118      */
119     @JRubyMethod(name = "name=")
setName(ThreadContext context, IRubyObject value)120     public IRubyObject setName(ThreadContext context, IRubyObject value) {
121         String nameStr = value.asJavaString();
122         this.name = context.runtime.newString(nameStr);
123         this.builder.setName(Utils.escapeIdentifier(nameStr));
124         return context.runtime.getNil();
125     }
126 
127 
128     @JRubyMethod(name = "subtype")
getSubType(ThreadContext context)129     public IRubyObject getSubType(ThreadContext context) {
130         return subType;
131     }
132 
133     /*
134      * call-seq:
135      *     FieldDescriptor.type => type
136      *
137      * Returns this field's type, as a Ruby symbol, or nil if not yet set.
138      *
139      * Valid field types are:
140      *     :int32, :int64, :uint32, :uint64, :float, :double, :bool, :string,
141      *     :bytes, :message.
142      */
143     @JRubyMethod(name = "type")
getType(ThreadContext context)144     public IRubyObject getType(ThreadContext context) {
145         return Utils.fieldTypeToRuby(context, this.builder.getType());
146     }
147 
148     /*
149      * call-seq:
150      *     FieldDescriptor.type = type
151      *
152      * Sets this field's type. Cannot be called if field is part of a message type
153      * already in a pool.
154      */
155     @JRubyMethod(name = "type=")
setType(ThreadContext context, IRubyObject value)156     public IRubyObject setType(ThreadContext context, IRubyObject value) {
157         this.builder.setType(DescriptorProtos.FieldDescriptorProto.Type.valueOf("TYPE_" + value.asJavaString().toUpperCase()));
158         return context.runtime.getNil();
159     }
160 
161     /*
162      * call-seq:
163      *     FieldDescriptor.number => number
164      *
165      * Returns this field's number, as a Ruby Integer, or nil if not yet set.
166      *
167      */
168     @JRubyMethod(name = "number")
getnumber(ThreadContext context)169     public IRubyObject getnumber(ThreadContext context) {
170         return this.number;
171     }
172 
173     /*
174      * call-seq:
175      *     FieldDescriptor.number = number
176      *
177      * Sets the tag number for this field. Cannot be called if field is part of a
178      * message type already in a pool.
179      */
180     @JRubyMethod(name = "number=")
setNumber(ThreadContext context, IRubyObject value)181     public IRubyObject setNumber(ThreadContext context, IRubyObject value) {
182         this.number = value;
183         this.builder.setNumber(RubyNumeric.num2int(value));
184         return context.runtime.getNil();
185     }
186 
187     /*
188      * call-seq:
189      *     FieldDescriptor.submsg_name = submsg_name
190      *
191      * Sets the name of the message or enum type corresponding to this field, if it
192      * is a message or enum field (respectively). This type name will be resolved
193      * within the context of the pool to which the containing message type is added.
194      * Cannot be called on field that are not of message or enum type, or on fields
195      * that are part of a message type already added to a pool.
196      */
197     @JRubyMethod(name = "submsg_name=")
setSubmsgName(ThreadContext context, IRubyObject name)198     public IRubyObject setSubmsgName(ThreadContext context, IRubyObject name) {
199         this.builder.setTypeName("." + Utils.escapeIdentifier(name.asJavaString()));
200         return context.runtime.getNil();
201     }
202 
203     /*
204      * call-seq:
205      *     FieldDescriptor.get(message) => value
206      *
207      * Returns the value set for this field on the given message. Raises an
208      * exception if message is of the wrong type.
209      */
210     @JRubyMethod(name = "get")
getValue(ThreadContext context, IRubyObject msgRb)211     public IRubyObject getValue(ThreadContext context, IRubyObject msgRb) {
212         RubyMessage message = (RubyMessage) msgRb;
213         if (message.getDescriptor() != fieldDef.getContainingType()) {
214             throw context.runtime.newTypeError("set method called on wrong message type");
215         }
216         return message.getField(context, fieldDef);
217     }
218 
219     /*
220      * call-seq:
221      *     FieldDescriptor.set(message, value)
222      *
223      * Sets the value corresponding to this field to the given value on the given
224      * message. Raises an exception if message is of the wrong type. Performs the
225      * ordinary type-checks for field setting.
226      */
227     @JRubyMethod(name = "set")
setValue(ThreadContext context, IRubyObject msgRb, IRubyObject value)228     public IRubyObject setValue(ThreadContext context, IRubyObject msgRb, IRubyObject value) {
229         RubyMessage message = (RubyMessage) msgRb;
230         if (message.getDescriptor() != fieldDef.getContainingType()) {
231             throw context.runtime.newTypeError("set method called on wrong message type");
232         }
233         message.setField(context, fieldDef, value);
234         return context.runtime.getNil();
235     }
236 
setSubType(IRubyObject rubyDescriptor)237     protected void setSubType(IRubyObject rubyDescriptor) {
238         this.subType = rubyDescriptor;
239     }
240 
setFieldDef(Descriptors.FieldDescriptor fieldDescriptor)241     protected void setFieldDef(Descriptors.FieldDescriptor fieldDescriptor) {
242         this.fieldDef = fieldDescriptor;
243     }
244 
setOneofName(IRubyObject name)245     protected void setOneofName(IRubyObject name) {
246         oneofName = name;
247     }
248 
setOneofIndex(int index)249     protected void setOneofIndex(int index) {
250         hasOneofIndex = true;
251         oneofIndex = index;
252     }
253 
getOneofName()254     protected IRubyObject getOneofName() {
255         return oneofName;
256     }
257 
getFieldDef()258     protected Descriptors.FieldDescriptor getFieldDef() {
259         return fieldDef;
260     }
261 
build()262     protected DescriptorProtos.FieldDescriptorProto build() {
263         if (hasOneofIndex)
264             builder.setOneofIndex(oneofIndex);
265         return this.builder.build();
266     }
267 
268     private DescriptorProtos.FieldDescriptorProto.Builder builder;
269     private IRubyObject name;
270     private IRubyObject label;
271     private IRubyObject number;
272     private IRubyObject subType;
273     private IRubyObject oneofName;
274     private Descriptors.FieldDescriptor fieldDef;
275     private int oneofIndex;
276     private boolean hasOneofIndex = false;
277 }
278