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