xref: /aosp_15_r20/external/protobuf/php/src/Google/Protobuf/Internal/FieldDescriptor.php (revision 1b3f573f81763fcece89efc2b6a5209149e44ab8)
1<?php
2
3// Protocol Buffers - Google's data interchange format
4// Copyright 2008 Google Inc.  All rights reserved.
5// https://developers.google.com/protocol-buffers/
6//
7// Redistribution and use in source and binary forms, with or without
8// modification, are permitted provided that the following conditions are
9// met:
10//
11//     * Redistributions of source code must retain the above copyright
12// notice, this list of conditions and the following disclaimer.
13//     * Redistributions in binary form must reproduce the above
14// copyright notice, this list of conditions and the following disclaimer
15// in the documentation and/or other materials provided with the
16// distribution.
17//     * Neither the name of Google Inc. nor the names of its
18// contributors may be used to endorse or promote products derived from
19// this software without specific prior written permission.
20//
21// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32
33namespace Google\Protobuf\Internal;
34
35class FieldDescriptor
36{
37    use HasPublicDescriptorTrait;
38
39    private $name;
40    private $json_name;
41    private $setter;
42    private $getter;
43    private $number;
44    private $label;
45    private $type;
46    private $message_type;
47    private $enum_type;
48    private $packed;
49    private $oneof_index = -1;
50    private $proto3_optional;
51
52    /** @var OneofDescriptor $containing_oneof */
53    private $containing_oneof;
54
55    public function __construct()
56    {
57        $this->public_desc = new \Google\Protobuf\FieldDescriptor($this);
58    }
59
60    public function setOneofIndex($index)
61    {
62        $this->oneof_index = $index;
63    }
64
65    public function getOneofIndex()
66    {
67        return $this->oneof_index;
68    }
69
70    public function setName($name)
71    {
72        $this->name = $name;
73    }
74
75    public function getName()
76    {
77        return $this->name;
78    }
79
80    public function setJsonName($json_name)
81    {
82        $this->json_name = $json_name;
83    }
84
85    public function getJsonName()
86    {
87        return $this->json_name;
88    }
89
90    public function setSetter($setter)
91    {
92        $this->setter = $setter;
93    }
94
95    public function getSetter()
96    {
97        return $this->setter;
98    }
99
100    public function setGetter($getter)
101    {
102        $this->getter = $getter;
103    }
104
105    public function getGetter()
106    {
107        return $this->getter;
108    }
109
110    public function setNumber($number)
111    {
112        $this->number = $number;
113    }
114
115    public function getNumber()
116    {
117        return $this->number;
118    }
119
120    public function setLabel($label)
121    {
122        $this->label = $label;
123    }
124
125    public function getLabel()
126    {
127        return $this->label;
128    }
129
130    public function isRepeated()
131    {
132        return $this->label === GPBLabel::REPEATED;
133    }
134
135    public function setType($type)
136    {
137        $this->type = $type;
138    }
139
140    public function getType()
141    {
142        return $this->type;
143    }
144
145    public function setMessageType($message_type)
146    {
147        $this->message_type = $message_type;
148    }
149
150    public function getMessageType()
151    {
152        return $this->message_type;
153    }
154
155    public function setEnumType($enum_type)
156    {
157        $this->enum_type = $enum_type;
158    }
159
160    public function getEnumType()
161    {
162        return $this->enum_type;
163    }
164
165    public function setPacked($packed)
166    {
167        $this->packed = $packed;
168    }
169
170    public function getPacked()
171    {
172        return $this->packed;
173    }
174
175    public function getProto3Optional()
176    {
177        return $this->proto3_optional;
178    }
179
180    public function setProto3Optional($proto3_optional)
181    {
182        $this->proto3_optional = $proto3_optional;
183    }
184
185    public function getContainingOneof()
186    {
187        return $this->containing_oneof;
188    }
189
190    public function setContainingOneof($containing_oneof)
191    {
192        $this->containing_oneof = $containing_oneof;
193    }
194
195    public function getRealContainingOneof()
196    {
197        return !is_null($this->containing_oneof) && !$this->containing_oneof->isSynthetic()
198            ? $this->containing_oneof : null;
199    }
200
201    public function isPackable()
202    {
203        return $this->isRepeated() && self::isTypePackable($this->type);
204    }
205
206    public function isMap()
207    {
208        return $this->getType() == GPBType::MESSAGE &&
209               !is_null($this->getMessageType()->getOptions()) &&
210               $this->getMessageType()->getOptions()->getMapEntry();
211    }
212
213    public function isTimestamp()
214    {
215        return $this->getType() == GPBType::MESSAGE &&
216            $this->getMessageType()->getClass() === "Google\Protobuf\Timestamp";
217    }
218
219    public function isWrapperType()
220    {
221        if ($this->getType() == GPBType::MESSAGE) {
222            $class = $this->getMessageType()->getClass();
223            return in_array($class, [
224                "Google\Protobuf\DoubleValue",
225                "Google\Protobuf\FloatValue",
226                "Google\Protobuf\Int64Value",
227                "Google\Protobuf\UInt64Value",
228                "Google\Protobuf\Int32Value",
229                "Google\Protobuf\UInt32Value",
230                "Google\Protobuf\BoolValue",
231                "Google\Protobuf\StringValue",
232                "Google\Protobuf\BytesValue",
233            ]);
234        }
235        return false;
236    }
237
238    private static function isTypePackable($field_type)
239    {
240        return ($field_type !== GPBType::STRING  &&
241            $field_type !== GPBType::GROUP   &&
242            $field_type !== GPBType::MESSAGE &&
243            $field_type !== GPBType::BYTES);
244    }
245
246    /**
247     * @param FieldDescriptorProto $proto
248     * @return FieldDescriptor
249     */
250    public static function getFieldDescriptor($proto)
251    {
252        $type_name = null;
253        $type = $proto->getType();
254        switch ($type) {
255            case GPBType::MESSAGE:
256            case GPBType::GROUP:
257            case GPBType::ENUM:
258                $type_name = $proto->getTypeName();
259                break;
260            default:
261                break;
262        }
263
264        $oneof_index = $proto->hasOneofIndex() ? $proto->getOneofIndex() : -1;
265        // TODO: once proto2 is supported, this default should be false
266        // for proto2.
267        if ($proto->getLabel() === GPBLabel::REPEATED &&
268            $proto->getType() !== GPBType::MESSAGE &&
269            $proto->getType() !== GPBType::GROUP &&
270            $proto->getType() !== GPBType::STRING &&
271            $proto->getType() !== GPBType::BYTES) {
272          $packed = true;
273        } else {
274          $packed = false;
275        }
276        $options = $proto->getOptions();
277        if ($options !== null) {
278            $packed = $options->getPacked();
279        }
280
281        $field = new FieldDescriptor();
282        $field->setName($proto->getName());
283
284        if ($proto->hasJsonName()) {
285            $json_name = $proto->getJsonName();
286        } else {
287            $proto_name = $proto->getName();
288            $json_name = implode('', array_map('ucwords', explode('_', $proto_name)));
289            if ($proto_name[0] !== "_" && !ctype_upper($proto_name[0])) {
290                $json_name = lcfirst($json_name);
291            }
292        }
293        $field->setJsonName($json_name);
294
295        $camel_name = implode('', array_map('ucwords', explode('_', $proto->getName())));
296        $field->setGetter('get' . $camel_name);
297        $field->setSetter('set' . $camel_name);
298        $field->setType($proto->getType());
299        $field->setNumber($proto->getNumber());
300        $field->setLabel($proto->getLabel());
301        $field->setPacked($packed);
302        $field->setOneofIndex($oneof_index);
303        $field->setProto3Optional($proto->getProto3Optional());
304
305        // At this time, the message/enum type may have not been added to pool.
306        // So we use the type name as place holder and will replace it with the
307        // actual descriptor in cross building.
308        switch ($type) {
309            case GPBType::MESSAGE:
310                $field->setMessageType($type_name);
311                break;
312            case GPBType::ENUM:
313                $field->setEnumType($type_name);
314                break;
315            default:
316                break;
317        }
318
319        return $field;
320    }
321
322    public static function buildFromProto($proto)
323    {
324        return FieldDescriptor::getFieldDescriptor($proto);
325    }
326}
327