1*890232f2SAndroid Build Coastguard Worker /*
2*890232f2SAndroid Build Coastguard Worker * Copyright 2014 Google Inc. All rights reserved.
3*890232f2SAndroid Build Coastguard Worker *
4*890232f2SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*890232f2SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*890232f2SAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*890232f2SAndroid Build Coastguard Worker *
8*890232f2SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*890232f2SAndroid Build Coastguard Worker *
10*890232f2SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*890232f2SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*890232f2SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*890232f2SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*890232f2SAndroid Build Coastguard Worker * limitations under the License.
15*890232f2SAndroid Build Coastguard Worker */
16*890232f2SAndroid Build Coastguard Worker
17*890232f2SAndroid Build Coastguard Worker // independent from idl_parser, since this code is not needed for most clients
18*890232f2SAndroid Build Coastguard Worker
19*890232f2SAndroid Build Coastguard Worker #include <functional>
20*890232f2SAndroid Build Coastguard Worker #include <unordered_set>
21*890232f2SAndroid Build Coastguard Worker
22*890232f2SAndroid Build Coastguard Worker #include "flatbuffers/code_generators.h"
23*890232f2SAndroid Build Coastguard Worker #include "flatbuffers/flatbuffers.h"
24*890232f2SAndroid Build Coastguard Worker #include "flatbuffers/idl.h"
25*890232f2SAndroid Build Coastguard Worker #include "flatbuffers/util.h"
26*890232f2SAndroid Build Coastguard Worker #include "idl_namer.h"
27*890232f2SAndroid Build Coastguard Worker
28*890232f2SAndroid Build Coastguard Worker namespace flatbuffers {
29*890232f2SAndroid Build Coastguard Worker
30*890232f2SAndroid Build Coastguard Worker namespace kotlin {
31*890232f2SAndroid Build Coastguard Worker
32*890232f2SAndroid Build Coastguard Worker namespace {
33*890232f2SAndroid Build Coastguard Worker
34*890232f2SAndroid Build Coastguard Worker typedef std::map<std::string, std::pair<std::string, std::string> > FbbParamMap;
35*890232f2SAndroid Build Coastguard Worker static TypedFloatConstantGenerator KotlinFloatGen("Double.", "Float.", "NaN",
36*890232f2SAndroid Build Coastguard Worker "POSITIVE_INFINITY",
37*890232f2SAndroid Build Coastguard Worker "NEGATIVE_INFINITY");
38*890232f2SAndroid Build Coastguard Worker
39*890232f2SAndroid Build Coastguard Worker static const CommentConfig comment_config = { "/**", " *", " */" };
40*890232f2SAndroid Build Coastguard Worker static const std::string ident_pad = " ";
KotlinKeywords()41*890232f2SAndroid Build Coastguard Worker static std::set<std::string> KotlinKeywords() {
42*890232f2SAndroid Build Coastguard Worker return { "package", "as", "typealias", "class", "this", "super",
43*890232f2SAndroid Build Coastguard Worker "val", "var", "fun", "for", "null", "true",
44*890232f2SAndroid Build Coastguard Worker "false", "is", "in", "throw", "return", "break",
45*890232f2SAndroid Build Coastguard Worker "continue", "object", "if", "try", "else", "while",
46*890232f2SAndroid Build Coastguard Worker "do", "when", "interface", "typeof", "Any", "Character" };
47*890232f2SAndroid Build Coastguard Worker }
48*890232f2SAndroid Build Coastguard Worker
KotlinDefaultConfig()49*890232f2SAndroid Build Coastguard Worker static Namer::Config KotlinDefaultConfig() {
50*890232f2SAndroid Build Coastguard Worker return { /*types=*/Case::kKeep,
51*890232f2SAndroid Build Coastguard Worker /*constants=*/Case::kKeep,
52*890232f2SAndroid Build Coastguard Worker /*methods=*/Case::kLowerCamel,
53*890232f2SAndroid Build Coastguard Worker /*functions=*/Case::kKeep,
54*890232f2SAndroid Build Coastguard Worker /*fields=*/Case::kLowerCamel,
55*890232f2SAndroid Build Coastguard Worker /*variables=*/Case::kLowerCamel,
56*890232f2SAndroid Build Coastguard Worker /*variants=*/Case::kLowerCamel,
57*890232f2SAndroid Build Coastguard Worker /*enum_variant_seperator=*/"", // I.e. Concatenate.
58*890232f2SAndroid Build Coastguard Worker /*escape_keywords=*/Namer::Config::Escape::BeforeConvertingCase,
59*890232f2SAndroid Build Coastguard Worker /*namespaces=*/Case::kKeep,
60*890232f2SAndroid Build Coastguard Worker /*namespace_seperator=*/"__",
61*890232f2SAndroid Build Coastguard Worker /*object_prefix=*/"",
62*890232f2SAndroid Build Coastguard Worker /*object_suffix=*/"T",
63*890232f2SAndroid Build Coastguard Worker /*keyword_prefix=*/"",
64*890232f2SAndroid Build Coastguard Worker /*keyword_suffix=*/"_",
65*890232f2SAndroid Build Coastguard Worker /*filenames=*/Case::kKeep,
66*890232f2SAndroid Build Coastguard Worker /*directories=*/Case::kKeep,
67*890232f2SAndroid Build Coastguard Worker /*output_path=*/"",
68*890232f2SAndroid Build Coastguard Worker /*filename_suffix=*/"",
69*890232f2SAndroid Build Coastguard Worker /*filename_extension=*/".kt" };
70*890232f2SAndroid Build Coastguard Worker }
71*890232f2SAndroid Build Coastguard Worker } // namespace
72*890232f2SAndroid Build Coastguard Worker
73*890232f2SAndroid Build Coastguard Worker class KotlinGenerator : public BaseGenerator {
74*890232f2SAndroid Build Coastguard Worker public:
KotlinGenerator(const Parser & parser,const std::string & path,const std::string & file_name)75*890232f2SAndroid Build Coastguard Worker KotlinGenerator(const Parser &parser, const std::string &path,
76*890232f2SAndroid Build Coastguard Worker const std::string &file_name)
77*890232f2SAndroid Build Coastguard Worker : BaseGenerator(parser, path, file_name, "", ".", "kt"),
78*890232f2SAndroid Build Coastguard Worker namer_(WithFlagOptions(KotlinDefaultConfig(), parser.opts, path),
79*890232f2SAndroid Build Coastguard Worker KotlinKeywords()) {}
80*890232f2SAndroid Build Coastguard Worker
81*890232f2SAndroid Build Coastguard Worker KotlinGenerator &operator=(const KotlinGenerator &);
generate()82*890232f2SAndroid Build Coastguard Worker bool generate() FLATBUFFERS_OVERRIDE {
83*890232f2SAndroid Build Coastguard Worker std::string one_file_code;
84*890232f2SAndroid Build Coastguard Worker
85*890232f2SAndroid Build Coastguard Worker for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
86*890232f2SAndroid Build Coastguard Worker ++it) {
87*890232f2SAndroid Build Coastguard Worker CodeWriter enumWriter(ident_pad);
88*890232f2SAndroid Build Coastguard Worker auto &enum_def = **it;
89*890232f2SAndroid Build Coastguard Worker GenEnum(enum_def, enumWriter);
90*890232f2SAndroid Build Coastguard Worker if (parser_.opts.one_file) {
91*890232f2SAndroid Build Coastguard Worker one_file_code += enumWriter.ToString();
92*890232f2SAndroid Build Coastguard Worker } else {
93*890232f2SAndroid Build Coastguard Worker if (!SaveType(enum_def.name, *enum_def.defined_namespace,
94*890232f2SAndroid Build Coastguard Worker enumWriter.ToString(), false))
95*890232f2SAndroid Build Coastguard Worker return false;
96*890232f2SAndroid Build Coastguard Worker }
97*890232f2SAndroid Build Coastguard Worker }
98*890232f2SAndroid Build Coastguard Worker
99*890232f2SAndroid Build Coastguard Worker for (auto it = parser_.structs_.vec.begin();
100*890232f2SAndroid Build Coastguard Worker it != parser_.structs_.vec.end(); ++it) {
101*890232f2SAndroid Build Coastguard Worker CodeWriter structWriter(ident_pad);
102*890232f2SAndroid Build Coastguard Worker auto &struct_def = **it;
103*890232f2SAndroid Build Coastguard Worker GenStruct(struct_def, structWriter, parser_.opts);
104*890232f2SAndroid Build Coastguard Worker if (parser_.opts.one_file) {
105*890232f2SAndroid Build Coastguard Worker one_file_code += structWriter.ToString();
106*890232f2SAndroid Build Coastguard Worker } else {
107*890232f2SAndroid Build Coastguard Worker if (!SaveType(struct_def.name, *struct_def.defined_namespace,
108*890232f2SAndroid Build Coastguard Worker structWriter.ToString(), true))
109*890232f2SAndroid Build Coastguard Worker return false;
110*890232f2SAndroid Build Coastguard Worker }
111*890232f2SAndroid Build Coastguard Worker }
112*890232f2SAndroid Build Coastguard Worker
113*890232f2SAndroid Build Coastguard Worker if (parser_.opts.one_file) {
114*890232f2SAndroid Build Coastguard Worker return SaveType(file_name_, *parser_.current_namespace_, one_file_code,
115*890232f2SAndroid Build Coastguard Worker true);
116*890232f2SAndroid Build Coastguard Worker }
117*890232f2SAndroid Build Coastguard Worker return true;
118*890232f2SAndroid Build Coastguard Worker }
119*890232f2SAndroid Build Coastguard Worker
120*890232f2SAndroid Build Coastguard Worker // Save out the generated code for a single class while adding
121*890232f2SAndroid Build Coastguard Worker // declaration boilerplate.
SaveType(const std::string & defname,const Namespace & ns,const std::string & classcode,bool needs_includes) const122*890232f2SAndroid Build Coastguard Worker bool SaveType(const std::string &defname, const Namespace &ns,
123*890232f2SAndroid Build Coastguard Worker const std::string &classcode, bool needs_includes) const {
124*890232f2SAndroid Build Coastguard Worker if (!classcode.length()) return true;
125*890232f2SAndroid Build Coastguard Worker
126*890232f2SAndroid Build Coastguard Worker std::string code =
127*890232f2SAndroid Build Coastguard Worker "// " + std::string(FlatBuffersGeneratedWarning()) + "\n\n";
128*890232f2SAndroid Build Coastguard Worker
129*890232f2SAndroid Build Coastguard Worker std::string namespace_name = FullNamespace(".", ns);
130*890232f2SAndroid Build Coastguard Worker if (!namespace_name.empty()) {
131*890232f2SAndroid Build Coastguard Worker code += "package " + namespace_name;
132*890232f2SAndroid Build Coastguard Worker code += "\n\n";
133*890232f2SAndroid Build Coastguard Worker }
134*890232f2SAndroid Build Coastguard Worker if (needs_includes) {
135*890232f2SAndroid Build Coastguard Worker code += "import java.nio.*\n";
136*890232f2SAndroid Build Coastguard Worker code += "import kotlin.math.sign\n";
137*890232f2SAndroid Build Coastguard Worker code += "import com.google.flatbuffers.*\n\n";
138*890232f2SAndroid Build Coastguard Worker }
139*890232f2SAndroid Build Coastguard Worker code += classcode;
140*890232f2SAndroid Build Coastguard Worker const std::string dirs = namer_.Directories(ns);
141*890232f2SAndroid Build Coastguard Worker EnsureDirExists(dirs);
142*890232f2SAndroid Build Coastguard Worker const std::string filename =
143*890232f2SAndroid Build Coastguard Worker dirs + namer_.File(defname, /*skips=*/SkipFile::Suffix);
144*890232f2SAndroid Build Coastguard Worker return SaveFile(filename.c_str(), code, false);
145*890232f2SAndroid Build Coastguard Worker }
146*890232f2SAndroid Build Coastguard Worker
IsEnum(const Type & type)147*890232f2SAndroid Build Coastguard Worker static bool IsEnum(const Type &type) {
148*890232f2SAndroid Build Coastguard Worker return type.enum_def != nullptr && IsInteger(type.base_type);
149*890232f2SAndroid Build Coastguard Worker }
150*890232f2SAndroid Build Coastguard Worker
GenTypeBasic(const BaseType & type)151*890232f2SAndroid Build Coastguard Worker static std::string GenTypeBasic(const BaseType &type) {
152*890232f2SAndroid Build Coastguard Worker // clang-format off
153*890232f2SAndroid Build Coastguard Worker static const char * const kotlin_typename[] = {
154*890232f2SAndroid Build Coastguard Worker #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
155*890232f2SAndroid Build Coastguard Worker CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE, ...) \
156*890232f2SAndroid Build Coastguard Worker #KTYPE,
157*890232f2SAndroid Build Coastguard Worker FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
158*890232f2SAndroid Build Coastguard Worker #undef FLATBUFFERS_TD
159*890232f2SAndroid Build Coastguard Worker };
160*890232f2SAndroid Build Coastguard Worker // clang-format on
161*890232f2SAndroid Build Coastguard Worker return kotlin_typename[type];
162*890232f2SAndroid Build Coastguard Worker }
163*890232f2SAndroid Build Coastguard Worker
GenTypePointer(const Type & type) const164*890232f2SAndroid Build Coastguard Worker std::string GenTypePointer(const Type &type) const {
165*890232f2SAndroid Build Coastguard Worker switch (type.base_type) {
166*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_STRING: return "String";
167*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_VECTOR: return GenTypeGet(type.VectorType());
168*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_STRUCT: return WrapInNameSpace(*type.struct_def);
169*890232f2SAndroid Build Coastguard Worker default: return "Table";
170*890232f2SAndroid Build Coastguard Worker }
171*890232f2SAndroid Build Coastguard Worker }
172*890232f2SAndroid Build Coastguard Worker
173*890232f2SAndroid Build Coastguard Worker // with the addition of optional scalar types,
174*890232f2SAndroid Build Coastguard Worker // we are adding the nullable '?' operator to return type of a field.
GetterReturnType(const FieldDef & field) const175*890232f2SAndroid Build Coastguard Worker std::string GetterReturnType(const FieldDef &field) const {
176*890232f2SAndroid Build Coastguard Worker auto base_type = field.value.type.base_type;
177*890232f2SAndroid Build Coastguard Worker
178*890232f2SAndroid Build Coastguard Worker auto r_type = GenTypeGet(field.value.type);
179*890232f2SAndroid Build Coastguard Worker if (field.IsScalarOptional() ||
180*890232f2SAndroid Build Coastguard Worker // string, structs and unions
181*890232f2SAndroid Build Coastguard Worker (base_type == BASE_TYPE_STRING || base_type == BASE_TYPE_STRUCT ||
182*890232f2SAndroid Build Coastguard Worker base_type == BASE_TYPE_UNION) ||
183*890232f2SAndroid Build Coastguard Worker // vector of anything not scalar
184*890232f2SAndroid Build Coastguard Worker (base_type == BASE_TYPE_VECTOR &&
185*890232f2SAndroid Build Coastguard Worker !IsScalar(field.value.type.VectorType().base_type))) {
186*890232f2SAndroid Build Coastguard Worker r_type += "?";
187*890232f2SAndroid Build Coastguard Worker }
188*890232f2SAndroid Build Coastguard Worker return r_type;
189*890232f2SAndroid Build Coastguard Worker }
190*890232f2SAndroid Build Coastguard Worker
GenTypeGet(const Type & type) const191*890232f2SAndroid Build Coastguard Worker std::string GenTypeGet(const Type &type) const {
192*890232f2SAndroid Build Coastguard Worker return IsScalar(type.base_type) ? GenTypeBasic(type.base_type)
193*890232f2SAndroid Build Coastguard Worker : GenTypePointer(type);
194*890232f2SAndroid Build Coastguard Worker }
195*890232f2SAndroid Build Coastguard Worker
GenEnumDefaultValue(const FieldDef & field) const196*890232f2SAndroid Build Coastguard Worker std::string GenEnumDefaultValue(const FieldDef &field) const {
197*890232f2SAndroid Build Coastguard Worker auto &value = field.value;
198*890232f2SAndroid Build Coastguard Worker FLATBUFFERS_ASSERT(value.type.enum_def);
199*890232f2SAndroid Build Coastguard Worker auto &enum_def = *value.type.enum_def;
200*890232f2SAndroid Build Coastguard Worker auto enum_val = enum_def.FindByValue(value.constant);
201*890232f2SAndroid Build Coastguard Worker return enum_val ? (WrapInNameSpace(enum_def) + "." + enum_val->name)
202*890232f2SAndroid Build Coastguard Worker : value.constant;
203*890232f2SAndroid Build Coastguard Worker }
204*890232f2SAndroid Build Coastguard Worker
205*890232f2SAndroid Build Coastguard Worker // Generate default values to compare against a default value when
206*890232f2SAndroid Build Coastguard Worker // `force_defaults` is `false`.
207*890232f2SAndroid Build Coastguard Worker // Main differences are:
208*890232f2SAndroid Build Coastguard Worker // - Floats are upcasted to doubles
209*890232f2SAndroid Build Coastguard Worker // - Unsigned are casted to signed
GenFBBDefaultValue(const FieldDef & field) const210*890232f2SAndroid Build Coastguard Worker std::string GenFBBDefaultValue(const FieldDef &field) const {
211*890232f2SAndroid Build Coastguard Worker if (field.IsScalarOptional()) {
212*890232f2SAndroid Build Coastguard Worker // although default value is null, java API forces us to present a real
213*890232f2SAndroid Build Coastguard Worker // default value for scalars, while adding a field to the buffer. This is
214*890232f2SAndroid Build Coastguard Worker // not a problem because the default can be representing just by not
215*890232f2SAndroid Build Coastguard Worker // calling builder.addMyField()
216*890232f2SAndroid Build Coastguard Worker switch (field.value.type.base_type) {
217*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_DOUBLE:
218*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_FLOAT: return "0.0";
219*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_BOOL: return "false";
220*890232f2SAndroid Build Coastguard Worker default: return "0";
221*890232f2SAndroid Build Coastguard Worker }
222*890232f2SAndroid Build Coastguard Worker }
223*890232f2SAndroid Build Coastguard Worker auto out = GenDefaultValue(field, true);
224*890232f2SAndroid Build Coastguard Worker // All FlatBufferBuilder default floating point values are doubles
225*890232f2SAndroid Build Coastguard Worker if (field.value.type.base_type == BASE_TYPE_FLOAT) {
226*890232f2SAndroid Build Coastguard Worker if (out.find("Float") != std::string::npos) {
227*890232f2SAndroid Build Coastguard Worker out.replace(0, 5, "Double");
228*890232f2SAndroid Build Coastguard Worker }
229*890232f2SAndroid Build Coastguard Worker }
230*890232f2SAndroid Build Coastguard Worker // Guarantee all values are doubles
231*890232f2SAndroid Build Coastguard Worker if (out.back() == 'f') out.pop_back();
232*890232f2SAndroid Build Coastguard Worker return out;
233*890232f2SAndroid Build Coastguard Worker }
234*890232f2SAndroid Build Coastguard Worker
235*890232f2SAndroid Build Coastguard Worker // FlatBufferBuilder only store signed types, so this function
236*890232f2SAndroid Build Coastguard Worker // returns a cast for unsigned values
GenFBBValueCast(const FieldDef & field) const237*890232f2SAndroid Build Coastguard Worker std::string GenFBBValueCast(const FieldDef &field) const {
238*890232f2SAndroid Build Coastguard Worker if (IsUnsigned(field.value.type.base_type)) {
239*890232f2SAndroid Build Coastguard Worker return CastToSigned(field.value.type);
240*890232f2SAndroid Build Coastguard Worker }
241*890232f2SAndroid Build Coastguard Worker return "";
242*890232f2SAndroid Build Coastguard Worker }
243*890232f2SAndroid Build Coastguard Worker
GenDefaultValue(const FieldDef & field,bool force_signed=false) const244*890232f2SAndroid Build Coastguard Worker std::string GenDefaultValue(const FieldDef &field,
245*890232f2SAndroid Build Coastguard Worker bool force_signed = false) const {
246*890232f2SAndroid Build Coastguard Worker auto &value = field.value;
247*890232f2SAndroid Build Coastguard Worker auto base_type = field.value.type.base_type;
248*890232f2SAndroid Build Coastguard Worker
249*890232f2SAndroid Build Coastguard Worker if (field.IsScalarOptional()) { return "null"; }
250*890232f2SAndroid Build Coastguard Worker if (IsFloat(base_type)) {
251*890232f2SAndroid Build Coastguard Worker auto val = KotlinFloatGen.GenFloatConstant(field);
252*890232f2SAndroid Build Coastguard Worker if (base_type == BASE_TYPE_DOUBLE && val.back() == 'f') {
253*890232f2SAndroid Build Coastguard Worker val.pop_back();
254*890232f2SAndroid Build Coastguard Worker }
255*890232f2SAndroid Build Coastguard Worker return val;
256*890232f2SAndroid Build Coastguard Worker }
257*890232f2SAndroid Build Coastguard Worker
258*890232f2SAndroid Build Coastguard Worker if (base_type == BASE_TYPE_BOOL) {
259*890232f2SAndroid Build Coastguard Worker return value.constant == "0" ? "false" : "true";
260*890232f2SAndroid Build Coastguard Worker }
261*890232f2SAndroid Build Coastguard Worker
262*890232f2SAndroid Build Coastguard Worker std::string suffix = "";
263*890232f2SAndroid Build Coastguard Worker
264*890232f2SAndroid Build Coastguard Worker if (base_type == BASE_TYPE_LONG || !force_signed) {
265*890232f2SAndroid Build Coastguard Worker suffix = LiteralSuffix(base_type);
266*890232f2SAndroid Build Coastguard Worker }
267*890232f2SAndroid Build Coastguard Worker return value.constant + suffix;
268*890232f2SAndroid Build Coastguard Worker }
269*890232f2SAndroid Build Coastguard Worker
GenEnum(EnumDef & enum_def,CodeWriter & writer) const270*890232f2SAndroid Build Coastguard Worker void GenEnum(EnumDef &enum_def, CodeWriter &writer) const {
271*890232f2SAndroid Build Coastguard Worker if (enum_def.generated) return;
272*890232f2SAndroid Build Coastguard Worker
273*890232f2SAndroid Build Coastguard Worker GenerateComment(enum_def.doc_comment, writer, &comment_config);
274*890232f2SAndroid Build Coastguard Worker
275*890232f2SAndroid Build Coastguard Worker writer += "@Suppress(\"unused\")";
276*890232f2SAndroid Build Coastguard Worker writer += "class " + namer_.Type(enum_def) + " private constructor() {";
277*890232f2SAndroid Build Coastguard Worker writer.IncrementIdentLevel();
278*890232f2SAndroid Build Coastguard Worker
279*890232f2SAndroid Build Coastguard Worker GenerateCompanionObject(writer, [&]() {
280*890232f2SAndroid Build Coastguard Worker // Write all properties
281*890232f2SAndroid Build Coastguard Worker auto vals = enum_def.Vals();
282*890232f2SAndroid Build Coastguard Worker for (auto it = vals.begin(); it != vals.end(); ++it) {
283*890232f2SAndroid Build Coastguard Worker auto &ev = **it;
284*890232f2SAndroid Build Coastguard Worker auto field_type = GenTypeBasic(enum_def.underlying_type.base_type);
285*890232f2SAndroid Build Coastguard Worker auto val = enum_def.ToString(ev);
286*890232f2SAndroid Build Coastguard Worker auto suffix = LiteralSuffix(enum_def.underlying_type.base_type);
287*890232f2SAndroid Build Coastguard Worker writer.SetValue("name", namer_.LegacyKotlinVariant(ev));
288*890232f2SAndroid Build Coastguard Worker writer.SetValue("type", field_type);
289*890232f2SAndroid Build Coastguard Worker writer.SetValue("val", val + suffix);
290*890232f2SAndroid Build Coastguard Worker GenerateComment(ev.doc_comment, writer, &comment_config);
291*890232f2SAndroid Build Coastguard Worker writer += "const val {{name}}: {{type}} = {{val}}";
292*890232f2SAndroid Build Coastguard Worker }
293*890232f2SAndroid Build Coastguard Worker
294*890232f2SAndroid Build Coastguard Worker // Generate a generate string table for enum values.
295*890232f2SAndroid Build Coastguard Worker // Problem is, if values are very sparse that could generate really
296*890232f2SAndroid Build Coastguard Worker // big tables. Ideally in that case we generate a map lookup
297*890232f2SAndroid Build Coastguard Worker // instead, but for the moment we simply don't output a table at all.
298*890232f2SAndroid Build Coastguard Worker auto range = enum_def.Distance();
299*890232f2SAndroid Build Coastguard Worker // Average distance between values above which we consider a table
300*890232f2SAndroid Build Coastguard Worker // "too sparse". Change at will.
301*890232f2SAndroid Build Coastguard Worker static const uint64_t kMaxSparseness = 5;
302*890232f2SAndroid Build Coastguard Worker if (range / static_cast<uint64_t>(enum_def.size()) < kMaxSparseness) {
303*890232f2SAndroid Build Coastguard Worker GeneratePropertyOneLine(writer, "names", "Array<String>", [&]() {
304*890232f2SAndroid Build Coastguard Worker writer += "arrayOf(\\";
305*890232f2SAndroid Build Coastguard Worker auto val = enum_def.Vals().front();
306*890232f2SAndroid Build Coastguard Worker for (auto it = vals.begin(); it != vals.end(); ++it) {
307*890232f2SAndroid Build Coastguard Worker auto ev = *it;
308*890232f2SAndroid Build Coastguard Worker for (auto k = enum_def.Distance(val, ev); k > 1; --k)
309*890232f2SAndroid Build Coastguard Worker writer += "\"\", \\";
310*890232f2SAndroid Build Coastguard Worker val = ev;
311*890232f2SAndroid Build Coastguard Worker writer += "\"" + (*it)->name + "\"\\";
312*890232f2SAndroid Build Coastguard Worker if (it + 1 != vals.end()) { writer += ", \\"; }
313*890232f2SAndroid Build Coastguard Worker }
314*890232f2SAndroid Build Coastguard Worker writer += ")";
315*890232f2SAndroid Build Coastguard Worker });
316*890232f2SAndroid Build Coastguard Worker GenerateFunOneLine(
317*890232f2SAndroid Build Coastguard Worker writer, "name", "e: Int", "String",
318*890232f2SAndroid Build Coastguard Worker [&]() {
319*890232f2SAndroid Build Coastguard Worker writer += "names[e\\";
320*890232f2SAndroid Build Coastguard Worker if (enum_def.MinValue()->IsNonZero())
321*890232f2SAndroid Build Coastguard Worker writer += " - " + enum_def.MinValue()->name + ".toInt()\\";
322*890232f2SAndroid Build Coastguard Worker writer += "]";
323*890232f2SAndroid Build Coastguard Worker },
324*890232f2SAndroid Build Coastguard Worker parser_.opts.gen_jvmstatic);
325*890232f2SAndroid Build Coastguard Worker }
326*890232f2SAndroid Build Coastguard Worker });
327*890232f2SAndroid Build Coastguard Worker writer.DecrementIdentLevel();
328*890232f2SAndroid Build Coastguard Worker writer += "}";
329*890232f2SAndroid Build Coastguard Worker }
330*890232f2SAndroid Build Coastguard Worker
331*890232f2SAndroid Build Coastguard Worker // Returns the function name that is able to read a value of the given type.
ByteBufferGetter(const Type & type,std::string bb_var_name) const332*890232f2SAndroid Build Coastguard Worker std::string ByteBufferGetter(const Type &type,
333*890232f2SAndroid Build Coastguard Worker std::string bb_var_name) const {
334*890232f2SAndroid Build Coastguard Worker switch (type.base_type) {
335*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_STRING: return "__string";
336*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_STRUCT: return "__struct";
337*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_UNION: return "__union";
338*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_VECTOR:
339*890232f2SAndroid Build Coastguard Worker return ByteBufferGetter(type.VectorType(), bb_var_name);
340*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_INT:
341*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_UINT: return bb_var_name + ".getInt";
342*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_SHORT:
343*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_USHORT: return bb_var_name + ".getShort";
344*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_ULONG:
345*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_LONG: return bb_var_name + ".getLong";
346*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_FLOAT: return bb_var_name + ".getFloat";
347*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_DOUBLE: return bb_var_name + ".getDouble";
348*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_CHAR:
349*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_UCHAR:
350*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_NONE:
351*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_UTYPE: return bb_var_name + ".get";
352*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_BOOL: return "0.toByte() != " + bb_var_name + ".get";
353*890232f2SAndroid Build Coastguard Worker default:
354*890232f2SAndroid Build Coastguard Worker return bb_var_name + "." +
355*890232f2SAndroid Build Coastguard Worker namer_.Method("get", GenTypeBasic(type.base_type));
356*890232f2SAndroid Build Coastguard Worker }
357*890232f2SAndroid Build Coastguard Worker }
358*890232f2SAndroid Build Coastguard Worker
ByteBufferSetter(const Type & type) const359*890232f2SAndroid Build Coastguard Worker std::string ByteBufferSetter(const Type &type) const {
360*890232f2SAndroid Build Coastguard Worker if (IsScalar(type.base_type)) {
361*890232f2SAndroid Build Coastguard Worker switch (type.base_type) {
362*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_INT:
363*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_UINT: return "bb.putInt";
364*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_SHORT:
365*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_USHORT: return "bb.putShort";
366*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_ULONG:
367*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_LONG: return "bb.putLong";
368*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_FLOAT: return "bb.putFloat";
369*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_DOUBLE: return "bb.putDouble";
370*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_CHAR:
371*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_UCHAR:
372*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_BOOL:
373*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_NONE:
374*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_UTYPE: return "bb.put";
375*890232f2SAndroid Build Coastguard Worker default:
376*890232f2SAndroid Build Coastguard Worker return "bb." + namer_.Method("put", GenTypeBasic(type.base_type));
377*890232f2SAndroid Build Coastguard Worker }
378*890232f2SAndroid Build Coastguard Worker }
379*890232f2SAndroid Build Coastguard Worker return "";
380*890232f2SAndroid Build Coastguard Worker }
381*890232f2SAndroid Build Coastguard Worker
382*890232f2SAndroid Build Coastguard Worker // Returns the function name that is able to read a value of the given type.
GenLookupByKey(flatbuffers::FieldDef * key_field,const std::string & bb_var_name,const char * num=nullptr) const383*890232f2SAndroid Build Coastguard Worker std::string GenLookupByKey(flatbuffers::FieldDef *key_field,
384*890232f2SAndroid Build Coastguard Worker const std::string &bb_var_name,
385*890232f2SAndroid Build Coastguard Worker const char *num = nullptr) const {
386*890232f2SAndroid Build Coastguard Worker auto type = key_field->value.type;
387*890232f2SAndroid Build Coastguard Worker return ByteBufferGetter(type, bb_var_name) + "(" +
388*890232f2SAndroid Build Coastguard Worker GenOffsetGetter(key_field, num) + ")";
389*890232f2SAndroid Build Coastguard Worker }
390*890232f2SAndroid Build Coastguard Worker
391*890232f2SAndroid Build Coastguard Worker // Returns the method name for use with add/put calls.
GenMethod(const Type & type)392*890232f2SAndroid Build Coastguard Worker static std::string GenMethod(const Type &type) {
393*890232f2SAndroid Build Coastguard Worker return IsScalar(type.base_type) ? ToSignedType(type)
394*890232f2SAndroid Build Coastguard Worker : (IsStruct(type) ? "Struct" : "Offset");
395*890232f2SAndroid Build Coastguard Worker }
396*890232f2SAndroid Build Coastguard Worker
397*890232f2SAndroid Build Coastguard Worker // Recursively generate arguments for a constructor, to deal with nested
398*890232f2SAndroid Build Coastguard Worker // structs.
GenStructArgs(const StructDef & struct_def,CodeWriter & writer,const char * nameprefix) const399*890232f2SAndroid Build Coastguard Worker void GenStructArgs(const StructDef &struct_def, CodeWriter &writer,
400*890232f2SAndroid Build Coastguard Worker const char *nameprefix) const {
401*890232f2SAndroid Build Coastguard Worker for (auto it = struct_def.fields.vec.begin();
402*890232f2SAndroid Build Coastguard Worker it != struct_def.fields.vec.end(); ++it) {
403*890232f2SAndroid Build Coastguard Worker auto &field = **it;
404*890232f2SAndroid Build Coastguard Worker if (IsStruct(field.value.type)) {
405*890232f2SAndroid Build Coastguard Worker // Generate arguments for a struct inside a struct. To ensure
406*890232f2SAndroid Build Coastguard Worker // names don't clash, and to make it obvious these arguments are
407*890232f2SAndroid Build Coastguard Worker // constructing a nested struct, prefix the name with the field
408*890232f2SAndroid Build Coastguard Worker // name.
409*890232f2SAndroid Build Coastguard Worker GenStructArgs(*field.value.type.struct_def, writer,
410*890232f2SAndroid Build Coastguard Worker (nameprefix + (field.name + "_")).c_str());
411*890232f2SAndroid Build Coastguard Worker } else {
412*890232f2SAndroid Build Coastguard Worker writer += std::string(", ") + nameprefix + "\\";
413*890232f2SAndroid Build Coastguard Worker writer += namer_.Field(field) + ": \\";
414*890232f2SAndroid Build Coastguard Worker writer += GenTypeBasic(field.value.type.base_type) + "\\";
415*890232f2SAndroid Build Coastguard Worker }
416*890232f2SAndroid Build Coastguard Worker }
417*890232f2SAndroid Build Coastguard Worker }
418*890232f2SAndroid Build Coastguard Worker
419*890232f2SAndroid Build Coastguard Worker // Recusively generate struct construction statements of the form:
420*890232f2SAndroid Build Coastguard Worker // builder.putType(name);
421*890232f2SAndroid Build Coastguard Worker // and insert manual padding.
GenStructBody(const StructDef & struct_def,CodeWriter & writer,const char * nameprefix) const422*890232f2SAndroid Build Coastguard Worker void GenStructBody(const StructDef &struct_def, CodeWriter &writer,
423*890232f2SAndroid Build Coastguard Worker const char *nameprefix) const {
424*890232f2SAndroid Build Coastguard Worker writer.SetValue("align", NumToString(struct_def.minalign));
425*890232f2SAndroid Build Coastguard Worker writer.SetValue("size", NumToString(struct_def.bytesize));
426*890232f2SAndroid Build Coastguard Worker writer += "builder.prep({{align}}, {{size}})";
427*890232f2SAndroid Build Coastguard Worker auto fields_vec = struct_def.fields.vec;
428*890232f2SAndroid Build Coastguard Worker for (auto it = fields_vec.rbegin(); it != fields_vec.rend(); ++it) {
429*890232f2SAndroid Build Coastguard Worker auto &field = **it;
430*890232f2SAndroid Build Coastguard Worker
431*890232f2SAndroid Build Coastguard Worker if (field.padding) {
432*890232f2SAndroid Build Coastguard Worker writer.SetValue("pad", NumToString(field.padding));
433*890232f2SAndroid Build Coastguard Worker writer += "builder.pad({{pad}})";
434*890232f2SAndroid Build Coastguard Worker }
435*890232f2SAndroid Build Coastguard Worker if (IsStruct(field.value.type)) {
436*890232f2SAndroid Build Coastguard Worker GenStructBody(*field.value.type.struct_def, writer,
437*890232f2SAndroid Build Coastguard Worker (nameprefix + (field.name + "_")).c_str());
438*890232f2SAndroid Build Coastguard Worker } else {
439*890232f2SAndroid Build Coastguard Worker writer.SetValue("type", GenMethod(field.value.type));
440*890232f2SAndroid Build Coastguard Worker writer.SetValue("argname", nameprefix + namer_.Variable(field));
441*890232f2SAndroid Build Coastguard Worker writer.SetValue("cast", CastToSigned(field.value.type));
442*890232f2SAndroid Build Coastguard Worker writer += "builder.put{{type}}({{argname}}{{cast}})";
443*890232f2SAndroid Build Coastguard Worker }
444*890232f2SAndroid Build Coastguard Worker }
445*890232f2SAndroid Build Coastguard Worker }
446*890232f2SAndroid Build Coastguard Worker
GenByteBufferLength(const char * bb_name) const447*890232f2SAndroid Build Coastguard Worker std::string GenByteBufferLength(const char *bb_name) const {
448*890232f2SAndroid Build Coastguard Worker std::string bb_len = bb_name;
449*890232f2SAndroid Build Coastguard Worker bb_len += ".capacity()";
450*890232f2SAndroid Build Coastguard Worker return bb_len;
451*890232f2SAndroid Build Coastguard Worker }
452*890232f2SAndroid Build Coastguard Worker
GenOffsetGetter(flatbuffers::FieldDef * key_field,const char * num=nullptr) const453*890232f2SAndroid Build Coastguard Worker std::string GenOffsetGetter(flatbuffers::FieldDef *key_field,
454*890232f2SAndroid Build Coastguard Worker const char *num = nullptr) const {
455*890232f2SAndroid Build Coastguard Worker std::string key_offset =
456*890232f2SAndroid Build Coastguard Worker "__offset(" + NumToString(key_field->value.offset) + ", ";
457*890232f2SAndroid Build Coastguard Worker if (num) {
458*890232f2SAndroid Build Coastguard Worker key_offset += num;
459*890232f2SAndroid Build Coastguard Worker key_offset += ", _bb)";
460*890232f2SAndroid Build Coastguard Worker } else {
461*890232f2SAndroid Build Coastguard Worker key_offset += GenByteBufferLength("bb");
462*890232f2SAndroid Build Coastguard Worker key_offset += " - tableOffset, bb)";
463*890232f2SAndroid Build Coastguard Worker }
464*890232f2SAndroid Build Coastguard Worker return key_offset;
465*890232f2SAndroid Build Coastguard Worker }
466*890232f2SAndroid Build Coastguard Worker
GenStruct(StructDef & struct_def,CodeWriter & writer,IDLOptions options) const467*890232f2SAndroid Build Coastguard Worker void GenStruct(StructDef &struct_def, CodeWriter &writer,
468*890232f2SAndroid Build Coastguard Worker IDLOptions options) const {
469*890232f2SAndroid Build Coastguard Worker if (struct_def.generated) return;
470*890232f2SAndroid Build Coastguard Worker
471*890232f2SAndroid Build Coastguard Worker GenerateComment(struct_def.doc_comment, writer, &comment_config);
472*890232f2SAndroid Build Coastguard Worker auto fixed = struct_def.fixed;
473*890232f2SAndroid Build Coastguard Worker
474*890232f2SAndroid Build Coastguard Worker writer.SetValue("struct_name", namer_.Type(struct_def));
475*890232f2SAndroid Build Coastguard Worker writer.SetValue("superclass", fixed ? "Struct" : "Table");
476*890232f2SAndroid Build Coastguard Worker
477*890232f2SAndroid Build Coastguard Worker writer += "@Suppress(\"unused\")";
478*890232f2SAndroid Build Coastguard Worker writer += "class {{struct_name}} : {{superclass}}() {\n";
479*890232f2SAndroid Build Coastguard Worker
480*890232f2SAndroid Build Coastguard Worker writer.IncrementIdentLevel();
481*890232f2SAndroid Build Coastguard Worker
482*890232f2SAndroid Build Coastguard Worker {
483*890232f2SAndroid Build Coastguard Worker // Generate the __init() method that sets the field in a pre-existing
484*890232f2SAndroid Build Coastguard Worker // accessor object. This is to allow object reuse.
485*890232f2SAndroid Build Coastguard Worker GenerateFun(writer, "__init", "_i: Int, _bb: ByteBuffer", "",
486*890232f2SAndroid Build Coastguard Worker [&]() { writer += "__reset(_i, _bb)"; });
487*890232f2SAndroid Build Coastguard Worker
488*890232f2SAndroid Build Coastguard Worker // Generate assign method
489*890232f2SAndroid Build Coastguard Worker GenerateFun(writer, "__assign", "_i: Int, _bb: ByteBuffer",
490*890232f2SAndroid Build Coastguard Worker namer_.Type(struct_def), [&]() {
491*890232f2SAndroid Build Coastguard Worker writer += "__init(_i, _bb)";
492*890232f2SAndroid Build Coastguard Worker writer += "return this";
493*890232f2SAndroid Build Coastguard Worker });
494*890232f2SAndroid Build Coastguard Worker
495*890232f2SAndroid Build Coastguard Worker // Generate all getters
496*890232f2SAndroid Build Coastguard Worker GenerateStructGetters(struct_def, writer);
497*890232f2SAndroid Build Coastguard Worker
498*890232f2SAndroid Build Coastguard Worker // Generate Static Fields
499*890232f2SAndroid Build Coastguard Worker GenerateCompanionObject(writer, [&]() {
500*890232f2SAndroid Build Coastguard Worker if (!struct_def.fixed) {
501*890232f2SAndroid Build Coastguard Worker FieldDef *key_field = nullptr;
502*890232f2SAndroid Build Coastguard Worker
503*890232f2SAndroid Build Coastguard Worker // Generate verson check method.
504*890232f2SAndroid Build Coastguard Worker // Force compile time error if not using the same version
505*890232f2SAndroid Build Coastguard Worker // runtime.
506*890232f2SAndroid Build Coastguard Worker GenerateFunOneLine(
507*890232f2SAndroid Build Coastguard Worker writer, "validateVersion", "", "",
508*890232f2SAndroid Build Coastguard Worker [&]() { writer += "Constants.FLATBUFFERS_2_0_0()"; },
509*890232f2SAndroid Build Coastguard Worker options.gen_jvmstatic);
510*890232f2SAndroid Build Coastguard Worker
511*890232f2SAndroid Build Coastguard Worker GenerateGetRootAsAccessors(namer_.Type(struct_def), writer, options);
512*890232f2SAndroid Build Coastguard Worker GenerateBufferHasIdentifier(struct_def, writer, options);
513*890232f2SAndroid Build Coastguard Worker GenerateTableCreator(struct_def, writer, options);
514*890232f2SAndroid Build Coastguard Worker
515*890232f2SAndroid Build Coastguard Worker GenerateStartStructMethod(struct_def, writer, options);
516*890232f2SAndroid Build Coastguard Worker
517*890232f2SAndroid Build Coastguard Worker // Static Add for fields
518*890232f2SAndroid Build Coastguard Worker auto fields = struct_def.fields.vec;
519*890232f2SAndroid Build Coastguard Worker int field_pos = -1;
520*890232f2SAndroid Build Coastguard Worker for (auto it = fields.begin(); it != fields.end(); ++it) {
521*890232f2SAndroid Build Coastguard Worker auto &field = **it;
522*890232f2SAndroid Build Coastguard Worker field_pos++;
523*890232f2SAndroid Build Coastguard Worker if (field.deprecated) continue;
524*890232f2SAndroid Build Coastguard Worker if (field.key) key_field = &field;
525*890232f2SAndroid Build Coastguard Worker GenerateAddField(NumToString(field_pos), field, writer, options);
526*890232f2SAndroid Build Coastguard Worker
527*890232f2SAndroid Build Coastguard Worker if (IsVector(field.value.type)) {
528*890232f2SAndroid Build Coastguard Worker auto vector_type = field.value.type.VectorType();
529*890232f2SAndroid Build Coastguard Worker if (!IsStruct(vector_type)) {
530*890232f2SAndroid Build Coastguard Worker GenerateCreateVectorField(field, writer, options);
531*890232f2SAndroid Build Coastguard Worker }
532*890232f2SAndroid Build Coastguard Worker GenerateStartVectorField(field, writer, options);
533*890232f2SAndroid Build Coastguard Worker }
534*890232f2SAndroid Build Coastguard Worker }
535*890232f2SAndroid Build Coastguard Worker
536*890232f2SAndroid Build Coastguard Worker GenerateEndStructMethod(struct_def, writer, options);
537*890232f2SAndroid Build Coastguard Worker auto file_identifier = parser_.file_identifier_;
538*890232f2SAndroid Build Coastguard Worker if (parser_.root_struct_def_ == &struct_def) {
539*890232f2SAndroid Build Coastguard Worker GenerateFinishStructBuffer(struct_def, file_identifier, writer,
540*890232f2SAndroid Build Coastguard Worker options);
541*890232f2SAndroid Build Coastguard Worker GenerateFinishSizePrefixed(struct_def, file_identifier, writer,
542*890232f2SAndroid Build Coastguard Worker options);
543*890232f2SAndroid Build Coastguard Worker }
544*890232f2SAndroid Build Coastguard Worker
545*890232f2SAndroid Build Coastguard Worker if (struct_def.has_key) {
546*890232f2SAndroid Build Coastguard Worker GenerateLookupByKey(key_field, struct_def, writer, options);
547*890232f2SAndroid Build Coastguard Worker }
548*890232f2SAndroid Build Coastguard Worker } else {
549*890232f2SAndroid Build Coastguard Worker GenerateStaticConstructor(struct_def, writer, options);
550*890232f2SAndroid Build Coastguard Worker }
551*890232f2SAndroid Build Coastguard Worker });
552*890232f2SAndroid Build Coastguard Worker }
553*890232f2SAndroid Build Coastguard Worker
554*890232f2SAndroid Build Coastguard Worker // class closing
555*890232f2SAndroid Build Coastguard Worker writer.DecrementIdentLevel();
556*890232f2SAndroid Build Coastguard Worker writer += "}";
557*890232f2SAndroid Build Coastguard Worker }
558*890232f2SAndroid Build Coastguard Worker
559*890232f2SAndroid Build Coastguard Worker // TODO: move key_field to reference instead of pointer
GenerateLookupByKey(FieldDef * key_field,StructDef & struct_def,CodeWriter & writer,const IDLOptions options) const560*890232f2SAndroid Build Coastguard Worker void GenerateLookupByKey(FieldDef *key_field, StructDef &struct_def,
561*890232f2SAndroid Build Coastguard Worker CodeWriter &writer, const IDLOptions options) const {
562*890232f2SAndroid Build Coastguard Worker std::stringstream params;
563*890232f2SAndroid Build Coastguard Worker params << "obj: " << namer_.Type(struct_def) << "?"
564*890232f2SAndroid Build Coastguard Worker << ", ";
565*890232f2SAndroid Build Coastguard Worker params << "vectorLocation: Int, ";
566*890232f2SAndroid Build Coastguard Worker params << "key: " << GenTypeGet(key_field->value.type) << ", ";
567*890232f2SAndroid Build Coastguard Worker params << "bb: ByteBuffer";
568*890232f2SAndroid Build Coastguard Worker
569*890232f2SAndroid Build Coastguard Worker auto statements = [&]() {
570*890232f2SAndroid Build Coastguard Worker auto base_type = key_field->value.type.base_type;
571*890232f2SAndroid Build Coastguard Worker writer.SetValue("struct_name", namer_.Type(struct_def));
572*890232f2SAndroid Build Coastguard Worker if (base_type == BASE_TYPE_STRING) {
573*890232f2SAndroid Build Coastguard Worker writer +=
574*890232f2SAndroid Build Coastguard Worker "val byteKey = key."
575*890232f2SAndroid Build Coastguard Worker "toByteArray(java.nio.charset.StandardCharsets.UTF_8)";
576*890232f2SAndroid Build Coastguard Worker }
577*890232f2SAndroid Build Coastguard Worker writer += "var span = bb.getInt(vectorLocation - 4)";
578*890232f2SAndroid Build Coastguard Worker writer += "var start = 0";
579*890232f2SAndroid Build Coastguard Worker writer += "while (span != 0) {";
580*890232f2SAndroid Build Coastguard Worker writer.IncrementIdentLevel();
581*890232f2SAndroid Build Coastguard Worker writer += "var middle = span / 2";
582*890232f2SAndroid Build Coastguard Worker writer +=
583*890232f2SAndroid Build Coastguard Worker "val tableOffset = __indirect(vector"
584*890232f2SAndroid Build Coastguard Worker "Location + 4 * (start + middle), bb)";
585*890232f2SAndroid Build Coastguard Worker if (IsString(key_field->value.type)) {
586*890232f2SAndroid Build Coastguard Worker writer += "val comp = compareStrings(\\";
587*890232f2SAndroid Build Coastguard Worker writer += GenOffsetGetter(key_field) + "\\";
588*890232f2SAndroid Build Coastguard Worker writer += ", byteKey, bb)";
589*890232f2SAndroid Build Coastguard Worker } else {
590*890232f2SAndroid Build Coastguard Worker auto cast = CastToUsigned(key_field->value.type);
591*890232f2SAndroid Build Coastguard Worker auto get_val = GenLookupByKey(key_field, "bb");
592*890232f2SAndroid Build Coastguard Worker writer += "val value = " + get_val + cast;
593*890232f2SAndroid Build Coastguard Worker writer += "val comp = value.compareTo(key)";
594*890232f2SAndroid Build Coastguard Worker }
595*890232f2SAndroid Build Coastguard Worker writer += "when {";
596*890232f2SAndroid Build Coastguard Worker writer.IncrementIdentLevel();
597*890232f2SAndroid Build Coastguard Worker writer += "comp > 0 -> span = middle";
598*890232f2SAndroid Build Coastguard Worker writer += "comp < 0 -> {";
599*890232f2SAndroid Build Coastguard Worker writer.IncrementIdentLevel();
600*890232f2SAndroid Build Coastguard Worker writer += "middle++";
601*890232f2SAndroid Build Coastguard Worker writer += "start += middle";
602*890232f2SAndroid Build Coastguard Worker writer += "span -= middle";
603*890232f2SAndroid Build Coastguard Worker writer.DecrementIdentLevel();
604*890232f2SAndroid Build Coastguard Worker writer += "}"; // end comp < 0
605*890232f2SAndroid Build Coastguard Worker writer += "else -> {";
606*890232f2SAndroid Build Coastguard Worker writer.IncrementIdentLevel();
607*890232f2SAndroid Build Coastguard Worker writer += "return (obj ?: {{struct_name}}()).__assign(tableOffset, bb)";
608*890232f2SAndroid Build Coastguard Worker writer.DecrementIdentLevel();
609*890232f2SAndroid Build Coastguard Worker writer += "}"; // end else
610*890232f2SAndroid Build Coastguard Worker writer.DecrementIdentLevel();
611*890232f2SAndroid Build Coastguard Worker writer += "}"; // end when
612*890232f2SAndroid Build Coastguard Worker writer.DecrementIdentLevel();
613*890232f2SAndroid Build Coastguard Worker writer += "}"; // end while
614*890232f2SAndroid Build Coastguard Worker writer += "return null";
615*890232f2SAndroid Build Coastguard Worker };
616*890232f2SAndroid Build Coastguard Worker GenerateFun(writer, "__lookup_by_key", params.str(),
617*890232f2SAndroid Build Coastguard Worker namer_.Type(struct_def) + "?", statements,
618*890232f2SAndroid Build Coastguard Worker options.gen_jvmstatic);
619*890232f2SAndroid Build Coastguard Worker }
620*890232f2SAndroid Build Coastguard Worker
GenerateFinishSizePrefixed(StructDef & struct_def,const std::string & identifier,CodeWriter & writer,const IDLOptions options) const621*890232f2SAndroid Build Coastguard Worker void GenerateFinishSizePrefixed(StructDef &struct_def,
622*890232f2SAndroid Build Coastguard Worker const std::string &identifier,
623*890232f2SAndroid Build Coastguard Worker CodeWriter &writer,
624*890232f2SAndroid Build Coastguard Worker const IDLOptions options) const {
625*890232f2SAndroid Build Coastguard Worker auto id = identifier.length() > 0 ? ", \"" + identifier + "\"" : "";
626*890232f2SAndroid Build Coastguard Worker auto params = "builder: FlatBufferBuilder, offset: Int";
627*890232f2SAndroid Build Coastguard Worker auto method_name =
628*890232f2SAndroid Build Coastguard Worker namer_.LegacyJavaMethod2("finishSizePrefixed", struct_def, "Buffer");
629*890232f2SAndroid Build Coastguard Worker GenerateFunOneLine(
630*890232f2SAndroid Build Coastguard Worker writer, method_name, params, "",
631*890232f2SAndroid Build Coastguard Worker [&]() { writer += "builder.finishSizePrefixed(offset" + id + ")"; },
632*890232f2SAndroid Build Coastguard Worker options.gen_jvmstatic);
633*890232f2SAndroid Build Coastguard Worker }
GenerateFinishStructBuffer(StructDef & struct_def,const std::string & identifier,CodeWriter & writer,const IDLOptions options) const634*890232f2SAndroid Build Coastguard Worker void GenerateFinishStructBuffer(StructDef &struct_def,
635*890232f2SAndroid Build Coastguard Worker const std::string &identifier,
636*890232f2SAndroid Build Coastguard Worker CodeWriter &writer,
637*890232f2SAndroid Build Coastguard Worker const IDLOptions options) const {
638*890232f2SAndroid Build Coastguard Worker auto id = identifier.length() > 0 ? ", \"" + identifier + "\"" : "";
639*890232f2SAndroid Build Coastguard Worker auto params = "builder: FlatBufferBuilder, offset: Int";
640*890232f2SAndroid Build Coastguard Worker auto method_name =
641*890232f2SAndroid Build Coastguard Worker namer_.LegacyKotlinMethod("finish", struct_def, "Buffer");
642*890232f2SAndroid Build Coastguard Worker GenerateFunOneLine(
643*890232f2SAndroid Build Coastguard Worker writer, method_name, params, "",
644*890232f2SAndroid Build Coastguard Worker [&]() { writer += "builder.finish(offset" + id + ")"; },
645*890232f2SAndroid Build Coastguard Worker options.gen_jvmstatic);
646*890232f2SAndroid Build Coastguard Worker }
647*890232f2SAndroid Build Coastguard Worker
GenerateEndStructMethod(StructDef & struct_def,CodeWriter & writer,const IDLOptions options) const648*890232f2SAndroid Build Coastguard Worker void GenerateEndStructMethod(StructDef &struct_def, CodeWriter &writer,
649*890232f2SAndroid Build Coastguard Worker const IDLOptions options) const {
650*890232f2SAndroid Build Coastguard Worker // Generate end{{TableName}}(builder: FlatBufferBuilder) method
651*890232f2SAndroid Build Coastguard Worker auto name = namer_.LegacyJavaMethod2("end", struct_def, "");
652*890232f2SAndroid Build Coastguard Worker auto params = "builder: FlatBufferBuilder";
653*890232f2SAndroid Build Coastguard Worker auto returns = "Int";
654*890232f2SAndroid Build Coastguard Worker auto field_vec = struct_def.fields.vec;
655*890232f2SAndroid Build Coastguard Worker
656*890232f2SAndroid Build Coastguard Worker GenerateFun(
657*890232f2SAndroid Build Coastguard Worker writer, name, params, returns,
658*890232f2SAndroid Build Coastguard Worker [&]() {
659*890232f2SAndroid Build Coastguard Worker writer += "val o = builder.endTable()";
660*890232f2SAndroid Build Coastguard Worker writer.IncrementIdentLevel();
661*890232f2SAndroid Build Coastguard Worker for (auto it = field_vec.begin(); it != field_vec.end(); ++it) {
662*890232f2SAndroid Build Coastguard Worker auto &field = **it;
663*890232f2SAndroid Build Coastguard Worker if (field.deprecated || !field.IsRequired()) { continue; }
664*890232f2SAndroid Build Coastguard Worker writer.SetValue("offset", NumToString(field.value.offset));
665*890232f2SAndroid Build Coastguard Worker writer += "builder.required(o, {{offset}})";
666*890232f2SAndroid Build Coastguard Worker }
667*890232f2SAndroid Build Coastguard Worker writer.DecrementIdentLevel();
668*890232f2SAndroid Build Coastguard Worker writer += "return o";
669*890232f2SAndroid Build Coastguard Worker },
670*890232f2SAndroid Build Coastguard Worker options.gen_jvmstatic);
671*890232f2SAndroid Build Coastguard Worker }
672*890232f2SAndroid Build Coastguard Worker
673*890232f2SAndroid Build Coastguard Worker // Generate a method to create a vector from a Kotlin array.
GenerateCreateVectorField(FieldDef & field,CodeWriter & writer,const IDLOptions options) const674*890232f2SAndroid Build Coastguard Worker void GenerateCreateVectorField(FieldDef &field, CodeWriter &writer,
675*890232f2SAndroid Build Coastguard Worker const IDLOptions options) const {
676*890232f2SAndroid Build Coastguard Worker auto vector_type = field.value.type.VectorType();
677*890232f2SAndroid Build Coastguard Worker auto method_name = namer_.Method("create", field, "vector");
678*890232f2SAndroid Build Coastguard Worker auto params = "builder: FlatBufferBuilder, data: " +
679*890232f2SAndroid Build Coastguard Worker GenTypeBasic(vector_type.base_type) + "Array";
680*890232f2SAndroid Build Coastguard Worker writer.SetValue("size", NumToString(InlineSize(vector_type)));
681*890232f2SAndroid Build Coastguard Worker writer.SetValue("align", NumToString(InlineAlignment(vector_type)));
682*890232f2SAndroid Build Coastguard Worker writer.SetValue("root", GenMethod(vector_type));
683*890232f2SAndroid Build Coastguard Worker writer.SetValue("cast", CastToSigned(vector_type));
684*890232f2SAndroid Build Coastguard Worker
685*890232f2SAndroid Build Coastguard Worker GenerateFun(
686*890232f2SAndroid Build Coastguard Worker writer, method_name, params, "Int",
687*890232f2SAndroid Build Coastguard Worker [&]() {
688*890232f2SAndroid Build Coastguard Worker writer += "builder.startVector({{size}}, data.size, {{align}})";
689*890232f2SAndroid Build Coastguard Worker writer += "for (i in data.size - 1 downTo 0) {";
690*890232f2SAndroid Build Coastguard Worker writer.IncrementIdentLevel();
691*890232f2SAndroid Build Coastguard Worker writer += "builder.add{{root}}(data[i]{{cast}})";
692*890232f2SAndroid Build Coastguard Worker writer.DecrementIdentLevel();
693*890232f2SAndroid Build Coastguard Worker writer += "}";
694*890232f2SAndroid Build Coastguard Worker writer += "return builder.endVector()";
695*890232f2SAndroid Build Coastguard Worker },
696*890232f2SAndroid Build Coastguard Worker options.gen_jvmstatic);
697*890232f2SAndroid Build Coastguard Worker }
698*890232f2SAndroid Build Coastguard Worker
GenerateStartVectorField(FieldDef & field,CodeWriter & writer,const IDLOptions options) const699*890232f2SAndroid Build Coastguard Worker void GenerateStartVectorField(FieldDef &field, CodeWriter &writer,
700*890232f2SAndroid Build Coastguard Worker const IDLOptions options) const {
701*890232f2SAndroid Build Coastguard Worker // Generate a method to start a vector, data to be added manually
702*890232f2SAndroid Build Coastguard Worker // after.
703*890232f2SAndroid Build Coastguard Worker auto vector_type = field.value.type.VectorType();
704*890232f2SAndroid Build Coastguard Worker auto params = "builder: FlatBufferBuilder, numElems: Int";
705*890232f2SAndroid Build Coastguard Worker writer.SetValue("size", NumToString(InlineSize(vector_type)));
706*890232f2SAndroid Build Coastguard Worker writer.SetValue("align", NumToString(InlineAlignment(vector_type)));
707*890232f2SAndroid Build Coastguard Worker
708*890232f2SAndroid Build Coastguard Worker GenerateFunOneLine(
709*890232f2SAndroid Build Coastguard Worker writer, namer_.Method("start", field, "Vector"), params, "",
710*890232f2SAndroid Build Coastguard Worker [&]() {
711*890232f2SAndroid Build Coastguard Worker writer += "builder.startVector({{size}}, numElems, {{align}})";
712*890232f2SAndroid Build Coastguard Worker },
713*890232f2SAndroid Build Coastguard Worker options.gen_jvmstatic);
714*890232f2SAndroid Build Coastguard Worker }
715*890232f2SAndroid Build Coastguard Worker
GenerateAddField(std::string field_pos,FieldDef & field,CodeWriter & writer,const IDLOptions options) const716*890232f2SAndroid Build Coastguard Worker void GenerateAddField(std::string field_pos, FieldDef &field,
717*890232f2SAndroid Build Coastguard Worker CodeWriter &writer, const IDLOptions options) const {
718*890232f2SAndroid Build Coastguard Worker auto field_type = GenTypeBasic(field.value.type.base_type);
719*890232f2SAndroid Build Coastguard Worker auto secondArg = namer_.Variable(field.name) + ": " + field_type;
720*890232f2SAndroid Build Coastguard Worker
721*890232f2SAndroid Build Coastguard Worker auto content = [&]() {
722*890232f2SAndroid Build Coastguard Worker auto method = GenMethod(field.value.type);
723*890232f2SAndroid Build Coastguard Worker writer.SetValue("field_name", namer_.Field(field));
724*890232f2SAndroid Build Coastguard Worker writer.SetValue("method_name", method);
725*890232f2SAndroid Build Coastguard Worker writer.SetValue("pos", field_pos);
726*890232f2SAndroid Build Coastguard Worker writer.SetValue("default", GenFBBDefaultValue(field));
727*890232f2SAndroid Build Coastguard Worker writer.SetValue("cast", GenFBBValueCast(field));
728*890232f2SAndroid Build Coastguard Worker if (field.key) {
729*890232f2SAndroid Build Coastguard Worker // field has key attribute, so always need to exist
730*890232f2SAndroid Build Coastguard Worker // even if its value is equal to default.
731*890232f2SAndroid Build Coastguard Worker // Generated code will bypass default checking
732*890232f2SAndroid Build Coastguard Worker // resulting in { builder.addShort(name); slot(id); }
733*890232f2SAndroid Build Coastguard Worker writer += "builder.add{{method_name}}({{field_name}}{{cast}})";
734*890232f2SAndroid Build Coastguard Worker writer += "builder.slot({{pos}})";
735*890232f2SAndroid Build Coastguard Worker } else {
736*890232f2SAndroid Build Coastguard Worker writer += "builder.add{{method_name}}({{pos}}, \\";
737*890232f2SAndroid Build Coastguard Worker writer += "{{field_name}}{{cast}}, {{default}})";
738*890232f2SAndroid Build Coastguard Worker }
739*890232f2SAndroid Build Coastguard Worker };
740*890232f2SAndroid Build Coastguard Worker auto signature = namer_.LegacyKotlinMethod("add", field, "");
741*890232f2SAndroid Build Coastguard Worker auto params = "builder: FlatBufferBuilder, " + secondArg;
742*890232f2SAndroid Build Coastguard Worker if (field.key) {
743*890232f2SAndroid Build Coastguard Worker GenerateFun(writer, signature, params, "", content,
744*890232f2SAndroid Build Coastguard Worker options.gen_jvmstatic);
745*890232f2SAndroid Build Coastguard Worker } else {
746*890232f2SAndroid Build Coastguard Worker GenerateFunOneLine(writer, signature, params, "", content,
747*890232f2SAndroid Build Coastguard Worker options.gen_jvmstatic);
748*890232f2SAndroid Build Coastguard Worker }
749*890232f2SAndroid Build Coastguard Worker }
750*890232f2SAndroid Build Coastguard Worker
ToSignedType(const Type & type)751*890232f2SAndroid Build Coastguard Worker static std::string ToSignedType(const Type &type) {
752*890232f2SAndroid Build Coastguard Worker switch (type.base_type) {
753*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_UINT: return GenTypeBasic(BASE_TYPE_INT);
754*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_ULONG: return GenTypeBasic(BASE_TYPE_LONG);
755*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_UCHAR:
756*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_NONE:
757*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_UTYPE: return GenTypeBasic(BASE_TYPE_CHAR);
758*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_USHORT: return GenTypeBasic(BASE_TYPE_SHORT);
759*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_VECTOR: return ToSignedType(type.VectorType());
760*890232f2SAndroid Build Coastguard Worker default: return GenTypeBasic(type.base_type);
761*890232f2SAndroid Build Coastguard Worker }
762*890232f2SAndroid Build Coastguard Worker }
763*890232f2SAndroid Build Coastguard Worker
FlexBufferBuilderCast(const std::string & method,FieldDef & field,bool isFirst)764*890232f2SAndroid Build Coastguard Worker static std::string FlexBufferBuilderCast(const std::string &method,
765*890232f2SAndroid Build Coastguard Worker FieldDef &field, bool isFirst) {
766*890232f2SAndroid Build Coastguard Worker auto field_type = GenTypeBasic(field.value.type.base_type);
767*890232f2SAndroid Build Coastguard Worker std::string to_type;
768*890232f2SAndroid Build Coastguard Worker if (method == "Boolean")
769*890232f2SAndroid Build Coastguard Worker to_type = "Boolean";
770*890232f2SAndroid Build Coastguard Worker else if (method == "Long")
771*890232f2SAndroid Build Coastguard Worker to_type = "Long";
772*890232f2SAndroid Build Coastguard Worker else if (method == "Int" || method == "Offset" || method == "Struct")
773*890232f2SAndroid Build Coastguard Worker to_type = "Int";
774*890232f2SAndroid Build Coastguard Worker else if (method == "Byte" || method.empty())
775*890232f2SAndroid Build Coastguard Worker to_type = isFirst ? "Byte" : "Int";
776*890232f2SAndroid Build Coastguard Worker else if (method == "Short")
777*890232f2SAndroid Build Coastguard Worker to_type = isFirst ? "Short" : "Int";
778*890232f2SAndroid Build Coastguard Worker else if (method == "Double")
779*890232f2SAndroid Build Coastguard Worker to_type = "Double";
780*890232f2SAndroid Build Coastguard Worker else if (method == "Float")
781*890232f2SAndroid Build Coastguard Worker to_type = isFirst ? "Float" : "Double";
782*890232f2SAndroid Build Coastguard Worker else if (method == "UByte")
783*890232f2SAndroid Build Coastguard Worker
784*890232f2SAndroid Build Coastguard Worker if (field_type != to_type) return ".to" + to_type + "()";
785*890232f2SAndroid Build Coastguard Worker return "";
786*890232f2SAndroid Build Coastguard Worker }
787*890232f2SAndroid Build Coastguard Worker
788*890232f2SAndroid Build Coastguard Worker // fun startMonster(builder: FlatBufferBuilder) = builder.startTable(11)
GenerateStartStructMethod(StructDef & struct_def,CodeWriter & code,const IDLOptions options) const789*890232f2SAndroid Build Coastguard Worker void GenerateStartStructMethod(StructDef &struct_def, CodeWriter &code,
790*890232f2SAndroid Build Coastguard Worker const IDLOptions options) const {
791*890232f2SAndroid Build Coastguard Worker GenerateFunOneLine(
792*890232f2SAndroid Build Coastguard Worker code, namer_.LegacyJavaMethod2("start", struct_def, ""),
793*890232f2SAndroid Build Coastguard Worker "builder: FlatBufferBuilder", "",
794*890232f2SAndroid Build Coastguard Worker [&]() {
795*890232f2SAndroid Build Coastguard Worker code += "builder.startTable(" +
796*890232f2SAndroid Build Coastguard Worker NumToString(struct_def.fields.vec.size()) + ")";
797*890232f2SAndroid Build Coastguard Worker },
798*890232f2SAndroid Build Coastguard Worker options.gen_jvmstatic);
799*890232f2SAndroid Build Coastguard Worker }
800*890232f2SAndroid Build Coastguard Worker
GenerateTableCreator(StructDef & struct_def,CodeWriter & writer,const IDLOptions options) const801*890232f2SAndroid Build Coastguard Worker void GenerateTableCreator(StructDef &struct_def, CodeWriter &writer,
802*890232f2SAndroid Build Coastguard Worker const IDLOptions options) const {
803*890232f2SAndroid Build Coastguard Worker // Generate a method that creates a table in one go. This is only possible
804*890232f2SAndroid Build Coastguard Worker // when the table has no struct fields, since those have to be created
805*890232f2SAndroid Build Coastguard Worker // inline, and there's no way to do so in Java.
806*890232f2SAndroid Build Coastguard Worker bool has_no_struct_fields = true;
807*890232f2SAndroid Build Coastguard Worker int num_fields = 0;
808*890232f2SAndroid Build Coastguard Worker auto fields_vec = struct_def.fields.vec;
809*890232f2SAndroid Build Coastguard Worker
810*890232f2SAndroid Build Coastguard Worker for (auto it = fields_vec.begin(); it != fields_vec.end(); ++it) {
811*890232f2SAndroid Build Coastguard Worker auto &field = **it;
812*890232f2SAndroid Build Coastguard Worker if (field.deprecated) continue;
813*890232f2SAndroid Build Coastguard Worker if (IsStruct(field.value.type)) {
814*890232f2SAndroid Build Coastguard Worker has_no_struct_fields = false;
815*890232f2SAndroid Build Coastguard Worker } else {
816*890232f2SAndroid Build Coastguard Worker num_fields++;
817*890232f2SAndroid Build Coastguard Worker }
818*890232f2SAndroid Build Coastguard Worker }
819*890232f2SAndroid Build Coastguard Worker // JVM specifications restrict default constructor params to be < 255.
820*890232f2SAndroid Build Coastguard Worker // Longs and doubles take up 2 units, so we set the limit to be < 127.
821*890232f2SAndroid Build Coastguard Worker if (has_no_struct_fields && num_fields && num_fields < 127) {
822*890232f2SAndroid Build Coastguard Worker // Generate a table constructor of the form:
823*890232f2SAndroid Build Coastguard Worker // public static int createName(FlatBufferBuilder builder, args...)
824*890232f2SAndroid Build Coastguard Worker
825*890232f2SAndroid Build Coastguard Worker auto name = namer_.LegacyJavaMethod2("create", struct_def, "");
826*890232f2SAndroid Build Coastguard Worker std::stringstream params;
827*890232f2SAndroid Build Coastguard Worker params << "builder: FlatBufferBuilder";
828*890232f2SAndroid Build Coastguard Worker for (auto it = fields_vec.begin(); it != fields_vec.end(); ++it) {
829*890232f2SAndroid Build Coastguard Worker auto &field = **it;
830*890232f2SAndroid Build Coastguard Worker if (field.deprecated) continue;
831*890232f2SAndroid Build Coastguard Worker params << ", " << namer_.Variable(field);
832*890232f2SAndroid Build Coastguard Worker if (!IsScalar(field.value.type.base_type)) {
833*890232f2SAndroid Build Coastguard Worker params << "Offset: ";
834*890232f2SAndroid Build Coastguard Worker } else {
835*890232f2SAndroid Build Coastguard Worker params << ": ";
836*890232f2SAndroid Build Coastguard Worker }
837*890232f2SAndroid Build Coastguard Worker auto optional = field.IsScalarOptional() ? "?" : "";
838*890232f2SAndroid Build Coastguard Worker params << GenTypeBasic(field.value.type.base_type) << optional;
839*890232f2SAndroid Build Coastguard Worker }
840*890232f2SAndroid Build Coastguard Worker
841*890232f2SAndroid Build Coastguard Worker GenerateFun(
842*890232f2SAndroid Build Coastguard Worker writer, name, params.str(), "Int",
843*890232f2SAndroid Build Coastguard Worker [&]() {
844*890232f2SAndroid Build Coastguard Worker writer.SetValue("vec_size", NumToString(fields_vec.size()));
845*890232f2SAndroid Build Coastguard Worker
846*890232f2SAndroid Build Coastguard Worker writer += "builder.startTable({{vec_size}})";
847*890232f2SAndroid Build Coastguard Worker
848*890232f2SAndroid Build Coastguard Worker auto sortbysize = struct_def.sortbysize;
849*890232f2SAndroid Build Coastguard Worker auto largest = sortbysize ? sizeof(largest_scalar_t) : 1;
850*890232f2SAndroid Build Coastguard Worker for (size_t size = largest; size; size /= 2) {
851*890232f2SAndroid Build Coastguard Worker for (auto it = fields_vec.rbegin(); it != fields_vec.rend();
852*890232f2SAndroid Build Coastguard Worker ++it) {
853*890232f2SAndroid Build Coastguard Worker auto &field = **it;
854*890232f2SAndroid Build Coastguard Worker auto base_type_size = SizeOf(field.value.type.base_type);
855*890232f2SAndroid Build Coastguard Worker if (!field.deprecated &&
856*890232f2SAndroid Build Coastguard Worker (!sortbysize || size == base_type_size)) {
857*890232f2SAndroid Build Coastguard Worker writer.SetValue("field_name", namer_.Field(field));
858*890232f2SAndroid Build Coastguard Worker
859*890232f2SAndroid Build Coastguard Worker // we wrap on null check for scalar optionals
860*890232f2SAndroid Build Coastguard Worker writer += field.IsScalarOptional()
861*890232f2SAndroid Build Coastguard Worker ? "{{field_name}}?.run { \\"
862*890232f2SAndroid Build Coastguard Worker : "\\";
863*890232f2SAndroid Build Coastguard Worker
864*890232f2SAndroid Build Coastguard Worker writer += namer_.LegacyKotlinMethod("add", field, "") +
865*890232f2SAndroid Build Coastguard Worker "(builder, {{field_name}}\\";
866*890232f2SAndroid Build Coastguard Worker if (!IsScalar(field.value.type.base_type)) {
867*890232f2SAndroid Build Coastguard Worker writer += "Offset\\";
868*890232f2SAndroid Build Coastguard Worker }
869*890232f2SAndroid Build Coastguard Worker // we wrap on null check for scalar optionals
870*890232f2SAndroid Build Coastguard Worker writer += field.IsScalarOptional() ? ") }" : ")";
871*890232f2SAndroid Build Coastguard Worker }
872*890232f2SAndroid Build Coastguard Worker }
873*890232f2SAndroid Build Coastguard Worker }
874*890232f2SAndroid Build Coastguard Worker writer += "return end{{struct_name}}(builder)";
875*890232f2SAndroid Build Coastguard Worker },
876*890232f2SAndroid Build Coastguard Worker options.gen_jvmstatic);
877*890232f2SAndroid Build Coastguard Worker }
878*890232f2SAndroid Build Coastguard Worker }
GenerateBufferHasIdentifier(StructDef & struct_def,CodeWriter & writer,IDLOptions options) const879*890232f2SAndroid Build Coastguard Worker void GenerateBufferHasIdentifier(StructDef &struct_def, CodeWriter &writer,
880*890232f2SAndroid Build Coastguard Worker IDLOptions options) const {
881*890232f2SAndroid Build Coastguard Worker auto file_identifier = parser_.file_identifier_;
882*890232f2SAndroid Build Coastguard Worker // Check if a buffer has the identifier.
883*890232f2SAndroid Build Coastguard Worker if (parser_.root_struct_def_ != &struct_def || !file_identifier.length())
884*890232f2SAndroid Build Coastguard Worker return;
885*890232f2SAndroid Build Coastguard Worker auto name = namer_.Function(struct_def);
886*890232f2SAndroid Build Coastguard Worker GenerateFunOneLine(
887*890232f2SAndroid Build Coastguard Worker writer, name + "BufferHasIdentifier", "_bb: ByteBuffer", "Boolean",
888*890232f2SAndroid Build Coastguard Worker [&]() {
889*890232f2SAndroid Build Coastguard Worker writer += "__has_identifier(_bb, \"" + file_identifier + "\")";
890*890232f2SAndroid Build Coastguard Worker },
891*890232f2SAndroid Build Coastguard Worker options.gen_jvmstatic);
892*890232f2SAndroid Build Coastguard Worker }
893*890232f2SAndroid Build Coastguard Worker
GenerateStructGetters(StructDef & struct_def,CodeWriter & writer) const894*890232f2SAndroid Build Coastguard Worker void GenerateStructGetters(StructDef &struct_def, CodeWriter &writer) const {
895*890232f2SAndroid Build Coastguard Worker auto fields_vec = struct_def.fields.vec;
896*890232f2SAndroid Build Coastguard Worker FieldDef *key_field = nullptr;
897*890232f2SAndroid Build Coastguard Worker for (auto it = fields_vec.begin(); it != fields_vec.end(); ++it) {
898*890232f2SAndroid Build Coastguard Worker auto &field = **it;
899*890232f2SAndroid Build Coastguard Worker if (field.deprecated) continue;
900*890232f2SAndroid Build Coastguard Worker if (field.key) key_field = &field;
901*890232f2SAndroid Build Coastguard Worker
902*890232f2SAndroid Build Coastguard Worker GenerateComment(field.doc_comment, writer, &comment_config);
903*890232f2SAndroid Build Coastguard Worker
904*890232f2SAndroid Build Coastguard Worker auto field_name = namer_.Field(field);
905*890232f2SAndroid Build Coastguard Worker auto field_type = GenTypeGet(field.value.type);
906*890232f2SAndroid Build Coastguard Worker auto field_default_value = GenDefaultValue(field);
907*890232f2SAndroid Build Coastguard Worker auto return_type = GetterReturnType(field);
908*890232f2SAndroid Build Coastguard Worker auto bbgetter = ByteBufferGetter(field.value.type, "bb");
909*890232f2SAndroid Build Coastguard Worker auto ucast = CastToUsigned(field);
910*890232f2SAndroid Build Coastguard Worker auto offset_val = NumToString(field.value.offset);
911*890232f2SAndroid Build Coastguard Worker auto offset_prefix =
912*890232f2SAndroid Build Coastguard Worker "val o = __offset(" + offset_val + "); return o != 0 ? ";
913*890232f2SAndroid Build Coastguard Worker auto value_base_type = field.value.type.base_type;
914*890232f2SAndroid Build Coastguard Worker // Most field accessors need to retrieve and test the field offset
915*890232f2SAndroid Build Coastguard Worker // first, this is the offset value for that:
916*890232f2SAndroid Build Coastguard Worker writer.SetValue("offset", NumToString(field.value.offset));
917*890232f2SAndroid Build Coastguard Worker writer.SetValue("return_type", return_type);
918*890232f2SAndroid Build Coastguard Worker writer.SetValue("field_type", field_type);
919*890232f2SAndroid Build Coastguard Worker writer.SetValue("field_name", field_name);
920*890232f2SAndroid Build Coastguard Worker writer.SetValue("field_default", field_default_value);
921*890232f2SAndroid Build Coastguard Worker writer.SetValue("bbgetter", bbgetter);
922*890232f2SAndroid Build Coastguard Worker writer.SetValue("ucast", ucast);
923*890232f2SAndroid Build Coastguard Worker
924*890232f2SAndroid Build Coastguard Worker // Generate the accessors that don't do object reuse.
925*890232f2SAndroid Build Coastguard Worker if (value_base_type == BASE_TYPE_STRUCT) {
926*890232f2SAndroid Build Coastguard Worker // Calls the accessor that takes an accessor object with a
927*890232f2SAndroid Build Coastguard Worker // new object.
928*890232f2SAndroid Build Coastguard Worker // val pos
929*890232f2SAndroid Build Coastguard Worker // get() = pos(Vec3())
930*890232f2SAndroid Build Coastguard Worker GenerateGetterOneLine(writer, field_name, return_type, [&]() {
931*890232f2SAndroid Build Coastguard Worker writer += "{{field_name}}({{field_type}}())";
932*890232f2SAndroid Build Coastguard Worker });
933*890232f2SAndroid Build Coastguard Worker } else if (value_base_type == BASE_TYPE_VECTOR &&
934*890232f2SAndroid Build Coastguard Worker field.value.type.element == BASE_TYPE_STRUCT) {
935*890232f2SAndroid Build Coastguard Worker // Accessors for vectors of structs also take accessor objects,
936*890232f2SAndroid Build Coastguard Worker // this generates a variant without that argument.
937*890232f2SAndroid Build Coastguard Worker // ex: fun weapons(j: Int) = weapons(Weapon(), j)
938*890232f2SAndroid Build Coastguard Worker GenerateFunOneLine(writer, field_name, "j: Int", return_type, [&]() {
939*890232f2SAndroid Build Coastguard Worker writer += "{{field_name}}({{field_type}}(), j)";
940*890232f2SAndroid Build Coastguard Worker });
941*890232f2SAndroid Build Coastguard Worker }
942*890232f2SAndroid Build Coastguard Worker
943*890232f2SAndroid Build Coastguard Worker if (IsScalar(value_base_type)) {
944*890232f2SAndroid Build Coastguard Worker if (struct_def.fixed) {
945*890232f2SAndroid Build Coastguard Worker GenerateGetterOneLine(writer, field_name, return_type, [&]() {
946*890232f2SAndroid Build Coastguard Worker writer += "{{bbgetter}}(bb_pos + {{offset}}){{ucast}}";
947*890232f2SAndroid Build Coastguard Worker });
948*890232f2SAndroid Build Coastguard Worker } else {
949*890232f2SAndroid Build Coastguard Worker GenerateGetter(writer, field_name, return_type, [&]() {
950*890232f2SAndroid Build Coastguard Worker writer += "val o = __offset({{offset}})";
951*890232f2SAndroid Build Coastguard Worker writer +=
952*890232f2SAndroid Build Coastguard Worker "return if(o != 0) {{bbgetter}}"
953*890232f2SAndroid Build Coastguard Worker "(o + bb_pos){{ucast}} else "
954*890232f2SAndroid Build Coastguard Worker "{{field_default}}";
955*890232f2SAndroid Build Coastguard Worker });
956*890232f2SAndroid Build Coastguard Worker }
957*890232f2SAndroid Build Coastguard Worker } else {
958*890232f2SAndroid Build Coastguard Worker switch (value_base_type) {
959*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_STRUCT:
960*890232f2SAndroid Build Coastguard Worker if (struct_def.fixed) {
961*890232f2SAndroid Build Coastguard Worker // create getter with object reuse
962*890232f2SAndroid Build Coastguard Worker // ex:
963*890232f2SAndroid Build Coastguard Worker // fun pos(obj: Vec3) : Vec3? = obj.__assign(bb_pos + 4, bb)
964*890232f2SAndroid Build Coastguard Worker // ? adds nullability annotation
965*890232f2SAndroid Build Coastguard Worker GenerateFunOneLine(
966*890232f2SAndroid Build Coastguard Worker writer, field_name, "obj: " + field_type, return_type,
967*890232f2SAndroid Build Coastguard Worker [&]() { writer += "obj.__assign(bb_pos + {{offset}}, bb)"; });
968*890232f2SAndroid Build Coastguard Worker } else {
969*890232f2SAndroid Build Coastguard Worker // create getter with object reuse
970*890232f2SAndroid Build Coastguard Worker // ex:
971*890232f2SAndroid Build Coastguard Worker // fun pos(obj: Vec3) : Vec3? {
972*890232f2SAndroid Build Coastguard Worker // val o = __offset(4)
973*890232f2SAndroid Build Coastguard Worker // return if(o != 0) {
974*890232f2SAndroid Build Coastguard Worker // obj.__assign(o + bb_pos, bb)
975*890232f2SAndroid Build Coastguard Worker // else {
976*890232f2SAndroid Build Coastguard Worker // null
977*890232f2SAndroid Build Coastguard Worker // }
978*890232f2SAndroid Build Coastguard Worker // }
979*890232f2SAndroid Build Coastguard Worker // ? adds nullability annotation
980*890232f2SAndroid Build Coastguard Worker GenerateFun(
981*890232f2SAndroid Build Coastguard Worker writer, field_name, "obj: " + field_type, return_type, [&]() {
982*890232f2SAndroid Build Coastguard Worker auto fixed = field.value.type.struct_def->fixed;
983*890232f2SAndroid Build Coastguard Worker
984*890232f2SAndroid Build Coastguard Worker writer.SetValue("seek", Indirect("o + bb_pos", fixed));
985*890232f2SAndroid Build Coastguard Worker OffsetWrapper(
986*890232f2SAndroid Build Coastguard Worker writer, offset_val,
987*890232f2SAndroid Build Coastguard Worker [&]() { writer += "obj.__assign({{seek}}, bb)"; },
988*890232f2SAndroid Build Coastguard Worker [&]() { writer += "null"; });
989*890232f2SAndroid Build Coastguard Worker });
990*890232f2SAndroid Build Coastguard Worker }
991*890232f2SAndroid Build Coastguard Worker break;
992*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_STRING:
993*890232f2SAndroid Build Coastguard Worker // create string getter
994*890232f2SAndroid Build Coastguard Worker // e.g.
995*890232f2SAndroid Build Coastguard Worker // val Name : String?
996*890232f2SAndroid Build Coastguard Worker // get() = {
997*890232f2SAndroid Build Coastguard Worker // val o = __offset(10)
998*890232f2SAndroid Build Coastguard Worker // return if (o != 0) __string(o + bb_pos) else null
999*890232f2SAndroid Build Coastguard Worker // }
1000*890232f2SAndroid Build Coastguard Worker // ? adds nullability annotation
1001*890232f2SAndroid Build Coastguard Worker GenerateGetter(writer, field_name, return_type, [&]() {
1002*890232f2SAndroid Build Coastguard Worker writer += "val o = __offset({{offset}})";
1003*890232f2SAndroid Build Coastguard Worker writer += "return if (o != 0) __string(o + bb_pos) else null";
1004*890232f2SAndroid Build Coastguard Worker });
1005*890232f2SAndroid Build Coastguard Worker break;
1006*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_VECTOR: {
1007*890232f2SAndroid Build Coastguard Worker // e.g.
1008*890232f2SAndroid Build Coastguard Worker // fun inventory(j: Int) : UByte {
1009*890232f2SAndroid Build Coastguard Worker // val o = __offset(14)
1010*890232f2SAndroid Build Coastguard Worker // return if (o != 0) {
1011*890232f2SAndroid Build Coastguard Worker // bb.get(__vector(o) + j * 1).toUByte()
1012*890232f2SAndroid Build Coastguard Worker // } else {
1013*890232f2SAndroid Build Coastguard Worker // 0
1014*890232f2SAndroid Build Coastguard Worker // }
1015*890232f2SAndroid Build Coastguard Worker // }
1016*890232f2SAndroid Build Coastguard Worker
1017*890232f2SAndroid Build Coastguard Worker auto vectortype = field.value.type.VectorType();
1018*890232f2SAndroid Build Coastguard Worker std::string params = "j: Int";
1019*890232f2SAndroid Build Coastguard Worker
1020*890232f2SAndroid Build Coastguard Worker if (vectortype.base_type == BASE_TYPE_STRUCT ||
1021*890232f2SAndroid Build Coastguard Worker vectortype.base_type == BASE_TYPE_UNION) {
1022*890232f2SAndroid Build Coastguard Worker params = "obj: " + field_type + ", j: Int";
1023*890232f2SAndroid Build Coastguard Worker }
1024*890232f2SAndroid Build Coastguard Worker
1025*890232f2SAndroid Build Coastguard Worker GenerateFun(writer, field_name, params, return_type, [&]() {
1026*890232f2SAndroid Build Coastguard Worker auto inline_size = NumToString(InlineSize(vectortype));
1027*890232f2SAndroid Build Coastguard Worker auto index = "__vector(o) + j * " + inline_size;
1028*890232f2SAndroid Build Coastguard Worker auto not_found = NotFoundReturn(field.value.type.element);
1029*890232f2SAndroid Build Coastguard Worker auto found = "";
1030*890232f2SAndroid Build Coastguard Worker writer.SetValue("index", index);
1031*890232f2SAndroid Build Coastguard Worker switch (vectortype.base_type) {
1032*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_STRUCT: {
1033*890232f2SAndroid Build Coastguard Worker bool fixed = vectortype.struct_def->fixed;
1034*890232f2SAndroid Build Coastguard Worker writer.SetValue("index", Indirect(index, fixed));
1035*890232f2SAndroid Build Coastguard Worker found = "obj.__assign({{index}}, bb)";
1036*890232f2SAndroid Build Coastguard Worker break;
1037*890232f2SAndroid Build Coastguard Worker }
1038*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_UNION:
1039*890232f2SAndroid Build Coastguard Worker found = "{{bbgetter}}(obj, {{index}}){{ucast}}";
1040*890232f2SAndroid Build Coastguard Worker break;
1041*890232f2SAndroid Build Coastguard Worker default: found = "{{bbgetter}}({{index}}){{ucast}}";
1042*890232f2SAndroid Build Coastguard Worker }
1043*890232f2SAndroid Build Coastguard Worker OffsetWrapper(
1044*890232f2SAndroid Build Coastguard Worker writer, offset_val, [&]() { writer += found; },
1045*890232f2SAndroid Build Coastguard Worker [&]() { writer += not_found; });
1046*890232f2SAndroid Build Coastguard Worker });
1047*890232f2SAndroid Build Coastguard Worker break;
1048*890232f2SAndroid Build Coastguard Worker }
1049*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_UNION:
1050*890232f2SAndroid Build Coastguard Worker GenerateFun(
1051*890232f2SAndroid Build Coastguard Worker writer, field_name, "obj: " + field_type, return_type, [&]() {
1052*890232f2SAndroid Build Coastguard Worker writer += OffsetWrapperOneLine(
1053*890232f2SAndroid Build Coastguard Worker offset_val, bbgetter + "(obj, o + bb_pos)", "null");
1054*890232f2SAndroid Build Coastguard Worker });
1055*890232f2SAndroid Build Coastguard Worker break;
1056*890232f2SAndroid Build Coastguard Worker default: FLATBUFFERS_ASSERT(0);
1057*890232f2SAndroid Build Coastguard Worker }
1058*890232f2SAndroid Build Coastguard Worker }
1059*890232f2SAndroid Build Coastguard Worker
1060*890232f2SAndroid Build Coastguard Worker if (value_base_type == BASE_TYPE_VECTOR) {
1061*890232f2SAndroid Build Coastguard Worker // Generate Lenght functions for vectors
1062*890232f2SAndroid Build Coastguard Worker GenerateGetter(writer, field_name + "Length", "Int", [&]() {
1063*890232f2SAndroid Build Coastguard Worker writer += OffsetWrapperOneLine(offset_val, "__vector_len(o)", "0");
1064*890232f2SAndroid Build Coastguard Worker });
1065*890232f2SAndroid Build Coastguard Worker
1066*890232f2SAndroid Build Coastguard Worker // See if we should generate a by-key accessor.
1067*890232f2SAndroid Build Coastguard Worker if (field.value.type.element == BASE_TYPE_STRUCT &&
1068*890232f2SAndroid Build Coastguard Worker !field.value.type.struct_def->fixed) {
1069*890232f2SAndroid Build Coastguard Worker auto &sd = *field.value.type.struct_def;
1070*890232f2SAndroid Build Coastguard Worker auto &fields = sd.fields.vec;
1071*890232f2SAndroid Build Coastguard Worker for (auto kit = fields.begin(); kit != fields.end(); ++kit) {
1072*890232f2SAndroid Build Coastguard Worker auto &kfield = **kit;
1073*890232f2SAndroid Build Coastguard Worker if (kfield.key) {
1074*890232f2SAndroid Build Coastguard Worker auto qualified_name = WrapInNameSpace(sd);
1075*890232f2SAndroid Build Coastguard Worker auto name = namer_.Method(field, "ByKey");
1076*890232f2SAndroid Build Coastguard Worker auto params = "key: " + GenTypeGet(kfield.value.type);
1077*890232f2SAndroid Build Coastguard Worker auto rtype = qualified_name + "?";
1078*890232f2SAndroid Build Coastguard Worker GenerateFun(writer, name, params, rtype, [&]() {
1079*890232f2SAndroid Build Coastguard Worker OffsetWrapper(
1080*890232f2SAndroid Build Coastguard Worker writer, offset_val,
1081*890232f2SAndroid Build Coastguard Worker [&]() {
1082*890232f2SAndroid Build Coastguard Worker writer += qualified_name +
1083*890232f2SAndroid Build Coastguard Worker ".__lookup_by_key(null, __vector(o), key, bb)";
1084*890232f2SAndroid Build Coastguard Worker },
1085*890232f2SAndroid Build Coastguard Worker [&]() { writer += "null"; });
1086*890232f2SAndroid Build Coastguard Worker });
1087*890232f2SAndroid Build Coastguard Worker
1088*890232f2SAndroid Build Coastguard Worker auto param2 = "obj: " + qualified_name +
1089*890232f2SAndroid Build Coastguard Worker ", key: " + GenTypeGet(kfield.value.type);
1090*890232f2SAndroid Build Coastguard Worker GenerateFun(writer, name, param2, rtype, [&]() {
1091*890232f2SAndroid Build Coastguard Worker OffsetWrapper(
1092*890232f2SAndroid Build Coastguard Worker writer, offset_val,
1093*890232f2SAndroid Build Coastguard Worker [&]() {
1094*890232f2SAndroid Build Coastguard Worker writer += qualified_name +
1095*890232f2SAndroid Build Coastguard Worker ".__lookup_by_key(obj, __vector(o), key, bb)";
1096*890232f2SAndroid Build Coastguard Worker },
1097*890232f2SAndroid Build Coastguard Worker [&]() { writer += "null"; });
1098*890232f2SAndroid Build Coastguard Worker });
1099*890232f2SAndroid Build Coastguard Worker
1100*890232f2SAndroid Build Coastguard Worker break;
1101*890232f2SAndroid Build Coastguard Worker }
1102*890232f2SAndroid Build Coastguard Worker }
1103*890232f2SAndroid Build Coastguard Worker }
1104*890232f2SAndroid Build Coastguard Worker }
1105*890232f2SAndroid Build Coastguard Worker
1106*890232f2SAndroid Build Coastguard Worker if ((value_base_type == BASE_TYPE_VECTOR &&
1107*890232f2SAndroid Build Coastguard Worker IsScalar(field.value.type.VectorType().base_type)) ||
1108*890232f2SAndroid Build Coastguard Worker value_base_type == BASE_TYPE_STRING) {
1109*890232f2SAndroid Build Coastguard Worker auto end_idx =
1110*890232f2SAndroid Build Coastguard Worker NumToString(value_base_type == BASE_TYPE_STRING
1111*890232f2SAndroid Build Coastguard Worker ? 1
1112*890232f2SAndroid Build Coastguard Worker : InlineSize(field.value.type.VectorType()));
1113*890232f2SAndroid Build Coastguard Worker // Generate a ByteBuffer accessor for strings & vectors of scalars.
1114*890232f2SAndroid Build Coastguard Worker // e.g.
1115*890232f2SAndroid Build Coastguard Worker // val inventoryByteBuffer: ByteBuffer
1116*890232f2SAndroid Build Coastguard Worker // get = __vector_as_bytebuffer(14, 1)
1117*890232f2SAndroid Build Coastguard Worker
1118*890232f2SAndroid Build Coastguard Worker GenerateGetterOneLine(
1119*890232f2SAndroid Build Coastguard Worker writer, field_name + "AsByteBuffer", "ByteBuffer", [&]() {
1120*890232f2SAndroid Build Coastguard Worker writer.SetValue("end", end_idx);
1121*890232f2SAndroid Build Coastguard Worker writer += "__vector_as_bytebuffer({{offset}}, {{end}})";
1122*890232f2SAndroid Build Coastguard Worker });
1123*890232f2SAndroid Build Coastguard Worker
1124*890232f2SAndroid Build Coastguard Worker // Generate a ByteBuffer accessor for strings & vectors of scalars.
1125*890232f2SAndroid Build Coastguard Worker // e.g.
1126*890232f2SAndroid Build Coastguard Worker // fun inventoryInByteBuffer(_bb: Bytebuffer):
1127*890232f2SAndroid Build Coastguard Worker // ByteBuffer = __vector_as_bytebuffer(_bb, 14, 1)
1128*890232f2SAndroid Build Coastguard Worker GenerateFunOneLine(
1129*890232f2SAndroid Build Coastguard Worker writer, field_name + "InByteBuffer", "_bb: ByteBuffer",
1130*890232f2SAndroid Build Coastguard Worker "ByteBuffer", [&]() {
1131*890232f2SAndroid Build Coastguard Worker writer.SetValue("end", end_idx);
1132*890232f2SAndroid Build Coastguard Worker writer += "__vector_in_bytebuffer(_bb, {{offset}}, {{end}})";
1133*890232f2SAndroid Build Coastguard Worker });
1134*890232f2SAndroid Build Coastguard Worker }
1135*890232f2SAndroid Build Coastguard Worker
1136*890232f2SAndroid Build Coastguard Worker // generate object accessors if is nested_flatbuffer
1137*890232f2SAndroid Build Coastguard Worker // fun testnestedflatbufferAsMonster() : Monster?
1138*890232f2SAndroid Build Coastguard Worker //{ return testnestedflatbufferAsMonster(new Monster()); }
1139*890232f2SAndroid Build Coastguard Worker
1140*890232f2SAndroid Build Coastguard Worker if (field.nested_flatbuffer) {
1141*890232f2SAndroid Build Coastguard Worker auto nested_type_name = WrapInNameSpace(*field.nested_flatbuffer);
1142*890232f2SAndroid Build Coastguard Worker auto nested_method_name =
1143*890232f2SAndroid Build Coastguard Worker field_name + "As" + field.nested_flatbuffer->name;
1144*890232f2SAndroid Build Coastguard Worker
1145*890232f2SAndroid Build Coastguard Worker GenerateGetterOneLine(
1146*890232f2SAndroid Build Coastguard Worker writer, nested_method_name, nested_type_name + "?", [&]() {
1147*890232f2SAndroid Build Coastguard Worker writer += nested_method_name + "(" + nested_type_name + "())";
1148*890232f2SAndroid Build Coastguard Worker });
1149*890232f2SAndroid Build Coastguard Worker
1150*890232f2SAndroid Build Coastguard Worker GenerateFun(writer, nested_method_name, "obj: " + nested_type_name,
1151*890232f2SAndroid Build Coastguard Worker nested_type_name + "?", [&]() {
1152*890232f2SAndroid Build Coastguard Worker OffsetWrapper(
1153*890232f2SAndroid Build Coastguard Worker writer, offset_val,
1154*890232f2SAndroid Build Coastguard Worker [&]() {
1155*890232f2SAndroid Build Coastguard Worker writer +=
1156*890232f2SAndroid Build Coastguard Worker "obj.__assign(__indirect(__vector(o)), bb)";
1157*890232f2SAndroid Build Coastguard Worker },
1158*890232f2SAndroid Build Coastguard Worker [&]() { writer += "null"; });
1159*890232f2SAndroid Build Coastguard Worker });
1160*890232f2SAndroid Build Coastguard Worker }
1161*890232f2SAndroid Build Coastguard Worker
1162*890232f2SAndroid Build Coastguard Worker // Generate mutators for scalar fields or vectors of scalars.
1163*890232f2SAndroid Build Coastguard Worker if (parser_.opts.mutable_buffer) {
1164*890232f2SAndroid Build Coastguard Worker auto value_type = field.value.type;
1165*890232f2SAndroid Build Coastguard Worker auto underlying_type = value_base_type == BASE_TYPE_VECTOR
1166*890232f2SAndroid Build Coastguard Worker ? value_type.VectorType()
1167*890232f2SAndroid Build Coastguard Worker : value_type;
1168*890232f2SAndroid Build Coastguard Worker auto name = namer_.LegacyKotlinMethod("mutate", field, "");
1169*890232f2SAndroid Build Coastguard Worker auto size = NumToString(InlineSize(underlying_type));
1170*890232f2SAndroid Build Coastguard Worker auto params = namer_.Field(field) + ": " + GenTypeGet(underlying_type);
1171*890232f2SAndroid Build Coastguard Worker // A vector mutator also needs the index of the vector element it should
1172*890232f2SAndroid Build Coastguard Worker // mutate.
1173*890232f2SAndroid Build Coastguard Worker if (value_base_type == BASE_TYPE_VECTOR) params.insert(0, "j: Int, ");
1174*890232f2SAndroid Build Coastguard Worker
1175*890232f2SAndroid Build Coastguard Worker // Boolean parameters have to be explicitly converted to byte
1176*890232f2SAndroid Build Coastguard Worker // representation.
1177*890232f2SAndroid Build Coastguard Worker auto setter_parameter =
1178*890232f2SAndroid Build Coastguard Worker underlying_type.base_type == BASE_TYPE_BOOL
1179*890232f2SAndroid Build Coastguard Worker ? "(if(" + namer_.Field(field) + ") 1 else 0).toByte()"
1180*890232f2SAndroid Build Coastguard Worker : namer_.Field(field);
1181*890232f2SAndroid Build Coastguard Worker
1182*890232f2SAndroid Build Coastguard Worker auto setter_index =
1183*890232f2SAndroid Build Coastguard Worker value_base_type == BASE_TYPE_VECTOR
1184*890232f2SAndroid Build Coastguard Worker ? "__vector(o) + j * " + size
1185*890232f2SAndroid Build Coastguard Worker : (struct_def.fixed ? "bb_pos + " + offset_val : "o + bb_pos");
1186*890232f2SAndroid Build Coastguard Worker if (IsScalar(value_base_type) ||
1187*890232f2SAndroid Build Coastguard Worker (value_base_type == BASE_TYPE_VECTOR &&
1188*890232f2SAndroid Build Coastguard Worker IsScalar(value_type.VectorType().base_type))) {
1189*890232f2SAndroid Build Coastguard Worker auto statements = [&]() {
1190*890232f2SAndroid Build Coastguard Worker writer.SetValue("bbsetter", ByteBufferSetter(underlying_type));
1191*890232f2SAndroid Build Coastguard Worker writer.SetValue("index", setter_index);
1192*890232f2SAndroid Build Coastguard Worker writer.SetValue("params", setter_parameter);
1193*890232f2SAndroid Build Coastguard Worker writer.SetValue("cast", CastToSigned(field));
1194*890232f2SAndroid Build Coastguard Worker if (struct_def.fixed) {
1195*890232f2SAndroid Build Coastguard Worker writer += "{{bbsetter}}({{index}}, {{params}}{{cast}})";
1196*890232f2SAndroid Build Coastguard Worker } else {
1197*890232f2SAndroid Build Coastguard Worker OffsetWrapper(
1198*890232f2SAndroid Build Coastguard Worker writer, offset_val,
1199*890232f2SAndroid Build Coastguard Worker [&]() {
1200*890232f2SAndroid Build Coastguard Worker writer += "{{bbsetter}}({{index}}, {{params}}{{cast}})";
1201*890232f2SAndroid Build Coastguard Worker writer += "true";
1202*890232f2SAndroid Build Coastguard Worker },
1203*890232f2SAndroid Build Coastguard Worker [&]() { writer += "false"; });
1204*890232f2SAndroid Build Coastguard Worker }
1205*890232f2SAndroid Build Coastguard Worker };
1206*890232f2SAndroid Build Coastguard Worker
1207*890232f2SAndroid Build Coastguard Worker if (struct_def.fixed) {
1208*890232f2SAndroid Build Coastguard Worker GenerateFunOneLine(writer, name, params, "ByteBuffer", statements);
1209*890232f2SAndroid Build Coastguard Worker } else {
1210*890232f2SAndroid Build Coastguard Worker GenerateFun(writer, name, params, "Boolean", statements);
1211*890232f2SAndroid Build Coastguard Worker }
1212*890232f2SAndroid Build Coastguard Worker }
1213*890232f2SAndroid Build Coastguard Worker }
1214*890232f2SAndroid Build Coastguard Worker }
1215*890232f2SAndroid Build Coastguard Worker if (struct_def.has_key && !struct_def.fixed) {
1216*890232f2SAndroid Build Coastguard Worker // Key Comparison method
1217*890232f2SAndroid Build Coastguard Worker GenerateOverrideFun(
1218*890232f2SAndroid Build Coastguard Worker writer, "keysCompare", "o1: Int, o2: Int, _bb: ByteBuffer", "Int",
1219*890232f2SAndroid Build Coastguard Worker [&]() {
1220*890232f2SAndroid Build Coastguard Worker if (IsString(key_field->value.type)) {
1221*890232f2SAndroid Build Coastguard Worker writer.SetValue("offset", NumToString(key_field->value.offset));
1222*890232f2SAndroid Build Coastguard Worker writer +=
1223*890232f2SAndroid Build Coastguard Worker " return compareStrings(__offset({{offset}}, o1, "
1224*890232f2SAndroid Build Coastguard Worker "_bb), __offset({{offset}}, o2, _bb), _bb)";
1225*890232f2SAndroid Build Coastguard Worker
1226*890232f2SAndroid Build Coastguard Worker } else {
1227*890232f2SAndroid Build Coastguard Worker auto getter1 = GenLookupByKey(key_field, "_bb", "o1");
1228*890232f2SAndroid Build Coastguard Worker auto getter2 = GenLookupByKey(key_field, "_bb", "o2");
1229*890232f2SAndroid Build Coastguard Worker writer += "val val_1 = " + getter1;
1230*890232f2SAndroid Build Coastguard Worker writer += "val val_2 = " + getter2;
1231*890232f2SAndroid Build Coastguard Worker writer += "return (val_1 - val_2).sign";
1232*890232f2SAndroid Build Coastguard Worker }
1233*890232f2SAndroid Build Coastguard Worker });
1234*890232f2SAndroid Build Coastguard Worker }
1235*890232f2SAndroid Build Coastguard Worker }
1236*890232f2SAndroid Build Coastguard Worker
CastToUsigned(const FieldDef & field)1237*890232f2SAndroid Build Coastguard Worker static std::string CastToUsigned(const FieldDef &field) {
1238*890232f2SAndroid Build Coastguard Worker return CastToUsigned(field.value.type);
1239*890232f2SAndroid Build Coastguard Worker }
1240*890232f2SAndroid Build Coastguard Worker
CastToUsigned(const Type type)1241*890232f2SAndroid Build Coastguard Worker static std::string CastToUsigned(const Type type) {
1242*890232f2SAndroid Build Coastguard Worker switch (type.base_type) {
1243*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_UINT: return ".toUInt()";
1244*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_UCHAR:
1245*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_UTYPE: return ".toUByte()";
1246*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_USHORT: return ".toUShort()";
1247*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_ULONG: return ".toULong()";
1248*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_VECTOR: return CastToUsigned(type.VectorType());
1249*890232f2SAndroid Build Coastguard Worker default: return "";
1250*890232f2SAndroid Build Coastguard Worker }
1251*890232f2SAndroid Build Coastguard Worker }
1252*890232f2SAndroid Build Coastguard Worker
CastToSigned(const FieldDef & field)1253*890232f2SAndroid Build Coastguard Worker static std::string CastToSigned(const FieldDef &field) {
1254*890232f2SAndroid Build Coastguard Worker return CastToSigned(field.value.type);
1255*890232f2SAndroid Build Coastguard Worker }
1256*890232f2SAndroid Build Coastguard Worker
CastToSigned(const Type type)1257*890232f2SAndroid Build Coastguard Worker static std::string CastToSigned(const Type type) {
1258*890232f2SAndroid Build Coastguard Worker switch (type.base_type) {
1259*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_UINT: return ".toInt()";
1260*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_UCHAR:
1261*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_UTYPE: return ".toByte()";
1262*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_USHORT: return ".toShort()";
1263*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_ULONG: return ".toLong()";
1264*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_VECTOR: return CastToSigned(type.VectorType());
1265*890232f2SAndroid Build Coastguard Worker default: return "";
1266*890232f2SAndroid Build Coastguard Worker }
1267*890232f2SAndroid Build Coastguard Worker }
1268*890232f2SAndroid Build Coastguard Worker
LiteralSuffix(const BaseType type)1269*890232f2SAndroid Build Coastguard Worker static std::string LiteralSuffix(const BaseType type) {
1270*890232f2SAndroid Build Coastguard Worker switch (type) {
1271*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_UINT:
1272*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_UCHAR:
1273*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_UTYPE:
1274*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_USHORT: return "u";
1275*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_ULONG: return "UL";
1276*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_LONG: return "L";
1277*890232f2SAndroid Build Coastguard Worker default: return "";
1278*890232f2SAndroid Build Coastguard Worker }
1279*890232f2SAndroid Build Coastguard Worker }
1280*890232f2SAndroid Build Coastguard Worker
GenerateCompanionObject(CodeWriter & code,const std::function<void ()> & callback) const1281*890232f2SAndroid Build Coastguard Worker void GenerateCompanionObject(CodeWriter &code,
1282*890232f2SAndroid Build Coastguard Worker const std::function<void()> &callback) const {
1283*890232f2SAndroid Build Coastguard Worker code += "companion object {";
1284*890232f2SAndroid Build Coastguard Worker code.IncrementIdentLevel();
1285*890232f2SAndroid Build Coastguard Worker callback();
1286*890232f2SAndroid Build Coastguard Worker code.DecrementIdentLevel();
1287*890232f2SAndroid Build Coastguard Worker code += "}";
1288*890232f2SAndroid Build Coastguard Worker }
1289*890232f2SAndroid Build Coastguard Worker
1290*890232f2SAndroid Build Coastguard Worker // Generate a documentation comment, if available.
GenerateComment(const std::vector<std::string> & dc,CodeWriter & writer,const CommentConfig * config) const1291*890232f2SAndroid Build Coastguard Worker void GenerateComment(const std::vector<std::string> &dc, CodeWriter &writer,
1292*890232f2SAndroid Build Coastguard Worker const CommentConfig *config) const {
1293*890232f2SAndroid Build Coastguard Worker if (dc.begin() == dc.end()) {
1294*890232f2SAndroid Build Coastguard Worker // Don't output empty comment blocks with 0 lines of comment content.
1295*890232f2SAndroid Build Coastguard Worker return;
1296*890232f2SAndroid Build Coastguard Worker }
1297*890232f2SAndroid Build Coastguard Worker
1298*890232f2SAndroid Build Coastguard Worker if (config != nullptr && config->first_line != nullptr) {
1299*890232f2SAndroid Build Coastguard Worker writer += std::string(config->first_line);
1300*890232f2SAndroid Build Coastguard Worker }
1301*890232f2SAndroid Build Coastguard Worker std::string line_prefix =
1302*890232f2SAndroid Build Coastguard Worker ((config != nullptr && config->content_line_prefix != nullptr)
1303*890232f2SAndroid Build Coastguard Worker ? config->content_line_prefix
1304*890232f2SAndroid Build Coastguard Worker : "///");
1305*890232f2SAndroid Build Coastguard Worker for (auto it = dc.begin(); it != dc.end(); ++it) {
1306*890232f2SAndroid Build Coastguard Worker writer += line_prefix + *it;
1307*890232f2SAndroid Build Coastguard Worker }
1308*890232f2SAndroid Build Coastguard Worker if (config != nullptr && config->last_line != nullptr) {
1309*890232f2SAndroid Build Coastguard Worker writer += std::string(config->last_line);
1310*890232f2SAndroid Build Coastguard Worker }
1311*890232f2SAndroid Build Coastguard Worker }
1312*890232f2SAndroid Build Coastguard Worker
GenerateGetRootAsAccessors(const std::string & struct_name,CodeWriter & writer,IDLOptions options) const1313*890232f2SAndroid Build Coastguard Worker void GenerateGetRootAsAccessors(const std::string &struct_name,
1314*890232f2SAndroid Build Coastguard Worker CodeWriter &writer,
1315*890232f2SAndroid Build Coastguard Worker IDLOptions options) const {
1316*890232f2SAndroid Build Coastguard Worker // Generate a special accessor for the table that when used as the root
1317*890232f2SAndroid Build Coastguard Worker // ex: fun getRootAsMonster(_bb: ByteBuffer): Monster {...}
1318*890232f2SAndroid Build Coastguard Worker writer.SetValue("gr_name", struct_name);
1319*890232f2SAndroid Build Coastguard Worker writer.SetValue("gr_method", "getRootAs" + struct_name);
1320*890232f2SAndroid Build Coastguard Worker
1321*890232f2SAndroid Build Coastguard Worker // create convenience method that doesn't require an existing object
1322*890232f2SAndroid Build Coastguard Worker GenerateJvmStaticAnnotation(writer, options.gen_jvmstatic);
1323*890232f2SAndroid Build Coastguard Worker writer += "fun {{gr_method}}(_bb: ByteBuffer): {{gr_name}} = \\";
1324*890232f2SAndroid Build Coastguard Worker writer += "{{gr_method}}(_bb, {{gr_name}}())";
1325*890232f2SAndroid Build Coastguard Worker
1326*890232f2SAndroid Build Coastguard Worker // create method that allows object reuse
1327*890232f2SAndroid Build Coastguard Worker // ex: fun Monster getRootAsMonster(_bb: ByteBuffer, obj: Monster) {...}
1328*890232f2SAndroid Build Coastguard Worker GenerateJvmStaticAnnotation(writer, options.gen_jvmstatic);
1329*890232f2SAndroid Build Coastguard Worker writer +=
1330*890232f2SAndroid Build Coastguard Worker "fun {{gr_method}}"
1331*890232f2SAndroid Build Coastguard Worker "(_bb: ByteBuffer, obj: {{gr_name}}): {{gr_name}} {";
1332*890232f2SAndroid Build Coastguard Worker writer.IncrementIdentLevel();
1333*890232f2SAndroid Build Coastguard Worker writer += "_bb.order(ByteOrder.LITTLE_ENDIAN)";
1334*890232f2SAndroid Build Coastguard Worker writer +=
1335*890232f2SAndroid Build Coastguard Worker "return (obj.__assign(_bb.getInt(_bb.position())"
1336*890232f2SAndroid Build Coastguard Worker " + _bb.position(), _bb))";
1337*890232f2SAndroid Build Coastguard Worker writer.DecrementIdentLevel();
1338*890232f2SAndroid Build Coastguard Worker writer += "}";
1339*890232f2SAndroid Build Coastguard Worker }
1340*890232f2SAndroid Build Coastguard Worker
GenerateStaticConstructor(const StructDef & struct_def,CodeWriter & code,const IDLOptions options) const1341*890232f2SAndroid Build Coastguard Worker void GenerateStaticConstructor(const StructDef &struct_def, CodeWriter &code,
1342*890232f2SAndroid Build Coastguard Worker const IDLOptions options) const {
1343*890232f2SAndroid Build Coastguard Worker // create a struct constructor function
1344*890232f2SAndroid Build Coastguard Worker auto params = StructConstructorParams(struct_def);
1345*890232f2SAndroid Build Coastguard Worker GenerateFun(
1346*890232f2SAndroid Build Coastguard Worker code, namer_.LegacyJavaMethod2("create", struct_def, ""), params, "Int",
1347*890232f2SAndroid Build Coastguard Worker [&]() {
1348*890232f2SAndroid Build Coastguard Worker GenStructBody(struct_def, code, "");
1349*890232f2SAndroid Build Coastguard Worker code += "return builder.offset()";
1350*890232f2SAndroid Build Coastguard Worker },
1351*890232f2SAndroid Build Coastguard Worker options.gen_jvmstatic);
1352*890232f2SAndroid Build Coastguard Worker }
1353*890232f2SAndroid Build Coastguard Worker
StructConstructorParams(const StructDef & struct_def,const std::string & prefix="") const1354*890232f2SAndroid Build Coastguard Worker std::string StructConstructorParams(const StructDef &struct_def,
1355*890232f2SAndroid Build Coastguard Worker const std::string &prefix = "") const {
1356*890232f2SAndroid Build Coastguard Worker // builder: FlatBufferBuilder
1357*890232f2SAndroid Build Coastguard Worker std::stringstream out;
1358*890232f2SAndroid Build Coastguard Worker auto field_vec = struct_def.fields.vec;
1359*890232f2SAndroid Build Coastguard Worker if (prefix.empty()) { out << "builder: FlatBufferBuilder"; }
1360*890232f2SAndroid Build Coastguard Worker for (auto it = field_vec.begin(); it != field_vec.end(); ++it) {
1361*890232f2SAndroid Build Coastguard Worker auto &field = **it;
1362*890232f2SAndroid Build Coastguard Worker if (IsStruct(field.value.type)) {
1363*890232f2SAndroid Build Coastguard Worker // Generate arguments for a struct inside a struct. To ensure
1364*890232f2SAndroid Build Coastguard Worker // names don't clash, and to make it obvious these arguments are
1365*890232f2SAndroid Build Coastguard Worker // constructing a nested struct, prefix the name with the field
1366*890232f2SAndroid Build Coastguard Worker // name.
1367*890232f2SAndroid Build Coastguard Worker out << StructConstructorParams(*field.value.type.struct_def,
1368*890232f2SAndroid Build Coastguard Worker prefix + (namer_.Variable(field) + "_"));
1369*890232f2SAndroid Build Coastguard Worker } else {
1370*890232f2SAndroid Build Coastguard Worker out << ", " << prefix << namer_.Variable(field) << ": "
1371*890232f2SAndroid Build Coastguard Worker << GenTypeBasic(field.value.type.base_type);
1372*890232f2SAndroid Build Coastguard Worker }
1373*890232f2SAndroid Build Coastguard Worker }
1374*890232f2SAndroid Build Coastguard Worker return out.str();
1375*890232f2SAndroid Build Coastguard Worker }
1376*890232f2SAndroid Build Coastguard Worker
GeneratePropertyOneLine(CodeWriter & writer,const std::string & name,const std::string & type,const std::function<void ()> & body)1377*890232f2SAndroid Build Coastguard Worker static void GeneratePropertyOneLine(CodeWriter &writer,
1378*890232f2SAndroid Build Coastguard Worker const std::string &name,
1379*890232f2SAndroid Build Coastguard Worker const std::string &type,
1380*890232f2SAndroid Build Coastguard Worker const std::function<void()> &body) {
1381*890232f2SAndroid Build Coastguard Worker // Generates Kotlin getter for properties
1382*890232f2SAndroid Build Coastguard Worker // e.g.:
1383*890232f2SAndroid Build Coastguard Worker // val prop: Mytype = x
1384*890232f2SAndroid Build Coastguard Worker writer.SetValue("_name", name);
1385*890232f2SAndroid Build Coastguard Worker writer.SetValue("_type", type);
1386*890232f2SAndroid Build Coastguard Worker writer += "val {{_name}} : {{_type}} = \\";
1387*890232f2SAndroid Build Coastguard Worker body();
1388*890232f2SAndroid Build Coastguard Worker }
GenerateGetterOneLine(CodeWriter & writer,const std::string & name,const std::string & type,const std::function<void ()> & body)1389*890232f2SAndroid Build Coastguard Worker static void GenerateGetterOneLine(CodeWriter &writer, const std::string &name,
1390*890232f2SAndroid Build Coastguard Worker const std::string &type,
1391*890232f2SAndroid Build Coastguard Worker const std::function<void()> &body) {
1392*890232f2SAndroid Build Coastguard Worker // Generates Kotlin getter for properties
1393*890232f2SAndroid Build Coastguard Worker // e.g.:
1394*890232f2SAndroid Build Coastguard Worker // val prop: Mytype get() = x
1395*890232f2SAndroid Build Coastguard Worker writer.SetValue("_name", name);
1396*890232f2SAndroid Build Coastguard Worker writer.SetValue("_type", type);
1397*890232f2SAndroid Build Coastguard Worker writer += "val {{_name}} : {{_type}} get() = \\";
1398*890232f2SAndroid Build Coastguard Worker body();
1399*890232f2SAndroid Build Coastguard Worker }
1400*890232f2SAndroid Build Coastguard Worker
GenerateGetter(CodeWriter & writer,const std::string & name,const std::string & type,const std::function<void ()> & body)1401*890232f2SAndroid Build Coastguard Worker static void GenerateGetter(CodeWriter &writer, const std::string &name,
1402*890232f2SAndroid Build Coastguard Worker const std::string &type,
1403*890232f2SAndroid Build Coastguard Worker const std::function<void()> &body) {
1404*890232f2SAndroid Build Coastguard Worker // Generates Kotlin getter for properties
1405*890232f2SAndroid Build Coastguard Worker // e.g.:
1406*890232f2SAndroid Build Coastguard Worker // val prop: Mytype
1407*890232f2SAndroid Build Coastguard Worker // get() = {
1408*890232f2SAndroid Build Coastguard Worker // return x
1409*890232f2SAndroid Build Coastguard Worker // }
1410*890232f2SAndroid Build Coastguard Worker writer.SetValue("name", name);
1411*890232f2SAndroid Build Coastguard Worker writer.SetValue("type", type);
1412*890232f2SAndroid Build Coastguard Worker writer += "val {{name}} : {{type}}";
1413*890232f2SAndroid Build Coastguard Worker writer.IncrementIdentLevel();
1414*890232f2SAndroid Build Coastguard Worker writer += "get() {";
1415*890232f2SAndroid Build Coastguard Worker writer.IncrementIdentLevel();
1416*890232f2SAndroid Build Coastguard Worker body();
1417*890232f2SAndroid Build Coastguard Worker writer.DecrementIdentLevel();
1418*890232f2SAndroid Build Coastguard Worker writer += "}";
1419*890232f2SAndroid Build Coastguard Worker writer.DecrementIdentLevel();
1420*890232f2SAndroid Build Coastguard Worker }
1421*890232f2SAndroid Build Coastguard Worker
GenerateFun(CodeWriter & writer,const std::string & name,const std::string & params,const std::string & returnType,const std::function<void ()> & body,bool gen_jvmstatic=false)1422*890232f2SAndroid Build Coastguard Worker static void GenerateFun(CodeWriter &writer, const std::string &name,
1423*890232f2SAndroid Build Coastguard Worker const std::string ¶ms,
1424*890232f2SAndroid Build Coastguard Worker const std::string &returnType,
1425*890232f2SAndroid Build Coastguard Worker const std::function<void()> &body,
1426*890232f2SAndroid Build Coastguard Worker bool gen_jvmstatic = false) {
1427*890232f2SAndroid Build Coastguard Worker // Generates Kotlin function
1428*890232f2SAndroid Build Coastguard Worker // e.g.:
1429*890232f2SAndroid Build Coastguard Worker // fun path(j: Int): Vec3 {
1430*890232f2SAndroid Build Coastguard Worker // return path(Vec3(), j)
1431*890232f2SAndroid Build Coastguard Worker // }
1432*890232f2SAndroid Build Coastguard Worker auto noreturn = returnType.empty();
1433*890232f2SAndroid Build Coastguard Worker writer.SetValue("name", name);
1434*890232f2SAndroid Build Coastguard Worker writer.SetValue("params", params);
1435*890232f2SAndroid Build Coastguard Worker writer.SetValue("return_type", noreturn ? "" : ": " + returnType);
1436*890232f2SAndroid Build Coastguard Worker GenerateJvmStaticAnnotation(writer, gen_jvmstatic);
1437*890232f2SAndroid Build Coastguard Worker writer += "fun {{name}}({{params}}) {{return_type}} {";
1438*890232f2SAndroid Build Coastguard Worker writer.IncrementIdentLevel();
1439*890232f2SAndroid Build Coastguard Worker body();
1440*890232f2SAndroid Build Coastguard Worker writer.DecrementIdentLevel();
1441*890232f2SAndroid Build Coastguard Worker writer += "}";
1442*890232f2SAndroid Build Coastguard Worker }
1443*890232f2SAndroid Build Coastguard Worker
GenerateFunOneLine(CodeWriter & writer,const std::string & name,const std::string & params,const std::string & returnType,const std::function<void ()> & body,bool gen_jvmstatic=false)1444*890232f2SAndroid Build Coastguard Worker static void GenerateFunOneLine(CodeWriter &writer, const std::string &name,
1445*890232f2SAndroid Build Coastguard Worker const std::string ¶ms,
1446*890232f2SAndroid Build Coastguard Worker const std::string &returnType,
1447*890232f2SAndroid Build Coastguard Worker const std::function<void()> &body,
1448*890232f2SAndroid Build Coastguard Worker bool gen_jvmstatic = false) {
1449*890232f2SAndroid Build Coastguard Worker // Generates Kotlin function
1450*890232f2SAndroid Build Coastguard Worker // e.g.:
1451*890232f2SAndroid Build Coastguard Worker // fun path(j: Int): Vec3 = return path(Vec3(), j)
1452*890232f2SAndroid Build Coastguard Worker writer.SetValue("name", name);
1453*890232f2SAndroid Build Coastguard Worker writer.SetValue("params", params);
1454*890232f2SAndroid Build Coastguard Worker writer.SetValue("return_type_p",
1455*890232f2SAndroid Build Coastguard Worker returnType.empty() ? "" : " : " + returnType);
1456*890232f2SAndroid Build Coastguard Worker GenerateJvmStaticAnnotation(writer, gen_jvmstatic);
1457*890232f2SAndroid Build Coastguard Worker writer += "fun {{name}}({{params}}){{return_type_p}} = \\";
1458*890232f2SAndroid Build Coastguard Worker body();
1459*890232f2SAndroid Build Coastguard Worker }
1460*890232f2SAndroid Build Coastguard Worker
GenerateOverrideFun(CodeWriter & writer,const std::string & name,const std::string & params,const std::string & returnType,const std::function<void ()> & body)1461*890232f2SAndroid Build Coastguard Worker static void GenerateOverrideFun(CodeWriter &writer, const std::string &name,
1462*890232f2SAndroid Build Coastguard Worker const std::string ¶ms,
1463*890232f2SAndroid Build Coastguard Worker const std::string &returnType,
1464*890232f2SAndroid Build Coastguard Worker const std::function<void()> &body) {
1465*890232f2SAndroid Build Coastguard Worker // Generates Kotlin function
1466*890232f2SAndroid Build Coastguard Worker // e.g.:
1467*890232f2SAndroid Build Coastguard Worker // override fun path(j: Int): Vec3 = return path(Vec3(), j)
1468*890232f2SAndroid Build Coastguard Worker writer += "override \\";
1469*890232f2SAndroid Build Coastguard Worker GenerateFun(writer, name, params, returnType, body);
1470*890232f2SAndroid Build Coastguard Worker }
1471*890232f2SAndroid Build Coastguard Worker
GenerateOverrideFunOneLine(CodeWriter & writer,const std::string & name,const std::string & params,const std::string & returnType,const std::string & statement)1472*890232f2SAndroid Build Coastguard Worker static void GenerateOverrideFunOneLine(CodeWriter &writer,
1473*890232f2SAndroid Build Coastguard Worker const std::string &name,
1474*890232f2SAndroid Build Coastguard Worker const std::string ¶ms,
1475*890232f2SAndroid Build Coastguard Worker const std::string &returnType,
1476*890232f2SAndroid Build Coastguard Worker const std::string &statement) {
1477*890232f2SAndroid Build Coastguard Worker // Generates Kotlin function
1478*890232f2SAndroid Build Coastguard Worker // e.g.:
1479*890232f2SAndroid Build Coastguard Worker // override fun path(j: Int): Vec3 = return path(Vec3(), j)
1480*890232f2SAndroid Build Coastguard Worker writer.SetValue("name", name);
1481*890232f2SAndroid Build Coastguard Worker writer.SetValue("params", params);
1482*890232f2SAndroid Build Coastguard Worker writer.SetValue("return_type",
1483*890232f2SAndroid Build Coastguard Worker returnType.empty() ? "" : " : " + returnType);
1484*890232f2SAndroid Build Coastguard Worker writer += "override fun {{name}}({{params}}){{return_type}} = \\";
1485*890232f2SAndroid Build Coastguard Worker writer += statement;
1486*890232f2SAndroid Build Coastguard Worker }
1487*890232f2SAndroid Build Coastguard Worker
OffsetWrapperOneLine(const std::string & offset,const std::string & found,const std::string & not_found)1488*890232f2SAndroid Build Coastguard Worker static std::string OffsetWrapperOneLine(const std::string &offset,
1489*890232f2SAndroid Build Coastguard Worker const std::string &found,
1490*890232f2SAndroid Build Coastguard Worker const std::string ¬_found) {
1491*890232f2SAndroid Build Coastguard Worker return "val o = __offset(" + offset + "); return if (o != 0) " + found +
1492*890232f2SAndroid Build Coastguard Worker " else " + not_found;
1493*890232f2SAndroid Build Coastguard Worker }
1494*890232f2SAndroid Build Coastguard Worker
OffsetWrapper(CodeWriter & code,const std::string & offset,const std::function<void ()> & found,const std::function<void ()> & not_found)1495*890232f2SAndroid Build Coastguard Worker static void OffsetWrapper(CodeWriter &code, const std::string &offset,
1496*890232f2SAndroid Build Coastguard Worker const std::function<void()> &found,
1497*890232f2SAndroid Build Coastguard Worker const std::function<void()> ¬_found) {
1498*890232f2SAndroid Build Coastguard Worker code += "val o = __offset(" + offset + ")";
1499*890232f2SAndroid Build Coastguard Worker code += "return if (o != 0) {";
1500*890232f2SAndroid Build Coastguard Worker code.IncrementIdentLevel();
1501*890232f2SAndroid Build Coastguard Worker found();
1502*890232f2SAndroid Build Coastguard Worker code.DecrementIdentLevel();
1503*890232f2SAndroid Build Coastguard Worker code += "} else {";
1504*890232f2SAndroid Build Coastguard Worker code.IncrementIdentLevel();
1505*890232f2SAndroid Build Coastguard Worker not_found();
1506*890232f2SAndroid Build Coastguard Worker code.DecrementIdentLevel();
1507*890232f2SAndroid Build Coastguard Worker code += "}";
1508*890232f2SAndroid Build Coastguard Worker }
1509*890232f2SAndroid Build Coastguard Worker
Indirect(const std::string & index,bool fixed)1510*890232f2SAndroid Build Coastguard Worker static std::string Indirect(const std::string &index, bool fixed) {
1511*890232f2SAndroid Build Coastguard Worker // We apply __indirect() and struct is not fixed.
1512*890232f2SAndroid Build Coastguard Worker if (!fixed) return "__indirect(" + index + ")";
1513*890232f2SAndroid Build Coastguard Worker return index;
1514*890232f2SAndroid Build Coastguard Worker }
1515*890232f2SAndroid Build Coastguard Worker
NotFoundReturn(BaseType el)1516*890232f2SAndroid Build Coastguard Worker static std::string NotFoundReturn(BaseType el) {
1517*890232f2SAndroid Build Coastguard Worker switch (el) {
1518*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_FLOAT: return "0.0f";
1519*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_DOUBLE: return "0.0";
1520*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_BOOL: return "false";
1521*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_LONG:
1522*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_INT:
1523*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_CHAR:
1524*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_SHORT: return "0";
1525*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_UINT:
1526*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_UCHAR:
1527*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_USHORT:
1528*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_UTYPE: return "0u";
1529*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_ULONG: return "0uL";
1530*890232f2SAndroid Build Coastguard Worker default: return "null";
1531*890232f2SAndroid Build Coastguard Worker }
1532*890232f2SAndroid Build Coastguard Worker }
1533*890232f2SAndroid Build Coastguard Worker
1534*890232f2SAndroid Build Coastguard Worker // Prepend @JvmStatic to methods in companion object.
GenerateJvmStaticAnnotation(CodeWriter & code,bool gen_jvmstatic)1535*890232f2SAndroid Build Coastguard Worker static void GenerateJvmStaticAnnotation(CodeWriter &code,
1536*890232f2SAndroid Build Coastguard Worker bool gen_jvmstatic) {
1537*890232f2SAndroid Build Coastguard Worker if (gen_jvmstatic) { code += "@JvmStatic"; }
1538*890232f2SAndroid Build Coastguard Worker }
1539*890232f2SAndroid Build Coastguard Worker
1540*890232f2SAndroid Build Coastguard Worker const IdlNamer namer_;
1541*890232f2SAndroid Build Coastguard Worker };
1542*890232f2SAndroid Build Coastguard Worker } // namespace kotlin
1543*890232f2SAndroid Build Coastguard Worker
GenerateKotlin(const Parser & parser,const std::string & path,const std::string & file_name)1544*890232f2SAndroid Build Coastguard Worker bool GenerateKotlin(const Parser &parser, const std::string &path,
1545*890232f2SAndroid Build Coastguard Worker const std::string &file_name) {
1546*890232f2SAndroid Build Coastguard Worker kotlin::KotlinGenerator generator(parser, path, file_name);
1547*890232f2SAndroid Build Coastguard Worker return generator.generate();
1548*890232f2SAndroid Build Coastguard Worker }
1549*890232f2SAndroid Build Coastguard Worker } // namespace flatbuffers
1550