1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2023 Google LLC. All rights reserved.
3 //
4 // Use of this source code is governed by a BSD-style
5 // license that can be found in the LICENSE file or at
6 // https://developers.google.com/open-source/licenses/bsd
7
8 #include "upb/reflection/internal/enum_value_def.h"
9
10 #include <stdint.h>
11
12 #include "upb/reflection/def_type.h"
13 #include "upb/reflection/enum_def.h"
14 #include "upb/reflection/enum_value_def.h"
15 #include "upb/reflection/file_def.h"
16 #include "upb/reflection/internal/def_builder.h"
17 #include "upb/reflection/internal/enum_def.h"
18
19 // Must be last.
20 #include "upb/port/def.inc"
21
22 struct upb_EnumValueDef {
23 const UPB_DESC(EnumValueOptions*) opts;
24 const UPB_DESC(FeatureSet*) resolved_features;
25 const upb_EnumDef* parent;
26 const char* full_name;
27 int32_t number;
28 #if UINTPTR_MAX == 0xffffffff
29 uint32_t padding; // Increase size to a multiple of 8.
30 #endif
31 };
32
_upb_EnumValueDef_At(const upb_EnumValueDef * v,int i)33 upb_EnumValueDef* _upb_EnumValueDef_At(const upb_EnumValueDef* v, int i) {
34 return (upb_EnumValueDef*)&v[i];
35 }
36
_upb_EnumValueDef_Compare(const void * p1,const void * p2)37 static int _upb_EnumValueDef_Compare(const void* p1, const void* p2) {
38 const uint32_t v1 = (*(const upb_EnumValueDef**)p1)->number;
39 const uint32_t v2 = (*(const upb_EnumValueDef**)p2)->number;
40 return (v1 < v2) ? -1 : (v1 > v2);
41 }
42
_upb_EnumValueDefs_Sorted(const upb_EnumValueDef * v,int n,upb_Arena * a)43 const upb_EnumValueDef** _upb_EnumValueDefs_Sorted(const upb_EnumValueDef* v,
44 int n, upb_Arena* a) {
45 // TODO: Try to replace this arena alloc with a persistent scratch buffer.
46 upb_EnumValueDef** out =
47 (upb_EnumValueDef**)upb_Arena_Malloc(a, n * sizeof(void*));
48 if (!out) return NULL;
49
50 for (int i = 0; i < n; i++) {
51 out[i] = (upb_EnumValueDef*)&v[i];
52 }
53 qsort(out, n, sizeof(void*), _upb_EnumValueDef_Compare);
54
55 return (const upb_EnumValueDef**)out;
56 }
57
UPB_DESC(EnumValueOptions)58 const UPB_DESC(EnumValueOptions) *
59 upb_EnumValueDef_Options(const upb_EnumValueDef* v) {
60 return v->opts;
61 }
62
upb_EnumValueDef_HasOptions(const upb_EnumValueDef * v)63 bool upb_EnumValueDef_HasOptions(const upb_EnumValueDef* v) {
64 return v->opts != (void*)kUpbDefOptDefault;
65 }
66
UPB_DESC(FeatureSet)67 const UPB_DESC(FeatureSet) *
68 upb_EnumValueDef_ResolvedFeatures(const upb_EnumValueDef* e) {
69 return e->resolved_features;
70 }
71
upb_EnumValueDef_Enum(const upb_EnumValueDef * v)72 const upb_EnumDef* upb_EnumValueDef_Enum(const upb_EnumValueDef* v) {
73 return v->parent;
74 }
75
upb_EnumValueDef_FullName(const upb_EnumValueDef * v)76 const char* upb_EnumValueDef_FullName(const upb_EnumValueDef* v) {
77 return v->full_name;
78 }
79
upb_EnumValueDef_Name(const upb_EnumValueDef * v)80 const char* upb_EnumValueDef_Name(const upb_EnumValueDef* v) {
81 return _upb_DefBuilder_FullToShort(v->full_name);
82 }
83
upb_EnumValueDef_Number(const upb_EnumValueDef * v)84 int32_t upb_EnumValueDef_Number(const upb_EnumValueDef* v) { return v->number; }
85
upb_EnumValueDef_Index(const upb_EnumValueDef * v)86 uint32_t upb_EnumValueDef_Index(const upb_EnumValueDef* v) {
87 // Compute index in our parent's array.
88 return v - upb_EnumDef_Value(v->parent, 0);
89 }
90
create_enumvaldef(upb_DefBuilder * ctx,const char * prefix,const UPB_DESC (EnumValueDescriptorProto *)val_proto,const UPB_DESC (FeatureSet *)parent_features,upb_EnumDef * e,upb_EnumValueDef * v)91 static void create_enumvaldef(upb_DefBuilder* ctx, const char* prefix,
92 const UPB_DESC(EnumValueDescriptorProto*)
93 val_proto,
94 const UPB_DESC(FeatureSet*) parent_features,
95 upb_EnumDef* e, upb_EnumValueDef* v) {
96 UPB_DEF_SET_OPTIONS(v->opts, EnumValueDescriptorProto, EnumValueOptions,
97 val_proto);
98 v->resolved_features = _upb_DefBuilder_ResolveFeatures(
99 ctx, parent_features, UPB_DESC(EnumValueOptions_features)(v->opts));
100
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 bool ok = _upb_EnumDef_Insert(e, v, ctx->arena);
110 if (!ok) _upb_DefBuilder_OomErr(ctx);
111 }
112
_upb_EnumValueDef_CheckZeroValue(upb_DefBuilder * ctx,const upb_EnumDef * e,const upb_EnumValueDef * v,int n)113 static void _upb_EnumValueDef_CheckZeroValue(upb_DefBuilder* ctx,
114 const upb_EnumDef* e,
115 const upb_EnumValueDef* v, int n) {
116 // When the special UPB_TREAT_CLOSED_ENUMS_LIKE_OPEN is enabled, we have to
117 // exempt closed enums from this check, even when we are treating them as
118 // open.
119 if (upb_EnumDef_IsSpecifiedAsClosed(e) || n == 0 || v[0].number == 0) return;
120
121 _upb_DefBuilder_Errf(ctx, "for open enums, the first value must be zero (%s)",
122 upb_EnumDef_FullName(e));
123 }
124
125 // 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,const UPB_DESC (FeatureSet *)parent_features,upb_EnumDef * e,bool * is_sorted)126 upb_EnumValueDef* _upb_EnumValueDefs_New(
127 upb_DefBuilder* ctx, const char* prefix, int n,
128 const UPB_DESC(EnumValueDescriptorProto*) const* protos,
129 const UPB_DESC(FeatureSet*) parent_features, upb_EnumDef* e,
130 bool* is_sorted) {
131 _upb_DefType_CheckPadding(sizeof(upb_EnumValueDef));
132
133 upb_EnumValueDef* v =
134 _upb_DefBuilder_Alloc(ctx, sizeof(upb_EnumValueDef) * n);
135
136 *is_sorted = true;
137 uint32_t previous = 0;
138 for (int i = 0; i < n; i++) {
139 create_enumvaldef(ctx, prefix, protos[i], parent_features, e, &v[i]);
140
141 const uint32_t current = v[i].number;
142 if (previous > current) *is_sorted = false;
143 previous = current;
144 }
145
146 _upb_EnumValueDef_CheckZeroValue(ctx, e, v, n);
147
148 return v;
149 }
150