1 /*
2  * Copyright (c) 2009-2021, Google LLC
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *     * Redistributions of source code must retain the above copyright
8  *       notice, this list of conditions and the following disclaimer.
9  *     * Redistributions in binary form must reproduce the above copyright
10  *       notice, this list of conditions and the following disclaimer in the
11  *       documentation and/or other materials provided with the distribution.
12  *     * Neither the name of Google LLC nor the
13  *       names of its contributors may be used to endorse or promote products
14  *       derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT,
20  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include "upb/reflection/def_builder_internal.h"
29 #include "upb/reflection/def_type.h"
30 #include "upb/reflection/enum_def_internal.h"
31 #include "upb/reflection/enum_value_def_internal.h"
32 #include "upb/reflection/file_def_internal.h"
33 
34 // Must be last.
35 #include "upb/port/def.inc"
36 
37 struct upb_EnumValueDef {
38   const UPB_DESC(EnumValueOptions) * opts;
39   const upb_EnumDef* parent;
40   const char* full_name;
41   int32_t number;
42 };
43 
_upb_EnumValueDef_At(const upb_EnumValueDef * v,int i)44 upb_EnumValueDef* _upb_EnumValueDef_At(const upb_EnumValueDef* v, int i) {
45   return (upb_EnumValueDef*)&v[i];
46 }
47 
_upb_EnumValueDef_Compare(const void * p1,const void * p2)48 static int _upb_EnumValueDef_Compare(const void* p1, const void* p2) {
49   const uint32_t v1 = (*(const upb_EnumValueDef**)p1)->number;
50   const uint32_t v2 = (*(const upb_EnumValueDef**)p2)->number;
51   return (v1 < v2) ? -1 : (v1 > v2);
52 }
53 
_upb_EnumValueDefs_Sorted(const upb_EnumValueDef * v,int n,upb_Arena * a)54 const upb_EnumValueDef** _upb_EnumValueDefs_Sorted(const upb_EnumValueDef* v,
55                                                    int n, upb_Arena* a) {
56   // TODO: Try to replace this arena alloc with a persistent scratch buffer.
57   upb_EnumValueDef** out =
58       (upb_EnumValueDef**)upb_Arena_Malloc(a, n * sizeof(void*));
59   if (!out) return NULL;
60 
61   for (int i = 0; i < n; i++) {
62     out[i] = (upb_EnumValueDef*)&v[i];
63   }
64   qsort(out, n, sizeof(void*), _upb_EnumValueDef_Compare);
65 
66   return (const upb_EnumValueDef**)out;
67 }
68 
UPB_DESC(EnumValueOptions)69 const UPB_DESC(EnumValueOptions) *
70     upb_EnumValueDef_Options(const upb_EnumValueDef* v) {
71   return v->opts;
72 }
73 
upb_EnumValueDef_HasOptions(const upb_EnumValueDef * v)74 bool upb_EnumValueDef_HasOptions(const upb_EnumValueDef* v) {
75   return v->opts != (void*)kUpbDefOptDefault;
76 }
77 
upb_EnumValueDef_Enum(const upb_EnumValueDef * v)78 const upb_EnumDef* upb_EnumValueDef_Enum(const upb_EnumValueDef* v) {
79   return v->parent;
80 }
81 
upb_EnumValueDef_FullName(const upb_EnumValueDef * v)82 const char* upb_EnumValueDef_FullName(const upb_EnumValueDef* v) {
83   return v->full_name;
84 }
85 
upb_EnumValueDef_Name(const upb_EnumValueDef * v)86 const char* upb_EnumValueDef_Name(const upb_EnumValueDef* v) {
87   return _upb_DefBuilder_FullToShort(v->full_name);
88 }
89 
upb_EnumValueDef_Number(const upb_EnumValueDef * v)90 int32_t upb_EnumValueDef_Number(const upb_EnumValueDef* v) { return v->number; }
91 
upb_EnumValueDef_Index(const upb_EnumValueDef * v)92 uint32_t upb_EnumValueDef_Index(const upb_EnumValueDef* v) {
93   // Compute index in our parent's array.
94   return v - upb_EnumDef_Value(v->parent, 0);
95 }
96 
create_enumvaldef(upb_DefBuilder * ctx,const char * prefix,const UPB_DESC (EnumValueDescriptorProto)* val_proto,upb_EnumDef * e,upb_EnumValueDef * v)97 static void create_enumvaldef(upb_DefBuilder* ctx, const char* prefix,
98                               const UPB_DESC(EnumValueDescriptorProto) *
99                                   val_proto,
100                               upb_EnumDef* e, upb_EnumValueDef* v) {
101   upb_StringView name = UPB_DESC(EnumValueDescriptorProto_name)(val_proto);
102 
103   v->parent = e;  // Must happen prior to _upb_DefBuilder_Add()
104   v->full_name = _upb_DefBuilder_MakeFullName(ctx, prefix, name);
105   v->number = UPB_DESC(EnumValueDescriptorProto_number)(val_proto);
106   _upb_DefBuilder_Add(ctx, v->full_name,
107                       _upb_DefType_Pack(v, UPB_DEFTYPE_ENUMVAL));
108 
109   UPB_DEF_SET_OPTIONS(v->opts, EnumValueDescriptorProto, EnumValueOptions,
110                       val_proto);
111 
112   bool ok = _upb_EnumDef_Insert(e, v, ctx->arena);
113   if (!ok) _upb_DefBuilder_OomErr(ctx);
114 }
115 
116 // Allocate and initialize an array of |n| enum value defs owned by |e|.
_upb_EnumValueDefs_New(upb_DefBuilder * ctx,const char * prefix,int n,const UPB_DESC (EnumValueDescriptorProto)* const * protos,upb_EnumDef * e,bool * is_sorted)117 upb_EnumValueDef* _upb_EnumValueDefs_New(
118     upb_DefBuilder* ctx, const char* prefix, int n,
119     const UPB_DESC(EnumValueDescriptorProto) * const* protos, upb_EnumDef* e,
120     bool* is_sorted) {
121   _upb_DefType_CheckPadding(sizeof(upb_EnumValueDef));
122 
123   upb_EnumValueDef* v =
124       _upb_DefBuilder_Alloc(ctx, sizeof(upb_EnumValueDef) * n);
125 
126   *is_sorted = true;
127   uint32_t previous = 0;
128   for (size_t i = 0; i < n; i++) {
129     create_enumvaldef(ctx, prefix, protos[i], e, &v[i]);
130 
131     const uint32_t current = v[i].number;
132     if (previous > current) *is_sorted = false;
133     previous = current;
134   }
135 
136   if (upb_FileDef_Syntax(ctx->file) == kUpb_Syntax_Proto3 && n > 0 &&
137       v[0].number != 0) {
138     _upb_DefBuilder_Errf(ctx,
139                          "for proto3, the first enum value must be zero (%s)",
140                          upb_EnumDef_FullName(e));
141   }
142 
143   return v;
144 }
145