blob: 3429fe4883098adf4885a7d4e709f38e8bfb7b8d [file] [log] [blame]
Austin Schuh43c6a352019-09-30 22:22:10 -07001#include "aos/flatbuffer_utils.h"
Brian Silvermancf4fb662021-02-10 17:54:53 -08002
3#include "flatbuffers/minireflect.h"
Brian Silvermanc5105ab2021-02-10 17:55:38 -08004#include "flatbuffers/reflection_generated.h"
Brian Silvermancf4fb662021-02-10 17:54:53 -08005#include "glog/logging.h"
6
7namespace aos {
8
9bool FlatbufferType::IsSequence() const {
10 if (type_table_) {
11 return type_table_->st != flatbuffers::ST_ENUM;
12 }
Brian Silvermanc5105ab2021-02-10 17:55:38 -080013 if (object_) {
14 return true;
15 }
16 if (enum_) {
17 return enum_->is_union();
18 }
Brian Silvermancf4fb662021-02-10 17:54:53 -080019 LOG(FATAL) << "Unimplemented";
20}
21
22bool FlatbufferType::IsEnum() const {
23 if (type_table_) {
24 return type_table_->st == flatbuffers::ST_ENUM;
25 }
Brian Silvermanc5105ab2021-02-10 17:55:38 -080026 if (object_) {
27 return false;
28 }
29 if (enum_) {
30 return !enum_->is_union();
31 }
Brian Silvermancf4fb662021-02-10 17:54:53 -080032 LOG(FATAL) << "Unimplemented";
33}
34
35bool FlatbufferType::FieldIsSequence(int index) const {
36 DCHECK(IsSequence());
37 if (type_table_) {
38 DCHECK_LT(static_cast<size_t>(index), type_table_->num_elems);
39 const flatbuffers::TypeCode &type_code = type_table_->type_codes[index];
40 if (type_code.base_type != flatbuffers::ET_SEQUENCE) {
41 return false;
42 }
43 DCHECK(FieldType(index).IsSequence());
44 return true;
45 }
Brian Silvermanc5105ab2021-02-10 17:55:38 -080046 if (object_ || enum_) {
47 const reflection::BaseType base_type = ReflectionElementBaseType(index);
48 return base_type == reflection::BaseType::Obj ||
49 base_type == reflection::BaseType::Union;
50 }
Brian Silvermancf4fb662021-02-10 17:54:53 -080051 LOG(FATAL) << "Unimplemented";
52}
53
54bool FlatbufferType::FieldIsEnum(int index) const {
55 DCHECK(IsSequence());
56 if (type_table_) {
57 DCHECK_LT(static_cast<size_t>(index), type_table_->num_elems);
58 const flatbuffers::TypeCode &type_code = type_table_->type_codes[index];
59 if (type_code.base_type == flatbuffers::ET_SEQUENCE) {
60 return false;
61 }
62 if (type_code.sequence_ref == -1) {
63 // Not an enum.
64 return false;
65 }
66 DCHECK(FieldType(index).IsEnum());
67 return true;
68 }
Brian Silvermanc5105ab2021-02-10 17:55:38 -080069 if (object_ || enum_) {
70 const reflection::BaseType base_type = ReflectionElementBaseType(index);
71 if (base_type == reflection::BaseType::Obj ||
72 base_type == reflection::BaseType::Union) {
73 return false;
74 }
75 return ReflectionType(index)->index() >= 0;
76 }
Brian Silvermancf4fb662021-02-10 17:54:53 -080077 LOG(FATAL) << "Unimplemented";
78}
79
80std::optional<int64_t> FlatbufferType::EnumValue(std::string_view name) const {
81 DCHECK(IsEnum());
Brian Silvermanc5105ab2021-02-10 17:55:38 -080082 DCHECK(!object_);
Brian Silvermancf4fb662021-02-10 17:54:53 -080083 if (type_table_) {
84 for (size_t i = 0; i < type_table_->num_elems; ++i) {
85 if (name == type_table_->names[i]) {
86 if (type_table_->values) {
87 return type_table_->values[i];
88 } else {
89 return i;
90 }
91 }
92 }
93 return std::nullopt;
94 }
Brian Silvermanc5105ab2021-02-10 17:55:38 -080095 if (enum_) {
96 for (size_t i = 0; i < enum_->values()->size(); ++i) {
97 const auto *const value = enum_->values()->Get(i);
98 if (name == value->name()->string_view()) {
99 return value->value();
100 }
101 }
102 return std::nullopt;
103 }
Brian Silvermancf4fb662021-02-10 17:54:53 -0800104 LOG(FATAL) << "Unimplemented";
105}
106
107bool FlatbufferType::FieldIsRepeating(int index) const {
108 DCHECK(IsSequence());
109 if (type_table_) {
110 DCHECK_LT(static_cast<size_t>(index), type_table_->num_elems);
111 const flatbuffers::TypeCode &type_code = type_table_->type_codes[index];
112 return type_code.is_repeating;
113 }
Brian Silvermanc5105ab2021-02-10 17:55:38 -0800114 if (object_ || enum_) {
115 const reflection::BaseType type = ReflectionType(index)->base_type();
116 CHECK(type != reflection::BaseType::None);
117 return type == reflection::BaseType::Vector ||
118 type == reflection::BaseType::Array;
119 }
Brian Silvermancf4fb662021-02-10 17:54:53 -0800120 LOG(FATAL) << "Unimplemented";
121}
122
123int FlatbufferType::FieldIndex(std::string_view field_name) const {
124 DCHECK(IsSequence());
125 if (type_table_) {
126 for (size_t i = 0; i < type_table_->num_elems; ++i) {
127 if (field_name == std::string_view(type_table_->names[i])) {
128 return i;
129 }
130 }
131 return -1;
132 }
Brian Silvermanc5105ab2021-02-10 17:55:38 -0800133 if (object_) {
134 for (size_t i = 0; i < object_->fields()->size(); ++i) {
135 const reflection::Field *const field = object_->fields()->Get(i);
136 if (field_name == field->name()->string_view()) {
137 return field->id();
138 }
139 }
140 return -1;
141 }
142 if (enum_) {
143 for (size_t i = 0; i < enum_->values()->size(); ++i) {
144 const reflection::EnumVal *const value = enum_->values()->Get(i);
145 if (field_name == value->name()->string_view()) {
146 return value->value();
147 }
148 }
149 return -1;
150 }
Brian Silvermancf4fb662021-02-10 17:54:53 -0800151 LOG(FATAL) << "Unimplemented";
152}
153
154std::string_view FlatbufferType::FieldName(int index) const {
155 DCHECK(IsSequence());
156 if (type_table_) {
157 DCHECK_LT(static_cast<size_t>(index), type_table_->num_elems);
158 return type_table_->names[index];
159 }
Brian Silvermanc5105ab2021-02-10 17:55:38 -0800160 if (object_) {
161 return ReflectionObjectField(index)->name()->string_view();
162 }
163 if (enum_) {
164 return ReflectionEnumValue(index)->name()->string_view();
165 }
Brian Silvermancf4fb662021-02-10 17:54:53 -0800166 LOG(FATAL) << "Unimplemented";
167}
168
Brian Silvermanc5105ab2021-02-10 17:55:38 -0800169namespace {
170
171flatbuffers::ElementaryType ElementaryTypeFromBaseType(
172 reflection::BaseType base_type) {
173 switch (base_type) {
174 case reflection::BaseType::None:
175 LOG(FATAL) << "Invalid schema";
176 case reflection::BaseType::UType:
177 return flatbuffers::ElementaryType::ET_UTYPE;
178 case reflection::BaseType::Bool:
179 return flatbuffers::ElementaryType::ET_BOOL;
180 case reflection::BaseType::Byte:
181 return flatbuffers::ElementaryType::ET_CHAR;
182 case reflection::BaseType::UByte:
183 return flatbuffers::ElementaryType::ET_UCHAR;
184 case reflection::BaseType::Short:
185 return flatbuffers::ElementaryType::ET_SHORT;
186 case reflection::BaseType::UShort:
187 return flatbuffers::ElementaryType::ET_USHORT;
188 case reflection::BaseType::Int:
189 return flatbuffers::ElementaryType::ET_INT;
190 case reflection::BaseType::UInt:
191 return flatbuffers::ElementaryType::ET_UINT;
192 case reflection::BaseType::Long:
193 return flatbuffers::ElementaryType::ET_LONG;
194 case reflection::BaseType::ULong:
195 return flatbuffers::ElementaryType::ET_ULONG;
196 case reflection::BaseType::Float:
197 return flatbuffers::ElementaryType::ET_FLOAT;
198 case reflection::BaseType::Double:
199 return flatbuffers::ElementaryType::ET_DOUBLE;
200 case reflection::BaseType::String:
201 return flatbuffers::ElementaryType::ET_STRING;
202 case reflection::BaseType::Obj:
203 return flatbuffers::ElementaryType::ET_SEQUENCE;
204 case reflection::BaseType::Union:
205 return flatbuffers::ElementaryType::ET_SEQUENCE;
206 default:
207 LOG(FATAL) << "Unknown BaseType";
208 }
209}
210
211} // namespace
212
Brian Silvermancf4fb662021-02-10 17:54:53 -0800213flatbuffers::ElementaryType FlatbufferType::FieldElementaryType(
214 int index) const {
215 DCHECK(IsSequence());
216 if (type_table_) {
217 DCHECK_LT(static_cast<size_t>(index), type_table_->num_elems);
218 const flatbuffers::TypeCode &type_code = type_table_->type_codes[index];
219 return static_cast<flatbuffers::ElementaryType>(type_code.base_type);
220 }
Brian Silvermanc5105ab2021-02-10 17:55:38 -0800221 if (object_ || enum_) {
222 return ElementaryTypeFromBaseType(ReflectionElementBaseType(index));
223 }
Brian Silvermancf4fb662021-02-10 17:54:53 -0800224 LOG(FATAL) << "Unimplemented";
225}
226
Brian Silvermanc5105ab2021-02-10 17:55:38 -0800227namespace {
228
229size_t BaseTypeInlineSize(reflection::BaseType base_type) {
230 switch (base_type) {
231 case reflection::BaseType::None:
232 LOG(FATAL) << "Invalid schema";
233 case reflection::BaseType::UType:
234 case reflection::BaseType::Bool:
235 case reflection::BaseType::Byte:
236 case reflection::BaseType::UByte:
237 return 1;
238 case reflection::BaseType::Short:
239 case reflection::BaseType::UShort:
240 return 2;
241 case reflection::BaseType::Int:
242 case reflection::BaseType::UInt:
243 case reflection::BaseType::Float:
244 case reflection::BaseType::String:
245 return 4;
246 case reflection::BaseType::Long:
247 case reflection::BaseType::ULong:
248 case reflection::BaseType::Double:
249 return 8;
250 case reflection::BaseType::Union:
251 return 4;
252 default:
253 LOG(FATAL) << "Unknown BaseType";
254 }
255}
256
257} // namespace
258
Brian Silvermancf4fb662021-02-10 17:54:53 -0800259size_t FlatbufferType::FieldInlineSize(int index) const {
260 DCHECK(IsSequence());
261 if (type_table_) {
262 return flatbuffers::InlineSize(FieldElementaryType(index), type_table_);
263 }
Brian Silvermanc5105ab2021-02-10 17:55:38 -0800264 if (object_ || enum_) {
265 const reflection::Type *const type = ReflectionType(index);
266 const reflection::BaseType element_base_type =
267 ReflectionElementBaseType(index);
268 int element_size;
269 if (element_base_type == reflection::BaseType::Obj) {
270 const FlatbufferType field_type = FieldType(index);
271 if (field_type.object_ && field_type.object_->is_struct()) {
272 element_size = field_type.object_->bytesize();
273 } else {
274 element_size = 4;
275 }
276 } else {
277 element_size = BaseTypeInlineSize(element_base_type);
278 }
279 if (type->base_type() == reflection::BaseType::Array) {
280 return element_size * type->fixed_length();
281 }
282 return element_size;
283 }
Brian Silvermancf4fb662021-02-10 17:54:53 -0800284 LOG(FATAL) << "Unimplemented";
285}
286
287int FlatbufferType::NumberFields() const {
288 DCHECK(IsSequence());
289 if (type_table_) {
290 return type_table_->num_elems;
291 }
Brian Silvermanc5105ab2021-02-10 17:55:38 -0800292 if (object_) {
293 return object_->fields()->size();
294 }
295 if (enum_) {
296 return enum_->values()->size();
297 }
Brian Silvermancf4fb662021-02-10 17:54:53 -0800298 LOG(FATAL) << "Unimplemented";
299}
300
301FlatbufferType FlatbufferType::FieldType(int index) const {
302 DCHECK(IsSequence());
303 if (type_table_) {
304 DCHECK_LT(static_cast<size_t>(index), type_table_->num_elems);
305 const flatbuffers::TypeCode &type_code = type_table_->type_codes[index];
306 CHECK_GE(type_code.sequence_ref, 0);
307 // type_refs can be shorter than num_elems, but not longer, so this is still
308 // a valid sanity check.
309 DCHECK_LT(static_cast<size_t>(type_code.sequence_ref),
310 type_table_->num_elems);
311 const flatbuffers::TypeFunction type_function =
312 type_table_->type_refs[type_code.sequence_ref];
313 return FlatbufferType(type_function());
314 }
Brian Silvermanc5105ab2021-02-10 17:55:38 -0800315 if (object_ || enum_) {
316 const reflection::BaseType base_type = ReflectionElementBaseType(index);
317 const int object_index = ReflectionType(index)->index();
318 CHECK(object_index >= 0) << ": Invalid schema";
319 if (base_type == reflection::BaseType::Obj ||
320 base_type == reflection::BaseType::Union) {
321 DCHECK_LT(static_cast<size_t>(object_index), schema_->objects()->size());
322 return FlatbufferType(schema_, schema_->objects()->Get(object_index));
323 } else {
324 DCHECK_LT(static_cast<size_t>(object_index), schema_->enums()->size());
325 return FlatbufferType(schema_, schema_->enums()->Get(object_index));
326 }
327 }
Brian Silvermancf4fb662021-02-10 17:54:53 -0800328 LOG(FATAL) << "Unimplemented";
329}
330
Brian Silvermanc5105ab2021-02-10 17:55:38 -0800331const reflection::Type *FlatbufferType::ReflectionType(int index) const {
332 if (object_) {
333 return ReflectionObjectField(index)->type();
334 } else {
335 return ReflectionEnumValue(index)->union_type();
336 }
337}
338
339const reflection::Field *FlatbufferType::ReflectionObjectField(
340 int index) const {
341 DCHECK(object_);
342 const auto result = std::find_if(
343 object_->fields()->begin(), object_->fields()->end(),
344 [index](const reflection::Field *field) { return field->id() == index; });
345 DCHECK(result != object_->fields()->end());
346 return *result;
347}
348
349const reflection::EnumVal *FlatbufferType::ReflectionEnumValue(
350 int index) const {
351 DCHECK(enum_);
352 const auto result =
353 std::find_if(enum_->values()->begin(), enum_->values()->end(),
354 [index](const reflection::EnumVal *value) {
355 return value->value() == index;
356 });
357 DCHECK(result != enum_->values()->end());
358 return *result;
359}
360
361reflection::BaseType FlatbufferType::ReflectionElementBaseType(
362 int index) const {
363 const reflection::Type *const type = ReflectionType(index);
364 reflection::BaseType base_type = type->base_type();
365 if (base_type == reflection::BaseType::Vector ||
366 base_type == reflection::BaseType::Array) {
367 base_type = type->element();
368 }
369 CHECK(base_type != reflection::BaseType::None);
370 return base_type;
371}
372
Brian Silvermancf4fb662021-02-10 17:54:53 -0800373} // namespace aos