xref: /aosp_15_r20/external/grpc-grpc/third_party/upb/upb/mini_descriptor/link.c (revision cc02d7e222339f7a4f6ba5f422e6413f4bd931f2)
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/mini_descriptor/link.h"
9 
10 #include <stddef.h>
11 #include <stdint.h>
12 
13 #include "upb/base/descriptor_constants.h"
14 #include "upb/mini_table/enum.h"
15 #include "upb/mini_table/field.h"
16 #include "upb/mini_table/message.h"
17 #include "upb/mini_table/sub.h"
18 
19 // Must be last.
20 #include "upb/port/def.inc"
21 
upb_MiniTable_SetSubMessage(upb_MiniTable * table,upb_MiniTableField * field,const upb_MiniTable * sub)22 bool upb_MiniTable_SetSubMessage(upb_MiniTable* table,
23                                  upb_MiniTableField* field,
24                                  const upb_MiniTable* sub) {
25   UPB_ASSERT((uintptr_t)table->UPB_PRIVATE(fields) <= (uintptr_t)field &&
26              (uintptr_t)field < (uintptr_t)(table->UPB_PRIVATE(fields) +
27                                             table->UPB_PRIVATE(field_count)));
28   UPB_ASSERT(sub);
29 
30   const bool sub_is_map = sub->UPB_PRIVATE(ext) & kUpb_ExtMode_IsMapEntry;
31 
32   switch (field->UPB_PRIVATE(descriptortype)) {
33     case kUpb_FieldType_Message:
34       if (sub_is_map) {
35         const bool table_is_map =
36             table->UPB_PRIVATE(ext) & kUpb_ExtMode_IsMapEntry;
37         if (UPB_UNLIKELY(table_is_map)) return false;
38 
39         field->UPB_PRIVATE(mode) =
40             (field->UPB_PRIVATE(mode) & ~kUpb_FieldMode_Mask) |
41             kUpb_FieldMode_Map;
42       }
43       break;
44 
45     case kUpb_FieldType_Group:
46       if (UPB_UNLIKELY(sub_is_map)) return false;
47       break;
48 
49     default:
50       return false;
51   }
52 
53   upb_MiniTableSub* table_sub =
54       (void*)&table->UPB_PRIVATE(subs)[field->UPB_PRIVATE(submsg_index)];
55   // TODO: Add this assert back once YouTube is updated to not call
56   // this function repeatedly.
57   // UPB_ASSERT(UPB_PRIVATE(_upb_MiniTable_IsEmpty)(table_sub->submsg));
58   *table_sub = upb_MiniTableSub_FromMessage(sub);
59   return true;
60 }
61 
upb_MiniTable_SetSubEnum(upb_MiniTable * table,upb_MiniTableField * field,const upb_MiniTableEnum * sub)62 bool upb_MiniTable_SetSubEnum(upb_MiniTable* table, upb_MiniTableField* field,
63                               const upb_MiniTableEnum* sub) {
64   UPB_ASSERT((uintptr_t)table->UPB_PRIVATE(fields) <= (uintptr_t)field &&
65              (uintptr_t)field < (uintptr_t)(table->UPB_PRIVATE(fields) +
66                                             table->UPB_PRIVATE(field_count)));
67   UPB_ASSERT(sub);
68 
69   upb_MiniTableSub* table_sub =
70       (void*)&table->UPB_PRIVATE(subs)[field->UPB_PRIVATE(submsg_index)];
71   *table_sub = upb_MiniTableSub_FromEnum(sub);
72   return true;
73 }
74 
upb_MiniTable_GetSubList(const upb_MiniTable * mt,const upb_MiniTableField ** subs)75 uint32_t upb_MiniTable_GetSubList(const upb_MiniTable* mt,
76                                   const upb_MiniTableField** subs) {
77   uint32_t msg_count = 0;
78   uint32_t enum_count = 0;
79 
80   for (int i = 0; i < mt->UPB_PRIVATE(field_count); i++) {
81     const upb_MiniTableField* f = &mt->UPB_PRIVATE(fields)[i];
82     if (upb_MiniTableField_CType(f) == kUpb_CType_Message) {
83       *subs = f;
84       ++subs;
85       msg_count++;
86     }
87   }
88 
89   for (int i = 0; i < mt->UPB_PRIVATE(field_count); i++) {
90     const upb_MiniTableField* f = &mt->UPB_PRIVATE(fields)[i];
91     if (upb_MiniTableField_CType(f) == kUpb_CType_Enum) {
92       *subs = f;
93       ++subs;
94       enum_count++;
95     }
96   }
97 
98   return (msg_count << 16) | enum_count;
99 }
100 
101 // The list of sub_tables and sub_enums must exactly match the number and order
102 // of sub-message fields and sub-enum fields given by upb_MiniTable_GetSubList()
103 // above.
upb_MiniTable_Link(upb_MiniTable * mt,const upb_MiniTable ** sub_tables,size_t sub_table_count,const upb_MiniTableEnum ** sub_enums,size_t sub_enum_count)104 bool upb_MiniTable_Link(upb_MiniTable* mt, const upb_MiniTable** sub_tables,
105                         size_t sub_table_count,
106                         const upb_MiniTableEnum** sub_enums,
107                         size_t sub_enum_count) {
108   uint32_t msg_count = 0;
109   uint32_t enum_count = 0;
110 
111   for (int i = 0; i < mt->UPB_PRIVATE(field_count); i++) {
112     upb_MiniTableField* f = (upb_MiniTableField*)&mt->UPB_PRIVATE(fields)[i];
113     if (upb_MiniTableField_CType(f) == kUpb_CType_Message) {
114       const upb_MiniTable* sub = sub_tables[msg_count++];
115       if (msg_count > sub_table_count) return false;
116       if (sub != NULL) {
117         if (!upb_MiniTable_SetSubMessage(mt, f, sub)) return false;
118       }
119     }
120   }
121 
122   for (int i = 0; i < mt->UPB_PRIVATE(field_count); i++) {
123     upb_MiniTableField* f = (upb_MiniTableField*)&mt->UPB_PRIVATE(fields)[i];
124     if (upb_MiniTableField_IsClosedEnum(f)) {
125       const upb_MiniTableEnum* sub = sub_enums[enum_count++];
126       if (enum_count > sub_enum_count) return false;
127       if (sub != NULL) {
128         if (!upb_MiniTable_SetSubEnum(mt, f, sub)) return false;
129       }
130     }
131   }
132 
133   return true;
134 }
135