blob: 9021c789fcdb9639c3947838d87741bf3594ab6e [file] [log] [blame]
Austin Schuh43c6a352019-09-30 22:22:10 -07001#include "aos/flatbuffer_utils.h"
Brian Silvermancf4fb662021-02-10 17:54:53 -08002
Austin Schuh99f7c6a2024-06-25 22:07:44 -07003#include "absl/log/check.h"
4#include "absl/log/log.h"
Brian Silvermancf4fb662021-02-10 17:54:53 -08005#include "flatbuffers/minireflect.h"
Brian Silvermanc5105ab2021-02-10 17:55:38 -08006#include "flatbuffers/reflection_generated.h"
Brian Silvermancf4fb662021-02-10 17:54:53 -08007
8namespace aos {
9
Austin Schuh6bdcc372024-06-27 14:49:11 -070010FlatbufferType::FlatbufferType(const flatbuffers::TypeTable *type_table) {
11 CHECK(type_table != nullptr);
12 type_table_ = type_table;
13}
14FlatbufferType::FlatbufferType(const reflection::Schema *schema) {
15 CHECK(schema != nullptr);
16 schema_ = schema;
17 DCHECK(schema->root_table() != nullptr);
18 object_ = schema->root_table();
19}
20
21FlatbufferType::FlatbufferType(const reflection::Schema *schema,
22 const reflection::Object *object) {
23 CHECK(schema != nullptr);
24 schema_ = schema;
25 DCHECK(object != nullptr);
26 object_ = object;
27}
28
29FlatbufferType::FlatbufferType(const reflection::Schema *schema,
30 const reflection::Enum *fb_enum) {
31 CHECK(schema != nullptr);
32 schema_ = schema;
33 CHECK(fb_enum != nullptr);
34 enum_ = fb_enum;
35}
36
Brian Silvermancf4fb662021-02-10 17:54:53 -080037bool FlatbufferType::IsSequence() const {
38 if (type_table_) {
39 return type_table_->st != flatbuffers::ST_ENUM;
40 }
Brian Silvermanc5105ab2021-02-10 17:55:38 -080041 if (object_) {
42 return true;
43 }
44 if (enum_) {
45 return enum_->is_union();
46 }
Brian Silvermancf4fb662021-02-10 17:54:53 -080047 LOG(FATAL) << "Unimplemented";
48}
49
James Kuszmaul768c4682023-10-12 21:07:16 -070050bool FlatbufferType::IsTable() const {
51 if (type_table_) {
52 return type_table_->st == flatbuffers::ST_TABLE;
53 }
54 if (object_) {
55 return !object_->is_struct();
56 }
57 LOG(FATAL) << "Unimplemented";
58}
59
60bool FlatbufferType::IsStruct() const {
61 if (type_table_) {
62 return type_table_->st == flatbuffers::ST_STRUCT;
63 }
64 if (object_) {
65 return object_->is_struct();
66 }
67 LOG(FATAL) << "Unimplemented";
68}
69
Brian Silvermancf4fb662021-02-10 17:54:53 -080070bool FlatbufferType::IsEnum() const {
71 if (type_table_) {
72 return type_table_->st == flatbuffers::ST_ENUM;
73 }
Brian Silvermanc5105ab2021-02-10 17:55:38 -080074 if (object_) {
75 return false;
76 }
77 if (enum_) {
78 return !enum_->is_union();
79 }
Brian Silvermancf4fb662021-02-10 17:54:53 -080080 LOG(FATAL) << "Unimplemented";
81}
82
83bool FlatbufferType::FieldIsSequence(int index) const {
84 DCHECK(IsSequence());
85 if (type_table_) {
86 DCHECK_LT(static_cast<size_t>(index), type_table_->num_elems);
87 const flatbuffers::TypeCode &type_code = type_table_->type_codes[index];
88 if (type_code.base_type != flatbuffers::ET_SEQUENCE) {
89 return false;
90 }
91 DCHECK(FieldType(index).IsSequence());
92 return true;
93 }
Brian Silvermanc5105ab2021-02-10 17:55:38 -080094 if (object_ || enum_) {
95 const reflection::BaseType base_type = ReflectionElementBaseType(index);
96 return base_type == reflection::BaseType::Obj ||
97 base_type == reflection::BaseType::Union;
98 }
Brian Silvermancf4fb662021-02-10 17:54:53 -080099 LOG(FATAL) << "Unimplemented";
100}
101
102bool FlatbufferType::FieldIsEnum(int index) const {
103 DCHECK(IsSequence());
104 if (type_table_) {
105 DCHECK_LT(static_cast<size_t>(index), type_table_->num_elems);
106 const flatbuffers::TypeCode &type_code = type_table_->type_codes[index];
107 if (type_code.base_type == flatbuffers::ET_SEQUENCE) {
108 return false;
109 }
110 if (type_code.sequence_ref == -1) {
111 // Not an enum.
112 return false;
113 }
114 DCHECK(FieldType(index).IsEnum());
115 return true;
116 }
Brian Silvermanc5105ab2021-02-10 17:55:38 -0800117 if (object_ || enum_) {
118 const reflection::BaseType base_type = ReflectionElementBaseType(index);
119 if (base_type == reflection::BaseType::Obj ||
120 base_type == reflection::BaseType::Union) {
121 return false;
122 }
123 return ReflectionType(index)->index() >= 0;
124 }
Brian Silvermancf4fb662021-02-10 17:54:53 -0800125 LOG(FATAL) << "Unimplemented";
126}
127
128std::optional<int64_t> FlatbufferType::EnumValue(std::string_view name) const {
129 DCHECK(IsEnum());
Brian Silvermanc5105ab2021-02-10 17:55:38 -0800130 DCHECK(!object_);
Brian Silvermancf4fb662021-02-10 17:54:53 -0800131 if (type_table_) {
132 for (size_t i = 0; i < type_table_->num_elems; ++i) {
133 if (name == type_table_->names[i]) {
134 if (type_table_->values) {
135 return type_table_->values[i];
136 } else {
137 return i;
138 }
139 }
140 }
141 return std::nullopt;
142 }
Brian Silvermanc5105ab2021-02-10 17:55:38 -0800143 if (enum_) {
144 for (size_t i = 0; i < enum_->values()->size(); ++i) {
145 const auto *const value = enum_->values()->Get(i);
146 if (name == value->name()->string_view()) {
147 return value->value();
148 }
149 }
150 return std::nullopt;
151 }
Brian Silvermancf4fb662021-02-10 17:54:53 -0800152 LOG(FATAL) << "Unimplemented";
153}
154
155bool FlatbufferType::FieldIsRepeating(int index) const {
156 DCHECK(IsSequence());
157 if (type_table_) {
158 DCHECK_LT(static_cast<size_t>(index), type_table_->num_elems);
159 const flatbuffers::TypeCode &type_code = type_table_->type_codes[index];
160 return type_code.is_repeating;
161 }
Brian Silvermanc5105ab2021-02-10 17:55:38 -0800162 if (object_ || enum_) {
163 const reflection::BaseType type = ReflectionType(index)->base_type();
164 CHECK(type != reflection::BaseType::None);
165 return type == reflection::BaseType::Vector ||
166 type == reflection::BaseType::Array;
167 }
Brian Silvermancf4fb662021-02-10 17:54:53 -0800168 LOG(FATAL) << "Unimplemented";
169}
170
171int FlatbufferType::FieldIndex(std::string_view field_name) const {
172 DCHECK(IsSequence());
173 if (type_table_) {
174 for (size_t i = 0; i < type_table_->num_elems; ++i) {
175 if (field_name == std::string_view(type_table_->names[i])) {
176 return i;
177 }
178 }
179 return -1;
180 }
Brian Silvermanc5105ab2021-02-10 17:55:38 -0800181 if (object_) {
182 for (size_t i = 0; i < object_->fields()->size(); ++i) {
183 const reflection::Field *const field = object_->fields()->Get(i);
184 if (field_name == field->name()->string_view()) {
185 return field->id();
186 }
187 }
188 return -1;
189 }
190 if (enum_) {
191 for (size_t i = 0; i < enum_->values()->size(); ++i) {
192 const reflection::EnumVal *const value = enum_->values()->Get(i);
193 if (field_name == value->name()->string_view()) {
194 return value->value();
195 }
196 }
197 return -1;
198 }
Brian Silvermancf4fb662021-02-10 17:54:53 -0800199 LOG(FATAL) << "Unimplemented";
200}
201
202std::string_view FlatbufferType::FieldName(int index) const {
203 DCHECK(IsSequence());
204 if (type_table_) {
205 DCHECK_LT(static_cast<size_t>(index), type_table_->num_elems);
206 return type_table_->names[index];
207 }
Brian Silvermanc5105ab2021-02-10 17:55:38 -0800208 if (object_) {
209 return ReflectionObjectField(index)->name()->string_view();
210 }
211 if (enum_) {
212 return ReflectionEnumValue(index)->name()->string_view();
213 }
Brian Silvermancf4fb662021-02-10 17:54:53 -0800214 LOG(FATAL) << "Unimplemented";
215}
216
Brian Silvermanc5105ab2021-02-10 17:55:38 -0800217namespace {
218
219flatbuffers::ElementaryType ElementaryTypeFromBaseType(
220 reflection::BaseType base_type) {
221 switch (base_type) {
222 case reflection::BaseType::None:
223 LOG(FATAL) << "Invalid schema";
224 case reflection::BaseType::UType:
225 return flatbuffers::ElementaryType::ET_UTYPE;
226 case reflection::BaseType::Bool:
227 return flatbuffers::ElementaryType::ET_BOOL;
228 case reflection::BaseType::Byte:
229 return flatbuffers::ElementaryType::ET_CHAR;
230 case reflection::BaseType::UByte:
231 return flatbuffers::ElementaryType::ET_UCHAR;
232 case reflection::BaseType::Short:
233 return flatbuffers::ElementaryType::ET_SHORT;
234 case reflection::BaseType::UShort:
235 return flatbuffers::ElementaryType::ET_USHORT;
236 case reflection::BaseType::Int:
237 return flatbuffers::ElementaryType::ET_INT;
238 case reflection::BaseType::UInt:
239 return flatbuffers::ElementaryType::ET_UINT;
240 case reflection::BaseType::Long:
241 return flatbuffers::ElementaryType::ET_LONG;
242 case reflection::BaseType::ULong:
243 return flatbuffers::ElementaryType::ET_ULONG;
244 case reflection::BaseType::Float:
245 return flatbuffers::ElementaryType::ET_FLOAT;
246 case reflection::BaseType::Double:
247 return flatbuffers::ElementaryType::ET_DOUBLE;
248 case reflection::BaseType::String:
249 return flatbuffers::ElementaryType::ET_STRING;
250 case reflection::BaseType::Obj:
251 return flatbuffers::ElementaryType::ET_SEQUENCE;
252 case reflection::BaseType::Union:
253 return flatbuffers::ElementaryType::ET_SEQUENCE;
254 default:
255 LOG(FATAL) << "Unknown BaseType";
256 }
257}
258
259} // namespace
260
Brian Silvermancf4fb662021-02-10 17:54:53 -0800261flatbuffers::ElementaryType FlatbufferType::FieldElementaryType(
262 int index) const {
263 DCHECK(IsSequence());
264 if (type_table_) {
265 DCHECK_LT(static_cast<size_t>(index), type_table_->num_elems);
266 const flatbuffers::TypeCode &type_code = type_table_->type_codes[index];
267 return static_cast<flatbuffers::ElementaryType>(type_code.base_type);
268 }
Brian Silvermanc5105ab2021-02-10 17:55:38 -0800269 if (object_ || enum_) {
270 return ElementaryTypeFromBaseType(ReflectionElementBaseType(index));
271 }
Brian Silvermancf4fb662021-02-10 17:54:53 -0800272 LOG(FATAL) << "Unimplemented";
273}
274
Brian Silvermanc5105ab2021-02-10 17:55:38 -0800275namespace {
276
277size_t BaseTypeInlineSize(reflection::BaseType base_type) {
278 switch (base_type) {
279 case reflection::BaseType::None:
280 LOG(FATAL) << "Invalid schema";
281 case reflection::BaseType::UType:
282 case reflection::BaseType::Bool:
283 case reflection::BaseType::Byte:
284 case reflection::BaseType::UByte:
285 return 1;
286 case reflection::BaseType::Short:
287 case reflection::BaseType::UShort:
288 return 2;
289 case reflection::BaseType::Int:
290 case reflection::BaseType::UInt:
291 case reflection::BaseType::Float:
292 case reflection::BaseType::String:
293 return 4;
294 case reflection::BaseType::Long:
295 case reflection::BaseType::ULong:
296 case reflection::BaseType::Double:
297 return 8;
298 case reflection::BaseType::Union:
299 return 4;
300 default:
301 LOG(FATAL) << "Unknown BaseType";
302 }
303}
304
305} // namespace
306
James Kuszmaul768c4682023-10-12 21:07:16 -0700307size_t FlatbufferType::InlineSize() const {
308 DCHECK(IsSequence());
309 if (type_table_) {
310 return flatbuffers::InlineSize(flatbuffers::ElementaryType::ET_SEQUENCE,
311 type_table_);
312 }
313 if (object_) {
314 return object_->is_struct() ? object_->bytesize() : /*offset size*/ 4u;
315 }
316 if (enum_) {
317 return BaseTypeInlineSize(enum_->underlying_type()->base_type());
318 }
319 LOG(FATAL) << "Unimplemented";
320}
321
322// Returns the required alignment for this type.
323size_t FlatbufferType::Alignment() const {
324 if (type_table_) {
325 // Attempt to derive alignment as max alignment of the members.
326 size_t alignment = 1u;
327 for (size_t field_index = 0;
328 field_index < static_cast<size_t>(NumberFields()); ++field_index) {
329 alignment = std::max(alignment, FieldInlineAlignment(field_index));
330 }
331 return alignment;
332 }
333 if (object_) {
334 return object_->minalign();
335 }
336 // We don't do a great job of supporting unions in general, and as of this
337 // writing did not try to look up what the alignment rules for unions were.
338 LOG(FATAL) << "Unimplemented";
339}
340
341size_t FlatbufferType::FieldInlineAlignment(size_t field_index) const {
342 if (FieldIsSequence(field_index) && FieldType(field_index).IsStruct()) {
343 return FieldType(field_index).Alignment();
344 }
345 return FieldInlineSize(field_index);
346}
347
348size_t FlatbufferType::StructFieldOffset(int index) const {
349 DCHECK(IsStruct());
350 if (type_table_) {
351 return type_table_->values[index];
352 }
353 if (object_) {
354 return ReflectionObjectField(index)->offset();
355 }
356 LOG(FATAL) << "Unimplemented";
357}
358
Brian Silvermancf4fb662021-02-10 17:54:53 -0800359size_t FlatbufferType::FieldInlineSize(int index) const {
360 DCHECK(IsSequence());
361 if (type_table_) {
James Kuszmaul768c4682023-10-12 21:07:16 -0700362 return flatbuffers::InlineSize(
363 FieldElementaryType(index),
364 FieldIsSequence(index) ? FieldType(index).type_table_ : nullptr);
Brian Silvermancf4fb662021-02-10 17:54:53 -0800365 }
Brian Silvermanc5105ab2021-02-10 17:55:38 -0800366 if (object_ || enum_) {
367 const reflection::Type *const type = ReflectionType(index);
368 const reflection::BaseType element_base_type =
369 ReflectionElementBaseType(index);
370 int element_size;
371 if (element_base_type == reflection::BaseType::Obj) {
372 const FlatbufferType field_type = FieldType(index);
373 if (field_type.object_ && field_type.object_->is_struct()) {
374 element_size = field_type.object_->bytesize();
375 } else {
376 element_size = 4;
377 }
378 } else {
379 element_size = BaseTypeInlineSize(element_base_type);
380 }
381 if (type->base_type() == reflection::BaseType::Array) {
382 return element_size * type->fixed_length();
383 }
384 return element_size;
385 }
Brian Silvermancf4fb662021-02-10 17:54:53 -0800386 LOG(FATAL) << "Unimplemented";
387}
388
389int FlatbufferType::NumberFields() const {
390 DCHECK(IsSequence());
391 if (type_table_) {
392 return type_table_->num_elems;
393 }
Brian Silvermanc5105ab2021-02-10 17:55:38 -0800394 if (object_) {
395 return object_->fields()->size();
396 }
397 if (enum_) {
398 return enum_->values()->size();
399 }
Brian Silvermancf4fb662021-02-10 17:54:53 -0800400 LOG(FATAL) << "Unimplemented";
401}
402
403FlatbufferType FlatbufferType::FieldType(int index) const {
404 DCHECK(IsSequence());
405 if (type_table_) {
406 DCHECK_LT(static_cast<size_t>(index), type_table_->num_elems);
407 const flatbuffers::TypeCode &type_code = type_table_->type_codes[index];
408 CHECK_GE(type_code.sequence_ref, 0);
409 // type_refs can be shorter than num_elems, but not longer, so this is still
410 // a valid sanity check.
411 DCHECK_LT(static_cast<size_t>(type_code.sequence_ref),
412 type_table_->num_elems);
413 const flatbuffers::TypeFunction type_function =
414 type_table_->type_refs[type_code.sequence_ref];
415 return FlatbufferType(type_function());
416 }
Brian Silvermanc5105ab2021-02-10 17:55:38 -0800417 if (object_ || enum_) {
418 const reflection::BaseType base_type = ReflectionElementBaseType(index);
419 const int object_index = ReflectionType(index)->index();
420 CHECK(object_index >= 0) << ": Invalid schema";
421 if (base_type == reflection::BaseType::Obj ||
422 base_type == reflection::BaseType::Union) {
423 DCHECK_LT(static_cast<size_t>(object_index), schema_->objects()->size());
424 return FlatbufferType(schema_, schema_->objects()->Get(object_index));
425 } else {
426 DCHECK_LT(static_cast<size_t>(object_index), schema_->enums()->size());
427 return FlatbufferType(schema_, schema_->enums()->Get(object_index));
428 }
429 }
Brian Silvermancf4fb662021-02-10 17:54:53 -0800430 LOG(FATAL) << "Unimplemented";
431}
432
Brian Silvermanc5105ab2021-02-10 17:55:38 -0800433const reflection::Type *FlatbufferType::ReflectionType(int index) const {
434 if (object_) {
435 return ReflectionObjectField(index)->type();
436 } else {
437 return ReflectionEnumValue(index)->union_type();
438 }
439}
440
441const reflection::Field *FlatbufferType::ReflectionObjectField(
442 int index) const {
443 DCHECK(object_);
444 const auto result = std::find_if(
445 object_->fields()->begin(), object_->fields()->end(),
446 [index](const reflection::Field *field) { return field->id() == index; });
447 DCHECK(result != object_->fields()->end());
448 return *result;
449}
450
451const reflection::EnumVal *FlatbufferType::ReflectionEnumValue(
452 int index) const {
453 DCHECK(enum_);
454 const auto result =
455 std::find_if(enum_->values()->begin(), enum_->values()->end(),
456 [index](const reflection::EnumVal *value) {
457 return value->value() == index;
458 });
459 DCHECK(result != enum_->values()->end());
460 return *result;
461}
462
463reflection::BaseType FlatbufferType::ReflectionElementBaseType(
464 int index) const {
465 const reflection::Type *const type = ReflectionType(index);
466 reflection::BaseType base_type = type->base_type();
467 if (base_type == reflection::BaseType::Vector ||
468 base_type == reflection::BaseType::Array) {
469 base_type = type->element();
470 }
471 CHECK(base_type != reflection::BaseType::None);
472 return base_type;
473}
474
Brian Silvermancf4fb662021-02-10 17:54:53 -0800475} // namespace aos