Squashed 'third_party/flatbuffers/' changes from acc9990ab..d6a8dbd26
d6a8dbd26 Experimental fix for failing oss-fuzz coverage build (#6259)
ed391e177 BREAKING: Rust flexbuffers serde human readable set to false (#6257)
a49531414 Update to flags in fuzzing-cmake file (#6256)
de1f0342c Remove _POSIX_C_SOURCE and _XOPEN_SOURCE definitions when compiling o… (#6205)
d0d51e2a5 flatc should support --binary --schema with optional scalar fields. (#6252)
33ab26017 Bump version of rules_go to 0.24.5 (#6234)
febb9d87c Union As Accessors for C# (#6251)
8778dc7c2 Resets buffer without deallocating current pointer (#6247)
aae376e9a Add GetBufferSpan() function to bufferbuilder (#6235)
0ff047148 Modernize android build and sample (#6229)
46a8c7e95 Added required-nested-flatbuffer to monster_test and fixed rust (#6236)
bc56c553e Notify based on Labelling issues and PR (#6241)
07d7cd78a Converted globs to use single quotes (#6240)
cdef70e24 More adjustments to the auto labeler (#6239)
9dd44df35 Updated Lua labeller glob (#6238)
c9b29d088 Support size-prefixed buffers and add tests for size-prefixed messages (#6232)
fba93e0ab Removes duplicate swift in labeler (#6228)
d1a545b1f Added more labels for auto labeler (#6227)
ea92a668d [C#] Optional Scalars (#6217)
6034de286 [Label Bot] Add Java and Kotlin support for the label bot (#6226)
b08b0a440 Implement `Debug` trait for Rust flatbuffers. (#6207)
17ae48dec [Label Bot] Adds some languages to labeler bot (#6222)
fc8097925 Auto Labeler Setup, Just C# for now (#6221)
55658f523 Auto Labeler Setup, Just C# for now (#6218)
14ecfe423 Updated comments and fixed a fundamental type error. (#6214)
a0182cdb1 optional scalars for ts/js (#6215)
0dfcc0a37 Adds NetTest.bat to run .NET Core tests on Windows (#6216)
f9a18ea63 [Java] Implement optional scalars (#6212)
c7586e85a Empties the sharedString map on reset on go and csharp (#6187)
914c64601 Removed C# references from java generator. Move annotations closer to definitions (#6204)
42d7c7997 Adds readable size to asserts in read functions (#6210)
e68e8d7de Refactor idl_gen_rust (#6206)
84809be7e Fix typo in flatbuffers::span declaration. (#6202)
1606fb637 Kotlin test optional enum (#6201)
fe8e3c7e5 Mass Refactoring to use `IsString` and other BASE_TYPE helpers (#6193)
8f6fa4b71 Updated SupportsAdvancedUnionFeatures to look out for string (#6190)
b46db38f5 [JS/TS] Rewrite flexbuffers JS to TS (#6148)
9fa1d2705 Rework enums in rust. (#6098)
a402b3aba idl_gen_json_schema Fix generation of arrays of enums (#6184)
0e1415b99 fix(go_test): remove deprecated grpc call (#6183)
5cd713710 Add generation of JSON Schema to library (#6165)
5be777e1d Bump junit from 4.12 to 4.13.1 in /grpc/tests (#6173)
a49d440ec Bump junit from 4.12 to 4.13.1 in /grpc (#6172)
4ec5e8db9 [C++] Add option to not generate direct copy methods. (#6166)
04bec23a3 Add Array initialization from struct constructor (#5865) (#6147)
77d57fd07 Cast to right type for reserved_ subtraction (#6167)
543c1bbeb Fixed rust nested flatbuffers for tables other than self (#6062)
cb971eece [C++] Fix -Wnarrowing and -Woverflow due to signed bitfields on G++ ARM (#6163)
7b9e61fcc [TS] GRPC Implementation (#6141)
3359e3042 Moved C++ to optional_scalars2 and added some tests. (#6162)
187a4787f [Rust] Upgrade flatbuffers library to 2018 edition (#6159)
08943aa26 Flatbuffer C++ UnpackTo optimization for vectors of non-bool bytes. (#6154)
5975658eb Enables optional enums in swift (#6160)
5d3cf440e Updated Lobster test for optional bools/enums
8ec8322f0 Ruopt enum (#6156)
bbcc85fd4 Fix generation of C++ code with Optional<Enum> (#6155)
0bdf2fa15 [C#] Fix and improve project files (#6142)
2eedc769d possibility to create a vector from an iterator (#6135)
ab01ae162 flatc should output a warning, when an attribute is attached more than once (#6146)
689bfafa7 [Python/JS/TS] Codegen SizeOf method for structs (#6136)
641309a5b unix2dos on tests/FlatBuffers.Test/FlatBuffers.Core.Test.csproj (#6133)
52e362879 SpanT is available in .Net Standard 2.0. (#6137)
dca12522a Add static cast to avoid implicit double promotion. (#6132)
e0bbaa6f9 [C#]Change to ENABLE_SPAN_T that doesn't require UNSAFE_BYTEBUFFER. (#6073)
ab139d6be Revert "[C#] Fix and improve project files (#6116)" (#6130)
34d67b425 Minireflect fixed array (#6129)
96d5e3597 [JS/TS] fix flatbuffers default export (#6123)
eb686a86f Add missed file generated by optional_scalar.fbs (#6125)
750281630 [C#] Fix and improve project files (#6116)
fb4e1c34f Add CharToLower and CharToUpper into util.s (#6126)
8c67b5b12 Add support of Optional<T> scalars to C++ code generator (#6092)
6228b66d3 [Kotlin] Support for optional scalars. (#6115)
e1be8aaad Bump version for latest swift version (#6121)
94873e595 [JS/TS] Modernize TypeScript / JavaScript flatbuffers support (#6095)
b8e87fafe [JS] Add getFullyQualifiedName() (#6119)
f96d1ef74 [Java] allowing larger buffer sizes when growing a byte buffer (#6118)
89435303b [Swift] Migrates struct write APIS to write directly to the buffer (#6093)
c75ae2429 Optional-ness in reflection (#6097)
338944d3d Rename Nullable scalars to Optional scalars (#6112)
f5ab24bc4 Avoid memcpy call for empty vectors (#6111)
92a8c1a0f [JS] FlexBuffers Fix for wrong type of offset and length values (#6107)
6cea45dcd fix c# json serializer commandline argument docs (#6104)
fec58aa12 Fix for issue 6100: incorrect shrinking logic in ResizeContext() (#6102)
71aca81ff [JS] FlexBuffers Support (#5973)
04d87ffec [C++] Small refactoring of the C++ code generator (#6091)
bb25956f0 Wrap verify file id condition in Check call (#6085)
49f4948f0 + Add `removable-media` plug to the snapcraft config (#6083)
eeacc53d2 Adds proper access types for swift object api & flatbuffers & grpc (#6081)
f3003e08d [Lobster] missed a test
d713a0084 [CMake] enabled multi-core builds in VS projects
77f966f89 [Lobster] optional scalars support
e86d5b8e9 [Kotlin] Attach JvmStatic annotation to each method in companion object (#6052)
db2aa9b4e [C#] Cleaned up .NET testing script for Mono (#6016)
63cc0eec4 Adds a serialize helper function to native table (#6059)
c30a87de6 [TS] Fix four bugs with imported types in TypeScript. (#6054)
a0fb30575 [Swift] Append namespace for Swift Grpc implementation (#6049)
77c18c1d6 export a __version__ variable for python module (#5309)
f1f23d08e adding fb import when no other imports are present (#6030)
f1025b284 [Feature] Checks for Nullable strings (#6050)
5d052f4e5 [Swift] RFC: Switch Swift namespace from public enum to ordinary concat with _ (#6045)
18b015d25 Rust codegen improvements and lint fixes (#6046)
d76e93f27 adds code gen for optional scalars in swift (#6038)
82fac326c [C++] Fix compiler error from deleted assignment operator (#6036) (#6047)
043b52bd4 Optional Scalars support for Rust (#6034)
c8fa0afdf Allow to run cpp tests under grpc/tests/ using bazel. (#6040)
6d0aae73c Fix git command executed in wrong folder when doing cmake superbuild (#6039)
ff1b73128 [Swift] Optional Scalars Preparation (#6028)
2e48c8dd3 tests: Check for both quiet and signaling NaN on mipsel/hppa (#6029)
6942704f2 support deprecated flag in json schema (#6022)
9ecd2e16c Flatc parser support for nullable scalars (#6026)
33e2d8079 [Dart] Generate constant values map for enums (#6025)
969d0f7a6 Using proper symbol name for reexport (#6021)
515a4052a Silence false positive "-Wstringop-overflow" on GCC 10.0 to 11.0 (#6020)
36fbe6f13 Updated FB import (#6019)
b69fc8cc9 [Java] Add support for shared strings on FlatBufferBuilder. (#6012)
ab6af18d9 Not using non-existent create method for obj api (#6015)
37a5dee10 Code cleanup + updates test and readme (#6004)
8a721f69a Serde with bytes maps to Blob (#6009)
e810635ea [Swift] FlatBuffers createMonster method doesn't treat struct properly (#5992)
4995e1527 Manage grpc dependency in Bazel's WORKSPACE file. (#5995)
60b6066fe Add warning to schema parser if field name is not snake_case. (#6005)
35d45cac7 [Rust] Flexbuffers dependency cleanup and fixes (#5998)
165a6e3d1 Re-added Evolution Schema Code Generation Command (#5999)
13d3fb2ea Fix RPM install conflict (#6003)
d64078eb2 [Swift] Initialize memory when clear ByteBuffer (#5982)
ca1190a3d [TS] Use proper TypedArray in create*Vector (#5991)
7571b2ac5 [C++] Updates real_path to be truly portable (#5787)
e5a8f76a4 [C++] Generate default member initializers for >= C++11 (#5989)
413bb9b55 [Kotlin] Fix Access to union of vector element (#5994)
f35184aef [Swift] Add parsing from unowned UnsafeMutableRawPointer for ByteBuffer (#5981)
b124b7625 Removed requirement that enums be declared in ascending order. (#5887)
0ec7600c6 Do not remove the last digit from float values (#5974)
14baf45c9 Mark GetBufferMinAlignment() const (#5985)
9abb2ec2c TypeScript/JavaScript docs improvements (#5984)
2e57d80b1 [Swift] Internal library improvements (#5965)
cfc7753a4 [Doc] Added missing letters to compiler options (#5976)
12ddc8a92 Rust Flexbuffers Documentation update (#5979)
24ad35709 [docs] typo: updates monsterdata.json to be valid json (#5978)
cc44a4442 [idl_parser] Mark typefield as deprecated (#5958)
9ab4a5c0e Deleted old stale bot
6682cfe87 Increased Operations per run in stale.yml
64922904b Adding Stale Action to clean up PR and Issues
8e505cb67 [C++] Fixed/Enabled --cpp-ptr-type std::shared_ptr [#5813] (#5959)
a28357d7a Propagate boolean default values from proto to fbs (#5964)
7cb4762a6 [Swift] Improving reallocation time by using memcpy and moving reallocation code to storage (#5960)
4e45f7c9e Fix error in SimpleQSort (#5955)
7ac026405 fix error on GRPC Python - ignore namespace tree if not specified (#5862) (#5922)
108e981db Required is now implemented in swift (#5952)
94a78e385 Fixed: Access violation and ASAN/UNSAN failures with sorted tables
53fb453e0 [rust] Add FlatBufferBuilder::force_defaults API (#5946)
17c1f35fa [FlexBuffer][Java] ReadWriteBuf and ReadBuf interface public (#5948)
2eaf57778 [Java] Grow ArrayReadWriteBuf enough to match requested capacity. (#5921)
666800da3 Adds bool support in structs + updates grpc support + CI upgrades (#5943)
38ed69eb3 fixed mutating inline values (#5942)
d026e6f07 Add static asserts to ensure that reflection API arrays are kept in sync (#5934)
988164f6e [C++] Got rid of memset's in constructors (#5938)
7179a5a8b General Codebase clean up (#5939)
a0da0c08c Add GetStringView like GetString, GetCstring (#5937)
ac203b209 [C#] Add file identifier to ObjectAPI Serialization Utility. (#5920)
8dd1bf25b not creating creation methods when using structs (#5919)
5aa443d98 [Dart] Adding FlexBuffers support (#5853)
0fa087657 [Dart] Getting tests/DartTest.sh to work on master. (#5915)
424a473e1 Schema parser: prohibit declaration of an array of pointers inside structs (#5907)
c3faa8346 Fix Cargo.toml dependencies (#5911)
91399ad05 fix union type names (#5902)
32782e4ad Update Rust Flexbuffers metadata before publishing (#5905)
e7f3b1690 [TS] Make Obj-API work with --short-names (#5898)
12ed1fe4a fixed invalid imports with --gen-all (#5895)
85ee4df7a [C#] Thread safe reads of Double and Float values from a ByteBuffer (#5900)
de89bd193 Implement flexbuffers in python (#5880)
8be05f6bd Rust Flexbuffers (#5669)
870ecbc09 [swift] Moves code to use VTablesStorage (#5888)
c2da8d5d8 [Java][FlexBuffers] Make FlexBuffersBuilder reusable by adding clear() (#5889) (#5890)
e84cbff67 Align package name to FindFlatBuffers.cmake (#5899)
f94e6c84e Small tutorial improvements - documentation only (#5894)
f12cca8bc Attempt at adding Github Actions CI
7e4124d6e Handle git program or .git folder absence (#5878)
a875d247a only add native_include_files if object based api is enabled (#5886)
6e9f5d981 Respect shared attribute in Parser (#5885)
ff1c78233 include/flatbuffers: typo fixes in comments (#5884)
2e9a19673 Updates swift docs for package management (#5883)
e3cb07d32 [Rust] idl_gen_rust.cpp: (Option/required-aware codegen for unions) (#5850)
712866d57 Propagate use_string_pooling in CopyTable (#5879)
44c919a9e Not using reexports with --gen-all (#5873)
99aa1ef21 Added INCLUDE_PREFIX option for flatbuffers_generate_headers (#5866)
40ba170c9 Fixed text in internals doc that implied structs can be root
cb4d0f72e [Swift] Object API support (#5826)
003e16405 [TS] Add Obj API (#5788)
21cf300f4 fix cpp usage markdown error (#5845)
9655e12d6 Upgraded swift implementation for grpc (#5843)
fb96fadc2 [C#] Fix nested structs and arrays in Object API (#5765)
408f11fbd [ts] Fix empty source/dest namespaces when reexporting. (#5841)
a83caf591 Improves performance for the swift library by using structs + a storage class (#5835)
925fab6b1 [Java][FlexBuffers] Optimize Map access (#5735)
d9fecc332 [CMake] : Add precompiled header support with FLATBUFFERS_ENABLE_PCH (#5827)
e9d453240 Added flatbuffers_generate_headers and flatbuffers_generate_binary_files cmake functions. (#5830)
c37c989ed Correct calculation of vector element size (#5831)
6b271b7ec Fix Clang-trunk warnings about special members deprecated in C++20. (#5829)
90f3b8e8c Fix `float_constant` definition in './doc/Grammar.md` (#5828)
3af735934 [csharp] flatc should generate a 'Create…' method for tables with struct field… (#5818)
c4231c3cb Updated doxyfile - added missing files (#5824)
9657df184 Update Grammar.md (#5820)
97ffc590e Include CPack only when explictly packaging (#5817)
8b52af65b [C++] Add max_depth and max_tables parameters to reflection::Verify (#5815)
9b034eee1 Fix interpretation of 'nan(number)' by the idl_parser (#5810)
3e9ac3cff [Scripts] Adds swift to generated code (#5806)
697147a2e updated maven build files
6df40a247 pre-tag version bump for 1.12
0dba63909 Removes the inner loop in the endtable check written tables (#5803)
0e3fdd0ee Escape characters in jsonschema descriptions (#5644)
45a2b07cb Remove `noexcept` qualifier copy-ctor of `union` type (#5800) (#5802)
d10c16314 Replace 'assert' by 'FLATBUFFERS_ASSERT' inside idl_parser.cpp (#5799)
35abb7f89 Add non-nullable modifier to return type of functions never returning null (#5797)
9954e09ab [C++] Generate code for vector force_align attribute. (#5796)
95a21327f rust: pub export the VectorIter type (#5736)
89b6183ee Fix Python min alignment
5a98d65e8 [Rust] Add gen-name-strings for Rust (#5757)
f73d205bc Removed assert that wasn't backwards compatible.
7c37abe92 [C#] add ObjectAPI Serialization Utility (#5785)
4749e77b0 Fixed docs on how to obtain parser error.
6ff189841 Added --filename-suffix and --filename-ext to flatc (#5778)
c9a30c9ca Fixed refractoring issue in reflection/generate_code.sh. Also, mv deletes the original file, so I don't need to clean it up manually in that case. (#5777)
8c02d17be Skip writing reflection_generated.h if not changed (#5776)
34305c4ce [Swift] Adds GRPC to Swift (#5758)
cd88e6b2a [Java][FlexBuffers] Abstract buffer access from ByteBuffer (#5743)
3ec7a53c6 Adds cocoapods and a readme of how to get the package (#5771)
6d44cede7 [snap] Fix versioning (#5727)
cc08c0835 [Python] Fixed potential allignment issue (#5768)
54f8b787c Fix memory leak on cpp object api (#5761)
17557f913 [Python] Fixed issue #5499 (#5764)
d54af8cd4 [C++] Use strong enum type for vectors when scoped-enums is on. (#5750)
173e10fdf [C#] support Json Serialization (#5752)
8f56990f6 FlexBuffers: C++: scalar-only typed vectors were not aligned.
6400c9b05 Bump Rust port to 0.6.1 (#5747)
7418d8587 [C#] support Object API (#5710)
c580fa284 Adds min and max, comments, and all of swift's keywords + fix docs (#5737)
f2a127230 Use VS 2017 and 2019 on CI, fix cast issue in dart_idl (#5740)
316d7c208 Creates a flatbuffers validation function + small fix (#5725)
47026ea6b Added the code to embed the binary schema to the source (--bfbs-gen-embed). (#5701)
3f677f241 [Java][FlexBuffers] Deprecate typed vector strings due to design flaw (#5722)
a593a11e5 [Go] Implements a SharedStrings function (#5733)
7cdfc8475 [Swift] Fix padding function overflow when bufSize is 0 (#5721)
bab2b0db4 Add vcpkg installation instructions (#5732)
89418eb84 [Dart] Fix deprecated field support, inf/nan (#5724)
9cadf05d8 [typescript] Size-prefixed root accessors not taking into account size prefix (#5717)
6da1cf79d [rust] Add use declarations to Rust-generated bindings for imported FB definitions (#5645)
bee1df96d [Go] Replace references to hardcoded ”Monster" etc with idiomatic go wherever possible (#5716)
01189d7ed [C++] Fix for printing of enum in case output_enum_identifiers=1. (#5706)
c4b2b0a25 [Swift] Support create long string (#5709)
a4b2884e4 Added create function for swift (#5707)
04d80f255 [Swift] Swift implementation 🎉🎉 (#5603)
55686100a Changed direct calls to strtod to use StringToNumber
718351831 Document JSON compatibility guarantees. (#5704)
d1b34f0f2 Add CMake 'generated_code' target to simplify resolution of build dependencies (#5697)
21b706196 (Optionally) add an additional suffix namespace to generated fbs files. (#5698)
35daaf83d [Java] Replace Table.UTF8_CHARSET with StandardCharsets.UTF_8 (#5696)
3b458f7a1 Rust: Temporarily disable 2 endianness unit tests (#5695)
a5d9d0f7d [C++17] Add Traits class for Tables and Factory function within it. (#5678)
3cd9b6434 Removed code_generators.cpp from library targets
355dfd48d [rust] Make enum names public (#5690)
bcd58a159 Correct inverted logic around include prefixes. (#5689)
a2c12900a Optimize Pack method using numpy (#5662)
901b89e73 [C++] Add Builder and Table typedefs (#5685)
31f879908 Minor doc updates: FlexBuffers C#, Discord, CppUsage.
8023d99e2 Upgrade rules_go (#5684)
b4154405d Fix --incompatible_load_cc_rules_from_bzl (#5683)
04c17c7a7 Add support for absl::string_view when available (#5682)
62ec7d52c [Bazel] Add support for compatible_with and restricted_to (#5681)
7de668053 CI: New Docker tests for Python with numpy (#5677)
3a70e0b30 Fixed struct initialization error on older versions of C#
9b1320135 Fixed warnings in FlexBuffers.java
5e3916050 Fixed out of date licenses on gRPC Python files.
c95755051 Removed test proto output.
44bf71988 Add flatc '--cpp_std' switch (#5656)
3e8f15df9 Fix for FlexBuffers FBT_VECTOR_STRING size bit-width.
602721a73 Added Check to VerifyAlignment (#5675)
13c05f4da Improve import handling for proto conversion (#5673)
ce3a1c43a [Dart] Fix prepare space for writeListInt64 and writeListUint64 (#5654)
aa75e5734 Make Rust constants public (#5659)
2790fee25 Add namespace qualification to union types (#5666)
eddebec1b Bugfix for Rust generation of union fields named with language keywords (#5592)
030fee36a wrap multiple statements in do {} while(!IsConstTrue(true)) (#5655)
f9724d1bd [gRPC] Uncomment MessageBuilder (#5658)
b20801ca4 Supress unsigned-integer-overflow for PaddingBytes (#5647)
a8e800bd7 Add --force-empty-vectors option (#5653)
d7530ae96 Fixed enum min/max values not properly escaped.
99d11e279 Split Bazel targets into multiple packages (#5640)
4fd8eb214 Remove a static_assert (#5643)
65f870357 Flatbuffers Python Object API (#5616)
75823cc27 [Clang 10]: definition of implicit copy constructor for 'TableKeyComparatoris deprecated #5649 (#5650)
58e279244 [docs]: add missing semicolon (#5648)
3c964e10a [GO] Fix support for enums with underscores and Unions with imported members (#5600)
c3c32ec94 Fix ambiguity of a type deduction in TEST_EQ macro if arguments have `enum class` type. (#5630)
075e8d676 Simplify declarations of x-macro FLATBUFFERS_TD (#5638)
bcf1bd5c9 read vtable size through ReadScalar() (#5636)
136d75fa6 Changed null checks in test. Removed verifier pointer usage (#5634)
091fa1fd1 Add testing of C++ with sanitizers (CI-Docker) (#5631)
ff3781dc2 add namespace prefix in FLATBUFFERS_MAX_BUFFER_SIZE (#5629)
6beb9f49c Support for python grpc - continuing the work from the pull request #4270 #4705 (#5613)
80988ea86 Removed idl_gen_general.cpp and move contents to code_generators.cpp (#5625)
0f2ff7eaa Lua cleanup (#5624)
dda095023 [C++] Adds basic schema evolution tests (#5611)
adbcbba5d [C++, C#, Java] Separated C# and Java generators into their own classes (#5618)
cbbd6aca0 add check for root_type specified for json schema generation (#5622)
405c64e07 [Rust] Bump smallvec version to 1.0 (#5621)
42c08cbca Ran src/clang-format-all.sh (#5617)
33d5dd9bd Improved pull request & clang-format instructions.
105dd528e Change monster_extra generation to use flatbuffers::unique_ptr (#5612)
f0f0efe7b [C++] Refactor to conform to Google C++ style guide (#5608)
e837d5a29 Fixed deprecated method in GRPC Java test.
9834ee978 Fixed Apache license not using canonical version.
44b2ab087 include/flatbuffers/base.h: fix no_sanitize issue with old clang (#5610)
46ae3f80a [C++, Java, C#, TypeScript, JavaScript] Skip generation of mutable union types (#5599)
7b38aa71e flatbuffers.h: fix documentation warning (#5607)
661bedd83 Add Lua FlatbufferBuilder Clean() method to enable reuseable builders (#5606)
8526e12d7 [Kotlin] Fix union vector accessor after change in Java API (#5605)
3c7b660d6 [flatc] Remove an always true condition for flexbuffers (#5604)
964365ba6 [Go] Add UnPackTo functions (#5598)
32254b7ac [Go] Object API support (#5339)
521e255ad Rust: Add idiomatic iterator for Vector type (#5579)
1b85292fd Fix typos in comments (#5590)
480815447 C++ verifier for evolved union fields should return true (#5586)
8d5e424c6 Add ByteBuffer copy for vector of bytes in Java (#5587)
b4774d235 Rust: Fix Copy and Clone impls for a few generic types (#5577)
26f238c24 Add `--clean-first` to the cmake-build command (travis) (#5574)
e93c8c46e Fix Follow implementation for bool (#5554)
e21516b9d Fix issue #5557 (#5573)
fbc11e8ae Avoid intentional unsigned integer overflow getting caught by sanitizers (#5572)
e9d29c21a Python: Add forceDefaults opt to python Builder (#5564)
8bfafc76d Java: Don't annotate vector-of-tables item getters with @nullable. (#5562)
df3e8bf4a Fixed warnings generated by recent JSON sorting feature.
5665cfe49 [Java] byte buffer factory returned buffer capcity is used instead of the requested size (#5558)
5797540ed #5544 Fix of Array of table is not sorted if Create<type>Direct() is used (#5546)
7f1af7cb0 Fix build with gcc version 7.4.0 (#5570)
32f47ad24 Fixed JSON parser not sorting vectors of tables/structs with key.
842f672ba [FlexBuffers][Java] Cache size of Sized objects in FlexBuffers (#5551)
d4cae0a62 Fix issue #5542 (#5543)
f1147f65b Fixed Android STLPort related error.
69d3fec48 Fix namespaced struct/field name collision detection (#5540) (#5545)
cfb4ecf6f [flac] Add FlexBuffers option for generating data (#5519)
a92039687 Update Rust versions under test from 1.30.1 to 1.37.0 (#5538)
625338d09 Adds XOPEN_SOURCE for PATH_MAX and POSIX 1993 for stat (#5529)
3f8ce99c5 [FlexBuffers][Java] Add override Key::toString (#5533)
0798b7b69 [FlexBuffers][Java] Fix wrong access to a string using Reference::asString(). (#5532)
cbdf82e2f Fix Mutate() methods of Array<scalar/struct> (override 5508) (#5526)
e365c502f Java: Added access object for vector of struct and vector of tables. (#5233)
97f3aa917 Fixed DetachedBuffer self move assignment (#5521)
2f5bb2eec Fix buildifier warnings found in new bazel (#5517)
917687c7a Fixed Reflection Verifier not handling vectors of unions.
f9277e691 Fixed GenerateText not handling vectors of unions.
2706381ee Add element size parameter to __vector_as_arraysegment [c#] (#5512)
b5560fcd5 [Java][FlexBuffers] Improve documentation for FlexBuffers in Java. (#5506)
782b865c5 Annotate getters with @Pure when --java-checkerframework is specified. (#5510)
3bfc86eaf [Dart]fix: segment fault with empty namespace when generating dart file (#5507)
c0282873f Rust: Fixed cargo clippy on non-generated code (#5485)
4b870aca9 [Javascript] Fix syntax error for signed enum (#5503)
d0e3870c0 [C#] Fix retrieving enumeration vectors as arrays (#5457)
fb25eb87f Doc typo fixes (#5505)
cb35d3a0e Use all of the available space in the buffer returned by ByteBufferFactory to allow the factory to keep a pool of larger than initialsize sized buffers. (#5500)
8e6cabb31 [FlexBuffers][Java] Implementation of FlexBuffers API (#5476)
bd31dd242 Clarified value reuse in FlexBuffers
65b67d213 Fixed test build invocation of arrays_test.fbs
1fbb71132 FlexBuffers: allow any values to be shared.
cd75a3658 Android: remove app_dummy() calls
ec6b0bf29 Fixed STLPort Android compile error
c11b5d744 [bugfix]flexbuffers isvector bugfix (#5488)
4525c91be Fix incorrect padding in arrays of structs (Issue #5484) (#5491)
b97b342f5 Fixed missing generated code.
c1058a903 C++ IDL generation adds superfluous semicolon in GenTablePost, causing (#5483)
303044934 [go]add Name() for ForceCodec interface (#5486)
a2485d4ec reflection: check for valid union enum value during object verification (#5475)
a20e71ac9 has_method support for primitive fields in java runtime. Changed: idl.h, FlatBufferBuilder.java , idl_gen_general.cpp, idl_parser.cpp, flatc.cpp (#5468)
Change-Id: I836f4b43e6818bb16425a87899e6234ac86242aa
git-subtree-dir: third_party/flatbuffers
git-subtree-split: d6a8dbd26ff08a8868e0d0c1b4b67d31b40e4a7f
diff --git a/src/BUILD b/src/BUILD
new file mode 100644
index 0000000..471d5da
--- /dev/null
+++ b/src/BUILD
@@ -0,0 +1,76 @@
+package(
+ default_visibility = ["//visibility:private"],
+)
+
+load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library")
+
+# Public flatc library to compile flatbuffer files at runtime.
+cc_library(
+ name = "flatbuffers",
+ srcs = [
+ "code_generators.cpp",
+ "idl_gen_fbs.cpp",
+ "idl_gen_text.cpp",
+ "idl_parser.cpp",
+ "reflection.cpp",
+ "util.cpp",
+ ],
+ hdrs = ["//:public_headers"],
+ strip_include_prefix = "/include",
+ visibility = ["//:__pkg__"],
+)
+
+# Public flatc compiler library.
+cc_library(
+ name = "flatc_library",
+ srcs = [
+ "flatc.cpp",
+ ],
+ hdrs = [
+ "//:flatc_headers",
+ ],
+ strip_include_prefix = "/include",
+ visibility = ["//:__pkg__"],
+ deps = [
+ ":flatbuffers",
+ ],
+)
+
+# Public flatc compiler.
+cc_library(
+ name = "flatc",
+ srcs = [
+ "flatc_main.cpp",
+ "idl_gen_cpp.cpp",
+ "idl_gen_csharp.cpp",
+ "idl_gen_dart.cpp",
+ "idl_gen_go.cpp",
+ "idl_gen_grpc.cpp",
+ "idl_gen_java.cpp",
+ "idl_gen_js_ts.cpp",
+ "idl_gen_json_schema.cpp",
+ "idl_gen_kotlin.cpp",
+ "idl_gen_lobster.cpp",
+ "idl_gen_lua.cpp",
+ "idl_gen_php.cpp",
+ "idl_gen_python.cpp",
+ "idl_gen_rust.cpp",
+ "idl_gen_swift.cpp",
+ "idl_gen_text.cpp",
+ "util.cpp",
+ ],
+ hdrs = [
+ "//:flatc_headers",
+ ],
+ strip_include_prefix = "/include",
+ visibility = ["//:__pkg__"],
+ deps = [
+ ":flatc_library",
+ "//grpc/src/compiler:cpp_generator",
+ "//grpc/src/compiler:go_generator",
+ "//grpc/src/compiler:java_generator",
+ "//grpc/src/compiler:python_generator",
+ "//grpc/src/compiler:swift_generator",
+ "//grpc/src/compiler:ts_generator",
+ ],
+)
diff --git a/src/clang-format-all.sh b/src/clang-format-all.sh
new file mode 100644
index 0000000..3fd9e33
--- /dev/null
+++ b/src/clang-format-all.sh
@@ -0,0 +1,6 @@
+# Running it twice corrects some bugs in clang-format.
+for run in {1..2}
+do
+ clang-format -i -style=file include/flatbuffers/* src/*.cpp tests/*.cpp samples/*.cpp grpc/src/compiler/schema_interface.h grpc/tests/*.cpp
+done
+git checkout include/flatbuffers/reflection_generated.h
diff --git a/src/clang-format-git.sh b/src/clang-format-git.sh
new file mode 100644
index 0000000..0611cbb
--- /dev/null
+++ b/src/clang-format-git.sh
@@ -0,0 +1,6 @@
+# Running it twice corrects some bugs in clang-format.
+for run in {1..2}
+do
+ git clang-format HEAD^ -- include/flatbuffers/* src/*.cpp tests/*.cpp samples/*.cpp grpc/src/compiler/schema_interface.h grpc/tests/*.cpp
+done
+git checkout include/flatbuffers/reflection_generated.h
diff --git a/src/clang-format.sh b/src/clang-format.sh
deleted file mode 100644
index fbce6b9..0000000
--- a/src/clang-format.sh
+++ /dev/null
@@ -1,2 +0,0 @@
-clang-format -i -style=file include/flatbuffers/* src/*.cpp tests/test.cpp samples/*.cpp grpc/src/compiler/schema_interface.h grpc/tests/*.cpp
-git checkout include/flatbuffers/reflection_generated.h
diff --git a/src/code_generators.cpp b/src/code_generators.cpp
index 52ca305..46d65f7 100644
--- a/src/code_generators.cpp
+++ b/src/code_generators.cpp
@@ -15,12 +15,14 @@
*/
#include "flatbuffers/code_generators.h"
+
#include <assert.h>
-#include "flatbuffers/base.h"
-#include "flatbuffers/util.h"
#include <cmath>
+#include "flatbuffers/base.h"
+#include "flatbuffers/util.h"
+
#if defined(_MSC_VER)
# pragma warning(push)
# pragma warning(disable : 4127) // C4127: conditional expression is constant
@@ -143,6 +145,14 @@
return qualified_name;
}
+std::string BaseGenerator::GeneratedFileName(const std::string &path,
+ const std::string &file_name,
+ const IDLOptions &options) const {
+ return path + file_name + options.filename_suffix + "." +
+ (options.filename_extension.empty() ? default_extension_
+ : options.filename_extension);
+}
+
// Generate a documentation comment, if available.
void GenComment(const std::vector<std::string> &dc, std::string *code_ptr,
const CommentConfig *config, const char *prefix) {
@@ -285,6 +295,80 @@
return this->NaN(static_cast<double>(v));
}
+std::string JavaCSharpMakeRule(const Parser &parser, const std::string &path,
+ const std::string &file_name) {
+ FLATBUFFERS_ASSERT(parser.opts.lang == IDLOptions::kJava ||
+ parser.opts.lang == IDLOptions::kCSharp);
+
+ std::string file_extension =
+ (parser.opts.lang == IDLOptions::kJava) ? ".java" : ".cs";
+
+ std::string make_rule;
+
+ for (auto it = parser.enums_.vec.begin(); it != parser.enums_.vec.end();
+ ++it) {
+ auto &enum_def = **it;
+ if (!make_rule.empty()) make_rule += " ";
+ std::string directory =
+ BaseGenerator::NamespaceDir(parser, path, *enum_def.defined_namespace);
+ make_rule += directory + enum_def.name + file_extension;
+ }
+
+ for (auto it = parser.structs_.vec.begin(); it != parser.structs_.vec.end();
+ ++it) {
+ auto &struct_def = **it;
+ if (!make_rule.empty()) make_rule += " ";
+ std::string directory = BaseGenerator::NamespaceDir(
+ parser, path, *struct_def.defined_namespace);
+ make_rule += directory + struct_def.name + file_extension;
+ }
+
+ make_rule += ": ";
+ auto included_files = parser.GetIncludedFilesRecursive(file_name);
+ for (auto it = included_files.begin(); it != included_files.end(); ++it) {
+ make_rule += " " + *it;
+ }
+ return make_rule;
+}
+
+std::string BinaryFileName(const Parser &parser, const std::string &path,
+ const std::string &file_name) {
+ auto ext = parser.file_extension_.length() ? parser.file_extension_ : "bin";
+ return path + file_name + "." + ext;
+}
+
+bool GenerateBinary(const Parser &parser, const std::string &path,
+ const std::string &file_name) {
+ if (parser.opts.use_flexbuffers) {
+ auto data_vec = parser.flex_builder_.GetBuffer();
+ auto data_ptr = reinterpret_cast<char *>(data(data_vec));
+ return !parser.flex_builder_.GetSize() ||
+ flatbuffers::SaveFile(
+ BinaryFileName(parser, path, file_name).c_str(), data_ptr,
+ parser.flex_builder_.GetSize(), true);
+ }
+ return !parser.builder_.GetSize() ||
+ flatbuffers::SaveFile(
+ BinaryFileName(parser, path, file_name).c_str(),
+ reinterpret_cast<char *>(parser.builder_.GetBufferPointer()),
+ parser.builder_.GetSize(), true);
+}
+
+std::string BinaryMakeRule(const Parser &parser, const std::string &path,
+ const std::string &file_name) {
+ if (!parser.builder_.GetSize()) return "";
+ std::string filebase =
+ flatbuffers::StripPath(flatbuffers::StripExtension(file_name));
+ std::string make_rule =
+ BinaryFileName(parser, path, filebase) + ": " + file_name;
+ auto included_files =
+ parser.GetIncludedFilesRecursive(parser.root_struct_def_->file);
+ for (auto it = included_files.begin(); it != included_files.end(); ++it) {
+ make_rule += " " + *it;
+ }
+ return make_rule;
+}
+
} // namespace flatbuffers
#if defined(_MSC_VER)
diff --git a/src/flatc.cpp b/src/flatc.cpp
index e1236bd..4a9df5f 100644
--- a/src/flatc.cpp
+++ b/src/flatc.cpp
@@ -42,7 +42,7 @@
const std::string &filename,
const std::string &contents) {
if (!parser.Deserialize(reinterpret_cast<const uint8_t *>(contents.c_str()),
- contents.size())) {
+ contents.size())) {
Error("failed to load binary schema: " + filename, false, false);
}
}
@@ -63,97 +63,120 @@
const Generator &g = params_.generators[i];
std::stringstream full_name;
- full_name << std::setw(12) << std::left << g.generator_opt_long;
+ full_name << std::setw(16) << std::left << g.generator_opt_long;
const char *name = g.generator_opt_short ? g.generator_opt_short : " ";
const char *help = g.generator_help;
ss << " " << full_name.str() << " " << name << " " << help << ".\n";
}
// clang-format off
+
+ // Output width
+ // 12345678901234567890123456789012345678901234567890123456789012345678901234567890
ss <<
- " -o PATH Prefix PATH to all generated files.\n"
- " -I PATH Search for includes in the specified path.\n"
- " -M Print make rules for generated files.\n"
- " --version Print the version number of flatc and exit.\n"
- " --strict-json Strict JSON: field names must be / will be quoted,\n"
- " no trailing commas in tables/vectors.\n"
- " --allow-non-utf8 Pass non-UTF-8 input through parser and emit nonstandard\n"
- " \\x escapes in JSON. (Default is to raise parse error on\n"
- " non-UTF-8 input.)\n"
- " --natural-utf8 Output strings with UTF-8 as human-readable strings.\n"
- " By default, UTF-8 characters are printed as \\uXXXX escapes.\n"
- " --defaults-json Output fields whose value is the default when\n"
- " writing JSON\n"
- " --unknown-json Allow fields in JSON that are not defined in the\n"
- " schema. These fields will be discared when generating\n"
- " binaries.\n"
- " --no-prefix Don\'t prefix enum values with the enum type in C++.\n"
- " --scoped-enums Use C++11 style scoped and strongly typed enums.\n"
- " also implies --no-prefix.\n"
- " --gen-includes (deprecated), this is the default behavior.\n"
- " If the original behavior is required (no include\n"
- " statements) use --no-includes.\n"
- " --no-includes Don\'t generate include statements for included\n"
- " schemas the generated file depends on (C++).\n"
- " --gen-mutable Generate accessors that can mutate buffers in-place.\n"
- " --gen-onefile Generate single output file for C# and Go.\n"
- " --gen-name-strings Generate type name functions for C++.\n"
- " --gen-object-api Generate an additional object-based API.\n"
- " --gen-compare Generate operator== for object-based API types.\n"
- " --gen-nullable Add Clang _Nullable for C++ pointer. or @Nullable for Java\n"
- " --gen-generated Add @Generated annotation for Java\n"
- " --gen-all Generate not just code for the current schema files,\n"
- " but for all files it includes as well.\n"
- " If the language uses a single file for output (by default\n"
- " the case for C++ and JS), all code will end up in this one\n"
- " file.\n"
- " --cpp-include Adds an #include in generated file.\n"
- " --cpp-ptr-type T Set object API pointer type (default std::unique_ptr).\n"
- " --cpp-str-type T Set object API string type (default std::string).\n"
- " T::c_str(), T::length() and T::empty() must be supported.\n"
- " The custom type also needs to be constructible from std::string\n"
- " (see the --cpp-str-flex-ctor option to change this behavior).\n"
- " --cpp-str-flex-ctor Don't construct custom string types by passing std::string\n"
- " from Flatbuffers, but (char* + length).\n"
- " --object-prefix Customise class prefix for C++ object-based API.\n"
- " --object-suffix Customise class suffix for C++ object-based API.\n"
- " Default value is \"T\".\n"
- " --no-js-exports Removes Node.js style export lines in JS.\n"
- " --goog-js-export Uses goog.exports* for closure compiler exporting in JS.\n"
- " --es6-js-export Uses ECMAScript 6 export style lines in JS.\n"
- " --go-namespace Generate the overrided namespace in Golang.\n"
- " --go-import Generate the overrided import for flatbuffers in Golang\n"
- " (default is \"github.com/google/flatbuffers/go\").\n"
- " --raw-binary Allow binaries without file_indentifier to be read.\n"
- " This may crash flatc given a mismatched schema.\n"
- " --size-prefixed Input binaries are size prefixed buffers.\n"
- " --proto Input is a .proto, translate to .fbs.\n"
- " --oneof-union Translate .proto oneofs to flatbuffer unions.\n"
- " --grpc Generate GRPC interfaces for the specified languages.\n"
- " --schema Serialize schemas instead of JSON (use with -b).\n"
- " --bfbs-comments Add doc comments to the binary schema files.\n"
- " --bfbs-builtins Add builtin attributes to the binary schema files.\n"
- " --conform FILE Specify a schema the following schemas should be\n"
- " an evolution of. Gives errors if not.\n"
- " --conform-includes Include path for the schema given with --conform PATH\n"
- " --include-prefix Prefix this path to any generated include statements.\n"
+ " -o PATH Prefix PATH to all generated files.\n"
+ " -I PATH Search for includes in the specified path.\n"
+ " -M Print make rules for generated files.\n"
+ " --version Print the version number of flatc and exit.\n"
+ " --strict-json Strict JSON: field names must be / will be quoted,\n"
+ " no trailing commas in tables/vectors.\n"
+ " --allow-non-utf8 Pass non-UTF-8 input through parser and emit nonstandard\n"
+ " \\x escapes in JSON. (Default is to raise parse error on\n"
+ " non-UTF-8 input.)\n"
+ " --natural-utf8 Output strings with UTF-8 as human-readable strings.\n"
+ " By default, UTF-8 characters are printed as \\uXXXX escapes.\n"
+ " --defaults-json Output fields whose value is the default when\n"
+ " writing JSON\n"
+ " --unknown-json Allow fields in JSON that are not defined in the\n"
+ " schema. These fields will be discared when generating\n"
+ " binaries.\n"
+ " --no-prefix Don\'t prefix enum values with the enum type in C++.\n"
+ " --scoped-enums Use C++11 style scoped and strongly typed enums.\n"
+ " also implies --no-prefix.\n"
+ " --gen-includes (deprecated), this is the default behavior.\n"
+ " If the original behavior is required (no include\n"
+ " statements) use --no-includes.\n"
+ " --no-includes Don\'t generate include statements for included\n"
+ " schemas the generated file depends on (C++ / Python).\n"
+ " --gen-mutable Generate accessors that can mutate buffers in-place.\n"
+ " --gen-onefile Generate single output file for C# and Go.\n"
+ " --gen-name-strings Generate type name functions for C++ and Rust.\n"
+ " --gen-object-api Generate an additional object-based API.\n"
+ " --gen-compare Generate operator== for object-based API types.\n"
+ " --gen-nullable Add Clang _Nullable for C++ pointer. or @Nullable for Java\n"
+ " --java-checkerframe work Add @Pure for Java.\n"
+ " --gen-generated Add @Generated annotation for Java\n"
+ " --gen-jvmstatic Add @JvmStatic annotation for Kotlin methods\n"
+ " in companion object for interop from Java to Kotlin.\n"
+ " --gen-all Generate not just code for the current schema files,\n"
+ " but for all files it includes as well.\n"
+ " If the language uses a single file for output (by default\n"
+ " the case for C++ and JS), all code will end up in this one\n"
+ " file.\n"
+ " --cpp-include Adds an #include in generated file.\n"
+ " --cpp-ptr-type T Set object API pointer type (default std::unique_ptr).\n"
+ " --cpp-str-type T Set object API string type (default std::string).\n"
+ " T::c_str(), T::length() and T::empty() must be supported.\n"
+ " The custom type also needs to be constructible from std::string\n"
+ " (see the --cpp-str-flex-ctor option to change this behavior).\n"
+ " --cpp-str-flex-ctor Don't construct custom string types by passing std::string\n"
+ " from Flatbuffers, but (char* + length).\n"
+ " --cpp-std CPP_STD Generate a C++ code using features of selected C++ standard.\n"
+ " Supported CPP_STD values:\n"
+ " * 'c++0x' - generate code compatible with old compilers;\n"
+ " * 'c++11' - use C++11 code generator (default);\n"
+ " * 'c++17' - use C++17 features in generated code (experimental).\n"
+ " --object-prefix Customise class prefix for C++ object-based API.\n"
+ " --object-suffix Customise class suffix for C++ object-based API.\n"
+ " Default value is \"T\".\n"
+ " --no-js-exports Removes Node.js style export lines in JS.\n"
+ " --goog-js-export Uses goog.exports* for closure compiler exporting in JS.\n"
+ " --es6-js-export Uses ECMAScript 6 export style lines in JS.\n"
+ " --go-namespace Generate the overrided namespace in Golang.\n"
+ " --go-import Generate the overrided import for flatbuffers in Golang\n"
+ " (default is \"github.com/google/flatbuffers/go\").\n"
+ " --raw-binary Allow binaries without file_indentifier to be read.\n"
+ " This may crash flatc given a mismatched schema.\n"
+ " --size-prefixed Input binaries are size prefixed buffers.\n"
+ " --proto Input is a .proto, translate to .fbs.\n"
+ " --proto-namespace-suffix Add this namespace to any flatbuffers generated\n"
+ " SUFFIX from protobufs.\n"
+ " --oneof-union Translate .proto oneofs to flatbuffer unions.\n"
+ " --grpc Generate GRPC interfaces for the specified languages.\n"
+ " --schema Serialize schemas instead of JSON (use with -b).\n"
+ " --bfbs-comments Add doc comments to the binary schema files.\n"
+ " --bfbs-builtins Add builtin attributes to the binary schema files.\n"
+ " --bfbs-gen-embed Generate code to embed the bfbs schema to the source.\n"
+ " --conform FILE Specify a schema the following schemas should be\n"
+ " an evolution of. Gives errors if not.\n"
+ " --conform-includes Include path for the schema given with --conform PATH\n"
+ " --filename-suffix The suffix appended to the generated file names.\n"
+ " Default is '_generated'.\n"
+ " --filename-ext The extension appended to the generated file names.\n"
+ " Default is language-specific (e.g., '.h' for C++)\n"
+ " --include-prefix Prefix this path to any generated include statements.\n"
" PATH\n"
- " --keep-prefix Keep original prefix of schema include statement.\n"
- " --no-fb-import Don't include flatbuffers import statement for TypeScript.\n"
- " --no-ts-reexport Don't re-export imported dependencies for TypeScript.\n"
- " --short-names Use short function names for JS and TypeScript.\n"
- " --reflect-types Add minimal type reflection to code generation.\n"
- " --reflect-names Add minimal type/name reflection.\n"
- " --root-type T Select or override the default root_type\n"
- " --force-defaults Emit default values in binary output from JSON\n"
- " --force-empty When serializing from object API representation,\n"
- " force strings and vectors to empty rather than null.\n"
+ " --keep-prefix Keep original prefix of schema include statement.\n"
+ " --no-fb-import Don't include flatbuffers import statement for TypeScript.\n"
+ " --no-ts-reexport Don't re-export imported dependencies for TypeScript.\n"
+ " --short-names Use short function names for JS and TypeScript.\n"
+ " --reflect-types Add minimal type reflection to code generation.\n"
+ " --reflect-names Add minimal type/name reflection.\n"
+ " --root-type T Select or override the default root_type\n"
+ " --force-defaults Emit default values in binary output from JSON\n"
+ " --force-empty When serializing from object API representation,\n"
+ " force strings and vectors to empty rather than null.\n"
+ " --force-empty-vectors When serializing from object API representation,\n"
+ " force vectors to empty rather than null.\n"
+ " --flexbuffers Used with \"binary\" and \"json\" options, it generates\n"
+ " data using schema-less FlexBuffers.\n"
"FILEs may be schemas (must end in .fbs), binary schemas (must end in .bfbs),\n"
"or JSON files (conforming to preceding schema). FILEs after the -- must be\n"
"binary flatbuffer format files.\n"
"Output files are named using the base file name of the input,\n"
"and written to the current directory or the path given by -o.\n"
"example: " << program_name << " -c -b schema1.fbs schema2.fbs data.json\n";
+ // 12345678901234567890123456789012345678901234567890123456789012345678901234567890
// clang-format on
return ss.str();
}
@@ -189,22 +212,22 @@
output_path = flatbuffers::ConCatPathFileName(
flatbuffers::PosixPath(argv[argi]), "");
} else if (arg == "-I") {
- if (++argi >= argc) Error("missing path following" + arg, true);
+ if (++argi >= argc) Error("missing path following: " + arg, true);
include_directories_storage.push_back(
flatbuffers::PosixPath(argv[argi]));
include_directories.push_back(
include_directories_storage.back().c_str());
} else if (arg == "--conform") {
- if (++argi >= argc) Error("missing path following" + arg, true);
+ if (++argi >= argc) Error("missing path following: " + arg, true);
conform_to_schema = flatbuffers::PosixPath(argv[argi]);
} else if (arg == "--conform-includes") {
- if (++argi >= argc) Error("missing path following" + arg, true);
+ if (++argi >= argc) Error("missing path following: " + arg, true);
include_directories_storage.push_back(
flatbuffers::PosixPath(argv[argi]));
conform_include_directories.push_back(
include_directories_storage.back().c_str());
} else if (arg == "--include-prefix") {
- if (++argi >= argc) Error("missing path following" + arg, true);
+ if (++argi >= argc) Error("missing path following: " + arg, true);
opts.include_prefix = flatbuffers::ConCatPathFileName(
flatbuffers::PosixPath(argv[argi]), "");
} else if (arg == "--keep-prefix") {
@@ -249,32 +272,37 @@
} else if (arg == "--gen-compare") {
opts.gen_compare = true;
} else if (arg == "--cpp-include") {
- if (++argi >= argc) Error("missing include following" + arg, true);
+ if (++argi >= argc) Error("missing include following: " + arg, true);
opts.cpp_includes.push_back(argv[argi]);
} else if (arg == "--cpp-ptr-type") {
- if (++argi >= argc) Error("missing type following" + arg, true);
+ if (++argi >= argc) Error("missing type following: " + arg, true);
opts.cpp_object_api_pointer_type = argv[argi];
} else if (arg == "--cpp-str-type") {
- if (++argi >= argc) Error("missing type following" + arg, true);
+ if (++argi >= argc) Error("missing type following: " + arg, true);
opts.cpp_object_api_string_type = argv[argi];
} else if (arg == "--cpp-str-flex-ctor") {
opts.cpp_object_api_string_flexible_constructor = true;
+ } else if (arg == "--no-cpp-direct-copy") {
+ opts.cpp_direct_copy = false;
} else if (arg == "--gen-nullable") {
opts.gen_nullable = true;
+ } else if (arg == "--java-checkerframework") {
+ opts.java_checkerframework = true;
} else if (arg == "--gen-generated") {
opts.gen_generated = true;
} else if (arg == "--object-prefix") {
- if (++argi >= argc) Error("missing prefix following" + arg, true);
+ if (++argi >= argc) Error("missing prefix following: " + arg, true);
opts.object_prefix = argv[argi];
} else if (arg == "--object-suffix") {
- if (++argi >= argc) Error("missing suffix following" + arg, true);
+ if (++argi >= argc) Error("missing suffix following: " + arg, true);
opts.object_suffix = argv[argi];
} else if (arg == "--gen-all") {
opts.generate_all = true;
opts.include_dependence_headers = false;
+ opts.reexport_ts_modules = false;
} else if (arg == "--gen-includes") {
// Deprecated, remove this option some time in the future.
- printf("warning: --gen-includes is deprecated (it is now default)\n");
+ Warn("warning: --gen-includes is deprecated (it is now default)\n");
} else if (arg == "--no-includes") {
opts.include_dependence_headers = false;
} else if (arg == "--gen-onefile") {
@@ -287,6 +315,9 @@
binary_files_from = filenames.size();
} else if (arg == "--proto") {
opts.proto_mode = true;
+ } else if (arg == "--proto-namespace-suffix") {
+ if (++argi >= argc) Error("missing namespace suffix" + arg, true);
+ opts.proto_namespace_suffix = argv[argi];
} else if (arg == "--oneof-union") {
opts.proto_oneof_union = true;
} else if (arg == "--schema") {
@@ -302,6 +333,8 @@
opts.binary_schema_comments = true;
} else if (arg == "--bfbs-builtins") {
opts.binary_schema_builtins = true;
+ } else if (arg == "--bfbs-gen-embed") {
+ opts.binary_schema_gen_embed = true;
} else if (arg == "--no-fb-import") {
opts.skip_flatbuffers_import = true;
} else if (arg == "--no-ts-reexport") {
@@ -313,12 +346,33 @@
} else if (arg == "--reflect-names") {
opts.mini_reflect = IDLOptions::kTypesAndNames;
} else if (arg == "--root-type") {
- if (++argi >= argc) Error("missing type following" + arg, true);
+ if (++argi >= argc) Error("missing type following: " + arg, true);
opts.root_type = argv[argi];
+ } else if (arg == "--filename-suffix") {
+ if (++argi >= argc) Error("missing filename suffix: " + arg, true);
+ opts.filename_suffix = argv[argi];
+ } else if (arg == "--filename-ext") {
+ if (++argi >= argc) Error("missing filename extension: " + arg, true);
+ opts.filename_extension = argv[argi];
} else if (arg == "--force-defaults") {
opts.force_defaults = true;
} else if (arg == "--force-empty") {
- opts.set_empty_to_null = false;
+ opts.set_empty_strings_to_null = false;
+ opts.set_empty_vectors_to_null = false;
+ } else if (arg == "--force-empty-vectors") {
+ opts.set_empty_vectors_to_null = false;
+ } else if (arg == "--java-primitive-has-method") {
+ opts.java_primitive_has_method = true;
+ } else if (arg == "--cs-gen-json-serializer") {
+ opts.cs_gen_json_serializer = true;
+ } else if (arg == "--flexbuffers") {
+ opts.use_flexbuffers = true;
+ } else if (arg == "--gen-jvmstatic") {
+ opts.gen_jvmstatic = true;
+ } else if (arg == "--cpp-std") {
+ if (++argi >= argc)
+ Error("missing C++ standard specification" + arg, true);
+ opts.cpp_std = argv[argi];
} else {
for (size_t i = 0; i < params_.num_generators; ++i) {
if (arg == params_.generators[i].generator_opt_long ||
@@ -393,7 +447,8 @@
"\" matches the schema, use --raw-binary to read this file"
" anyway.");
} else if (!flatbuffers::BufferHasIdentifier(
- contents.c_str(), parser->file_identifier_.c_str(), opts.size_prefixed)) {
+ contents.c_str(), parser->file_identifier_.c_str(),
+ opts.size_prefixed)) {
Error("binary \"" + filename +
"\" does not have expected file_identifier \"" +
parser->file_identifier_ +
@@ -402,7 +457,8 @@
}
} else {
// Check if file contains 0 bytes.
- if (!is_binary_schema && contents.length() != strlen(contents.c_str())) {
+ if (!opts.use_flexbuffers && !is_binary_schema &&
+ contents.length() != strlen(contents.c_str())) {
Error("input file appears to be binary: " + filename, true);
}
if (is_schema) {
@@ -413,6 +469,16 @@
}
if (is_binary_schema) {
LoadBinarySchema(*parser.get(), filename, contents);
+ }
+ if (opts.use_flexbuffers) {
+ if (opts.lang_to_generate == IDLOptions::kJson) {
+ parser->flex_root_ = flexbuffers::GetRoot(
+ reinterpret_cast<const uint8_t *>(contents.c_str()),
+ contents.size());
+ } else {
+ parser->flex_builder_.Clear();
+ ParseFile(*parser.get(), filename, contents, include_directories);
+ }
} else {
ParseFile(*parser.get(), filename, contents, include_directories);
if (!is_schema && !parser->builder_.GetSize()) {
@@ -427,8 +493,10 @@
auto err = parser->ConformTo(conform_parser);
if (!err.empty()) Error("schemas don\'t conform: " + err);
}
- if (schema_binary) {
+ if (schema_binary || opts.binary_schema_gen_embed) {
parser->Serialize();
+ }
+ if (schema_binary) {
parser->file_extension_ = reflection::SchemaExtension();
}
}
@@ -449,11 +517,16 @@
params_.generators[i].lang_name + " for " + filebase);
}
} else {
- std::string make_rule = params_.generators[i].make_rule(
- *parser.get(), output_path, filename);
- if (!make_rule.empty())
- printf("%s\n",
- flatbuffers::WordWrap(make_rule, 80, " ", " \\").c_str());
+ if (params_.generators[i].make_rule == nullptr) {
+ Error(std::string("Cannot generate make rule for ") +
+ params_.generators[i].lang_name);
+ } else {
+ std::string make_rule = params_.generators[i].make_rule(
+ *parser.get(), output_path, filename);
+ if (!make_rule.empty())
+ printf("%s\n",
+ flatbuffers::WordWrap(make_rule, 80, " ", " \\").c_str());
+ }
}
if (grpc_enabled) {
if (params_.generators[i].generateGRPC != nullptr) {
diff --git a/src/flatc_main.cpp b/src/flatc_main.cpp
index 72bb4a2..c942bda 100644
--- a/src/flatc_main.cpp
+++ b/src/flatc_main.cpp
@@ -30,10 +30,22 @@
const std::string &err, bool usage, bool show_exe_name) {
if (show_exe_name) { printf("%s: ", g_program_name); }
printf("error: %s\n", err.c_str());
- if (usage) { printf("%s", flatc->GetUsageString(g_program_name).c_str()); }
+ if (usage && flatc) {
+ printf("%s", flatc->GetUsageString(g_program_name).c_str());
+ }
exit(1);
}
+namespace flatbuffers {
+void LogCompilerWarn(const std::string &warn) {
+ Warn(static_cast<const flatbuffers::FlatCompiler *>(nullptr), warn, true);
+}
+void LogCompilerError(const std::string &err) {
+ Error(static_cast<const flatbuffers::FlatCompiler *>(nullptr), err, false,
+ true);
+}
+} // namespace flatbuffers
+
int main(int argc, const char *argv[]) {
// Prevent Appveyor-CI hangs.
flatbuffers::SetupDefaultCRTReportMode();
@@ -54,48 +66,50 @@
"Generate C++ headers for tables/structs", flatbuffers::CPPMakeRule },
{ flatbuffers::GenerateGo, "-g", "--go", "Go", true,
flatbuffers::GenerateGoGRPC, flatbuffers::IDLOptions::kGo,
- "Generate Go files for tables/structs", flatbuffers::GeneralMakeRule },
- { flatbuffers::GenerateGeneral, "-j", "--java", "Java", true,
+ "Generate Go files for tables/structs", nullptr },
+ { flatbuffers::GenerateJava, "-j", "--java", "Java", true,
flatbuffers::GenerateJavaGRPC, flatbuffers::IDLOptions::kJava,
"Generate Java classes for tables/structs",
- flatbuffers::GeneralMakeRule },
+ flatbuffers::JavaCSharpMakeRule },
{ flatbuffers::GenerateJSTS, "-s", "--js", "JavaScript", true, nullptr,
flatbuffers::IDLOptions::kJs,
- "Generate JavaScript code for tables/structs", flatbuffers::JSTSMakeRule },
+ "Generate JavaScript code for tables/structs",
+ flatbuffers::JSTSMakeRule },
{ flatbuffers::GenerateDart, "-d", "--dart", "Dart", true, nullptr,
flatbuffers::IDLOptions::kDart,
"Generate Dart classes for tables/structs", flatbuffers::DartMakeRule },
- { flatbuffers::GenerateJSTS, "-T", "--ts", "TypeScript", true, nullptr,
- flatbuffers::IDLOptions::kTs,
- "Generate TypeScript code for tables/structs", flatbuffers::JSTSMakeRule },
- { flatbuffers::GenerateGeneral, "-n", "--csharp", "C#", true, nullptr,
+ { flatbuffers::GenerateJSTS, "-T", "--ts", "TypeScript", true,
+ flatbuffers::GenerateTSGRPC, flatbuffers::IDLOptions::kTs,
+ "Generate TypeScript code for tables/structs",
+ flatbuffers::JSTSMakeRule },
+ { flatbuffers::GenerateCSharp, "-n", "--csharp", "C#", true, nullptr,
flatbuffers::IDLOptions::kCSharp,
- "Generate C# classes for tables/structs", flatbuffers::GeneralMakeRule },
- { flatbuffers::GeneratePython, "-p", "--python", "Python", true, nullptr,
- flatbuffers::IDLOptions::kPython,
- "Generate Python files for tables/structs",
- flatbuffers::GeneralMakeRule },
- { flatbuffers::GenerateLobster, nullptr, "--lobster", "Lobster", true, nullptr,
- flatbuffers::IDLOptions::kLobster,
- "Generate Lobster files for tables/structs",
- flatbuffers::GeneralMakeRule },
+ "Generate C# classes for tables/structs",
+ flatbuffers::JavaCSharpMakeRule },
+ { flatbuffers::GeneratePython, "-p", "--python", "Python", true,
+ flatbuffers::GeneratePythonGRPC, flatbuffers::IDLOptions::kPython,
+ "Generate Python files for tables/structs", nullptr },
+ { flatbuffers::GenerateLobster, nullptr, "--lobster", "Lobster", true,
+ nullptr, flatbuffers::IDLOptions::kLobster,
+ "Generate Lobster files for tables/structs", nullptr },
{ flatbuffers::GenerateLua, "-l", "--lua", "Lua", true, nullptr,
- flatbuffers::IDLOptions::kLua,
- "Generate Lua files for tables/structs",
- flatbuffers::GeneralMakeRule },
+ flatbuffers::IDLOptions::kLua, "Generate Lua files for tables/structs",
+ nullptr },
{ flatbuffers::GenerateRust, "-r", "--rust", "Rust", true, nullptr,
- flatbuffers::IDLOptions::kRust,
- "Generate Rust files for tables/structs",
+ flatbuffers::IDLOptions::kRust, "Generate Rust files for tables/structs",
flatbuffers::RustMakeRule },
{ flatbuffers::GeneratePhp, nullptr, "--php", "PHP", true, nullptr,
flatbuffers::IDLOptions::kPhp, "Generate PHP files for tables/structs",
- flatbuffers::GeneralMakeRule },
+ nullptr },
{ flatbuffers::GenerateKotlin, nullptr, "--kotlin", "Kotlin", true, nullptr,
- flatbuffers::IDLOptions::kKotlin, "Generate Kotlin classes for tables/structs",
- flatbuffers::GeneralMakeRule },
+ flatbuffers::IDLOptions::kKotlin,
+ "Generate Kotlin classes for tables/structs", nullptr },
{ flatbuffers::GenerateJsonSchema, nullptr, "--jsonschema", "JsonSchema",
true, nullptr, flatbuffers::IDLOptions::kJsonSchema,
- "Generate Json schema", flatbuffers::GeneralMakeRule },
+ "Generate Json schema", nullptr },
+ { flatbuffers::GenerateSwift, nullptr, "--swift", "swift", true,
+ flatbuffers::GenerateSwiftGRPC, flatbuffers::IDLOptions::kSwift,
+ "Generate Swift files for tables/structs", nullptr },
};
flatbuffers::FlatCompiler::InitParams params;
diff --git a/src/flathash.cpp b/src/flathash.cpp
index bc3d2df..1264f82 100644
--- a/src/flathash.cpp
+++ b/src/flathash.cpp
@@ -15,9 +15,11 @@
*/
#include <stdio.h>
+
#include <iostream>
#include <sstream>
#include <string>
+
#include "flatbuffers/hash.h"
enum OutputFormat { kDecimal, kHexadecimal, kHexadecimal0x };
@@ -35,7 +37,7 @@
}
printf(" 32 bit:\n");
size = sizeof(flatbuffers::kHashFunctions32) /
- sizeof(flatbuffers::kHashFunctions32[0]);
+ sizeof(flatbuffers::kHashFunctions32[0]);
for (size_t i = 0; i < size; ++i) {
printf(" * %s\n", flatbuffers::kHashFunctions32[i].name);
}
diff --git a/src/idl_gen_cpp.cpp b/src/idl_gen_cpp.cpp
index b667ea4..a56dad9 100644
--- a/src/idl_gen_cpp.cpp
+++ b/src/idl_gen_cpp.cpp
@@ -1,4 +1,4 @@
-/*
+ /*
* Copyright 2014 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,18 +16,16 @@
// independent from idl_parser, since this code is not needed for most clients
+#include <unordered_set>
+
#include "flatbuffers/code_generators.h"
#include "flatbuffers/flatbuffers.h"
+#include "flatbuffers/flatc.h"
#include "flatbuffers/idl.h"
#include "flatbuffers/util.h"
-#include <unordered_set>
-
namespace flatbuffers {
-// Pedantic warning free version of toupper().
-inline char ToUpper(char c) { return static_cast<char>(::toupper(c)); }
-
// Make numerical literal with type-suffix.
// This function is only needed for C++! Other languages do not need it.
static inline std::string NumToStringCpp(std::string val, BaseType type) {
@@ -45,18 +43,58 @@
}
}
-static std::string GeneratedFileName(const std::string &path,
- const std::string &file_name) {
- return path + file_name + "_generated.h";
+static std::string GenIncludeGuard(const std::string &file_name,
+ const Namespace &name_space,
+ const std::string &postfix = "") {
+ // Generate include guard.
+ std::string guard = file_name;
+ // Remove any non-alpha-numeric characters that may appear in a filename.
+ struct IsAlnum {
+ bool operator()(char c) const { return !is_alnum(c); }
+ };
+ guard.erase(std::remove_if(guard.begin(), guard.end(), IsAlnum()),
+ guard.end());
+ guard = "FLATBUFFERS_GENERATED_" + guard;
+ guard += "_";
+ // For further uniqueness, also add the namespace.
+ for (auto it = name_space.components.begin();
+ it != name_space.components.end(); ++it) {
+ guard += *it + "_";
+ }
+ // Anything extra to add to the guard?
+ if (!postfix.empty()) { guard += postfix + "_"; }
+ guard += "H_";
+ std::transform(guard.begin(), guard.end(), guard.begin(), CharToUpper);
+ return guard;
}
namespace cpp {
+
+enum CppStandard { CPP_STD_X0 = 0, CPP_STD_11, CPP_STD_17 };
+
+// Define a style of 'struct' constructor if it has 'Array' fields.
+enum GenArrayArgMode {
+ kArrayArgModeNone, // don't generate initialization args
+ kArrayArgModeSpanStatic, // generate flatbuffers::span<T,N>
+};
+
+// Extension of IDLOptions for cpp-generator.
+struct IDLOptionsCpp : public IDLOptions {
+ // All fields start with 'g_' prefix to distinguish from the base IDLOptions.
+ CppStandard g_cpp_std; // Base version of C++ standard.
+ bool g_only_fixed_enums; // Generate underlaying type for all enums.
+
+ IDLOptionsCpp(const IDLOptions &opts)
+ : IDLOptions(opts), g_cpp_std(CPP_STD_11), g_only_fixed_enums(true) {}
+};
+
class CppGenerator : public BaseGenerator {
public:
CppGenerator(const Parser &parser, const std::string &path,
- const std::string &file_name)
- : BaseGenerator(parser, path, file_name, "", "::"),
+ const std::string &file_name, IDLOptionsCpp opts)
+ : BaseGenerator(parser, path, file_name, "", "::", "h"),
cur_name_space_(nullptr),
+ opts_(opts),
float_const_gen_("std::numeric_limits<double>::",
"std::numeric_limits<float>::", "quiet_NaN()",
"infinity()") {
@@ -161,56 +199,34 @@
for (auto kw = keywords; *kw; kw++) keywords_.insert(*kw);
}
- std::string GenIncludeGuard() const {
- // Generate include guard.
- std::string guard = file_name_;
- // Remove any non-alpha-numeric characters that may appear in a filename.
- struct IsAlnum {
- bool operator()(char c) const { return !is_alnum(c); }
- };
- guard.erase(std::remove_if(guard.begin(), guard.end(), IsAlnum()),
- guard.end());
- guard = "FLATBUFFERS_GENERATED_" + guard;
- guard += "_";
- // For further uniqueness, also add the namespace.
- auto name_space = parser_.current_namespace_;
- for (auto it = name_space->components.begin();
- it != name_space->components.end(); ++it) {
- guard += *it + "_";
- }
- guard += "H_";
- std::transform(guard.begin(), guard.end(), guard.begin(), ToUpper);
- return guard;
- }
-
void GenIncludeDependencies() {
int num_includes = 0;
- for (auto it = parser_.native_included_files_.begin();
- it != parser_.native_included_files_.end(); ++it) {
- code_ += "#include \"" + *it + "\"";
- num_includes++;
+ if (opts_.generate_object_based_api) {
+ for (auto it = parser_.native_included_files_.begin();
+ it != parser_.native_included_files_.end(); ++it) {
+ code_ += "#include \"" + *it + "\"";
+ num_includes++;
+ }
}
for (auto it = parser_.included_files_.begin();
it != parser_.included_files_.end(); ++it) {
if (it->second.empty()) continue;
auto noext = flatbuffers::StripExtension(it->second);
auto basename = flatbuffers::StripPath(noext);
-
- code_ += "#include \"" + parser_.opts.include_prefix +
- (parser_.opts.keep_include_path ? noext : basename) +
- "_generated.h\"";
+ auto includeName =
+ GeneratedFileName(opts_.include_prefix,
+ opts_.keep_include_path ? noext : basename, opts_);
+ code_ += "#include \"" + includeName + "\"";
num_includes++;
}
if (num_includes) code_ += "";
}
void GenExtraIncludes() {
- for(std::size_t i = 0; i < parser_.opts.cpp_includes.size(); ++i) {
- code_ += "#include \"" + parser_.opts.cpp_includes[i] + "\"";
+ for (std::size_t i = 0; i < opts_.cpp_includes.size(); ++i) {
+ code_ += "#include \"" + opts_.cpp_includes[i] + "\"";
}
- if (!parser_.opts.cpp_includes.empty()) {
- code_ += "";
- }
+ if (!opts_.cpp_includes.empty()) { code_ += ""; }
}
std::string EscapeKeyword(const std::string &name) const {
@@ -223,20 +239,83 @@
std::string Name(const EnumVal &ev) const { return EscapeKeyword(ev.name); }
+ bool generate_bfbs_embed() {
+ code_.Clear();
+ code_ += "// " + std::string(FlatBuffersGeneratedWarning()) + "\n\n";
+
+ // If we don't have a root struct definition,
+ if (!parser_.root_struct_def_) {
+ // put a comment in the output why there is no code generated.
+ code_ += "// Binary schema not generated, no root struct found";
+ } else {
+ auto &struct_def = *parser_.root_struct_def_;
+ const auto include_guard =
+ GenIncludeGuard(file_name_, *struct_def.defined_namespace, "bfbs");
+
+ code_ += "#ifndef " + include_guard;
+ code_ += "#define " + include_guard;
+ code_ += "";
+ if (parser_.opts.gen_nullable) {
+ code_ += "#pragma clang system_header\n\n";
+ }
+
+ SetNameSpace(struct_def.defined_namespace);
+ auto name = Name(struct_def);
+ code_.SetValue("STRUCT_NAME", name);
+
+ // Create code to return the binary schema data.
+ auto binary_schema_hex_text =
+ BufferToHexText(parser_.builder_.GetBufferPointer(),
+ parser_.builder_.GetSize(), 105, " ", "");
+
+ code_ += "struct {{STRUCT_NAME}}BinarySchema {";
+ code_ += " static const uint8_t *data() {";
+ code_ += " // Buffer containing the binary schema.";
+ code_ += " static const uint8_t bfbsData[" +
+ NumToString(parser_.builder_.GetSize()) + "] = {";
+ code_ += binary_schema_hex_text;
+ code_ += " };";
+ code_ += " return bfbsData;";
+ code_ += " }";
+ code_ += " static size_t size() {";
+ code_ += " return " + NumToString(parser_.builder_.GetSize()) + ";";
+ code_ += " }";
+ code_ += " const uint8_t *begin() {";
+ code_ += " return data();";
+ code_ += " }";
+ code_ += " const uint8_t *end() {";
+ code_ += " return data() + size();";
+ code_ += " }";
+ code_ += "};";
+ code_ += "";
+
+ if (cur_name_space_) SetNameSpace(nullptr);
+
+ // Close the include guard.
+ code_ += "#endif // " + include_guard;
+ }
+
+ // We are just adding "_bfbs" to the generated filename.
+ const auto file_path =
+ GeneratedFileName(path_, file_name_ + "_bfbs", opts_);
+ const auto final_code = code_.ToString();
+
+ return SaveFile(file_path.c_str(), final_code, false);
+ }
+
// Iterate through all definitions we haven't generate code for (enums,
// structs, and tables) and output them to a single file.
bool generate() {
code_.Clear();
code_ += "// " + std::string(FlatBuffersGeneratedWarning()) + "\n\n";
- const auto include_guard = GenIncludeGuard();
+ const auto include_guard =
+ GenIncludeGuard(file_name_, *parser_.current_namespace_);
code_ += "#ifndef " + include_guard;
code_ += "#define " + include_guard;
code_ += "";
- if (parser_.opts.gen_nullable) {
- code_ += "#pragma clang system_header\n\n";
- }
+ if (opts_.gen_nullable) { code_ += "#pragma clang system_header\n\n"; }
code_ += "#include \"flatbuffers/flatbuffers.h\"";
if (parser_.uses_flexbuffers_) {
@@ -244,7 +323,7 @@
}
code_ += "";
- if (parser_.opts.include_dependence_headers) { GenIncludeDependencies(); }
+ if (opts_.include_dependence_headers) { GenIncludeDependencies(); }
GenExtraIncludes();
FLATBUFFERS_ASSERT(!cur_name_space_);
@@ -257,9 +336,11 @@
if (!struct_def.generated) {
SetNameSpace(struct_def.defined_namespace);
code_ += "struct " + Name(struct_def) + ";";
- if (parser_.opts.generate_object_based_api) {
- auto nativeName =
- NativeName(Name(struct_def), &struct_def, parser_.opts);
+ if (!struct_def.fixed) {
+ code_ += "struct " + Name(struct_def) + "Builder;";
+ }
+ if (opts_.generate_object_based_api) {
+ auto nativeName = NativeName(Name(struct_def), &struct_def, opts_);
if (!struct_def.fixed) { code_ += "struct " + nativeName + ";"; }
}
code_ += "";
@@ -267,25 +348,24 @@
}
// Generate forward declarations for all equal operators
- if (parser_.opts.generate_object_based_api && parser_.opts.gen_compare) {
+ if (opts_.generate_object_based_api && opts_.gen_compare) {
for (auto it = parser_.structs_.vec.begin();
it != parser_.structs_.vec.end(); ++it) {
const auto &struct_def = **it;
if (!struct_def.generated) {
SetNameSpace(struct_def.defined_namespace);
- auto nativeName =
- NativeName(Name(struct_def), &struct_def, parser_.opts);
+ auto nativeName = NativeName(Name(struct_def), &struct_def, opts_);
code_ += "bool operator==(const " + nativeName + " &lhs, const " +
nativeName + " &rhs);";
code_ += "bool operator!=(const " + nativeName + " &lhs, const " +
- nativeName + " &rhs);";
+ nativeName + " &rhs);";
}
}
code_ += "";
}
// Generate preablmle code for mini reflection.
- if (parser_.opts.mini_reflect != IDLOptions::kNone) {
+ if (opts_.mini_reflect != IDLOptions::kNone) {
// To break cyclic dependencies, first pre-declare all tables/structs.
for (auto it = parser_.structs_.vec.begin();
it != parser_.structs_.vec.end(); ++it) {
@@ -344,7 +424,7 @@
}
// Generate code for mini reflection.
- if (parser_.opts.mini_reflect != IDLOptions::kNone) {
+ if (opts_.mini_reflect != IDLOptions::kNone) {
// Then the unions/enums that may refer to them.
for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
++it) {
@@ -395,7 +475,7 @@
code_ += "}";
code_ += "";
- if (parser_.opts.mutable_buffer) {
+ if (opts_.mutable_buffer) {
code_ += "inline \\";
code_ += "{{STRUCT_NAME}} *GetMutable{{STRUCT_NAME}}(void *buf) {";
code_ += " return flatbuffers::GetMutableRoot<{{STRUCT_NAME}}>(buf);";
@@ -468,10 +548,10 @@
code_ += "}";
code_ += "";
- if (parser_.opts.generate_object_based_api) {
+ if (opts_.generate_object_based_api) {
// A convenient root unpack function.
auto native_name =
- NativeName(WrapInNameSpace(struct_def), &struct_def, parser_.opts);
+ NativeName(WrapInNameSpace(struct_def), &struct_def, opts_);
code_.SetValue("UNPACK_RETURN",
GenTypeNativePtr(native_name, nullptr, false));
code_.SetValue("UNPACK_TYPE",
@@ -500,9 +580,12 @@
// Close the include guard.
code_ += "#endif // " + include_guard;
- const auto file_path = GeneratedFileName(path_, file_name_);
+ const auto file_path = GeneratedFileName(path_, file_name_, opts_);
const auto final_code = code_.ToString();
- return SaveFile(file_path.c_str(), final_code, false);
+
+ // Save the file and optionally generate the binary schema code.
+ return SaveFile(file_path.c_str(), final_code, false) &&
+ (!parser_.opts.binary_schema_gen_embed || generate_bfbs_embed());
}
private:
@@ -513,6 +596,9 @@
// This tracks the current namespace so we can insert namespace declarations.
const Namespace *cur_name_space_;
+ const IDLOptionsCpp opts_;
+ const TypedFloatConstantGenerator float_const_gen_;
+
const Namespace *CurrentNameSpace() const { return cur_name_space_; }
// Translates a qualified name in flatbuffer text format to the same name in
@@ -527,6 +613,21 @@
return cpp_qualified_name;
}
+ bool TypeHasKey(const Type &type) {
+ if (type.base_type != BASE_TYPE_STRUCT) { return false; }
+ for (auto it = type.struct_def->fields.vec.begin();
+ it != type.struct_def->fields.vec.end(); ++it) {
+ const auto &field = **it;
+ if (field.key) { return true; }
+ }
+ return false;
+ }
+
+ bool VectorElementUserFacing(const Type &type) const {
+ return opts_.g_cpp_std >= cpp::CPP_STD_17 && opts_.g_only_fixed_enums &&
+ IsEnum(type);
+ }
+
void GenComment(const std::vector<std::string> &dc, const char *prefix = "") {
std::string text;
::flatbuffers::GenComment(dc, &text, nullptr, prefix);
@@ -537,11 +638,10 @@
std::string GenTypeBasic(const Type &type, bool user_facing_type) const {
// clang-format off
static const char *const ctypename[] = {
- #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, \
- RTYPE, KTYPE) \
- #CTYPE,
+ #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \
+ #CTYPE,
FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
- #undef FLATBUFFERS_TD
+ #undef FLATBUFFERS_TD
};
// clang-format on
if (user_facing_type) {
@@ -559,15 +659,18 @@
return "flatbuffers::String";
}
case BASE_TYPE_VECTOR: {
- const auto type_name = GenTypeWire(type.VectorType(), "", false);
+ const auto type_name = GenTypeWire(
+ type.VectorType(), "", VectorElementUserFacing(type.VectorType()));
return "flatbuffers::Vector<" + type_name + ">";
}
case BASE_TYPE_STRUCT: {
return WrapInNameSpace(*type.struct_def);
}
case BASE_TYPE_UNION:
- // fall through
- default: { return "void"; }
+ // fall through
+ default: {
+ return "void";
+ }
}
}
@@ -597,7 +700,7 @@
}
std::string NullableExtension() {
- return parser_.opts.gen_nullable ? " _Nullable " : "";
+ return opts_.gen_nullable ? " _Nullable " : "";
}
static std::string NativeName(const std::string &name, const StructDef *sd,
@@ -608,12 +711,12 @@
const std::string &PtrType(const FieldDef *field) {
auto attr = field ? field->attributes.Lookup("cpp_ptr_type") : nullptr;
- return attr ? attr->constant : parser_.opts.cpp_object_api_pointer_type;
+ return attr ? attr->constant : opts_.cpp_object_api_pointer_type;
}
const std::string NativeString(const FieldDef *field) {
auto attr = field ? field->attributes.Lookup("cpp_str_type") : nullptr;
- auto &ret = attr ? attr->constant : parser_.opts.cpp_object_api_string_type;
+ auto &ret = attr ? attr->constant : opts_.cpp_object_api_string_type;
if (ret.empty()) { return "std::string"; }
return ret;
}
@@ -622,8 +725,7 @@
auto attr = field
? (field->attributes.Lookup("cpp_str_flex_ctor") != nullptr)
: false;
- auto ret =
- attr ? attr : parser_.opts.cpp_object_api_string_flexible_constructor;
+ auto ret = attr ? attr : opts_.cpp_object_api_string_flexible_constructor;
return ret && NativeString(field) !=
"std::string"; // Only for custom string types.
}
@@ -634,7 +736,7 @@
if (ptr_type != "naked") {
return (ptr_type != "default_ptr_type"
? ptr_type
- : parser_.opts.cpp_object_api_pointer_type) +
+ : opts_.cpp_object_api_pointer_type) +
"<" + type + ">";
} else if (is_constructor) {
return "";
@@ -650,6 +752,12 @@
return ptr_type == "naked" ? "" : ".get()";
}
+ std::string GenOptionalNull() { return "flatbuffers::nullopt"; }
+
+ std::string GenOptionalDecl(const Type &type) {
+ return "flatbuffers::Optional<" + GenTypeBasic(type, true) + ">";
+ }
+
std::string GenTypeNative(const Type &type, bool invector,
const FieldDef &field) {
switch (type.base_type) {
@@ -678,15 +786,18 @@
return GenTypeNativePtr(type_name, &field, false);
}
} else {
- return GenTypeNativePtr(
- NativeName(type_name, type.struct_def, parser_.opts), &field,
- false);
+ return GenTypeNativePtr(NativeName(type_name, type.struct_def, opts_),
+ &field, false);
}
}
case BASE_TYPE_UNION: {
- return type.enum_def->name + "Union";
+ auto type_name = WrapInNameSpace(*type.enum_def);
+ return type_name + "Union";
}
- default: { return GenTypeBasic(type, true); }
+ default: {
+ return field.IsScalarOptional() ? GenOptionalDecl(type)
+ : GenTypeBasic(type, true);
+ }
}
}
@@ -699,6 +810,12 @@
return GenTypeBasic(type, user_facing_type) + afterbasic;
} else if (IsArray(type)) {
auto element_type = type.VectorType();
+ // Check if enum arrays are used in C++ without specifying --scoped-enums
+ if (IsEnum(element_type) && !opts_.g_only_fixed_enums) {
+ LogCompilerError(
+ "--scoped-enums must be enabled to use enum arrays in C++");
+ FLATBUFFERS_ASSERT(true);
+ }
return beforeptr +
(IsScalar(element_type.base_type)
? GenTypeBasic(element_type, user_facing_type)
@@ -709,23 +826,48 @@
}
}
- std::string GenEnumDecl(const EnumDef &enum_def) const {
- const IDLOptions &opts = parser_.opts;
- return (opts.scoped_enums ? "enum class " : "enum ") + Name(enum_def);
+ std::string GenTypeSpan(const Type &type, bool immutable, size_t extent) {
+ // Generate "flatbuffers::span<const U, extent>".
+ FLATBUFFERS_ASSERT(IsSeries(type) && "unexpected type");
+ auto element_type = type.VectorType();
+ std::string text = "flatbuffers::span<";
+ text += immutable ? "const " : "";
+ if (IsScalar(element_type.base_type)) {
+ text += GenTypeBasic(element_type, IsEnum(element_type));
+ } else {
+ switch (element_type.base_type) {
+ case BASE_TYPE_STRING: {
+ text += "char";
+ break;
+ }
+ case BASE_TYPE_STRUCT: {
+ FLATBUFFERS_ASSERT(type.struct_def);
+ text += WrapInNameSpace(*type.struct_def);
+ break;
+ }
+ default:
+ FLATBUFFERS_ASSERT(false && "unexpected element's type");
+ break;
+ }
+ }
+ if (extent != flatbuffers::dynamic_extent) {
+ text += ", ";
+ text += NumToString(extent);
+ }
+ text += "> ";
+ return text;
}
std::string GenEnumValDecl(const EnumDef &enum_def,
const std::string &enum_val) const {
- const IDLOptions &opts = parser_.opts;
- return opts.prefixed_enums ? Name(enum_def) + "_" + enum_val : enum_val;
+ return opts_.prefixed_enums ? Name(enum_def) + "_" + enum_val : enum_val;
}
std::string GetEnumValUse(const EnumDef &enum_def,
const EnumVal &enum_val) const {
- const IDLOptions &opts = parser_.opts;
- if (opts.scoped_enums) {
+ if (opts_.scoped_enums) {
return Name(enum_def) + "::" + Name(enum_val);
- } else if (opts.prefixed_enums) {
+ } else if (opts_.prefixed_enums) {
return Name(enum_def) + "_" + Name(enum_val);
} else {
return Name(enum_val);
@@ -743,7 +885,7 @@
return wrap ? WrapInNameSpace(ev.union_type.struct_def->defined_namespace,
name)
: name;
- } else if (ev.union_type.base_type == BASE_TYPE_STRING) {
+ } else if (IsString(ev.union_type)) {
return actual_type ? (native_type ? "std::string" : "flatbuffers::String")
: Name(ev);
} else {
@@ -850,11 +992,13 @@
}
std::string ts;
std::vector<std::string> type_refs;
+ std::vector<uint16_t> array_sizes;
for (auto it = types.begin(); it != types.end(); ++it) {
auto &type = *it;
if (!ts.empty()) ts += ",\n ";
- auto is_vector = type.base_type == BASE_TYPE_VECTOR;
- auto bt = is_vector ? type.element : type.base_type;
+ auto is_vector = IsVector(type);
+ auto is_array = IsArray(type);
+ auto bt = is_vector || is_array ? type.element : type.base_type;
auto et = IsScalar(bt) || bt == BASE_TYPE_STRING
? bt - BASE_TYPE_UTYPE + ET_UTYPE
: ET_SEQUENCE;
@@ -876,14 +1020,21 @@
type_refs.push_back(ref_name);
}
}
+ if (is_array) { array_sizes.push_back(type.fixed_length); }
ts += "{ flatbuffers::" + std::string(ElementaryTypeNames()[et]) + ", " +
- NumToString(is_vector) + ", " + NumToString(ref_idx) + " }";
+ NumToString(is_vector || is_array) + ", " + NumToString(ref_idx) +
+ " }";
}
std::string rs;
for (auto it = type_refs.begin(); it != type_refs.end(); ++it) {
if (!rs.empty()) rs += ",\n ";
rs += *it + "TypeTable";
}
+ std::string as;
+ for (auto it = array_sizes.begin(); it != array_sizes.end(); ++it) {
+ as += NumToString(*it);
+ as += ", ";
+ }
std::string ns;
for (auto it = names.begin(); it != names.end(); ++it) {
if (!ns.empty()) ns += ",\n ";
@@ -912,6 +1063,7 @@
}
code_.SetValue("TYPES", ts);
code_.SetValue("REFS", rs);
+ code_.SetValue("ARRAYSIZES", as);
code_.SetValue("NAMES", ns);
code_.SetValue("VALUES", vs);
code_ += "inline const flatbuffers::TypeTable *{{NAME}}TypeTable() {";
@@ -925,12 +1077,15 @@
code_ += " {{REFS}}";
code_ += " };";
}
+ if (!as.empty()) {
+ code_ += " static const int16_t array_sizes[] = { {{ARRAYSIZES}} };";
+ }
if (!vs.empty()) {
// Problem with uint64_t values greater than 9223372036854775807ULL.
code_ += " static const int64_t values[] = { {{VALUES}} };";
}
auto has_names =
- num_fields && parser_.opts.mini_reflect == IDLOptions::kTypesAndNames;
+ num_fields && opts_.mini_reflect == IDLOptions::kTypesAndNames;
if (has_names) {
code_ += " static const char * const names[] = {";
code_ += " {{NAMES}}";
@@ -940,6 +1095,7 @@
code_ += std::string(" flatbuffers::{{SEQ_TYPE}}, {{NUM_FIELDS}}, ") +
(num_fields ? "type_codes, " : "nullptr, ") +
(!type_refs.empty() ? "type_refs, " : "nullptr, ") +
+ (!as.empty() ? "array_sizes, " : "nullptr, ") +
(!vs.empty() ? "values, " : "nullptr, ") +
(has_names ? "names" : "nullptr");
code_ += " };";
@@ -957,14 +1113,9 @@
code_.SetValue("BASE_TYPE", GenTypeBasic(enum_def.underlying_type, false));
GenComment(enum_def.doc_comment);
- code_ += GenEnumDecl(enum_def) + "\\";
- // MSVC doesn't support int64/uint64 enum without explicitly declared enum
- // type. The value 4611686018427387904ULL is truncated to zero with warning:
- // "warning C4309: 'initializing': truncation of constant value".
- auto add_type = parser_.opts.scoped_enums;
- add_type |= (enum_def.underlying_type.base_type == BASE_TYPE_LONG);
- add_type |= (enum_def.underlying_type.base_type == BASE_TYPE_ULONG);
- if (add_type) code_ += " : {{BASE_TYPE}}\\";
+ code_ +=
+ (opts_.scoped_enums ? "enum class " : "enum ") + Name(enum_def) + "\\";
+ if (opts_.g_only_fixed_enums) { code_ += " : {{BASE_TYPE}}\\"; }
code_ += " {";
code_.SetValue("SEP", ",");
@@ -983,7 +1134,7 @@
const EnumVal *minv = enum_def.MinValue();
const EnumVal *maxv = enum_def.MaxValue();
- if (parser_.opts.scoped_enums || parser_.opts.prefixed_enums) {
+ if (opts_.scoped_enums || opts_.prefixed_enums) {
FLATBUFFERS_ASSERT(minv && maxv);
code_.SetValue("SEP", ",\n");
@@ -999,18 +1150,18 @@
code_ += "{{SEP}} {{KEY}} = {{VALUE}}\\";
} else { // MIN & MAX are useless for bit_flags
code_.SetValue("KEY", GenEnumValDecl(enum_def, "MIN"));
- code_.SetValue("VALUE", GenEnumValDecl(enum_def, minv->name));
+ code_.SetValue("VALUE", GenEnumValDecl(enum_def, Name(*minv)));
code_ += "{{SEP}} {{KEY}} = {{VALUE}}\\";
code_.SetValue("KEY", GenEnumValDecl(enum_def, "MAX"));
- code_.SetValue("VALUE", GenEnumValDecl(enum_def, maxv->name));
+ code_.SetValue("VALUE", GenEnumValDecl(enum_def, Name(*maxv)));
code_ += "{{SEP}} {{KEY}} = {{VALUE}}\\";
}
}
code_ += "";
code_ += "};";
- if (parser_.opts.scoped_enums && enum_def.attributes.Lookup("bit_flags")) {
+ if (opts_.scoped_enums && enum_def.attributes.Lookup("bit_flags")) {
code_ +=
"FLATBUFFERS_DEFINE_BITMASK_OPERATORS({{ENUM_NAME}}, {{BASE_TYPE}})";
}
@@ -1064,9 +1215,10 @@
code_ += "inline const char *EnumName{{ENUM_NAME}}({{ENUM_NAME}} e) {";
- code_ += " if (e < " + GetEnumValUse(enum_def, *enum_def.MinValue()) +
- " || e > " + GetEnumValUse(enum_def, *enum_def.MaxValue()) +
- ") return \"\";";
+ code_ += " if (flatbuffers::IsOutRange(e, " +
+ GetEnumValUse(enum_def, *enum_def.MinValue()) + ", " +
+ GetEnumValUse(enum_def, *enum_def.MaxValue()) +
+ ")) return \"\";";
code_ += " const size_t index = static_cast<size_t>(e)\\";
if (enum_def.MinValue()->IsNonZero()) {
@@ -1117,7 +1269,7 @@
}
}
- if (parser_.opts.generate_object_based_api && enum_def.is_union) {
+ if (opts_.generate_object_based_api && enum_def.is_union) {
// Generate a union type
code_.SetValue("NAME", Name(enum_def));
FLATBUFFERS_ASSERT(enum_def.Lookup("NONE"));
@@ -1131,10 +1283,8 @@
code_ += " {{NAME}}Union({{NAME}}Union&& u) FLATBUFFERS_NOEXCEPT :";
code_ += " type({{NONE}}), value(nullptr)";
code_ += " { std::swap(type, u.type); std::swap(value, u.value); }";
- code_ += " {{NAME}}Union(const {{NAME}}Union &) FLATBUFFERS_NOEXCEPT;";
- code_ +=
- " {{NAME}}Union &operator=(const {{NAME}}Union &u) "
- "FLATBUFFERS_NOEXCEPT";
+ code_ += " {{NAME}}Union(const {{NAME}}Union &);";
+ code_ += " {{NAME}}Union &operator=(const {{NAME}}Union &u)";
code_ +=
" { {{NAME}}Union t(u); std::swap(type, t.type); std::swap(value, "
"t.value); return *this; }";
@@ -1153,7 +1303,8 @@
code_ += " void Set(T&& val) {";
code_ += " using RT = typename std::remove_reference<T>::type;";
code_ += " Reset();";
- code_ += " type = {{NAME}}Traits<typename RT::TableType>::enum_value;";
+ code_ +=
+ " type = {{NAME}}Traits<typename RT::TableType>::enum_value;";
code_ += " if (type != {{NONE}}) {";
code_ += " value = new RT(std::forward<T>(val));";
code_ += " }";
@@ -1172,7 +1323,7 @@
const auto native_type =
NativeName(GetUnionElement(ev, true, true, true),
- ev.union_type.struct_def, parser_.opts);
+ ev.union_type.struct_def, opts_);
code_.SetValue("NATIVE_TYPE", native_type);
code_.SetValue("NATIVE_NAME", Name(ev));
code_.SetValue("NATIVE_ID", GetEnumValUse(enum_def, ev));
@@ -1191,7 +1342,7 @@
code_ += "};";
code_ += "";
- if (parser_.opts.gen_compare) {
+ if (opts_.gen_compare) {
code_ += "";
code_ +=
"inline bool operator==(const {{NAME}}Union &lhs, const "
@@ -1206,7 +1357,7 @@
if (ev.IsNonZero()) {
const auto native_type =
NativeName(GetUnionElement(ev, true, true, true),
- ev.union_type.struct_def, parser_.opts);
+ ev.union_type.struct_def, opts_);
code_.SetValue("NATIVE_TYPE", native_type);
code_ += " case {{NATIVE_ID}}: {";
code_ +=
@@ -1266,13 +1417,14 @@
" auto ptr = reinterpret_cast<const {{TYPE}} *>(obj);";
if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
if (ev.union_type.struct_def->fixed) {
- code_ += " return verifier.Verify<{{TYPE}}>(static_cast<const "
- "uint8_t *>(obj), 0);";
+ code_ +=
+ " return verifier.Verify<{{TYPE}}>(static_cast<const "
+ "uint8_t *>(obj), 0);";
} else {
code_ += getptr;
code_ += " return verifier.VerifyTable(ptr);";
}
- } else if (ev.union_type.base_type == BASE_TYPE_STRING) {
+ } else if (IsString(ev.union_type)) {
code_ += getptr;
code_ += " return verifier.VerifyString(ptr);";
} else {
@@ -1285,7 +1437,7 @@
code_ += " }";
}
}
- code_ += " default: return false;";
+ code_ += " default: return true;"; // unknown values are OK.
code_ += " }";
code_ += "}";
code_ += "";
@@ -1304,7 +1456,7 @@
code_ += "}";
code_ += "";
- if (parser_.opts.generate_object_based_api) {
+ if (opts_.generate_object_based_api) {
// Generate union Unpack() and Pack() functions.
code_ += "inline " + UnionUnPackSignature(enum_def, false) + " {";
code_ += " switch (type) {";
@@ -1324,7 +1476,7 @@
} else {
code_ += " return ptr->UnPack(resolver);";
}
- } else if (ev.union_type.base_type == BASE_TYPE_STRING) {
+ } else if (IsString(ev.union_type)) {
code_ += " return new std::string(ptr->c_str(), ptr->size());";
} else {
FLATBUFFERS_ASSERT(false);
@@ -1344,9 +1496,8 @@
if (ev.IsZero()) { continue; }
code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
- code_.SetValue("TYPE",
- NativeName(GetUnionElement(ev, true, true, true),
- ev.union_type.struct_def, parser_.opts));
+ code_.SetValue("TYPE", NativeName(GetUnionElement(ev, true, true, true),
+ ev.union_type.struct_def, opts_));
code_.SetValue("NAME", GetUnionElement(ev, false, true));
code_ += " case {{LABEL}}: {";
code_ += " auto ptr = reinterpret_cast<const {{TYPE}} *>(value);";
@@ -1357,7 +1508,7 @@
code_ +=
" return Create{{NAME}}(_fbb, ptr, _rehasher).Union();";
}
- } else if (ev.union_type.base_type == BASE_TYPE_STRING) {
+ } else if (IsString(ev.union_type)) {
code_ += " return _fbb.CreateString(*ptr).Union();";
} else {
FLATBUFFERS_ASSERT(false);
@@ -1372,17 +1523,15 @@
// Union copy constructor
code_ +=
"inline {{ENUM_NAME}}Union::{{ENUM_NAME}}Union(const "
- "{{ENUM_NAME}}Union &u) FLATBUFFERS_NOEXCEPT : type(u.type), "
- "value(nullptr) {";
+ "{{ENUM_NAME}}Union &u) : type(u.type), value(nullptr) {";
code_ += " switch (type) {";
for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
++it) {
const auto &ev = **it;
if (ev.IsZero()) { continue; }
code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
- code_.SetValue("TYPE",
- NativeName(GetUnionElement(ev, true, true, true),
- ev.union_type.struct_def, parser_.opts));
+ code_.SetValue("TYPE", NativeName(GetUnionElement(ev, true, true, true),
+ ev.union_type.struct_def, opts_));
code_ += " case {{LABEL}}: {";
bool copyable = true;
if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
@@ -1426,9 +1575,8 @@
const auto &ev = **it;
if (ev.IsZero()) { continue; }
code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
- code_.SetValue("TYPE",
- NativeName(GetUnionElement(ev, true, true, true),
- ev.union_type.struct_def, parser_.opts));
+ code_.SetValue("TYPE", NativeName(GetUnionElement(ev, true, true, true),
+ ev.union_type.struct_def, opts_));
code_ += " case {{LABEL}}: {";
code_ += " auto ptr = reinterpret_cast<{{TYPE}} *>(value);";
code_ += " delete ptr;";
@@ -1464,13 +1612,13 @@
std::string GenFieldOffsetName(const FieldDef &field) {
std::string uname = Name(field);
- std::transform(uname.begin(), uname.end(), uname.begin(), ToUpper);
+ std::transform(uname.begin(), uname.end(), uname.begin(), CharToUpper);
return "VT_" + uname;
}
void GenFullyQualifiedNameGetter(const StructDef &struct_def,
const std::string &name) {
- if (!parser_.opts.generate_name_strings) { return; }
+ if (!opts_.generate_name_strings) { return; }
auto fullname = struct_def.defined_namespace->GetFullyQualifiedName(name);
code_.SetValue("NAME", fullname);
code_.SetValue("CONSTEXPR", "FLATBUFFERS_CONSTEXPR");
@@ -1487,17 +1635,19 @@
}
std::string GetDefaultScalarValue(const FieldDef &field, bool is_ctor) {
- if (field.value.type.enum_def && IsScalar(field.value.type.base_type)) {
- auto ev = field.value.type.enum_def->FindByValue(field.value.constant);
+ const auto &type = field.value.type;
+ if (field.IsScalarOptional()) {
+ return GenOptionalNull();
+ } else if (type.enum_def && IsScalar(type.base_type)) {
+ auto ev = type.enum_def->FindByValue(field.value.constant);
if (ev) {
- return WrapInNameSpace(field.value.type.enum_def->defined_namespace,
- GetEnumValUse(*field.value.type.enum_def, *ev));
+ return WrapInNameSpace(type.enum_def->defined_namespace,
+ GetEnumValUse(*type.enum_def, *ev));
} else {
return GenUnderlyingCast(
- field, true,
- NumToStringCpp(field.value.constant, field.value.type.base_type));
+ field, true, NumToStringCpp(field.value.constant, type.base_type));
}
- } else if (field.value.type.base_type == BASE_TYPE_BOOL) {
+ } else if (type.base_type == BASE_TYPE_BOOL) {
return field.value.constant == "0" ? "false" : "true";
} else if (field.attributes.Lookup("cpp_type")) {
if (is_ctor) {
@@ -1517,22 +1667,30 @@
void GenParam(const FieldDef &field, bool direct, const char *prefix) {
code_.SetValue("PRE", prefix);
code_.SetValue("PARAM_NAME", Name(field));
- if (direct && field.value.type.base_type == BASE_TYPE_STRING) {
+ if (direct && IsString(field.value.type)) {
code_.SetValue("PARAM_TYPE", "const char *");
code_.SetValue("PARAM_VALUE", "nullptr");
- } else if (direct && field.value.type.base_type == BASE_TYPE_VECTOR) {
+ } else if (direct && IsVector(field.value.type)) {
const auto vtype = field.value.type.VectorType();
std::string type;
if (IsStruct(vtype)) {
type = WrapInNameSpace(*vtype.struct_def);
} else {
- type = GenTypeWire(vtype, "", false);
+ type = GenTypeWire(vtype, "", VectorElementUserFacing(vtype));
}
- code_.SetValue("PARAM_TYPE", "const std::vector<" + type + "> *");
+ if (TypeHasKey(vtype)) {
+ code_.SetValue("PARAM_TYPE", "std::vector<" + type + "> *");
+ } else {
+ code_.SetValue("PARAM_TYPE", "const std::vector<" + type + "> *");
+ }
code_.SetValue("PARAM_VALUE", "nullptr");
} else {
- code_.SetValue("PARAM_TYPE", GenTypeWire(field.value.type, " ", true));
+ const auto &type = field.value.type;
code_.SetValue("PARAM_VALUE", GetDefaultScalarValue(field, false));
+ if (field.IsScalarOptional())
+ code_.SetValue("PARAM_TYPE", GenOptionalDecl(type) + " ");
+ else
+ code_.SetValue("PARAM_TYPE", GenTypeWire(type, " ", true));
}
code_ += "{{PRE}}{{PARAM_TYPE}}{{PARAM_NAME}} = {{PARAM_VALUE}}\\";
}
@@ -1547,22 +1705,43 @@
auto cpp_type = field.attributes.Lookup("cpp_type");
auto full_type =
(cpp_type
- ? (field.value.type.base_type == BASE_TYPE_VECTOR
+ ? (IsVector(field.value.type)
? "std::vector<" +
GenTypeNativePtr(cpp_type->constant, &field,
false) +
"> "
: GenTypeNativePtr(cpp_type->constant, &field, false))
: type + " ");
+ // Generate default member initializers for >= C++11.
+ std::string field_di = "";
+ if (opts_.g_cpp_std >= cpp::CPP_STD_11) {
+ field_di = "{}";
+ auto native_default = field.attributes.Lookup("native_default");
+ // Scalar types get parsed defaults, raw pointers get nullptrs.
+ if (IsScalar(field.value.type.base_type)) {
+ field_di =
+ " = " + (native_default ? std::string(native_default->constant)
+ : GetDefaultScalarValue(field, true));
+ } else if (field.value.type.base_type == BASE_TYPE_STRUCT) {
+ if (IsStruct(field.value.type) && native_default) {
+ field_di = " = " + native_default->constant;
+ }
+ }
+ }
code_.SetValue("FIELD_TYPE", full_type);
code_.SetValue("FIELD_NAME", Name(field));
- code_ += " {{FIELD_TYPE}}{{FIELD_NAME}};";
+ code_.SetValue("FIELD_DI", field_di);
+ code_ += " {{FIELD_TYPE}}{{FIELD_NAME}}{{FIELD_DI}};";
}
}
// Generate the default constructor for this struct. Properly initialize all
// scalar members with default values.
void GenDefaultConstructor(const StructDef &struct_def) {
+ code_.SetValue("NATIVE_NAME",
+ NativeName(Name(struct_def), &struct_def, opts_));
+ // In >= C++11, default member initializers are generated.
+ if (opts_.g_cpp_std >= cpp::CPP_STD_11) { return; }
std::string initializer_list;
for (auto it = struct_def.fields.vec.begin();
it != struct_def.fields.vec.end(); ++it) {
@@ -1600,8 +1779,6 @@
initializer_list = "\n : " + initializer_list;
}
- code_.SetValue("NATIVE_NAME",
- NativeName(Name(struct_def), &struct_def, parser_.opts));
code_.SetValue("INIT_LIST", initializer_list);
code_ += " {{NATIVE_NAME}}(){{INIT_LIST}} {";
@@ -1671,8 +1848,7 @@
}
void GenNativeTable(const StructDef &struct_def) {
- const auto native_name =
- NativeName(Name(struct_def), &struct_def, parser_.opts);
+ const auto native_name = NativeName(Name(struct_def), &struct_def, opts_);
code_.SetValue("STRUCT_NAME", Name(struct_def));
code_.SetValue("NATIVE_NAME", native_name);
@@ -1687,7 +1863,7 @@
GenOperatorNewDelete(struct_def);
GenDefaultConstructor(struct_def);
code_ += "};";
- if (parser_.opts.gen_compare) GenCompareOperator(struct_def);
+ if (opts_.gen_compare) GenCompareOperator(struct_def);
code_ += "";
}
@@ -1749,14 +1925,16 @@
}
break;
}
- default: { break; }
+ default: {
+ break;
+ }
}
}
// Generate CompareWithValue method for a key field.
void GenKeyFieldMethods(const FieldDef &field) {
FLATBUFFERS_ASSERT(field.key);
- const bool is_string = (field.value.type.base_type == BASE_TYPE_STRING);
+ const bool is_string = (IsString(field.value.type));
code_ += " bool KeyCompareLessThan(const {{STRUCT_NAME}} *o) const {";
if (is_string) {
@@ -1774,7 +1952,7 @@
} else {
FLATBUFFERS_ASSERT(IsScalar(field.value.type.base_type));
auto type = GenTypeBasic(field.value.type, false);
- if (parser_.opts.scoped_enums && field.value.type.enum_def &&
+ if (opts_.scoped_enums && field.value.type.enum_def &&
IsScalar(field.value.type.base_type)) {
type = GenTypeGet(field.value.type, " ", "const ", " *", true);
}
@@ -1788,9 +1966,126 @@
}
}
+ void GenTableUnionAsGetters(const FieldDef &field) {
+ const auto &type = field.value.type;
+ auto u = type.enum_def;
+
+ if (!type.enum_def->uses_multiple_type_instances)
+ code_ +=
+ " template<typename T> "
+ "const T *{{NULLABLE_EXT}}{{FIELD_NAME}}_as() const;";
+
+ for (auto u_it = u->Vals().begin(); u_it != u->Vals().end(); ++u_it) {
+ auto &ev = **u_it;
+ if (ev.union_type.base_type == BASE_TYPE_NONE) { continue; }
+ auto full_struct_name = GetUnionElement(ev, true, true);
+
+ // @TODO: Mby make this decisions more universal? How?
+ code_.SetValue("U_GET_TYPE",
+ EscapeKeyword(field.name + UnionTypeFieldSuffix()));
+ code_.SetValue("U_ELEMENT_TYPE", WrapInNameSpace(u->defined_namespace,
+ GetEnumValUse(*u, ev)));
+ code_.SetValue("U_FIELD_TYPE", "const " + full_struct_name + " *");
+ code_.SetValue("U_FIELD_NAME", Name(field) + "_as_" + Name(ev));
+ code_.SetValue("U_NULLABLE", NullableExtension());
+
+ // `const Type *union_name_asType() const` accessor.
+ code_ += " {{U_FIELD_TYPE}}{{U_NULLABLE}}{{U_FIELD_NAME}}() const {";
+ code_ +=
+ " return {{U_GET_TYPE}}() == {{U_ELEMENT_TYPE}} ? "
+ "static_cast<{{U_FIELD_TYPE}}>({{FIELD_NAME}}()) "
+ ": nullptr;";
+ code_ += " }";
+ }
+ }
+
+ void GenTableFieldGetter(const FieldDef &field) {
+ const auto &type = field.value.type;
+ const auto offset_str = GenFieldOffsetName(field);
+
+ GenComment(field.doc_comment, " ");
+ // Call a different accessor for pointers, that indirects.
+ if (false == field.IsScalarOptional()) {
+ const bool is_scalar = IsScalar(type.base_type);
+ std::string accessor;
+ if (is_scalar)
+ accessor = "GetField<";
+ else if (IsStruct(type))
+ accessor = "GetStruct<";
+ else
+ accessor = "GetPointer<";
+ auto offset_type = GenTypeGet(type, "", "const ", " *", false);
+ auto call = accessor + offset_type + ">(" + offset_str;
+ // Default value as second arg for non-pointer types.
+ if (is_scalar) { call += ", " + GenDefaultConstant(field); }
+ call += ")";
+
+ std::string afterptr = " *" + NullableExtension();
+ code_.SetValue("FIELD_TYPE",
+ GenTypeGet(type, " ", "const ", afterptr.c_str(), true));
+ code_.SetValue("FIELD_VALUE", GenUnderlyingCast(field, true, call));
+ code_.SetValue("NULLABLE_EXT", NullableExtension());
+ code_ += " {{FIELD_TYPE}}{{FIELD_NAME}}() const {";
+ code_ += " return {{FIELD_VALUE}};";
+ code_ += " }";
+ } else {
+ auto wire_type = GenTypeBasic(type, false);
+ auto face_type = GenTypeBasic(type, true);
+ auto opt_value = "GetOptional<" + wire_type + ", " + face_type + ">(" +
+ offset_str + ")";
+ code_.SetValue("FIELD_TYPE", GenOptionalDecl(type));
+ code_ += " {{FIELD_TYPE}} {{FIELD_NAME}}() const {";
+ code_ += " return " + opt_value + ";";
+ code_ += " }";
+ }
+
+ if (type.base_type == BASE_TYPE_UNION) { GenTableUnionAsGetters(field); }
+ }
+
+ void GenTableFieldSetter(const FieldDef &field) {
+ const auto &type = field.value.type;
+ const bool is_scalar = IsScalar(type.base_type);
+ if (is_scalar && IsUnion(type))
+ return; // changing of a union's type is forbidden
+
+ auto offset_str = GenFieldOffsetName(field);
+ if (is_scalar) {
+ const auto wire_type = GenTypeWire(type, "", false);
+ code_.SetValue("SET_FN", "SetField<" + wire_type + ">");
+ code_.SetValue("OFFSET_NAME", offset_str);
+ code_.SetValue("FIELD_TYPE", GenTypeBasic(type, true));
+ code_.SetValue("FIELD_VALUE",
+ GenUnderlyingCast(field, false, "_" + Name(field)));
+
+ code_ +=
+ " bool mutate_{{FIELD_NAME}}({{FIELD_TYPE}} "
+ "_{{FIELD_NAME}}) {";
+ if (false == field.IsScalarOptional()) {
+ code_.SetValue("DEFAULT_VALUE", GenDefaultConstant(field));
+ code_ +=
+ " return {{SET_FN}}({{OFFSET_NAME}}, {{FIELD_VALUE}}, "
+ "{{DEFAULT_VALUE}});";
+ } else {
+ code_ += " return {{SET_FN}}({{OFFSET_NAME}}, {{FIELD_VALUE}});";
+ }
+ code_ += " }";
+ } else {
+ auto postptr = " *" + NullableExtension();
+ auto wire_type = GenTypeGet(type, " ", "", postptr.c_str(), true);
+ std::string accessor = IsStruct(type) ? "GetStruct<" : "GetPointer<";
+ auto underlying = accessor + wire_type + ">(" + offset_str + ")";
+ code_.SetValue("FIELD_TYPE", wire_type);
+ code_.SetValue("FIELD_VALUE", GenUnderlyingCast(field, true, underlying));
+
+ code_ += " {{FIELD_TYPE}}mutable_{{FIELD_NAME}}() {";
+ code_ += " return {{FIELD_VALUE}};";
+ code_ += " }";
+ }
+ }
+
// Generate an accessor struct, builder structs & function for a table.
void GenTable(const StructDef &struct_def) {
- if (parser_.opts.generate_object_based_api) { GenNativeTable(struct_def); }
+ if (opts_.generate_object_based_api) { GenNativeTable(struct_def); }
// Generate an accessor struct, with methods of the form:
// type name() const { return GetField<type>(offset, defaultval); }
@@ -1800,10 +2095,12 @@
code_ +=
"struct {{STRUCT_NAME}} FLATBUFFERS_FINAL_CLASS"
" : private flatbuffers::Table {";
- if (parser_.opts.generate_object_based_api) {
+ if (opts_.generate_object_based_api) {
code_ += " typedef {{NATIVE_NAME}} NativeTableType;";
}
- if (parser_.opts.mini_reflect != IDLOptions::kNone) {
+ code_ += " typedef {{STRUCT_NAME}}Builder Builder;";
+ if (opts_.g_cpp_std >= cpp::CPP_STD_17) { code_ += " struct Traits;"; }
+ if (opts_.mini_reflect != IDLOptions::kNone) {
code_ +=
" static const flatbuffers::TypeTable *MiniReflectTypeTable() {";
code_ += " return {{STRUCT_NAME}}TypeTable();";
@@ -1845,103 +2142,9 @@
continue;
}
- const bool is_struct = IsStruct(field.value.type);
- const bool is_scalar = IsScalar(field.value.type.base_type);
code_.SetValue("FIELD_NAME", Name(field));
-
- // Call a different accessor for pointers, that indirects.
- std::string accessor = "";
- if (is_scalar) {
- accessor = "GetField<";
- } else if (is_struct) {
- accessor = "GetStruct<";
- } else {
- accessor = "GetPointer<";
- }
- auto offset_str = GenFieldOffsetName(field);
- auto offset_type =
- GenTypeGet(field.value.type, "", "const ", " *", false);
-
- auto call = accessor + offset_type + ">(" + offset_str;
- // Default value as second arg for non-pointer types.
- if (is_scalar) { call += ", " + GenDefaultConstant(field); }
- call += ")";
-
- std::string afterptr = " *" + NullableExtension();
- GenComment(field.doc_comment, " ");
- code_.SetValue("FIELD_TYPE", GenTypeGet(field.value.type, " ", "const ",
- afterptr.c_str(), true));
- code_.SetValue("FIELD_VALUE", GenUnderlyingCast(field, true, call));
- code_.SetValue("NULLABLE_EXT", NullableExtension());
-
- code_ += " {{FIELD_TYPE}}{{FIELD_NAME}}() const {";
- code_ += " return {{FIELD_VALUE}};";
- code_ += " }";
-
- if (field.value.type.base_type == BASE_TYPE_UNION) {
- auto u = field.value.type.enum_def;
-
- if (!field.value.type.enum_def->uses_multiple_type_instances)
- code_ +=
- " template<typename T> "
- "const T *{{NULLABLE_EXT}}{{FIELD_NAME}}_as() const;";
-
- for (auto u_it = u->Vals().begin(); u_it != u->Vals().end(); ++u_it) {
- auto &ev = **u_it;
- if (ev.union_type.base_type == BASE_TYPE_NONE) { continue; }
- auto full_struct_name = GetUnionElement(ev, true, true);
-
- // @TODO: Mby make this decisions more universal? How?
- code_.SetValue("U_GET_TYPE",
- EscapeKeyword(field.name + UnionTypeFieldSuffix()));
- code_.SetValue(
- "U_ELEMENT_TYPE",
- WrapInNameSpace(u->defined_namespace, GetEnumValUse(*u, ev)));
- code_.SetValue("U_FIELD_TYPE", "const " + full_struct_name + " *");
- code_.SetValue("U_FIELD_NAME", Name(field) + "_as_" + Name(ev));
- code_.SetValue("U_NULLABLE", NullableExtension());
-
- // `const Type *union_name_asType() const` accessor.
- code_ += " {{U_FIELD_TYPE}}{{U_NULLABLE}}{{U_FIELD_NAME}}() const {";
- code_ +=
- " return {{U_GET_TYPE}}() == {{U_ELEMENT_TYPE}} ? "
- "static_cast<{{U_FIELD_TYPE}}>({{FIELD_NAME}}()) "
- ": nullptr;";
- code_ += " }";
- }
- }
-
- if (parser_.opts.mutable_buffer) {
- if (is_scalar) {
- const auto type = GenTypeWire(field.value.type, "", false);
- code_.SetValue("SET_FN", "SetField<" + type + ">");
- code_.SetValue("OFFSET_NAME", offset_str);
- code_.SetValue("FIELD_TYPE", GenTypeBasic(field.value.type, true));
- code_.SetValue("FIELD_VALUE",
- GenUnderlyingCast(field, false, "_" + Name(field)));
- code_.SetValue("DEFAULT_VALUE", GenDefaultConstant(field));
-
- code_ +=
- " bool mutate_{{FIELD_NAME}}({{FIELD_TYPE}} "
- "_{{FIELD_NAME}}) {";
- code_ +=
- " return {{SET_FN}}({{OFFSET_NAME}}, {{FIELD_VALUE}}, "
- "{{DEFAULT_VALUE}});";
- code_ += " }";
- } else {
- auto postptr = " *" + NullableExtension();
- auto type =
- GenTypeGet(field.value.type, " ", "", postptr.c_str(), true);
- auto underlying = accessor + type + ">(" + offset_str + ")";
- code_.SetValue("FIELD_TYPE", type);
- code_.SetValue("FIELD_VALUE",
- GenUnderlyingCast(field, true, underlying));
-
- code_ += " {{FIELD_TYPE}}mutable_{{FIELD_NAME}}() {";
- code_ += " return {{FIELD_VALUE}};";
- code_ += " }";
- }
- }
+ GenTableFieldGetter(field);
+ if (opts_.mutable_buffer) { GenTableFieldSetter(field); }
auto nested = field.attributes.Lookup("nested_flatbuffer");
if (nested) {
@@ -1993,13 +2196,11 @@
code_ += " &&\n verifier.EndTable();";
code_ += " }";
- if (parser_.opts.generate_object_based_api) {
+ if (opts_.generate_object_based_api) {
// Generate the UnPack() pre declaration.
- code_ +=
- " " + TableUnPackSignature(struct_def, true, parser_.opts) + ";";
- code_ +=
- " " + TableUnPackToSignature(struct_def, true, parser_.opts) + ";";
- code_ += " " + TablePackSignature(struct_def, true, parser_.opts) + ";";
+ code_ += " " + TableUnPackSignature(struct_def, true, opts_) + ";";
+ code_ += " " + TableUnPackToSignature(struct_def, true, opts_) + ";";
+ code_ += " " + TablePackSignature(struct_def, true, opts_) + ";";
}
code_ += "};"; // End of table.
@@ -2044,19 +2245,39 @@
GenBuilders(struct_def);
- if (parser_.opts.generate_object_based_api) {
+ if (opts_.generate_object_based_api) {
// Generate a pre-declaration for a CreateX method that works with an
// unpacked C++ object.
- code_ += TableCreateSignature(struct_def, true, parser_.opts) + ";";
+ code_ += TableCreateSignature(struct_def, true, opts_) + ";";
code_ += "";
}
}
+ // Generate code to force vector alignment. Return empty string for vector
+ // that doesn't need alignment code.
+ std::string GenVectorForceAlign(const FieldDef &field,
+ const std::string &field_size) {
+ FLATBUFFERS_ASSERT(IsVector(field.value.type));
+ // Get the value of the force_align attribute.
+ const auto *force_align = field.attributes.Lookup("force_align");
+ const int align = force_align ? atoi(force_align->constant.c_str()) : 1;
+ // Generate code to do force_align for the vector.
+ if (align > 1) {
+ const auto vtype = field.value.type.VectorType();
+ const auto type = IsStruct(vtype) ? WrapInNameSpace(*vtype.struct_def)
+ : GenTypeWire(vtype, "", false);
+ return "_fbb.ForceVectorAlignment(" + field_size + ", sizeof(" + type +
+ "), " + std::to_string(static_cast<long long>(align)) + ");";
+ }
+ return "";
+ }
+
void GenBuilders(const StructDef &struct_def) {
code_.SetValue("STRUCT_NAME", Name(struct_def));
// Generate a builder struct:
code_ += "struct {{STRUCT_NAME}}Builder {";
+ code_ += " typedef {{STRUCT_NAME}} Table;";
code_ += " flatbuffers::FlatBufferBuilder &fbb_;";
code_ += " flatbuffers::uoffset_t start_;";
@@ -2064,43 +2285,43 @@
for (auto it = struct_def.fields.vec.begin();
it != struct_def.fields.vec.end(); ++it) {
const auto &field = **it;
- if (!field.deprecated) {
- const bool is_scalar = IsScalar(field.value.type.base_type);
- const bool is_string = field.value.type.base_type == BASE_TYPE_STRING;
- const bool is_vector = field.value.type.base_type == BASE_TYPE_VECTOR;
- if (is_string || is_vector) { has_string_or_vector_fields = true; }
+ if (field.deprecated) continue;
+ const bool is_scalar = IsScalar(field.value.type.base_type);
+ const bool is_default_scalar = is_scalar && !field.IsScalarOptional();
+ const bool is_string = IsString(field.value.type);
+ const bool is_vector = IsVector(field.value.type);
+ if (is_string || is_vector) { has_string_or_vector_fields = true; }
- std::string offset = GenFieldOffsetName(field);
- std::string name = GenUnderlyingCast(field, false, Name(field));
- std::string value = is_scalar ? GenDefaultConstant(field) : "";
+ std::string offset = GenFieldOffsetName(field);
+ std::string name = GenUnderlyingCast(field, false, Name(field));
+ std::string value = is_default_scalar ? GenDefaultConstant(field) : "";
- // Generate accessor functions of the form:
- // void add_name(type name) {
- // fbb_.AddElement<type>(offset, name, default);
- // }
- code_.SetValue("FIELD_NAME", Name(field));
- code_.SetValue("FIELD_TYPE", GenTypeWire(field.value.type, " ", true));
- code_.SetValue("ADD_OFFSET", Name(struct_def) + "::" + offset);
- code_.SetValue("ADD_NAME", name);
- code_.SetValue("ADD_VALUE", value);
- if (is_scalar) {
- const auto type = GenTypeWire(field.value.type, "", false);
- code_.SetValue("ADD_FN", "AddElement<" + type + ">");
- } else if (IsStruct(field.value.type)) {
- code_.SetValue("ADD_FN", "AddStruct");
- } else {
- code_.SetValue("ADD_FN", "AddOffset");
- }
-
- code_ += " void add_{{FIELD_NAME}}({{FIELD_TYPE}}{{FIELD_NAME}}) {";
- code_ += " fbb_.{{ADD_FN}}(\\";
- if (is_scalar) {
- code_ += "{{ADD_OFFSET}}, {{ADD_NAME}}, {{ADD_VALUE}});";
- } else {
- code_ += "{{ADD_OFFSET}}, {{ADD_NAME}});";
- }
- code_ += " }";
+ // Generate accessor functions of the form:
+ // void add_name(type name) {
+ // fbb_.AddElement<type>(offset, name, default);
+ // }
+ code_.SetValue("FIELD_NAME", Name(field));
+ code_.SetValue("FIELD_TYPE", GenTypeWire(field.value.type, " ", true));
+ code_.SetValue("ADD_OFFSET", Name(struct_def) + "::" + offset);
+ code_.SetValue("ADD_NAME", name);
+ code_.SetValue("ADD_VALUE", value);
+ if (is_scalar) {
+ const auto type = GenTypeWire(field.value.type, "", false);
+ code_.SetValue("ADD_FN", "AddElement<" + type + ">");
+ } else if (IsStruct(field.value.type)) {
+ code_.SetValue("ADD_FN", "AddStruct");
+ } else {
+ code_.SetValue("ADD_FN", "AddOffset");
}
+
+ code_ += " void add_{{FIELD_NAME}}({{FIELD_TYPE}}{{FIELD_NAME}}) {";
+ code_ += " fbb_.{{ADD_FN}}(\\";
+ if (is_default_scalar) {
+ code_ += "{{ADD_OFFSET}}, {{ADD_NAME}}, {{ADD_VALUE}});";
+ } else {
+ code_ += "{{ADD_OFFSET}}, {{ADD_NAME}});";
+ }
+ code_ += " }";
}
// Builder constructor
@@ -2111,11 +2332,6 @@
code_ += " start_ = fbb_.StartTable();";
code_ += " }";
- // Assignment operator;
- code_ +=
- " {{STRUCT_NAME}}Builder &operator="
- "(const {{STRUCT_NAME}}Builder &);";
-
// Finish() function.
code_ += " flatbuffers::Offset<{{STRUCT_NAME}}> Finish() {";
code_ += " const auto end = fbb_.EndTable(start_);";
@@ -2157,7 +2373,13 @@
if (!field.deprecated && (!struct_def.sortbysize ||
size == SizeOf(field.value.type.base_type))) {
code_.SetValue("FIELD_NAME", Name(field));
- code_ += " builder_.add_{{FIELD_NAME}}({{FIELD_NAME}});";
+ if (field.IsScalarOptional()) {
+ code_ +=
+ " if({{FIELD_NAME}}) { "
+ "builder_.add_{{FIELD_NAME}}(*{{FIELD_NAME}}); }";
+ } else {
+ code_ += " builder_.add_{{FIELD_NAME}}({{FIELD_NAME}});";
+ }
}
}
}
@@ -2165,8 +2387,18 @@
code_ += "}";
code_ += "";
+ // Definition for type traits for this table type. This allows querying var-
+ // ious compile-time traits of the table.
+ if (opts_.g_cpp_std >= cpp::CPP_STD_17) {
+ code_ += "struct {{STRUCT_NAME}}::Traits {";
+ code_ += " using type = {{STRUCT_NAME}};";
+ code_ += " static auto constexpr Create = Create{{STRUCT_NAME}};";
+ code_ += "};";
+ code_ += "";
+ }
+
// Generate a CreateXDirect function with vector types as parameters
- if (has_string_or_vector_fields) {
+ if (opts_.cpp_direct_copy && has_string_or_vector_fields) {
code_ +=
"inline flatbuffers::Offset<{{STRUCT_NAME}}> "
"Create{{STRUCT_NAME}}Direct(";
@@ -2186,7 +2418,7 @@
const auto &field = **it;
if (!field.deprecated) {
code_.SetValue("FIELD_NAME", Name(field));
- if (field.value.type.base_type == BASE_TYPE_STRING) {
+ if (IsString(field.value.type)) {
if (!field.shared) {
code_.SetValue("CREATE_STRING", "CreateString");
} else {
@@ -2195,17 +2427,30 @@
code_ +=
" auto {{FIELD_NAME}}__ = {{FIELD_NAME}} ? "
"_fbb.{{CREATE_STRING}}({{FIELD_NAME}}) : 0;";
- } else if (field.value.type.base_type == BASE_TYPE_VECTOR) {
+ } else if (IsVector(field.value.type)) {
+ const std::string force_align_code =
+ GenVectorForceAlign(field, Name(field) + "->size()");
+ if (!force_align_code.empty()) {
+ code_ += " if ({{FIELD_NAME}}) { " + force_align_code + " }";
+ }
code_ += " auto {{FIELD_NAME}}__ = {{FIELD_NAME}} ? \\";
const auto vtype = field.value.type.VectorType();
+ const auto has_key = TypeHasKey(vtype);
if (IsStruct(vtype)) {
const auto type = WrapInNameSpace(*vtype.struct_def);
- code_ += "_fbb.CreateVectorOfStructs<" + type + ">\\";
+ code_ += (has_key ? "_fbb.CreateVectorOfSortedStructs<"
+ : "_fbb.CreateVectorOfStructs<") +
+ type + ">\\";
+ } else if (has_key) {
+ const auto type = WrapInNameSpace(*vtype.struct_def);
+ code_ += "_fbb.CreateVectorOfSortedTables<" + type + ">\\";
} else {
- const auto type = GenTypeWire(vtype, "", false);
+ const auto type =
+ GenTypeWire(vtype, "", VectorElementUserFacing(vtype));
code_ += "_fbb.CreateVector<" + type + ">\\";
}
- code_ += "(*{{FIELD_NAME}}) : 0;";
+ code_ +=
+ has_key ? "({{FIELD_NAME}}) : 0;" : "(*{{FIELD_NAME}}) : 0;";
}
}
}
@@ -2217,8 +2462,8 @@
if (!field.deprecated) {
code_.SetValue("FIELD_NAME", Name(field));
code_ += ",\n {{FIELD_NAME}}\\";
- if (field.value.type.base_type == BASE_TYPE_STRING ||
- field.value.type.base_type == BASE_TYPE_VECTOR) {
+ if (IsString(field.value.type) ||
+ IsVector(field.value.type)) {
code_ += "__\\";
}
}
@@ -2232,8 +2477,8 @@
std::string GenUnionUnpackVal(const FieldDef &afield,
const char *vec_elem_access,
const char *vec_type_access) {
- return afield.value.type.enum_def->name + "Union::UnPack(" + "_e" +
- vec_elem_access + ", " +
+ auto type_name = WrapInNameSpace(*afield.value.type.enum_def);
+ return type_name + "Union::UnPack(" + "_e" + vec_elem_access + ", " +
EscapeKeyword(afield.name + UnionTypeFieldSuffix()) + "()" +
vec_type_access + ", _resolver)";
}
@@ -2263,7 +2508,7 @@
}
} else {
const auto ptype = GenTypeNativePtr(
- NativeName(name, type.struct_def, parser_.opts), &afield, true);
+ NativeName(name, type.struct_def, opts_), &afield, true);
return ptype + "(" + val + "->UnPack(_resolver))";
}
}
@@ -2285,58 +2530,75 @@
std::string code;
switch (field.value.type.base_type) {
case BASE_TYPE_VECTOR: {
- auto cpp_type = field.attributes.Lookup("cpp_type");
- std::string indexing;
- if (field.value.type.enum_def) {
- indexing += "static_cast<" +
- WrapInNameSpace(*field.value.type.enum_def) + ">(";
- }
- indexing += "_e->Get(_i)";
- if (field.value.type.enum_def) { indexing += ")"; }
- if (field.value.type.element == BASE_TYPE_BOOL) { indexing += " != 0"; }
-
- // Generate code that pushes data from _e to _o in the form:
- // for (uoffset_t i = 0; i < _e->size(); ++i) {
- // _o->field.push_back(_e->Get(_i));
- // }
auto name = Name(field);
if (field.value.type.element == BASE_TYPE_UTYPE) {
name = StripUnionType(Name(field));
}
- auto access =
- field.value.type.element == BASE_TYPE_UTYPE
- ? ".type"
- : (field.value.type.element == BASE_TYPE_UNION ? ".value" : "");
code += "{ _o->" + name + ".resize(_e->size()); ";
- code += "for (flatbuffers::uoffset_t _i = 0;";
- code += " _i < _e->size(); _i++) { ";
- if (cpp_type) {
- // Generate code that resolves the cpp pointer type, of the form:
- // if (resolver)
- // (*resolver)(&_o->field, (hash_value_t)(_e));
- // else
- // _o->field = nullptr;
- code += "//vector resolver, " + PtrType(&field) + "\n";
- code += "if (_resolver) ";
- code += "(*_resolver)";
- code += "(reinterpret_cast<void **>(&_o->" + name + "[_i]" + access +
- "), ";
- code += "static_cast<flatbuffers::hash_value_t>(" + indexing + "));";
- if (PtrType(&field) == "naked") {
- code += " else ";
- code += "_o->" + name + "[_i]" + access + " = nullptr";
- } else {
- // code += " else ";
- // code += "_o->" + name + "[_i]" + access + " = " +
- // GenTypeNativePtr(cpp_type->constant, &field, true) + "();";
- code += "/* else do nothing */";
- }
+ if (!field.value.type.enum_def && !IsBool(field.value.type.element) &&
+ IsOneByte(field.value.type.element)) {
+ // For vectors of bytes, std::copy is used to improve performance.
+ // This doesn't work for:
+ // - enum types because they have to be explicitly static_cast.
+ // - vectors of bool, since they are a template specialization.
+ // - multiple-byte types due to endianness.
+ code +=
+ "std::copy(_e->begin(), _e->end(), _o->" + name + ".begin()); }";
} else {
- code += "_o->" + name + "[_i]" + access + " = ";
- code += GenUnpackVal(field.value.type.VectorType(), indexing, true,
- field);
+ std::string indexing;
+ if (field.value.type.enum_def) {
+ indexing += "static_cast<" +
+ WrapInNameSpace(*field.value.type.enum_def) + ">(";
+ }
+ indexing += "_e->Get(_i)";
+ if (field.value.type.enum_def) {
+ indexing += ")";
+ }
+ if (field.value.type.element == BASE_TYPE_BOOL) {
+ indexing += " != 0";
+ }
+ // Generate code that pushes data from _e to _o in the form:
+ // for (uoffset_t i = 0; i < _e->size(); ++i) {
+ // _o->field.push_back(_e->Get(_i));
+ // }
+ auto access =
+ field.value.type.element == BASE_TYPE_UTYPE
+ ? ".type"
+ : (field.value.type.element == BASE_TYPE_UNION ? ".value"
+ : "");
+
+ code += "for (flatbuffers::uoffset_t _i = 0;";
+ code += " _i < _e->size(); _i++) { ";
+ auto cpp_type = field.attributes.Lookup("cpp_type");
+ if (cpp_type) {
+ // Generate code that resolves the cpp pointer type, of the form:
+ // if (resolver)
+ // (*resolver)(&_o->field, (hash_value_t)(_e));
+ // else
+ // _o->field = nullptr;
+ code += "//vector resolver, " + PtrType(&field) + "\n";
+ code += "if (_resolver) ";
+ code += "(*_resolver)";
+ code += "(reinterpret_cast<void **>(&_o->" + name + "[_i]" +
+ access + "), ";
+ code +=
+ "static_cast<flatbuffers::hash_value_t>(" + indexing + "));";
+ if (PtrType(&field) == "naked") {
+ code += " else ";
+ code += "_o->" + name + "[_i]" + access + " = nullptr";
+ } else {
+ // code += " else ";
+ // code += "_o->" + name + "[_i]" + access + " = " +
+ // GenTypeNativePtr(cpp_type->constant, &field, true) + "();";
+ code += "/* else do nothing */";
+ }
+ } else {
+ code += "_o->" + name + "[_i]" + access + " = ";
+ code += GenUnpackVal(field.value.type.VectorType(), indexing, true,
+ field);
+ }
+ code += "; } }";
}
- code += "; } }";
break;
}
case BASE_TYPE_UTYPE: {
@@ -2390,8 +2652,6 @@
}
std::string GenCreateParam(const FieldDef &field) {
- const IDLOptions &opts = parser_.opts;
-
std::string value = "_o->";
if (field.value.type.base_type == BASE_TYPE_UTYPE) {
value += StripUnionType(Name(field));
@@ -2425,22 +2685,24 @@
// For optional fields, check to see if there actually is any data
// in _o->field before attempting to access it. If there isn't,
- // depending on set_empty_to_null either set it to 0 or an empty string.
+ // depending on set_empty_strings_to_null either set it to 0 or an empty
+ // string.
if (!field.required) {
- auto empty_value =
- opts.set_empty_to_null ? "0" : "_fbb.CreateSharedString(\"\")";
+ auto empty_value = opts_.set_empty_strings_to_null
+ ? "0"
+ : "_fbb.CreateSharedString(\"\")";
code = value + ".empty() ? " + empty_value + " : " + code;
}
break;
}
- // Vector fields come in several flavours, of the forms:
- // _fbb.CreateVector(_o->field);
- // _fbb.CreateVector((const utype*)_o->field.data(), _o->field.size());
- // _fbb.CreateVectorOfStrings(_o->field)
- // _fbb.CreateVectorOfStructs(_o->field)
- // _fbb.CreateVector<Offset<T>>(_o->field.size() [&](size_t i) {
- // return CreateT(_fbb, _o->Get(i), rehasher);
- // });
+ // Vector fields come in several flavours, of the forms:
+ // _fbb.CreateVector(_o->field);
+ // _fbb.CreateVector((const utype*)_o->field.data(),
+ // _o->field.size()); _fbb.CreateVectorOfStrings(_o->field)
+ // _fbb.CreateVectorOfStructs(_o->field)
+ // _fbb.CreateVector<Offset<T>>(_o->field.size() [&](size_t i) {
+ // return CreateT(_fbb, _o->Get(i), rehasher);
+ // });
case BASE_TYPE_VECTOR: {
auto vector_type = field.value.type.VectorType();
switch (vector_type.base_type) {
@@ -2507,7 +2769,8 @@
break;
}
default: {
- if (field.value.type.enum_def) {
+ if (field.value.type.enum_def &&
+ !VectorElementUserFacing(vector_type)) {
// For enumerations, we need to get access to the array data for
// the underlying storage type (eg. uint8_t).
const auto basetype = GenTypeBasic(
@@ -2530,10 +2793,10 @@
}
}
- // If set_empty_to_null option is enabled, for optional fields, check to
- // see if there actually is any data in _o->field before attempting to
- // access it.
- if (opts.set_empty_to_null && !field.required) {
+ // If set_empty_vectors_to_null option is enabled, for optional fields,
+ // check to see if there actually is any data in _o->field before
+ // attempting to access it.
+ if (opts_.set_empty_vectors_to_null && !field.required) {
code = value + ".size() ? " + code + " : 0";
}
break;
@@ -2575,20 +2838,33 @@
void GenTablePost(const StructDef &struct_def) {
code_.SetValue("STRUCT_NAME", Name(struct_def));
code_.SetValue("NATIVE_NAME",
- NativeName(Name(struct_def), &struct_def, parser_.opts));
+ NativeName(Name(struct_def), &struct_def, opts_));
- if (parser_.opts.generate_object_based_api) {
+ if (opts_.generate_object_based_api) {
// Generate the X::UnPack() method.
- code_ += "inline " +
- TableUnPackSignature(struct_def, false, parser_.opts) + " {";
- code_ += " auto _o = new {{NATIVE_NAME}}();";
- code_ += " UnPackTo(_o, _resolver);";
- code_ += " return _o;";
+ code_ +=
+ "inline " + TableUnPackSignature(struct_def, false, opts_) + " {";
+
+ if (opts_.g_cpp_std == cpp::CPP_STD_X0) {
+ auto native_name =
+ NativeName(WrapInNameSpace(struct_def), &struct_def, parser_.opts);
+ code_.SetValue("POINTER_TYPE",
+ GenTypeNativePtr(native_name, nullptr, false));
+ code_ +=
+ " {{POINTER_TYPE}} _o = {{POINTER_TYPE}}(new {{NATIVE_NAME}}());";
+ } else if (opts_.g_cpp_std == cpp::CPP_STD_11) {
+ code_ +=
+ " auto _o = std::unique_ptr<{{NATIVE_NAME}}>(new "
+ "{{NATIVE_NAME}}());";
+ } else {
+ code_ += " auto _o = std::make_unique<{{NATIVE_NAME}}>();";
+ }
+ code_ += " UnPackTo(_o.get(), _resolver);";
+ code_ += " return _o.release();";
code_ += "}";
code_ += "";
-
- code_ += "inline " +
- TableUnPackToSignature(struct_def, false, parser_.opts) + " {";
+ code_ +=
+ "inline " + TableUnPackToSignature(struct_def, false, opts_) + " {";
code_ += " (void)_o;";
code_ += " (void)_resolver;";
@@ -2607,7 +2883,7 @@
code_.SetValue("FIELD_NAME", Name(field));
auto prefix = " { auto _e = {{FIELD_NAME}}(); ";
auto check = IsScalar(field.value.type.base_type) ? "" : "if (_e) ";
- auto postfix = " };";
+ auto postfix = " }";
code_ += std::string(prefix) + check + statement + postfix;
}
code_ += "}";
@@ -2615,15 +2891,14 @@
// Generate the X::Pack member function that simply calls the global
// CreateX function.
- code_ += "inline " + TablePackSignature(struct_def, false, parser_.opts) +
- " {";
+ code_ += "inline " + TablePackSignature(struct_def, false, opts_) + " {";
code_ += " return Create{{STRUCT_NAME}}(_fbb, _o, _rehasher);";
code_ += "}";
code_ += "";
// Generate a CreateX method that works with an unpacked C++ object.
- code_ += "inline " +
- TableCreateSignature(struct_def, false, parser_.opts) + " {";
+ code_ +=
+ "inline " + TableCreateSignature(struct_def, false, opts_) + " {";
code_ += " (void)_rehasher;";
code_ += " (void)_o;";
@@ -2631,7 +2906,7 @@
" struct _VectorArgs "
"{ flatbuffers::FlatBufferBuilder *__fbb; "
"const " +
- NativeName(Name(struct_def), &struct_def, parser_.opts) +
+ NativeName(Name(struct_def), &struct_def, opts_) +
"* __o; "
"const flatbuffers::rehasher_function_t *__rehasher; } _va = { "
"&_fbb, _o, _rehasher}; (void)_va;";
@@ -2640,6 +2915,11 @@
it != struct_def.fields.vec.end(); ++it) {
auto &field = **it;
if (field.deprecated) { continue; }
+ if (IsVector(field.value.type)) {
+ const std::string force_align_code =
+ GenVectorForceAlign(field, "_o->" + Name(field) + ".size()");
+ if (!force_align_code.empty()) { code_ += " " + force_align_code; }
+ }
code_ += " auto _" + Name(field) + " = " + GenCreateParam(field) + ";";
}
// Need to call "Create" with the struct namespace.
@@ -2696,15 +2976,162 @@
static void PaddingInitializer(int bits, std::string *code_ptr, int *id) {
(void)bits;
- if (*code_ptr != "") *code_ptr += ",\n ";
+ if (!code_ptr->empty()) *code_ptr += ",\n ";
*code_ptr += "padding" + NumToString((*id)++) + "__(0)";
}
static void PaddingNoop(int bits, std::string *code_ptr, int *id) {
(void)bits;
+ if (!code_ptr->empty()) *code_ptr += '\n';
*code_ptr += " (void)padding" + NumToString((*id)++) + "__;";
}
+ void GenStructDefaultConstructor(const StructDef &struct_def) {
+ std::string init_list;
+ std::string body;
+ bool first_in_init_list = true;
+ int padding_initializer_id = 0;
+ int padding_body_id = 0;
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ const auto field = *it;
+ const auto field_name = field->name + "_";
+
+ if (first_in_init_list) {
+ first_in_init_list = false;
+ } else {
+ init_list += ",";
+ init_list += "\n ";
+ }
+
+ init_list += field_name;
+ if (IsStruct(field->value.type) || IsArray(field->value.type)) {
+ // this is either default initialization of struct
+ // or
+ // implicit initialization of array
+ // for each object in array it:
+ // * sets it as zeros for POD types (integral, floating point, etc)
+ // * calls default constructor for classes/structs
+ init_list += "()";
+ } else {
+ init_list += "(0)";
+ }
+ if (field->padding) {
+ GenPadding(*field, &init_list, &padding_initializer_id,
+ PaddingInitializer);
+ GenPadding(*field, &body, &padding_body_id, PaddingNoop);
+ }
+ }
+
+ if (init_list.empty()) {
+ code_ += " {{STRUCT_NAME}}()";
+ code_ += " {}";
+ } else {
+ code_.SetValue("INIT_LIST", init_list);
+ code_ += " {{STRUCT_NAME}}()";
+ code_ += " : {{INIT_LIST}} {";
+ if (!body.empty()) { code_ += body; }
+ code_ += " }";
+ }
+ }
+
+ void GenStructConstructor(const StructDef &struct_def,
+ GenArrayArgMode array_mode) {
+ std::string arg_list;
+ std::string init_list;
+ int padding_id = 0;
+ auto first = struct_def.fields.vec.begin();
+ // skip arrays if generate ctor without array assignment
+ const auto init_arrays = (array_mode != kArrayArgModeNone);
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ const auto &field = **it;
+ const auto &type = field.value.type;
+ const auto is_array = IsArray(type);
+ const auto arg_name = "_" + Name(field);
+ if (!is_array || init_arrays) {
+ if (it != first && !arg_list.empty()) { arg_list += ", "; }
+ arg_list += !is_array ? GenTypeGet(type, " ", "const ", " &", true)
+ : GenTypeSpan(type, true, type.fixed_length);
+ arg_list += arg_name;
+ }
+ // skip an array with initialization from span
+ if (false == (is_array && init_arrays)) {
+ if (it != first && !init_list.empty()) { init_list += ",\n "; }
+ init_list += Name(field) + "_";
+ if (IsScalar(type.base_type)) {
+ auto scalar_type = GenUnderlyingCast(field, false, arg_name);
+ init_list += "(flatbuffers::EndianScalar(" + scalar_type + "))";
+ } else {
+ FLATBUFFERS_ASSERT((is_array && !init_arrays) || IsStruct(type));
+ if (!is_array)
+ init_list += "(" + arg_name + ")";
+ else
+ init_list += "()";
+ }
+ }
+ if (field.padding)
+ GenPadding(field, &init_list, &padding_id, PaddingInitializer);
+ }
+
+ if (!arg_list.empty()) {
+ code_.SetValue("ARG_LIST", arg_list);
+ code_.SetValue("INIT_LIST", init_list);
+ if (!init_list.empty()) {
+ code_ += " {{STRUCT_NAME}}({{ARG_LIST}})";
+ code_ += " : {{INIT_LIST}} {";
+ } else {
+ code_ += " {{STRUCT_NAME}}({{ARG_LIST}}) {";
+ }
+ padding_id = 0;
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ const auto &field = **it;
+ const auto &type = field.value.type;
+ if (IsArray(type) && init_arrays) {
+ const auto &element_type = type.VectorType();
+ const auto is_enum = IsEnum(element_type);
+ FLATBUFFERS_ASSERT(
+ (IsScalar(element_type.base_type) || IsStruct(element_type)) &&
+ "invalid declaration");
+ const auto face_type = GenTypeGet(type, " ", "", "", is_enum);
+ std::string get_array =
+ is_enum ? "CastToArrayOfEnum<" + face_type + ">" : "CastToArray";
+ const auto field_name = Name(field) + "_";
+ const auto arg_name = "_" + Name(field);
+ code_ += " flatbuffers::" + get_array + "(" + field_name +
+ ").CopyFromSpan(" + arg_name + ");";
+ }
+ if (field.padding) {
+ std::string padding;
+ GenPadding(field, &padding, &padding_id, PaddingNoop);
+ code_ += padding;
+ }
+ }
+ code_ += " }";
+ }
+ }
+
+ void GenArrayAccessor(const Type &type, bool mutable_accessor) {
+ FLATBUFFERS_ASSERT(IsArray(type));
+ const auto is_enum = IsEnum(type.VectorType());
+ // The Array<bool,N> is a tricky case, like std::vector<bool>.
+ // It requires a specialization of Array class.
+ // Generate Array<uint8_t> for Array<bool>.
+ const auto face_type = GenTypeGet(type, " ", "", "", is_enum);
+ std::string ret_type = "flatbuffers::Array<" + face_type + ", " +
+ NumToString(type.fixed_length) + ">";
+ if (mutable_accessor)
+ code_ += " " + ret_type + " *mutable_{{FIELD_NAME}}() {";
+ else
+ code_ += " const " + ret_type + " *{{FIELD_NAME}}() const {";
+
+ std::string get_array =
+ is_enum ? "CastToArrayOfEnum<" + face_type + ">" : "CastToArray";
+ code_ += " return &flatbuffers::" + get_array + "({{FIELD_VALUE}});";
+ code_ += " }";
+ }
+
// Generate an accessor struct with constructor for a flatbuffers struct.
void GenStruct(const StructDef &struct_def) {
// Generate an accessor struct, with private variables of the form:
@@ -2746,7 +3173,7 @@
code_ += " public:";
// Make TypeTable accessible via the generated struct.
- if (parser_.opts.mini_reflect != IDLOptions::kNone) {
+ if (opts_.mini_reflect != IDLOptions::kNone) {
code_ +=
" static const flatbuffers::TypeTable *MiniReflectTypeTable() {";
code_ += " return {{STRUCT_NAME}}TypeTable();";
@@ -2756,72 +3183,19 @@
GenFullyQualifiedNameGetter(struct_def, Name(struct_def));
// Generate a default constructor.
- code_ += " {{STRUCT_NAME}}() {";
- code_ +=
- " memset(static_cast<void *>(this), 0, sizeof({{STRUCT_NAME}}));";
- code_ += " }";
+ GenStructDefaultConstructor(struct_def);
// Generate a constructor that takes all fields as arguments,
- // excluding arrays
- std::string arg_list;
- std::string init_list;
- padding_id = 0;
- auto first = struct_def.fields.vec.begin();
- for (auto it = struct_def.fields.vec.begin();
- it != struct_def.fields.vec.end(); ++it) {
- const auto &field = **it;
- if (IsArray(field.value.type)) {
- first++;
- continue;
- }
- const auto member_name = Name(field) + "_";
- const auto arg_name = "_" + Name(field);
- const auto arg_type =
- GenTypeGet(field.value.type, " ", "const ", " &", true);
+ // excluding arrays.
+ GenStructConstructor(struct_def, kArrayArgModeNone);
- if (it != first) { arg_list += ", "; }
- arg_list += arg_type;
- arg_list += arg_name;
- if (!IsArray(field.value.type)) {
- if (it != first && init_list != "") { init_list += ",\n "; }
- init_list += member_name;
- if (IsScalar(field.value.type.base_type)) {
- auto type = GenUnderlyingCast(field, false, arg_name);
- init_list += "(flatbuffers::EndianScalar(" + type + "))";
- } else {
- init_list += "(" + arg_name + ")";
- }
- }
- if (field.padding) {
- GenPadding(field, &init_list, &padding_id, PaddingInitializer);
- }
- }
-
- if (!arg_list.empty()) {
- code_.SetValue("ARG_LIST", arg_list);
- code_.SetValue("INIT_LIST", init_list);
- if (!init_list.empty()) {
- code_ += " {{STRUCT_NAME}}({{ARG_LIST}})";
- code_ += " : {{INIT_LIST}} {";
- } else {
- code_ += " {{STRUCT_NAME}}({{ARG_LIST}}) {";
- }
- padding_id = 0;
- for (auto it = struct_def.fields.vec.begin();
- it != struct_def.fields.vec.end(); ++it) {
- const auto &field = **it;
- if (IsArray(field.value.type)) {
- const auto &member = Name(field) + "_";
- code_ +=
- " std::memset(" + member + ", 0, sizeof(" + member + "));";
- }
- if (field.padding) {
- std::string padding;
- GenPadding(field, &padding, &padding_id, PaddingNoop);
- code_ += padding;
- }
- }
- code_ += " }";
+ auto arrays_num = std::count_if(struct_def.fields.vec.begin(),
+ struct_def.fields.vec.end(),
+ [](const flatbuffers::FieldDef *fd) {
+ return IsArray(fd->value.type);
+ });
+ if (arrays_num > 0) {
+ GenStructConstructor(struct_def, kArrayArgModeSpanStatic);
}
// Generate accessor methods of the form:
@@ -2829,11 +3203,12 @@
for (auto it = struct_def.fields.vec.begin();
it != struct_def.fields.vec.end(); ++it) {
const auto &field = **it;
+ const auto &type = field.value.type;
+ const auto is_scalar = IsScalar(type.base_type);
+ const auto is_array = IsArray(type);
- auto field_type = GenTypeGet(field.value.type, " ",
- IsArray(field.value.type) ? "" : "const ",
- IsArray(field.value.type) ? "" : " &", true);
- auto is_scalar = IsScalar(field.value.type.base_type);
+ const auto field_type = GenTypeGet(type, " ", is_array ? "" : "const ",
+ is_array ? "" : " &", true);
auto member = Name(field) + "_";
auto value =
is_scalar ? "flatbuffers::EndianScalar(" + member + ")" : member;
@@ -2845,16 +3220,8 @@
GenComment(field.doc_comment, " ");
// Generate a const accessor function.
- if (IsArray(field.value.type)) {
- auto underlying = GenTypeGet(field.value.type, "", "", "", false);
- code_ += " const flatbuffers::Array<" + field_type + ", " +
- NumToString(field.value.type.fixed_length) + "> *" +
- "{{FIELD_NAME}}() const {";
- code_ += " return reinterpret_cast<const flatbuffers::Array<" +
- field_type + ", " +
- NumToString(field.value.type.fixed_length) +
- "> *>({{FIELD_VALUE}});";
- code_ += " }";
+ if (is_array) {
+ GenArrayAccessor(type, false);
} else {
code_ += " {{FIELD_TYPE}}{{FIELD_NAME}}() const {";
code_ += " return {{FIELD_VALUE}};";
@@ -2862,13 +3229,12 @@
}
// Generate a mutable accessor function.
- if (parser_.opts.mutable_buffer) {
+ if (opts_.mutable_buffer) {
auto mut_field_type =
- GenTypeGet(field.value.type, " ", "",
- IsArray(field.value.type) ? "" : " &", true);
+ GenTypeGet(type, " ", "", is_array ? "" : " &", true);
code_.SetValue("FIELD_TYPE", mut_field_type);
if (is_scalar) {
- code_.SetValue("ARG", GenTypeBasic(field.value.type, true));
+ code_.SetValue("ARG", GenTypeBasic(type, true));
code_.SetValue("FIELD_VALUE",
GenUnderlyingCast(field, false, "_" + Name(field)));
@@ -2877,16 +3243,8 @@
" flatbuffers::WriteScalar(&{{FIELD_NAME}}_, "
"{{FIELD_VALUE}});";
code_ += " }";
- } else if (IsArray(field.value.type)) {
- auto underlying = GenTypeGet(field.value.type, "", "", "", false);
- code_ += " flatbuffers::Array<" + mut_field_type + ", " +
- NumToString(field.value.type.fixed_length) +
- "> *" + "mutable_{{FIELD_NAME}}() {";
- code_ += " return reinterpret_cast<flatbuffers::Array<" +
- mut_field_type + ", " +
- NumToString(field.value.type.fixed_length) +
- "> *>({{FIELD_VALUE}});";
- code_ += " }";
+ } else if (is_array) {
+ GenArrayAccessor(type, true);
} else {
code_ += " {{FIELD_TYPE}}mutable_{{FIELD_NAME}}() {";
code_ += " return {{FIELD_VALUE}};";
@@ -2903,7 +3261,7 @@
code_.SetValue("STRUCT_BYTE_SIZE", NumToString(struct_def.bytesize));
code_ += "FLATBUFFERS_STRUCT_END({{STRUCT_NAME}}, {{STRUCT_BYTE_SIZE}});";
- if (parser_.opts.gen_compare) GenCompareOperator(struct_def, "()");
+ if (opts_.gen_compare) GenCompareOperator(struct_def, "()");
code_ += "";
}
@@ -2945,15 +3303,39 @@
cur_name_space_ = ns;
}
-
- const TypedFloatConstantGenerator float_const_gen_;
};
} // namespace cpp
bool GenerateCPP(const Parser &parser, const std::string &path,
const std::string &file_name) {
- cpp::CppGenerator generator(parser, path, file_name);
+ cpp::IDLOptionsCpp opts(parser.opts);
+ // The '--cpp_std' argument could be extended (like ASAN):
+ // Example: "flatc --cpp_std c++17:option1:option2".
+ auto cpp_std = !opts.cpp_std.empty() ? opts.cpp_std : "C++0X";
+ std::transform(cpp_std.begin(), cpp_std.end(), cpp_std.begin(), CharToUpper);
+ if (cpp_std == "C++0X") {
+ opts.g_cpp_std = cpp::CPP_STD_X0;
+ opts.g_only_fixed_enums = false;
+ } else if (cpp_std == "C++11") {
+ // Use the standard C++11 code generator.
+ opts.g_cpp_std = cpp::CPP_STD_11;
+ opts.g_only_fixed_enums = true;
+ } else if (cpp_std == "C++17") {
+ opts.g_cpp_std = cpp::CPP_STD_17;
+ // With c++17 generate strong enums only.
+ opts.scoped_enums = true;
+ // By default, prefixed_enums==true, reset it.
+ opts.prefixed_enums = false;
+ } else {
+ LogCompilerError("Unknown value of the '--cpp-std' switch: " +
+ opts.cpp_std);
+ return false;
+ }
+ // The opts.scoped_enums has priority.
+ opts.g_only_fixed_enums |= opts.scoped_enums;
+
+ cpp::CppGenerator generator(parser, path, file_name, opts);
return generator.generate();
}
@@ -2961,8 +3343,10 @@
const std::string &file_name) {
const auto filebase =
flatbuffers::StripPath(flatbuffers::StripExtension(file_name));
+ cpp::CppGenerator geneartor(parser, path, file_name, parser.opts);
const auto included_files = parser.GetIncludedFilesRecursive(file_name);
- std::string make_rule = GeneratedFileName(path, filebase) + ": ";
+ std::string make_rule =
+ geneartor.GeneratedFileName(path, filebase, parser.opts) + ": ";
for (auto it = included_files.begin(); it != included_files.end(); ++it) {
make_rule += " " + *it;
}
diff --git a/src/idl_gen_csharp.cpp b/src/idl_gen_csharp.cpp
new file mode 100644
index 0000000..d2f14f0
--- /dev/null
+++ b/src/idl_gen_csharp.cpp
@@ -0,0 +1,2098 @@
+/*
+ * Copyright 2014 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// independent from idl_parser, since this code is not needed for most clients
+
+#include "flatbuffers/code_generators.h"
+#include "flatbuffers/flatbuffers.h"
+#include "flatbuffers/idl.h"
+#include "flatbuffers/util.h"
+
+#if defined(FLATBUFFERS_CPP98_STL)
+# include <cctype>
+#endif // defined(FLATBUFFERS_CPP98_STL)
+
+namespace flatbuffers {
+
+static TypedFloatConstantGenerator CSharpFloatGen("Double.", "Single.", "NaN",
+ "PositiveInfinity",
+ "NegativeInfinity");
+static CommentConfig comment_config = {
+ nullptr,
+ "///",
+ nullptr,
+};
+
+namespace csharp {
+class CSharpGenerator : public BaseGenerator {
+ struct FieldArrayLength {
+ std::string name;
+ int length;
+ };
+
+ public:
+ CSharpGenerator(const Parser &parser, const std::string &path,
+ const std::string &file_name)
+ : BaseGenerator(parser, path, file_name, "", ".", "cs"),
+ cur_name_space_(nullptr) {}
+
+ CSharpGenerator &operator=(const CSharpGenerator &);
+
+ bool generate() {
+ std::string one_file_code;
+ cur_name_space_ = parser_.current_namespace_;
+
+ for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
+ ++it) {
+ std::string enumcode;
+ auto &enum_def = **it;
+ if (!parser_.opts.one_file) cur_name_space_ = enum_def.defined_namespace;
+ GenEnum(enum_def, &enumcode, parser_.opts);
+ if (parser_.opts.one_file) {
+ one_file_code += enumcode;
+ } else {
+ if (!SaveType(enum_def.name, *enum_def.defined_namespace, enumcode,
+ false))
+ return false;
+ }
+ }
+
+ for (auto it = parser_.structs_.vec.begin();
+ it != parser_.structs_.vec.end(); ++it) {
+ std::string declcode;
+ auto &struct_def = **it;
+ if (!parser_.opts.one_file)
+ cur_name_space_ = struct_def.defined_namespace;
+ GenStruct(struct_def, &declcode, parser_.opts);
+ if (parser_.opts.one_file) {
+ one_file_code += declcode;
+ } else {
+ if (!SaveType(struct_def.name, *struct_def.defined_namespace, declcode,
+ true))
+ return false;
+ }
+ }
+
+ if (parser_.opts.one_file) {
+ return SaveType(file_name_, *parser_.current_namespace_, one_file_code,
+ true);
+ }
+ return true;
+ }
+
+ // Save out the generated code for a single class while adding
+ // declaration boilerplate.
+ bool SaveType(const std::string &defname, const Namespace &ns,
+ const std::string &classcode, bool needs_includes) const {
+ if (!classcode.length()) return true;
+
+ std::string code =
+ "// <auto-generated>\n"
+ "// " +
+ std::string(FlatBuffersGeneratedWarning()) +
+ "\n"
+ "// </auto-generated>\n\n";
+
+ std::string namespace_name = FullNamespace(".", ns);
+ if (!namespace_name.empty()) {
+ code += "namespace " + namespace_name + "\n{\n\n";
+ }
+ if (needs_includes) {
+ code += "using global::System;\n";
+ code += "using global::System.Collections.Generic;\n";
+ code += "using global::FlatBuffers;\n\n";
+ }
+ code += classcode;
+ if (!namespace_name.empty()) { code += "\n}\n"; }
+ auto filename = NamespaceDir(ns) + defname + ".cs";
+ return SaveFile(filename.c_str(), code, false);
+ }
+
+ const Namespace *CurrentNameSpace() const { return cur_name_space_; }
+
+ std::string GenTypeBasic(const Type &type, bool enableLangOverrides) const {
+ // clang-format off
+ static const char * const csharp_typename[] = {
+ #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, ...) \
+ #NTYPE,
+ FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
+ #undef FLATBUFFERS_TD
+ };
+ // clang-format on
+
+ if (enableLangOverrides) {
+ if (IsEnum(type)) return WrapInNameSpace(*type.enum_def);
+ if (type.base_type == BASE_TYPE_STRUCT) {
+ return "Offset<" + WrapInNameSpace(*type.struct_def) + ">";
+ }
+ }
+
+ return csharp_typename[type.base_type];
+ }
+
+ inline std::string GenTypeBasic(const Type &type) const {
+ return GenTypeBasic(type, true);
+ }
+
+ std::string GenTypePointer(const Type &type) const {
+ switch (type.base_type) {
+ case BASE_TYPE_STRING: return "string";
+ case BASE_TYPE_VECTOR: return GenTypeGet(type.VectorType());
+ case BASE_TYPE_STRUCT: return WrapInNameSpace(*type.struct_def);
+ case BASE_TYPE_UNION: return "TTable";
+ default: return "Table";
+ }
+ }
+
+ std::string GenTypeGet(const Type &type) const {
+ return IsScalar(type.base_type)
+ ? GenTypeBasic(type)
+ : (IsArray(type) ? GenTypeGet(type.VectorType())
+ : GenTypePointer(type));
+ }
+
+ std::string GenOffsetType(const StructDef &struct_def) const {
+ return "Offset<" + WrapInNameSpace(struct_def) + ">";
+ }
+
+ std::string GenOffsetConstruct(const StructDef &struct_def,
+ const std::string &variable_name) const {
+ return "new Offset<" + WrapInNameSpace(struct_def) + ">(" + variable_name +
+ ")";
+ }
+
+ // Casts necessary to correctly read serialized data
+ std::string DestinationCast(const Type &type) const {
+ if (IsSeries(type)) {
+ return DestinationCast(type.VectorType());
+ } else {
+ if (IsEnum(type)) return "(" + WrapInNameSpace(*type.enum_def) + ")";
+ }
+ return "";
+ }
+
+ // Cast statements for mutator method parameters.
+ // In Java, parameters representing unsigned numbers need to be cast down to
+ // their respective type. For example, a long holding an unsigned int value
+ // would be cast down to int before being put onto the buffer. In C#, one cast
+ // directly cast an Enum to its underlying type, which is essential before
+ // putting it onto the buffer.
+ std::string SourceCast(const Type &type) const {
+ if (IsSeries(type)) {
+ return SourceCast(type.VectorType());
+ } else {
+ if (IsEnum(type)) return "(" + GenTypeBasic(type, false) + ")";
+ }
+ return "";
+ }
+
+ std::string SourceCastBasic(const Type &type) const {
+ return IsScalar(type.base_type) ? SourceCast(type) : "";
+ }
+
+ std::string GenEnumDefaultValue(const FieldDef &field) const {
+ auto &value = field.value;
+ FLATBUFFERS_ASSERT(value.type.enum_def);
+ auto &enum_def = *value.type.enum_def;
+ auto enum_val = enum_def.FindByValue(value.constant);
+ return enum_val ? (WrapInNameSpace(enum_def) + "." + enum_val->name)
+ : value.constant;
+ }
+
+ std::string GenDefaultValue(const FieldDef &field,
+ bool enableLangOverrides) const {
+ // If it is an optional scalar field, the default is null
+ if (field.IsScalarOptional()) { return "null"; }
+
+ auto &value = field.value;
+ if (enableLangOverrides) {
+ // handles both enum case and vector of enum case
+ if (value.type.enum_def != nullptr &&
+ value.type.base_type != BASE_TYPE_UNION) {
+ return GenEnumDefaultValue(field);
+ }
+ }
+
+ auto longSuffix = "";
+ switch (value.type.base_type) {
+ case BASE_TYPE_BOOL: return value.constant == "0" ? "false" : "true";
+ case BASE_TYPE_ULONG: return value.constant;
+ case BASE_TYPE_UINT:
+ case BASE_TYPE_LONG: return value.constant + longSuffix;
+ default:
+ if (IsFloat(value.type.base_type))
+ return CSharpFloatGen.GenFloatConstant(field);
+ else
+ return value.constant;
+ }
+ }
+
+ std::string GenDefaultValue(const FieldDef &field) const {
+ return GenDefaultValue(field, true);
+ }
+
+ std::string GenDefaultValueBasic(const FieldDef &field,
+ bool enableLangOverrides) const {
+ auto &value = field.value;
+ if (!IsScalar(value.type.base_type)) {
+ if (enableLangOverrides) {
+ switch (value.type.base_type) {
+ case BASE_TYPE_STRING: return "default(StringOffset)";
+ case BASE_TYPE_STRUCT:
+ return "default(Offset<" + WrapInNameSpace(*value.type.struct_def) +
+ ">)";
+ case BASE_TYPE_VECTOR: return "default(VectorOffset)";
+ default: break;
+ }
+ }
+ return "0";
+ }
+ return GenDefaultValue(field, enableLangOverrides);
+ }
+
+ std::string GenDefaultValueBasic(const FieldDef &field) const {
+ return GenDefaultValueBasic(field, true);
+ }
+
+ void GenEnum(EnumDef &enum_def, std::string *code_ptr,
+ const IDLOptions &opts) const {
+ std::string &code = *code_ptr;
+ if (enum_def.generated) return;
+
+ // Generate enum definitions of the form:
+ // public static (final) int name = value;
+ // In Java, we use ints rather than the Enum feature, because we want them
+ // to map directly to how they're used in C/C++ and file formats.
+ // That, and Java Enums are expensive, and not universally liked.
+ GenComment(enum_def.doc_comment, code_ptr, &comment_config);
+
+ if (opts.cs_gen_json_serializer && opts.generate_object_based_api) {
+ code +=
+ "[Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters."
+ "StringEnumConverter))]\n";
+ }
+ // In C# this indicates enumeration values can be treated as bit flags.
+ if (enum_def.attributes.Lookup("bit_flags")) {
+ code += "[System.FlagsAttribute]\n";
+ }
+ if (enum_def.attributes.Lookup("private")) {
+ code += "internal ";
+ } else {
+ code += "public ";
+ }
+ code += "enum " + enum_def.name;
+ code += " : " + GenTypeBasic(enum_def.underlying_type, false);
+ code += "\n{\n";
+ for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
+ auto &ev = **it;
+ GenComment(ev.doc_comment, code_ptr, &comment_config, " ");
+ code += " ";
+ code += ev.name + " = ";
+ code += enum_def.ToString(ev);
+ code += ",\n";
+ }
+ // Close the class
+ code += "};\n\n";
+
+ if (opts.generate_object_based_api) {
+ GenEnum_ObjectAPI(enum_def, code_ptr, opts);
+ }
+ }
+
+ bool HasUnionStringValue(const EnumDef &enum_def) const {
+ if (!enum_def.is_union) return false;
+ for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
+ auto &val = **it;
+ if (IsString(val.union_type)) { return true; }
+ }
+ return false;
+ }
+
+ // Returns the function name that is able to read a value of the given type.
+ std::string GenGetter(const Type &type) const {
+ switch (type.base_type) {
+ case BASE_TYPE_STRING: return "__p.__string";
+ case BASE_TYPE_STRUCT: return "__p.__struct";
+ case BASE_TYPE_UNION: return "__p.__union";
+ case BASE_TYPE_VECTOR: return GenGetter(type.VectorType());
+ case BASE_TYPE_ARRAY: return GenGetter(type.VectorType());
+ default: {
+ std::string getter = "__p.bb.Get";
+ if (type.base_type == BASE_TYPE_BOOL) {
+ getter = "0!=" + getter;
+ } else if (GenTypeBasic(type, false) != "byte") {
+ getter += MakeCamel(GenTypeBasic(type, false));
+ }
+ return getter;
+ }
+ }
+ }
+
+ // Returns the function name that is able to read a value of the given type.
+ std::string GenGetterForLookupByKey(flatbuffers::FieldDef *key_field,
+ const std::string &data_buffer,
+ const char *num = nullptr) const {
+ auto type = key_field->value.type;
+ auto dest_mask = "";
+ auto dest_cast = DestinationCast(type);
+ auto getter = data_buffer + ".Get";
+ if (GenTypeBasic(type, false) != "byte") {
+ getter += MakeCamel(GenTypeBasic(type, false));
+ }
+ getter = dest_cast + getter + "(" + GenOffsetGetter(key_field, num) + ")" +
+ dest_mask;
+ return getter;
+ }
+
+ // Direct mutation is only allowed for scalar fields.
+ // Hence a setter method will only be generated for such fields.
+ std::string GenSetter(const Type &type) const {
+ if (IsScalar(type.base_type)) {
+ std::string setter = "__p.bb.Put";
+ if (GenTypeBasic(type, false) != "byte" &&
+ type.base_type != BASE_TYPE_BOOL) {
+ setter += MakeCamel(GenTypeBasic(type, false));
+ }
+ return setter;
+ } else {
+ return "";
+ }
+ }
+
+ // Returns the method name for use with add/put calls.
+ std::string GenMethod(const Type &type) const {
+ return IsScalar(type.base_type) ? MakeCamel(GenTypeBasic(type, false))
+ : (IsStruct(type) ? "Struct" : "Offset");
+ }
+
+ // Recursively generate arguments for a constructor, to deal with nested
+ // structs.
+ void GenStructArgs(const StructDef &struct_def, std::string *code_ptr,
+ const char *nameprefix, size_t array_count = 0) const {
+ std::string &code = *code_ptr;
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ const auto &field_type = field.value.type;
+ const auto array_field = IsArray(field_type);
+ const auto &type = array_field ? field_type.VectorType() : field_type;
+ const auto array_cnt = array_field ? (array_count + 1) : array_count;
+ if (IsStruct(type)) {
+ // Generate arguments for a struct inside a struct. To ensure names
+ // don't clash, and to make it obvious these arguments are constructing
+ // a nested struct, prefix the name with the field name.
+ GenStructArgs(*field_type.struct_def, code_ptr,
+ (nameprefix + (field.name + "_")).c_str(), array_cnt);
+ } else {
+ code += ", ";
+ code += GenTypeBasic(type);
+ if (field.IsScalarOptional()) { code += "?"; }
+ if (array_cnt > 0) {
+ code += "[";
+ for (size_t i = 1; i < array_cnt; i++) code += ",";
+ code += "]";
+ }
+ code += " ";
+ code += nameprefix;
+ code += MakeCamel(field.name, true);
+ }
+ }
+ }
+
+ // Recusively generate struct construction statements of the form:
+ // builder.putType(name);
+ // and insert manual padding.
+ void GenStructBody(const StructDef &struct_def, std::string *code_ptr,
+ const char *nameprefix, size_t index = 0,
+ bool in_array = false) const {
+ std::string &code = *code_ptr;
+ std::string indent((index + 1) * 2, ' ');
+ code += indent + " builder.Prep(";
+ code += NumToString(struct_def.minalign) + ", ";
+ code += NumToString(struct_def.bytesize) + ");\n";
+ for (auto it = struct_def.fields.vec.rbegin();
+ it != struct_def.fields.vec.rend(); ++it) {
+ auto &field = **it;
+ const auto &field_type = field.value.type;
+ if (field.padding) {
+ code += indent + " builder.Pad(";
+ code += NumToString(field.padding) + ");\n";
+ }
+ if (IsStruct(field_type)) {
+ GenStructBody(*field_type.struct_def, code_ptr,
+ (nameprefix + (field.name + "_")).c_str(), index,
+ in_array);
+ } else {
+ const auto &type =
+ IsArray(field_type) ? field_type.VectorType() : field_type;
+ const auto index_var = "_idx" + NumToString(index);
+ if (IsArray(field_type)) {
+ code += indent + " for (int " + index_var + " = ";
+ code += NumToString(field_type.fixed_length);
+ code += "; " + index_var + " > 0; " + index_var + "--) {\n";
+ in_array = true;
+ }
+ if (IsStruct(type)) {
+ GenStructBody(*field_type.struct_def, code_ptr,
+ (nameprefix + (field.name + "_")).c_str(), index + 1,
+ in_array);
+ } else {
+ code += IsArray(field_type) ? " " : "";
+ code += indent + " builder.Put";
+ code += GenMethod(type) + "(";
+ code += SourceCast(type);
+ auto argname = nameprefix + MakeCamel(field.name, true);
+ code += argname;
+ size_t array_cnt = index + (IsArray(field_type) ? 1 : 0);
+ if (array_cnt > 0) {
+ code += "[";
+ for (size_t i = 0; in_array && i < array_cnt; i++) {
+ code += "_idx" + NumToString(i) + "-1";
+ if (i != (array_cnt - 1)) code += ",";
+ }
+ code += "]";
+ }
+ code += ");\n";
+ }
+ if (IsArray(field_type)) { code += indent + " }\n"; }
+ }
+ }
+ }
+ std::string GenOffsetGetter(flatbuffers::FieldDef *key_field,
+ const char *num = nullptr) const {
+ std::string key_offset =
+ "Table.__offset(" + NumToString(key_field->value.offset) + ", ";
+ if (num) {
+ key_offset += num;
+ key_offset += ".Value, builder.DataBuffer)";
+ } else {
+ key_offset += "bb.Length";
+ key_offset += " - tableOffset, bb)";
+ }
+ return key_offset;
+ }
+
+ std::string GenLookupKeyGetter(flatbuffers::FieldDef *key_field) const {
+ std::string key_getter = " ";
+ key_getter += "int tableOffset = Table.";
+ key_getter += "__indirect(vectorLocation + 4 * (start + middle)";
+ key_getter += ", bb);\n ";
+ if (IsString(key_field->value.type)) {
+ key_getter += "int comp = Table.";
+ key_getter += "CompareStrings(";
+ key_getter += GenOffsetGetter(key_field);
+ key_getter += ", byteKey, bb);\n";
+ } else {
+ auto get_val = GenGetterForLookupByKey(key_field, "bb");
+ key_getter += "int comp = " + get_val + ".CompareTo(key);\n";
+ }
+ return key_getter;
+ }
+
+ std::string GenKeyGetter(flatbuffers::FieldDef *key_field) const {
+ std::string key_getter = "";
+ auto data_buffer = "builder.DataBuffer";
+ if (IsString(key_field->value.type)) {
+ key_getter += "Table.CompareStrings(";
+ key_getter += GenOffsetGetter(key_field, "o1") + ", ";
+ key_getter += GenOffsetGetter(key_field, "o2") + ", " + data_buffer + ")";
+ } else {
+ auto field_getter = GenGetterForLookupByKey(key_field, data_buffer, "o1");
+ key_getter += field_getter;
+ field_getter = GenGetterForLookupByKey(key_field, data_buffer, "o2");
+ key_getter += ".CompareTo(" + field_getter + ")";
+ }
+ return key_getter;
+ }
+
+ void GenStruct(StructDef &struct_def, std::string *code_ptr,
+ const IDLOptions &opts) const {
+ if (struct_def.generated) return;
+ std::string &code = *code_ptr;
+
+ // Generate a struct accessor class, with methods of the form:
+ // public type name() { return bb.getType(i + offset); }
+ // or for tables of the form:
+ // public type name() {
+ // int o = __offset(offset); return o != 0 ? bb.getType(o + i) : default;
+ // }
+ GenComment(struct_def.doc_comment, code_ptr, &comment_config);
+ if (struct_def.attributes.Lookup("private")) {
+ code += "internal ";
+ } else {
+ code += "public ";
+ }
+ if (struct_def.attributes.Lookup("csharp_partial")) {
+ // generate a partial class for this C# struct/table
+ code += "partial ";
+ }
+ code += "struct " + struct_def.name;
+ code += " : IFlatbufferObject";
+ code += "\n{\n";
+ code += " private ";
+ code += struct_def.fixed ? "Struct" : "Table";
+ code += " __p;\n";
+
+ code += " public ByteBuffer ByteBuffer { get { return __p.bb; } }\n";
+
+ if (!struct_def.fixed) {
+ // Generate verson check method.
+ // Force compile time error if not using the same version runtime.
+ code += " public static void ValidateVersion() {";
+ code += " FlatBufferConstants.";
+ code += "FLATBUFFERS_1_12_0(); ";
+ code += "}\n";
+
+ // Generate a special accessor for the table that when used as the root
+ // of a FlatBuffer
+ std::string method_name = "GetRootAs" + struct_def.name;
+ std::string method_signature =
+ " public static " + struct_def.name + " " + method_name;
+
+ // create convenience method that doesn't require an existing object
+ code += method_signature + "(ByteBuffer _bb) ";
+ code += "{ return " + method_name + "(_bb, new " + struct_def.name +
+ "()); }\n";
+
+ // create method that allows object reuse
+ code +=
+ method_signature + "(ByteBuffer _bb, " + struct_def.name + " obj) { ";
+ code += "return (obj.__assign(_bb.GetInt(_bb.Position";
+ code += ") + _bb.Position";
+ code += ", _bb)); }\n";
+ if (parser_.root_struct_def_ == &struct_def) {
+ if (parser_.file_identifier_.length()) {
+ // Check if a buffer has the identifier.
+ code += " public static ";
+ code += "bool " + struct_def.name;
+ code += "BufferHasIdentifier(ByteBuffer _bb) { return ";
+ code += "Table.__has_identifier(_bb, \"";
+ code += parser_.file_identifier_;
+ code += "\"); }\n";
+ }
+ }
+ }
+ // Generate the __init method that sets the field in a pre-existing
+ // accessor object. This is to allow object reuse.
+ code += " public void __init(int _i, ByteBuffer _bb) ";
+ code += "{ ";
+ code += "__p = new ";
+ code += struct_def.fixed ? "Struct" : "Table";
+ code += "(_i, _bb); ";
+ code += "}\n";
+ code +=
+ " public " + struct_def.name + " __assign(int _i, ByteBuffer _bb) ";
+ code += "{ __init(_i, _bb); return this; }\n\n";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+ GenComment(field.doc_comment, code_ptr, &comment_config, " ");
+ std::string type_name = GenTypeGet(field.value.type);
+ std::string type_name_dest = GenTypeGet(field.value.type);
+ std::string conditional_cast = "";
+ std::string optional = "";
+ if (!struct_def.fixed &&
+ (field.value.type.base_type == BASE_TYPE_STRUCT ||
+ field.value.type.base_type == BASE_TYPE_UNION ||
+ (IsVector(field.value.type) &&
+ (field.value.type.element == BASE_TYPE_STRUCT ||
+ field.value.type.element == BASE_TYPE_UNION)))) {
+ optional = "?";
+ conditional_cast = "(" + type_name_dest + optional + ")";
+ }
+ if (field.IsScalarOptional()) { optional = "?"; }
+ std::string dest_mask = "";
+ std::string dest_cast = DestinationCast(field.value.type);
+ std::string src_cast = SourceCast(field.value.type);
+ std::string field_name_camel = MakeCamel(field.name, true);
+ std::string method_start =
+ " public " + type_name_dest + optional + " " + field_name_camel;
+ std::string obj = "(new " + type_name + "())";
+
+ // Most field accessors need to retrieve and test the field offset first,
+ // this is the prefix code for that:
+ auto offset_prefix =
+ IsArray(field.value.type)
+ ? " { return "
+ : (" { int o = __p.__offset(" + NumToString(field.value.offset) +
+ "); return o != 0 ? ");
+ // Generate the accessors that don't do object reuse.
+ if (field.value.type.base_type == BASE_TYPE_STRUCT) {
+ } else if (IsVector(field.value.type) &&
+ field.value.type.element == BASE_TYPE_STRUCT) {
+ } else if (field.value.type.base_type == BASE_TYPE_UNION ||
+ (IsVector(field.value.type) &&
+ field.value.type.VectorType().base_type == BASE_TYPE_UNION)) {
+ method_start += "<TTable>";
+ type_name = type_name_dest;
+ }
+ std::string getter = dest_cast + GenGetter(field.value.type);
+ code += method_start;
+ std::string default_cast = "";
+ // only create default casts for c# scalars or vectors of scalars
+ if ((IsScalar(field.value.type.base_type) ||
+ (IsVector(field.value.type) &&
+ IsScalar(field.value.type.element)))) {
+ // For scalars, default value will be returned by GetDefaultValue().
+ // If the scalar is an enum, GetDefaultValue() returns an actual c# enum
+ // that doesn't need to be casted. However, default values for enum
+ // elements of vectors are integer literals ("0") and are still casted
+ // for clarity.
+ // If the scalar is optional and enum, we still need the cast.
+ if ((field.value.type.enum_def == nullptr ||
+ IsVector(field.value.type)) ||
+ (IsEnum(field.value.type) && field.IsScalarOptional())) {
+ default_cast = "(" + type_name_dest + optional + ")";
+ }
+ }
+ std::string member_suffix = "; ";
+ if (IsScalar(field.value.type.base_type)) {
+ code += " { get";
+ member_suffix += "} ";
+ if (struct_def.fixed) {
+ code += " { return " + getter;
+ code += "(__p.bb_pos + ";
+ code += NumToString(field.value.offset) + ")";
+ code += dest_mask;
+ } else {
+ code += offset_prefix + getter;
+ code += "(o + __p.bb_pos)" + dest_mask;
+ code += " : " + default_cast;
+ code += GenDefaultValue(field);
+ }
+ } else {
+ switch (field.value.type.base_type) {
+ case BASE_TYPE_STRUCT:
+ code += " { get";
+ member_suffix += "} ";
+ if (struct_def.fixed) {
+ code += " { return " + obj + ".__assign(" + "__p.";
+ code += "bb_pos + " + NumToString(field.value.offset) + ", ";
+ code += "__p.bb)";
+ } else {
+ code += offset_prefix + conditional_cast;
+ code += obj + ".__assign(";
+ code += field.value.type.struct_def->fixed
+ ? "o + __p.bb_pos"
+ : "__p.__indirect(o + __p.bb_pos)";
+ code += ", __p.bb) : null";
+ }
+ break;
+ case BASE_TYPE_STRING:
+ code += " { get";
+ member_suffix += "} ";
+ code += offset_prefix + getter + "(o + " + "__p.";
+ code += "bb_pos) : null";
+ break;
+ case BASE_TYPE_ARRAY: FLATBUFFERS_FALLTHROUGH(); // fall thru
+ case BASE_TYPE_VECTOR: {
+ auto vectortype = field.value.type.VectorType();
+ if (vectortype.base_type == BASE_TYPE_UNION) {
+ conditional_cast = "(TTable?)";
+ getter += "<TTable>";
+ }
+ code += "(";
+ if (vectortype.base_type == BASE_TYPE_STRUCT) {
+ getter = obj + ".__assign";
+ } else if (vectortype.base_type == BASE_TYPE_UNION) {
+ }
+ code += "int j)";
+ const auto body = offset_prefix + conditional_cast + getter + "(";
+ if (vectortype.base_type == BASE_TYPE_UNION) {
+ code += " where TTable : struct, IFlatbufferObject" + body;
+ } else {
+ code += body;
+ }
+ std::string index = "__p.";
+ if (IsArray(field.value.type)) {
+ index += "bb_pos + " + NumToString(field.value.offset) + " + ";
+ } else {
+ index += "__vector(o) + ";
+ }
+ index += "j * " + NumToString(InlineSize(vectortype));
+ if (vectortype.base_type == BASE_TYPE_STRUCT) {
+ code += vectortype.struct_def->fixed
+ ? index
+ : "__p.__indirect(" + index + ")";
+ code += ", __p.bb";
+ } else {
+ code += index;
+ }
+ code += ")" + dest_mask;
+ if (!IsArray(field.value.type)) {
+ code += " : ";
+ code +=
+ field.value.type.element == BASE_TYPE_BOOL
+ ? "false"
+ : (IsScalar(field.value.type.element) ? default_cast + "0"
+ : "null");
+ }
+ if (vectortype.base_type == BASE_TYPE_UNION &&
+ HasUnionStringValue(*vectortype.enum_def)) {
+ code += member_suffix;
+ code += "}\n";
+ code += " public string " + MakeCamel(field.name, true) +
+ "AsString(int j)";
+ code += offset_prefix + GenGetter(Type(BASE_TYPE_STRING));
+ code += "(" + index + ") : null";
+ }
+ break;
+ }
+ case BASE_TYPE_UNION:
+ code += "() where TTable : struct, IFlatbufferObject";
+ code += offset_prefix + "(TTable?)" + getter;
+ code += "<TTable>(o + __p.bb_pos) : null";
+ if (HasUnionStringValue(*field.value.type.enum_def)) {
+ code += member_suffix;
+ code += "}\n";
+ code += " public string " + MakeCamel(field.name, true) +
+ "AsString()";
+ code += offset_prefix + GenGetter(Type(BASE_TYPE_STRING));
+ code += "(o + __p.bb_pos) : null";
+ }
+ // As<> accesors for Unions
+ // Loop through all the possible union types and generate an As
+ // accessor that casts to the correct type.
+ for (auto uit = field.value.type.enum_def->Vals().begin();
+ uit != field.value.type.enum_def->Vals().end(); ++uit) {
+ auto val = *uit;
+ if (val->union_type.base_type == BASE_TYPE_NONE) { continue; }
+ auto union_field_type_name = GenTypeGet(val->union_type);
+ code += member_suffix + "}\n";
+ if (val->union_type.base_type == BASE_TYPE_STRUCT &&
+ val->union_type.struct_def->attributes.Lookup("private")) {
+ code += " internal ";
+ } else {
+ code += " public ";
+ }
+ code += union_field_type_name + " ";
+ code += field_name_camel + "As" + val->name + "() { return ";
+ code += field_name_camel;
+ if (IsString(val->union_type)) {
+ code += "AsString()";
+ } else {
+ code += "<" + union_field_type_name + ">().Value";
+ }
+ }
+ break;
+ default: FLATBUFFERS_ASSERT(0);
+ }
+ }
+ code += member_suffix;
+ code += "}\n";
+ if (IsVector(field.value.type)) {
+ code += " public int " + MakeCamel(field.name, true);
+ code += "Length";
+ code += " { get";
+ code += offset_prefix;
+ code += "__p.__vector_len(o) : 0; ";
+ code += "} ";
+ code += "}\n";
+ // See if we should generate a by-key accessor.
+ if (field.value.type.element == BASE_TYPE_STRUCT &&
+ !field.value.type.struct_def->fixed) {
+ auto &sd = *field.value.type.struct_def;
+ auto &fields = sd.fields.vec;
+ for (auto kit = fields.begin(); kit != fields.end(); ++kit) {
+ auto &key_field = **kit;
+ if (key_field.key) {
+ auto qualified_name = WrapInNameSpace(sd);
+ code += " public " + qualified_name + "? ";
+ code += MakeCamel(field.name, true) + "ByKey(";
+ code += GenTypeGet(key_field.value.type) + " key)";
+ code += offset_prefix;
+ code += qualified_name + ".__lookup_by_key(";
+ code += "__p.__vector(o), key, ";
+ code += "__p.bb) : null; ";
+ code += "}\n";
+ break;
+ }
+ }
+ }
+ }
+ // Generate a ByteBuffer accessor for strings & vectors of scalars.
+ if ((IsVector(field.value.type) &&
+ IsScalar(field.value.type.VectorType().base_type)) ||
+ IsString(field.value.type)) {
+ code += "#if ENABLE_SPAN_T\n";
+ code += " public Span<" + GenTypeBasic(field.value.type.VectorType()) +
+ "> Get";
+ code += MakeCamel(field.name, true);
+ code += "Bytes() { return ";
+ code += "__p.__vector_as_span<" +
+ GenTypeBasic(field.value.type.VectorType()) + ">(";
+ code += NumToString(field.value.offset);
+ code +=
+ ", " + NumToString(SizeOf(field.value.type.VectorType().base_type));
+ code += "); }\n";
+ code += "#else\n";
+ code += " public ArraySegment<byte>? Get";
+ code += MakeCamel(field.name, true);
+ code += "Bytes() { return ";
+ code += "__p.__vector_as_arraysegment(";
+ code += NumToString(field.value.offset);
+ code += "); }\n";
+ code += "#endif\n";
+
+ // For direct blockcopying the data into a typed array
+ code += " public ";
+ code += GenTypeBasic(field.value.type.VectorType());
+ code += "[] Get";
+ code += MakeCamel(field.name, true);
+ code += "Array() { ";
+ if (IsEnum(field.value.type.VectorType())) {
+ // Since __vector_as_array does not work for enum types,
+ // fill array using an explicit loop.
+ code += "int o = __p.__offset(";
+ code += NumToString(field.value.offset);
+ code += "); if (o == 0) return null; int p = ";
+ code += "__p.__vector(o); int l = ";
+ code += "__p.__vector_len(o); ";
+ code += GenTypeBasic(field.value.type.VectorType());
+ code += "[] a = new ";
+ code += GenTypeBasic(field.value.type.VectorType());
+ code += "[l]; for (int i = 0; i < l; i++) { a[i] = " + getter;
+ code += "(p + i * ";
+ code += NumToString(InlineSize(field.value.type.VectorType()));
+ code += "); } return a;";
+ } else {
+ code += "return ";
+ code += "__p.__vector_as_array<";
+ code += GenTypeBasic(field.value.type.VectorType());
+ code += ">(";
+ code += NumToString(field.value.offset);
+ code += ");";
+ }
+ code += " }\n";
+ }
+ // generate object accessors if is nested_flatbuffer
+ if (field.nested_flatbuffer) {
+ auto nested_type_name = WrapInNameSpace(*field.nested_flatbuffer);
+ auto nested_method_name =
+ MakeCamel(field.name, true) + "As" + field.nested_flatbuffer->name;
+ auto get_nested_method_name = nested_method_name;
+ get_nested_method_name = "Get" + nested_method_name;
+ conditional_cast = "(" + nested_type_name + "?)";
+ obj = "(new " + nested_type_name + "())";
+ code += " public " + nested_type_name + "? ";
+ code += get_nested_method_name + "(";
+ code += ") { int o = __p.__offset(";
+ code += NumToString(field.value.offset) + "); ";
+ code += "return o != 0 ? " + conditional_cast + obj + ".__assign(";
+ code += "__p.";
+ code += "__indirect(__p.__vector(o)), ";
+ code += "__p.bb) : null; }\n";
+ }
+ // Generate mutators for scalar fields or vectors of scalars.
+ if (parser_.opts.mutable_buffer) {
+ auto is_series = (IsSeries(field.value.type));
+ const auto &underlying_type =
+ is_series ? field.value.type.VectorType() : field.value.type;
+ // Boolean parameters have to be explicitly converted to byte
+ // representation.
+ auto setter_parameter = underlying_type.base_type == BASE_TYPE_BOOL
+ ? "(byte)(" + field.name + " ? 1 : 0)"
+ : field.name;
+ auto mutator_prefix = MakeCamel("mutate", true);
+ // A vector mutator also needs the index of the vector element it should
+ // mutate.
+ auto mutator_params = (is_series ? "(int j, " : "(") +
+ GenTypeGet(underlying_type) + " " + field.name +
+ ") { ";
+ auto setter_index =
+ is_series
+ ? "__p." +
+ (IsArray(field.value.type)
+ ? "bb_pos + " + NumToString(field.value.offset)
+ : "__vector(o)") +
+ +" + j * " + NumToString(InlineSize(underlying_type))
+ : (struct_def.fixed
+ ? "__p.bb_pos + " + NumToString(field.value.offset)
+ : "o + __p.bb_pos");
+ if (IsScalar(underlying_type.base_type) && !IsUnion(field.value.type)) {
+ code += " public ";
+ code += struct_def.fixed ? "void " : "bool ";
+ code += mutator_prefix + MakeCamel(field.name, true);
+ code += mutator_params;
+ if (struct_def.fixed) {
+ code += GenSetter(underlying_type) + "(" + setter_index + ", ";
+ code += src_cast + setter_parameter + "); }\n";
+ } else {
+ code += "int o = __p.__offset(";
+ code += NumToString(field.value.offset) + ");";
+ code += " if (o != 0) { " + GenSetter(underlying_type);
+ code += "(" + setter_index + ", " + src_cast + setter_parameter +
+ "); return true; } else { return false; } }\n";
+ }
+ }
+ }
+ if (parser_.opts.java_primitive_has_method &&
+ IsScalar(field.value.type.base_type) && !struct_def.fixed) {
+ auto vt_offset_constant = " public static final int VT_" +
+ MakeScreamingCamel(field.name) + " = " +
+ NumToString(field.value.offset) + ";";
+
+ code += vt_offset_constant;
+ code += "\n";
+ }
+ }
+ code += "\n";
+ auto struct_has_create = false;
+ std::set<flatbuffers::FieldDef *> field_has_create_set;
+ flatbuffers::FieldDef *key_field = nullptr;
+ if (struct_def.fixed) {
+ struct_has_create = true;
+ // create a struct constructor function
+ code += " public static " + GenOffsetType(struct_def) + " ";
+ code += "Create";
+ code += struct_def.name + "(FlatBufferBuilder builder";
+ GenStructArgs(struct_def, code_ptr, "");
+ code += ") {\n";
+ GenStructBody(struct_def, code_ptr, "");
+ code += " return ";
+ code += GenOffsetConstruct(struct_def, "builder.Offset");
+ code += ";\n }\n";
+ } else {
+ // Generate a method that creates a table in one go. This is only possible
+ // when the table has no struct fields, since those have to be created
+ // inline, and there's no way to do so in Java.
+ bool has_no_struct_fields = true;
+ int num_fields = 0;
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+ if (IsStruct(field.value.type)) {
+ has_no_struct_fields = false;
+ } else {
+ num_fields++;
+ }
+ }
+ // JVM specifications restrict default constructor params to be < 255.
+ // Longs and doubles take up 2 units, so we set the limit to be < 127.
+ if ((has_no_struct_fields || opts.generate_object_based_api) &&
+ num_fields && num_fields < 127) {
+ struct_has_create = true;
+ // Generate a table constructor of the form:
+ // public static int createName(FlatBufferBuilder builder, args...)
+ code += " public static " + GenOffsetType(struct_def) + " ";
+ code += "Create" + struct_def.name;
+ code += "(FlatBufferBuilder builder";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+ code += ",\n ";
+ if (IsStruct(field.value.type) && opts.generate_object_based_api) {
+ code += WrapInNameSpace(
+ field.value.type.struct_def->defined_namespace,
+ GenTypeName_ObjectAPI(field.value.type.struct_def->name, opts));
+ code += " ";
+ code += field.name;
+ code += " = null";
+ } else {
+ code += GenTypeBasic(field.value.type);
+ if (field.IsScalarOptional()) { code += "?"; }
+ code += " ";
+ code += field.name;
+ if (!IsScalar(field.value.type.base_type)) code += "Offset";
+
+ code += " = ";
+ code += GenDefaultValueBasic(field);
+ }
+ }
+ code += ") {\n builder.";
+ code += "StartTable(";
+ code += NumToString(struct_def.fields.vec.size()) + ");\n";
+ for (size_t size = struct_def.sortbysize ? sizeof(largest_scalar_t) : 1;
+ size; size /= 2) {
+ for (auto it = struct_def.fields.vec.rbegin();
+ it != struct_def.fields.vec.rend(); ++it) {
+ auto &field = **it;
+ if (!field.deprecated &&
+ (!struct_def.sortbysize ||
+ size == SizeOf(field.value.type.base_type))) {
+ code += " " + struct_def.name + ".";
+ code += "Add";
+ code += MakeCamel(field.name) + "(builder, ";
+ if (IsStruct(field.value.type) &&
+ opts.generate_object_based_api) {
+ code += GenTypePointer(field.value.type) + ".Pack(builder, " +
+ field.name + ")";
+ } else {
+ code += field.name;
+ if (!IsScalar(field.value.type.base_type)) code += "Offset";
+ }
+
+ code += ");\n";
+ }
+ }
+ }
+ code += " return " + struct_def.name + ".";
+ code += "End" + struct_def.name;
+ code += "(builder);\n }\n\n";
+ }
+ // Generate a set of static methods that allow table construction,
+ // of the form:
+ // public static void addName(FlatBufferBuilder builder, short name)
+ // { builder.addShort(id, name, default); }
+ // Unlike the Create function, these always work.
+ code += " public static void Start";
+ code += struct_def.name;
+ code += "(FlatBufferBuilder builder) { builder.";
+ code += "StartTable(";
+ code += NumToString(struct_def.fields.vec.size()) + "); }\n";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+ if (field.key) key_field = &field;
+ code += " public static void Add";
+ code += MakeCamel(field.name);
+ code += "(FlatBufferBuilder builder, ";
+ code += GenTypeBasic(field.value.type);
+ auto argname = MakeCamel(field.name, false);
+ if (!IsScalar(field.value.type.base_type)) argname += "Offset";
+ if (field.IsScalarOptional()) { code += "?"; }
+ code += " " + argname + ") { builder.Add";
+ code += GenMethod(field.value.type) + "(";
+ code += NumToString(it - struct_def.fields.vec.begin()) + ", ";
+ code += SourceCastBasic(field.value.type);
+ code += argname;
+ if (!IsScalar(field.value.type.base_type) &&
+ field.value.type.base_type != BASE_TYPE_UNION) {
+ code += ".Value";
+ }
+ if (!field.IsScalarOptional()) {
+ // When the scalar is optional, use the builder method that doesn't
+ // supply a default value. Otherwise, we to continue to use the
+ // default value method.
+ code += ", ";
+ code += GenDefaultValue(field, false);
+ }
+ code += "); }\n";
+ if (IsVector(field.value.type)) {
+ auto vector_type = field.value.type.VectorType();
+ auto alignment = InlineAlignment(vector_type);
+ auto elem_size = InlineSize(vector_type);
+ if (!IsStruct(vector_type)) {
+ field_has_create_set.insert(&field);
+ code += " public static VectorOffset ";
+ code += "Create";
+ code += MakeCamel(field.name);
+ code += "Vector(FlatBufferBuilder builder, ";
+ code += GenTypeBasic(vector_type) + "[] data) ";
+ code += "{ builder.StartVector(";
+ code += NumToString(elem_size);
+ code += ", data.Length, ";
+ code += NumToString(alignment);
+ code += "); for (int i = data.";
+ code += "Length - 1; i >= 0; i--) builder.";
+ code += "Add";
+ code += GenMethod(vector_type);
+ code += "(";
+ code += SourceCastBasic(vector_type);
+ code += "data[i]";
+ if (vector_type.base_type == BASE_TYPE_STRUCT ||
+ IsString(vector_type))
+ code += ".Value";
+ code += "); return ";
+ code += "builder.EndVector(); }\n";
+
+ code += " public static VectorOffset ";
+ code += "Create";
+ code += MakeCamel(field.name);
+ code += "VectorBlock(FlatBufferBuilder builder, ";
+ code += GenTypeBasic(vector_type) + "[] data) ";
+ code += "{ builder.StartVector(";
+ code += NumToString(elem_size);
+ code += ", data.Length, ";
+ code += NumToString(alignment);
+ code += "); builder.Add(data); return builder.EndVector(); }\n";
+ }
+ // Generate a method to start a vector, data to be added manually
+ // after.
+ code += " public static void Start";
+ code += MakeCamel(field.name);
+ code += "Vector(FlatBufferBuilder builder, int numElems) ";
+ code += "{ builder.StartVector(";
+ code += NumToString(elem_size);
+ code += ", numElems, " + NumToString(alignment);
+ code += "); }\n";
+ }
+ }
+ code += " public static " + GenOffsetType(struct_def) + " ";
+ code += "End" + struct_def.name;
+ code += "(FlatBufferBuilder builder) {\n int o = builder.";
+ code += "EndTable();\n";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (!field.deprecated && field.required) {
+ code += " builder.Required(o, ";
+ code += NumToString(field.value.offset);
+ code += "); // " + field.name + "\n";
+ }
+ }
+ code += " return " + GenOffsetConstruct(struct_def, "o") + ";\n }\n";
+ if (parser_.root_struct_def_ == &struct_def) {
+ std::string size_prefix[] = { "", "SizePrefixed" };
+ for (int i = 0; i < 2; ++i) {
+ code += " public static void ";
+ code += "Finish" + size_prefix[i] + struct_def.name;
+ code +=
+ "Buffer(FlatBufferBuilder builder, " + GenOffsetType(struct_def);
+ code += " offset) {";
+ code += " builder.Finish" + size_prefix[i] + "(offset";
+ code += ".Value";
+
+ if (parser_.file_identifier_.length())
+ code += ", \"" + parser_.file_identifier_ + "\"";
+ code += "); }\n";
+ }
+ }
+ }
+ // Only generate key compare function for table,
+ // because `key_field` is not set for struct
+ if (struct_def.has_key && !struct_def.fixed) {
+ FLATBUFFERS_ASSERT(key_field);
+ code += "\n public static VectorOffset ";
+ code += "CreateSortedVectorOf" + struct_def.name;
+ code += "(FlatBufferBuilder builder, ";
+ code += "Offset<" + struct_def.name + ">";
+ code += "[] offsets) {\n";
+ code += " Array.Sort(offsets, (Offset<" + struct_def.name +
+ "> o1, Offset<" + struct_def.name + "> o2) => " +
+ GenKeyGetter(key_field);
+ code += ");\n";
+ code += " return builder.CreateVectorOfTables(offsets);\n }\n";
+
+ code += "\n public static " + struct_def.name + "?";
+ code += " __lookup_by_key(";
+ code += "int vectorLocation, ";
+ code += GenTypeGet(key_field->value.type);
+ code += " key, ByteBuffer bb) {\n";
+ if (IsString(key_field->value.type)) {
+ code += " byte[] byteKey = ";
+ code += "System.Text.Encoding.UTF8.GetBytes(key);\n";
+ }
+ code += " int span = ";
+ code += "bb.GetInt(vectorLocation - 4);\n";
+ code += " int start = 0;\n";
+ code += " while (span != 0) {\n";
+ code += " int middle = span / 2;\n";
+ code += GenLookupKeyGetter(key_field);
+ code += " if (comp > 0) {\n";
+ code += " span = middle;\n";
+ code += " } else if (comp < 0) {\n";
+ code += " middle++;\n";
+ code += " start += middle;\n";
+ code += " span -= middle;\n";
+ code += " } else {\n";
+ code += " return ";
+ code += "new " + struct_def.name + "()";
+ code += ".__assign(tableOffset, bb);\n";
+ code += " }\n }\n";
+ code += " return null;\n";
+ code += " }\n";
+ }
+
+ if (opts.generate_object_based_api) {
+ GenPackUnPack_ObjectAPI(struct_def, code_ptr, opts, struct_has_create,
+ field_has_create_set);
+ }
+ code += "};\n\n";
+
+ if (opts.generate_object_based_api) {
+ GenStruct_ObjectAPI(struct_def, code_ptr, opts);
+ }
+ }
+
+ void GenVectorAccessObject(StructDef &struct_def,
+ std::string *code_ptr) const {
+ auto &code = *code_ptr;
+ // Generate a vector of structs accessor class.
+ code += "\n";
+ code += " ";
+ if (!struct_def.attributes.Lookup("private")) code += "public ";
+ code += "static struct Vector : BaseVector\n{\n";
+
+ // Generate the __assign method that sets the field in a pre-existing
+ // accessor object. This is to allow object reuse.
+ std::string method_indent = " ";
+ code += method_indent + "public Vector ";
+ code += "__assign(int _vector, int _element_size, ByteBuffer _bb) { ";
+ code += "__reset(_vector, _element_size, _bb); return this; }\n\n";
+
+ auto type_name = struct_def.name;
+ auto method_start = method_indent + "public " + type_name + " Get";
+ // Generate the accessors that don't do object reuse.
+ code += method_start + "(int j) { return Get";
+ code += "(new " + type_name + "(), j); }\n";
+ code += method_start + "(" + type_name + " obj, int j) { ";
+ code += " return obj.__assign(";
+ code += struct_def.fixed ? "__p.__element(j)"
+ : "__p.__indirect(__p.__element(j), bb)";
+ code += ", __p.bb); }\n";
+ // See if we should generate a by-key accessor.
+ if (!struct_def.fixed) {
+ auto &fields = struct_def.fields.vec;
+ for (auto kit = fields.begin(); kit != fields.end(); ++kit) {
+ auto &key_field = **kit;
+ if (key_field.key) {
+ auto nullable_annotation =
+ parser_.opts.gen_nullable ? "@Nullable " : "";
+ code += method_indent + nullable_annotation;
+ code += "public " + type_name + "? ";
+ code += "GetByKey(";
+ code += GenTypeGet(key_field.value.type) + " key) { ";
+ code += " return __lookup_by_key(null, ";
+ code += "__p.__vector(), key, ";
+ code += "__p.bb); ";
+ code += "}\n";
+ code += method_indent + nullable_annotation;
+ code += "public " + type_name + "?" + " ";
+ code += "GetByKey(";
+ code += type_name + "? obj, ";
+ code += GenTypeGet(key_field.value.type) + " key) { ";
+ code += " return __lookup_by_key(obj, ";
+ code += "__p.__vector(), key, ";
+ code += "__p.bb); ";
+ code += "}\n";
+ break;
+ }
+ }
+ }
+ code += " }\n";
+ }
+
+ void GenEnum_ObjectAPI(EnumDef &enum_def, std::string *code_ptr,
+ const IDLOptions &opts) const {
+ auto &code = *code_ptr;
+ if (enum_def.generated) return;
+ if (!enum_def.is_union) return;
+ if (enum_def.attributes.Lookup("private")) {
+ code += "internal ";
+ } else {
+ code += "public ";
+ }
+ auto union_name = enum_def.name + "Union";
+ code += "class " + union_name + " {\n";
+ // Type
+ code += " public " + enum_def.name + " Type { get; set; }\n";
+ // Value
+ code += " public object Value { get; set; }\n";
+ code += "\n";
+ // Constructor
+ code += " public " + union_name + "() {\n";
+ code += " this.Type = " + enum_def.name + "." +
+ enum_def.Vals()[0]->name + ";\n";
+ code += " this.Value = null;\n";
+ code += " }\n\n";
+ // As<T>
+ code += " public T As<T>() where T : class { return this.Value as T; }\n";
+ // As
+ for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
+ auto &ev = **it;
+ if (ev.union_type.base_type == BASE_TYPE_NONE) continue;
+ auto type_name = GenTypeGet_ObjectAPI(ev.union_type, opts);
+ if (ev.union_type.base_type == BASE_TYPE_STRUCT &&
+ ev.union_type.struct_def->attributes.Lookup("private")) {
+ code += " internal ";
+ } else {
+ code += " public ";
+ }
+ code += type_name + " As" + ev.name + "() { return this.As<" + type_name +
+ ">(); }\n";
+ }
+ code += "\n";
+ // Pack()
+ code += " public static int Pack(FlatBuffers.FlatBufferBuilder builder, " +
+ union_name + " _o) {\n";
+ code += " switch (_o.Type) {\n";
+ for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
+ auto &ev = **it;
+ if (ev.union_type.base_type == BASE_TYPE_NONE) {
+ code += " default: return 0;\n";
+ } else {
+ code += " case " + enum_def.name + "." + ev.name + ": return ";
+ if (IsString(ev.union_type)) {
+ code += "builder.CreateString(_o.As" + ev.name + "()).Value;\n";
+ } else {
+ code += GenTypeGet(ev.union_type) + ".Pack(builder, _o.As" + ev.name +
+ "()).Value;\n";
+ }
+ }
+ }
+ code += " }\n";
+ code += " }\n";
+ code += "}\n\n";
+ // JsonConverter
+ if (opts.cs_gen_json_serializer) {
+ if (enum_def.attributes.Lookup("private")) {
+ code += "internal ";
+ } else {
+ code += "public ";
+ }
+ code += "class " + union_name +
+ "_JsonConverter : Newtonsoft.Json.JsonConverter {\n";
+ code += " public override bool CanConvert(System.Type objectType) {\n";
+ code += " return objectType == typeof(" + union_name +
+ ") || objectType == typeof(System.Collections.Generic.List<" +
+ union_name + ">);\n";
+ code += " }\n";
+ code +=
+ " public override void WriteJson(Newtonsoft.Json.JsonWriter writer, "
+ "object value, "
+ "Newtonsoft.Json.JsonSerializer serializer) {\n";
+ code += " var _olist = value as System.Collections.Generic.List<" +
+ union_name + ">;\n";
+ code += " if (_olist != null) {\n";
+ code += " writer.WriteStartArray();\n";
+ code +=
+ " foreach (var _o in _olist) { this.WriteJson(writer, _o, "
+ "serializer); }\n";
+ code += " writer.WriteEndArray();\n";
+ code += " } else {\n";
+ code += " this.WriteJson(writer, value as " + union_name +
+ ", serializer);\n";
+ code += " }\n";
+ code += " }\n";
+ code += " public void WriteJson(Newtonsoft.Json.JsonWriter writer, " +
+ union_name +
+ " _o, "
+ "Newtonsoft.Json.JsonSerializer serializer) {\n";
+ code += " if (_o == null) return;\n";
+ code += " serializer.Serialize(writer, _o.Value);\n";
+ code += " }\n";
+ code +=
+ " public override object ReadJson(Newtonsoft.Json.JsonReader "
+ "reader, "
+ "System.Type objectType, "
+ "object existingValue, Newtonsoft.Json.JsonSerializer serializer) "
+ "{\n";
+ code +=
+ " var _olist = existingValue as System.Collections.Generic.List<" +
+ union_name + ">;\n";
+ code += " if (_olist != null) {\n";
+ code += " for (var _j = 0; _j < _olist.Count; ++_j) {\n";
+ code += " reader.Read();\n";
+ code +=
+ " _olist[_j] = this.ReadJson(reader, _olist[_j], "
+ "serializer);\n";
+ code += " }\n";
+ code += " reader.Read();\n";
+ code += " return _olist;\n";
+ code += " } else {\n";
+ code += " return this.ReadJson(reader, existingValue as " +
+ union_name + ", serializer);\n";
+ code += " }\n";
+ code += " }\n";
+ code += " public " + union_name +
+ " ReadJson(Newtonsoft.Json.JsonReader reader, " + union_name +
+ " _o, Newtonsoft.Json.JsonSerializer serializer) {\n";
+ code += " if (_o == null) return null;\n";
+ code += " switch (_o.Type) {\n";
+ for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
+ ++it) {
+ auto &ev = **it;
+ if (ev.union_type.base_type == BASE_TYPE_NONE) {
+ code += " default: break;\n";
+ } else {
+ auto type_name = GenTypeGet_ObjectAPI(ev.union_type, opts);
+ code += " case " + enum_def.name + "." + ev.name +
+ ": _o.Value = serializer.Deserialize<" + type_name +
+ ">(reader); break;\n";
+ }
+ }
+ code += " }\n";
+ code += " return _o;\n";
+ code += " }\n";
+ code += "}\n\n";
+ }
+ }
+
+ std::string GenTypeName_ObjectAPI(const std::string &name,
+ const IDLOptions &opts) const {
+ return opts.object_prefix + name + opts.object_suffix;
+ }
+
+ void GenUnionUnPack_ObjectAPI(const EnumDef &enum_def, std::string *code_ptr,
+ const std::string &camel_name,
+ bool is_vector) const {
+ auto &code = *code_ptr;
+ std::string varialbe_name = "_o." + camel_name;
+ std::string type_suffix = "";
+ std::string func_suffix = "()";
+ std::string indent = " ";
+ if (is_vector) {
+ varialbe_name = "_o_" + camel_name;
+ type_suffix = "(_j)";
+ func_suffix = "(_j)";
+ indent = " ";
+ }
+ if (is_vector) {
+ code += indent + "var " + varialbe_name + " = new ";
+ } else {
+ code += indent + varialbe_name + " = new ";
+ }
+ code += WrapInNameSpace(enum_def) + "Union();\n";
+ code += indent + varialbe_name + ".Type = this." + camel_name + "Type" +
+ type_suffix + ";\n";
+ code +=
+ indent + "switch (this." + camel_name + "Type" + type_suffix + ") {\n";
+ for (auto eit = enum_def.Vals().begin(); eit != enum_def.Vals().end();
+ ++eit) {
+ auto &ev = **eit;
+ if (ev.union_type.base_type == BASE_TYPE_NONE) {
+ code += indent + " default: break;\n";
+ } else {
+ code += indent + " case " + WrapInNameSpace(enum_def) + "." + ev.name +
+ ":\n";
+ code += indent + " " + varialbe_name + ".Value = this." + camel_name;
+ if (IsString(ev.union_type)) {
+ code += "AsString" + func_suffix + ";\n";
+ } else {
+ code += "<" + GenTypeGet(ev.union_type) + ">" + func_suffix;
+ code += ".HasValue ? this." + camel_name;
+ code += "<" + GenTypeGet(ev.union_type) + ">" + func_suffix +
+ ".Value.UnPack() : null;\n";
+ }
+ code += indent + " break;\n";
+ }
+ }
+ code += indent + "}\n";
+ if (is_vector) {
+ code += indent + "_o." + camel_name + ".Add(" + varialbe_name + ");\n";
+ }
+ }
+
+ void GenPackUnPack_ObjectAPI(
+ StructDef &struct_def, std::string *code_ptr, const IDLOptions &opts,
+ bool struct_has_create,
+ const std::set<FieldDef *> &field_has_create) const {
+ auto &code = *code_ptr;
+ auto struct_name = GenTypeName_ObjectAPI(struct_def.name, opts);
+ // UnPack()
+ code += " public " + struct_name + " UnPack() {\n";
+ code += " var _o = new " + struct_name + "();\n";
+ code += " this.UnPackTo(_o);\n";
+ code += " return _o;\n";
+ code += " }\n";
+ // UnPackTo()
+ code += " public void UnPackTo(" + struct_name + " _o) {\n";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+ auto camel_name = MakeCamel(field.name);
+ auto start = " _o." + camel_name + " = ";
+ switch (field.value.type.base_type) {
+ case BASE_TYPE_STRUCT: {
+ auto fixed = struct_def.fixed && field.value.type.struct_def->fixed;
+ if (fixed) {
+ code += start + "this." + camel_name + ".UnPack();\n";
+ } else {
+ code += start + "this." + camel_name + ".HasValue ? this." +
+ camel_name + ".Value.UnPack() : null;\n";
+ }
+ break;
+ }
+ case BASE_TYPE_ARRAY: {
+ auto type_name = GenTypeGet_ObjectAPI(field.value.type, opts);
+ auto length_str = NumToString(field.value.type.fixed_length);
+ auto unpack_method = field.value.type.struct_def == nullptr ? ""
+ : field.value.type.struct_def->fixed
+ ? ".UnPack()"
+ : "?.UnPack()";
+ code += start + "new " + type_name.substr(0, type_name.length() - 1) +
+ length_str + "];\n";
+ code += " for (var _j = 0; _j < " + length_str + "; ++_j) { _o." +
+ camel_name + "[_j] = this." + camel_name + "(_j)" +
+ unpack_method + "; }\n";
+ break;
+ }
+ case BASE_TYPE_VECTOR:
+ if (field.value.type.element == BASE_TYPE_UNION) {
+ code += start + "new " +
+ GenTypeGet_ObjectAPI(field.value.type, opts) + "();\n";
+ code += " for (var _j = 0; _j < this." + camel_name +
+ "Length; ++_j) {\n";
+ GenUnionUnPack_ObjectAPI(*field.value.type.enum_def, code_ptr,
+ camel_name, true);
+ code += " }\n";
+ } else if (field.value.type.element != BASE_TYPE_UTYPE) {
+ auto fixed = field.value.type.struct_def == nullptr;
+ code += start + "new " +
+ GenTypeGet_ObjectAPI(field.value.type, opts) + "();\n";
+ code += " for (var _j = 0; _j < this." + camel_name +
+ "Length; ++_j) {";
+ code += "_o." + camel_name + ".Add(";
+ if (fixed) {
+ code += "this." + camel_name + "(_j)";
+ } else {
+ code += "this." + camel_name + "(_j).HasValue ? this." +
+ camel_name + "(_j).Value.UnPack() : null";
+ }
+ code += ");}\n";
+ }
+ break;
+ case BASE_TYPE_UTYPE: break;
+ case BASE_TYPE_UNION: {
+ GenUnionUnPack_ObjectAPI(*field.value.type.enum_def, code_ptr,
+ camel_name, false);
+ break;
+ }
+ default: {
+ code += start + "this." + camel_name + ";\n";
+ break;
+ }
+ }
+ }
+ code += " }\n";
+ // Pack()
+ code += " public static " + GenOffsetType(struct_def) +
+ " Pack(FlatBufferBuilder builder, " + struct_name + " _o) {\n";
+ code += " if (_o == null) return default(" + GenOffsetType(struct_def) +
+ ");\n";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+ auto camel_name = MakeCamel(field.name);
+ // pre
+ switch (field.value.type.base_type) {
+ case BASE_TYPE_STRUCT: {
+ if (!field.value.type.struct_def->fixed) {
+ code += " var _" + field.name + " = _o." + camel_name +
+ " == null ? default(" +
+ GenOffsetType(*field.value.type.struct_def) +
+ ") : " + GenTypeGet(field.value.type) +
+ ".Pack(builder, _o." + camel_name + ");\n";
+ } else if (struct_def.fixed && struct_has_create) {
+ std::vector<FieldArrayLength> array_lengths;
+ FieldArrayLength tmp_array_length = {
+ field.name,
+ field.value.type.fixed_length,
+ };
+ array_lengths.push_back(tmp_array_length);
+ GenStructPackDecl_ObjectAPI(*field.value.type.struct_def, code_ptr,
+ array_lengths);
+ }
+ break;
+ }
+ case BASE_TYPE_STRING: {
+ std::string create_string =
+ field.shared ? "CreateSharedString" : "CreateString";
+ code += " var _" + field.name + " = _o." + camel_name +
+ " == null ? default(StringOffset) : "
+ "builder." +
+ create_string + "(_o." + camel_name + ");\n";
+ break;
+ }
+ case BASE_TYPE_VECTOR: {
+ if (field_has_create.find(&field) != field_has_create.end()) {
+ auto property_name = camel_name;
+ auto gen_for_loop = true;
+ std::string array_name = "__" + field.name;
+ std::string array_type = "";
+ std::string to_array = "";
+ switch (field.value.type.element) {
+ case BASE_TYPE_STRING: {
+ std::string create_string =
+ field.shared ? "CreateSharedString" : "CreateString";
+ array_type = "StringOffset";
+ to_array += "builder." + create_string + "(_o." +
+ property_name + "[_j])";
+ break;
+ }
+ case BASE_TYPE_STRUCT:
+ array_type = "Offset<" + GenTypeGet(field.value.type) + ">";
+ to_array = GenTypeGet(field.value.type) + ".Pack(builder, _o." +
+ property_name + "[_j])";
+ break;
+ case BASE_TYPE_UTYPE:
+ property_name = camel_name.substr(0, camel_name.size() - 4);
+ array_type = WrapInNameSpace(*field.value.type.enum_def);
+ to_array = "_o." + property_name + "[_j].Type";
+ break;
+ case BASE_TYPE_UNION:
+ array_type = "int";
+ to_array = WrapInNameSpace(*field.value.type.enum_def) +
+ "Union.Pack(builder, _o." + property_name + "[_j])";
+ break;
+ default: gen_for_loop = false; break;
+ }
+ code += " var _" + field.name + " = default(VectorOffset);\n";
+ code += " if (_o." + property_name + " != null) {\n";
+ if (gen_for_loop) {
+ code += " var " + array_name + " = new " + array_type +
+ "[_o." + property_name + ".Count];\n";
+ code += " for (var _j = 0; _j < " + array_name +
+ ".Length; ++_j) { ";
+ code += array_name + "[_j] = " + to_array + "; }\n";
+ } else {
+ code += " var " + array_name + " = _o." + property_name +
+ ".ToArray();\n";
+ }
+ code += " _" + field.name + " = Create" + camel_name +
+ "Vector(builder, " + array_name + ");\n";
+ code += " }\n";
+ } else {
+ auto pack_method =
+ field.value.type.struct_def == nullptr
+ ? "builder.Add" + GenMethod(field.value.type.VectorType()) +
+ "(_o." + camel_name + "[_j]);"
+ : GenTypeGet(field.value.type) + ".Pack(builder, _o." +
+ camel_name + "[_j]);";
+ code += " var _" + field.name + " = default(VectorOffset);\n";
+ code += " if (_o." + camel_name + " != null) {\n";
+ code += " Start" + camel_name + "Vector(builder, _o." +
+ camel_name + ".Count);\n";
+ code += " for (var _j = _o." + camel_name +
+ ".Count - 1; _j >= 0; --_j) { " + pack_method + " }\n";
+ code += " _" + field.name + " = builder.EndVector();\n";
+ code += " }\n";
+ }
+ break;
+ }
+ case BASE_TYPE_ARRAY: {
+ if (field.value.type.struct_def != nullptr) {
+ std::vector<FieldArrayLength> array_lengths;
+ FieldArrayLength tmp_array_length = {
+ field.name,
+ field.value.type.fixed_length,
+ };
+ array_lengths.push_back(tmp_array_length);
+ GenStructPackDecl_ObjectAPI(*field.value.type.struct_def, code_ptr,
+ array_lengths);
+ } else {
+ code += " var _" + field.name + " = _o." + camel_name + ";\n";
+ }
+ break;
+ }
+ case BASE_TYPE_UNION: {
+ code += " var _" + field.name + "_type = _o." + camel_name +
+ " == null ? " + WrapInNameSpace(*field.value.type.enum_def) +
+ ".NONE : " + "_o." + camel_name + ".Type;\n";
+ code +=
+ " var _" + field.name + " = _o." + camel_name +
+ " == null ? 0 : " + GenTypeGet_ObjectAPI(field.value.type, opts) +
+ ".Pack(builder, _o." + camel_name + ");\n";
+ break;
+ }
+ default: break;
+ }
+ }
+ if (struct_has_create) {
+ // Create
+ code += " return Create" + struct_def.name + "(\n";
+ code += " builder";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+ auto camel_name = MakeCamel(field.name);
+ switch (field.value.type.base_type) {
+ case BASE_TYPE_STRUCT: {
+ if (struct_def.fixed) {
+ GenStructPackCall_ObjectAPI(*field.value.type.struct_def,
+ code_ptr,
+ " _" + field.name + "_");
+ } else {
+ code += ",\n";
+ if (field.value.type.struct_def->fixed) {
+ if (opts.generate_object_based_api)
+ code += " _o." + camel_name;
+ else
+ code += " " + GenTypeGet(field.value.type) +
+ ".Pack(builder, _o." + camel_name + ")";
+ } else {
+ code += " _" + field.name;
+ }
+ }
+ break;
+ }
+ case BASE_TYPE_ARRAY: {
+ if (field.value.type.struct_def != nullptr) {
+ GenStructPackCall_ObjectAPI(*field.value.type.struct_def,
+ code_ptr,
+ " _" + field.name + "_");
+ } else {
+ code += ",\n";
+ code += " _" + field.name;
+ }
+ break;
+ }
+ case BASE_TYPE_UNION: FLATBUFFERS_FALLTHROUGH(); // fall thru
+ case BASE_TYPE_UTYPE: FLATBUFFERS_FALLTHROUGH(); // fall thru
+ case BASE_TYPE_STRING: FLATBUFFERS_FALLTHROUGH(); // fall thru
+ case BASE_TYPE_VECTOR: {
+ code += ",\n";
+ code += " _" + field.name;
+ break;
+ }
+ default: // scalar
+ code += ",\n";
+ code += " _o." + camel_name;
+ break;
+ }
+ }
+ code += ");\n";
+ } else {
+ // Start, End
+ code += " Start" + struct_def.name + "(builder);\n";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+ auto camel_name = MakeCamel(field.name);
+ switch (field.value.type.base_type) {
+ case BASE_TYPE_STRUCT: {
+ if (field.value.type.struct_def->fixed) {
+ code += " Add" + camel_name + "(builder, " +
+ GenTypeGet(field.value.type) + ".Pack(builder, _o." +
+ camel_name + "));\n";
+ } else {
+ code +=
+ " Add" + camel_name + "(builder, _" + field.name + ");\n";
+ }
+ break;
+ }
+ case BASE_TYPE_STRING: FLATBUFFERS_FALLTHROUGH(); // fall thru
+ case BASE_TYPE_ARRAY: FLATBUFFERS_FALLTHROUGH(); // fall thru
+ case BASE_TYPE_VECTOR: {
+ code +=
+ " Add" + camel_name + "(builder, _" + field.name + ");\n";
+ break;
+ }
+ case BASE_TYPE_UTYPE: break;
+ case BASE_TYPE_UNION: {
+ code += " Add" + camel_name + "Type(builder, _" + field.name +
+ "_type);\n";
+ code +=
+ " Add" + camel_name + "(builder, _" + field.name + ");\n";
+ break;
+ }
+ // scalar
+ default: {
+ code +=
+ " Add" + camel_name + "(builder, _o." + camel_name + ");\n";
+ break;
+ }
+ }
+ }
+ code += " return End" + struct_def.name + "(builder);\n";
+ }
+ code += " }\n";
+ }
+
+ void GenStructPackDecl_ObjectAPI(
+ const StructDef &struct_def, std::string *code_ptr,
+ std::vector<FieldArrayLength> &array_lengths) const {
+ auto &code = *code_ptr;
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ auto is_array = IsArray(field.value.type);
+ const auto &field_type =
+ is_array ? field.value.type.VectorType() : field.value.type;
+ FieldArrayLength tmp_array_length = {
+ field.name,
+ field_type.fixed_length,
+ };
+ array_lengths.push_back(tmp_array_length);
+ if (field_type.struct_def != nullptr) {
+ GenStructPackDecl_ObjectAPI(*field_type.struct_def, code_ptr,
+ array_lengths);
+ } else {
+ std::vector<FieldArrayLength> array_only_lengths;
+ for (size_t i = 0; i < array_lengths.size(); ++i) {
+ if (array_lengths[i].length > 0) {
+ array_only_lengths.push_back(array_lengths[i]);
+ }
+ }
+ std::string name;
+ for (size_t i = 0; i < array_lengths.size(); ++i) {
+ name += "_" + array_lengths[i].name;
+ }
+ code += " var " + name + " = ";
+ if (array_only_lengths.size() > 0) {
+ code += "new " + GenTypeBasic(field_type) + "[";
+ for (size_t i = 0; i < array_only_lengths.size(); ++i) {
+ if (i != 0) { code += ","; }
+ code += NumToString(array_only_lengths[i].length);
+ }
+ code += "];\n";
+ code += " ";
+ // initialize array
+ for (size_t i = 0; i < array_only_lengths.size(); ++i) {
+ auto idx = "idx" + NumToString(i);
+ code += "for (var " + idx + " = 0; " + idx + " < " +
+ NumToString(array_only_lengths[i].length) + "; ++" + idx +
+ ") {";
+ }
+ for (size_t i = 0; i < array_only_lengths.size(); ++i) {
+ auto idx = "idx" + NumToString(i);
+ if (i == 0) {
+ code += name + "[" + idx;
+ } else {
+ code += "," + idx;
+ }
+ }
+ code += "] = _o";
+ for (size_t i = 0, j = 0; i < array_lengths.size(); ++i) {
+ code += "." + MakeCamel(array_lengths[i].name);
+ if (array_lengths[i].length <= 0) continue;
+ code += "[idx" + NumToString(j++) + "]";
+ }
+ code += ";";
+ for (size_t i = 0; i < array_only_lengths.size(); ++i) {
+ code += "}";
+ }
+ } else {
+ code += "_o";
+ for (size_t i = 0; i < array_lengths.size(); ++i) {
+ code += "." + MakeCamel(array_lengths[i].name);
+ }
+ code += ";";
+ }
+ code += "\n";
+ }
+ array_lengths.pop_back();
+ }
+ }
+
+ void GenStructPackCall_ObjectAPI(const StructDef &struct_def,
+ std::string *code_ptr,
+ std::string prefix) const {
+ auto &code = *code_ptr;
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ const auto &field_type = field.value.type;
+ if (field_type.struct_def != nullptr) {
+ GenStructPackCall_ObjectAPI(*field_type.struct_def, code_ptr,
+ prefix + field.name + "_");
+ } else {
+ code += ",\n";
+ code += prefix + field.name;
+ }
+ }
+ }
+
+ std::string GenTypeGet_ObjectAPI(flatbuffers::Type type,
+ const IDLOptions &opts) const {
+ auto type_name = GenTypeGet(type);
+ // Replace to ObjectBaseAPI Type Name
+ switch (type.base_type) {
+ case BASE_TYPE_STRUCT: FLATBUFFERS_FALLTHROUGH(); // fall thru
+ case BASE_TYPE_ARRAY: FLATBUFFERS_FALLTHROUGH(); // fall thru
+ case BASE_TYPE_VECTOR: {
+ if (type.struct_def != nullptr) {
+ auto type_name_length = type.struct_def->name.length();
+ auto new_type_name =
+ GenTypeName_ObjectAPI(type.struct_def->name, opts);
+ type_name.replace(type_name.length() - type_name_length,
+ type_name_length, new_type_name);
+ } else if (type.element == BASE_TYPE_UNION) {
+ type_name = WrapInNameSpace(*type.enum_def) + "Union";
+ }
+ break;
+ }
+
+ case BASE_TYPE_UNION: {
+ type_name = WrapInNameSpace(*type.enum_def) + "Union";
+ break;
+ }
+ default: break;
+ }
+
+ switch (type.base_type) {
+ case BASE_TYPE_ARRAY: {
+ type_name = type_name + "[]";
+ break;
+ }
+ case BASE_TYPE_VECTOR: {
+ type_name = "List<" + type_name + ">";
+ break;
+ }
+ default: break;
+ }
+ return type_name;
+ }
+
+ void GenStruct_ObjectAPI(StructDef &struct_def, std::string *code_ptr,
+ const IDLOptions &opts) const {
+ auto &code = *code_ptr;
+ if (struct_def.attributes.Lookup("private")) {
+ code += "internal ";
+ } else {
+ code += "public ";
+ }
+ if (struct_def.attributes.Lookup("csharp_partial")) {
+ // generate a partial class for this C# struct/table
+ code += "partial ";
+ }
+ auto class_name = GenTypeName_ObjectAPI(struct_def.name, opts);
+ code += "class " + class_name;
+ code += "\n{\n";
+ // Generate Properties
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+ if (field.value.type.base_type == BASE_TYPE_UTYPE) continue;
+ if (field.value.type.element == BASE_TYPE_UTYPE) continue;
+ auto type_name = GenTypeGet_ObjectAPI(field.value.type, opts);
+ auto camel_name = MakeCamel(field.name, true);
+ if (opts.cs_gen_json_serializer) {
+ if (IsUnion(field.value.type)) {
+ auto utype_name = WrapInNameSpace(*field.value.type.enum_def);
+ code +=
+ " [Newtonsoft.Json.JsonProperty(\"" + field.name + "_type\")]\n";
+ if (IsVector(field.value.type)) {
+ code += " private " + utype_name + "[] " + camel_name + "Type {\n";
+ code += " get {\n";
+ code += " if (this." + camel_name + " == null) return null;\n";
+ code += " var _o = new " + utype_name + "[this." + camel_name +
+ ".Count];\n";
+ code +=
+ " for (var _j = 0; _j < _o.Length; ++_j) { _o[_j] = "
+ "this." +
+ camel_name + "[_j].Type; }\n";
+ code += " return _o;\n";
+ code += " }\n";
+ code += " set {\n";
+ code += " this." + camel_name + " = new List<" + utype_name +
+ "Union>();\n";
+ code += " for (var _j = 0; _j < value.Length; ++_j) {\n";
+ code += " var _o = new " + utype_name + "Union();\n";
+ code += " _o.Type = value[_j];\n";
+ code += " this." + camel_name + ".Add(_o);\n";
+ code += " }\n";
+ code += " }\n";
+ code += " }\n";
+ } else {
+ code += " private " + utype_name + " " + camel_name + "Type {\n";
+ code += " get {\n";
+ code += " return this." + camel_name + " != null ? this." +
+ camel_name + ".Type : " + utype_name + ".NONE;\n";
+ code += " }\n";
+ code += " set {\n";
+ code += " this." + camel_name + " = new " + utype_name +
+ "Union();\n";
+ code += " this." + camel_name + ".Type = value;\n";
+ code += " }\n";
+ code += " }\n";
+ }
+ }
+ code += " [Newtonsoft.Json.JsonProperty(\"" + field.name + "\")]\n";
+ if (IsUnion(field.value.type)) {
+ auto union_name =
+ (IsVector(field.value.type))
+ ? GenTypeGet_ObjectAPI(field.value.type.VectorType(), opts)
+ : type_name;
+ code += " [Newtonsoft.Json.JsonConverter(typeof(" + union_name +
+ "_JsonConverter))]\n";
+ }
+ if (field.attributes.Lookup("hash")) {
+ code += " [Newtonsoft.Json.JsonIgnore()]\n";
+ }
+ }
+ code += " public " + type_name + " " + camel_name + " { get; set; }\n";
+ }
+ // Generate Constructor
+ code += "\n";
+ code += " public " + class_name + "() {\n";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+ if (field.value.type.base_type == BASE_TYPE_UTYPE) continue;
+ if (field.value.type.element == BASE_TYPE_UTYPE) continue;
+ code += " this." + MakeCamel(field.name) + " = ";
+ auto type_name = GenTypeGet_ObjectAPI(field.value.type, opts);
+ if (IsScalar(field.value.type.base_type)) {
+ code += GenDefaultValue(field) + ";\n";
+ } else {
+ switch (field.value.type.base_type) {
+ case BASE_TYPE_STRUCT: {
+ if (IsStruct(field.value.type)) {
+ code += "new " + type_name + "();\n";
+ } else {
+ code += "null;\n";
+ }
+ break;
+ }
+ case BASE_TYPE_ARRAY: {
+ code += "new " + type_name.substr(0, type_name.length() - 1) +
+ NumToString(field.value.type.fixed_length) + "];\n";
+ break;
+ }
+ default: {
+ code += "null;\n";
+ break;
+ }
+ }
+ }
+ }
+ code += " }\n";
+ // Generate Serialization
+ if (opts.cs_gen_json_serializer &&
+ parser_.root_struct_def_ == &struct_def) {
+ code += "\n";
+ code += " public static " + class_name +
+ " DeserializeFromJson(string jsonText) {\n";
+ code += " return Newtonsoft.Json.JsonConvert.DeserializeObject<" +
+ class_name + ">(jsonText);\n";
+ code += " }\n";
+ code += " public string SerializeToJson() {\n";
+ code +=
+ " return Newtonsoft.Json.JsonConvert.SerializeObject(this, "
+ "Newtonsoft.Json.Formatting.Indented);\n";
+ code += " }\n";
+ }
+ if (parser_.root_struct_def_ == &struct_def) {
+ code += " public static " + class_name +
+ " DeserializeFromBinary(byte[] fbBuffer) {\n";
+ code += " return " + struct_def.name + ".GetRootAs" + struct_def.name +
+ "(new ByteBuffer(fbBuffer)).UnPack();\n";
+ code += " }\n";
+ code += " public byte[] SerializeToBinary() {\n";
+ code += " var fbb = new FlatBufferBuilder(0x10000);\n";
+ code += " " + struct_def.name + ".Finish" + struct_def.name +
+ "Buffer(fbb, " + struct_def.name + ".Pack(fbb, this));\n";
+ code += " return fbb.DataBuffer.ToSizedArray();\n";
+ code += " }\n";
+ }
+ code += "}\n\n";
+ }
+
+ // This tracks the current namespace used to determine if a type need to be
+ // prefixed by its namespace
+ const Namespace *cur_name_space_;
+};
+} // namespace csharp
+
+bool GenerateCSharp(const Parser &parser, const std::string &path,
+ const std::string &file_name) {
+ csharp::CSharpGenerator generator(parser, path, file_name);
+ return generator.generate();
+}
+
+} // namespace flatbuffers
diff --git a/src/idl_gen_dart.cpp b/src/idl_gen_dart.cpp
index 2346a85..eec05a7 100644
--- a/src/idl_gen_dart.cpp
+++ b/src/idl_gen_dart.cpp
@@ -24,11 +24,6 @@
namespace flatbuffers {
-static std::string GeneratedFileName(const std::string &path,
- const std::string &file_name) {
- return path + file_name + "_generated.dart";
-}
-
namespace dart {
const std::string _kFb = "fb";
@@ -55,7 +50,7 @@
DartGenerator(const Parser &parser, const std::string &path,
const std::string &file_name)
- : BaseGenerator(parser, path, file_name, "", ".") {}
+ : BaseGenerator(parser, path, file_name, "", ".", "dart") {}
// Iterate through all definitions we haven't generate code for (enums,
// structs, and tables) and output them to a single file.
bool generate() {
@@ -71,29 +66,33 @@
"// ignore_for_file: unused_import, unused_field, "
"unused_local_variable\n\n";
- code += "library " + kv->first + ";\n\n";
+ if (!kv->first.empty()) { code += "library " + kv->first + ";\n\n"; }
code += "import 'dart:typed_data' show Uint8List;\n";
code += "import 'package:flat_buffers/flat_buffers.dart' as " + _kFb +
";\n\n";
- if (parser_.opts.include_dependence_headers) {
- GenIncludeDependencies(&code, kv->first);
- }
-
for (auto kv2 = namespace_code.begin(); kv2 != namespace_code.end();
++kv2) {
if (kv2->first != kv->first) {
- code += "import '" +
- GeneratedFileName("./", file_name_ + "_" + kv2->first) +
- "' as " + ImportAliasName(kv2->first) + ";\n";
+ code +=
+ "import '" +
+ GeneratedFileName(
+ "./",
+ file_name_ + (!kv2->first.empty() ? "_" + kv2->first : ""),
+ parser_.opts) +
+ "' as " + ImportAliasName(kv2->first) + ";\n";
}
}
code += "\n";
code += kv->second;
if (!SaveFile(
- GeneratedFileName(path_, file_name_ + "_" + kv->first).c_str(),
+ GeneratedFileName(
+ path_,
+ file_name_ + (!kv->first.empty() ? "_" + kv->first : ""),
+ parser_.opts)
+ .c_str(),
code, false)) {
return false;
}
@@ -115,26 +114,28 @@
}
static std::string BuildNamespaceName(const Namespace &ns) {
+ if (ns.components.empty()) { return ""; }
std::stringstream sstream;
std::copy(ns.components.begin(), ns.components.end() - 1,
std::ostream_iterator<std::string>(sstream, "."));
auto ret = sstream.str() + ns.components.back();
for (size_t i = 0; i < ret.size(); i++) {
- auto lower = tolower(ret[i]);
+ auto lower = CharToLower(ret[i]);
if (lower != ret[i]) {
- ret[i] = static_cast<char>(lower);
+ ret[i] = lower;
if (i != 0 && ret[i - 1] != '.') {
ret.insert(i, "_");
i++;
}
}
}
- // std::transform(ret.begin(), ret.end(), ret.begin(), ::tolower);
+ // std::transform(ret.begin(), ret.end(), ret.begin(), CharToLower);
return ret;
}
- void GenIncludeDependencies(std::string* code, const std::string& the_namespace) {
+ void GenIncludeDependencies(std::string *code,
+ const std::string &the_namespace) {
for (auto it = parser_.included_files_.begin();
it != parser_.included_files_.end(); ++it) {
if (it->second.empty()) continue;
@@ -142,7 +143,12 @@
auto noext = flatbuffers::StripExtension(it->second);
auto basename = flatbuffers::StripPath(noext);
- *code += "import '" + GeneratedFileName("", basename + "_" + the_namespace) + "';\n";
+ *code +=
+ "import '" +
+ GeneratedFileName(
+ "", basename + (the_namespace == "" ? "" : "_" + the_namespace),
+ parser_.opts) +
+ "';\n";
}
}
@@ -261,7 +267,7 @@
code += "const " + name + "._(" + enum_def.ToString(ev) + ");\n";
}
- code += " static get values => {";
+ code += " static const values = {";
for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
auto &ev = **it;
code += enum_def.ToString(ev) + ": " + ev.name + ",";
@@ -324,13 +330,13 @@
bool parent_is_vector = false) {
if (type.base_type == BASE_TYPE_BOOL) {
return "const " + _kFb + ".BoolReader()";
- } else if (type.base_type == BASE_TYPE_VECTOR) {
+ } else if (IsVector(type)) {
return "const " + _kFb + ".ListReader<" +
GenDartTypeName(type.VectorType(), current_namespace, def) + ">(" +
GenReaderTypeName(type.VectorType(), current_namespace, def,
true) +
")";
- } else if (type.base_type == BASE_TYPE_STRING) {
+ } else if (IsString(type)) {
return "const " + _kFb + ".StringReader()";
}
if (IsScalar(type.base_type)) {
@@ -439,13 +445,23 @@
code += " final " + _kFb + ".BufferContext _bc;\n";
code += " final int _bcOffset;\n\n";
- GenImplementationGetters(struct_def, &code);
+ std::vector<std::pair<int, FieldDef *>> non_deprecated_fields;
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+ auto offset = static_cast<int>(it - struct_def.fields.vec.begin());
+ non_deprecated_fields.push_back(std::make_pair(offset, &field));
+ }
+
+ GenImplementationGetters(struct_def, non_deprecated_fields, &code);
code += "}\n\n";
GenReader(struct_def, &reader_name, &reader_code);
- GenBuilder(struct_def, &builder_name, &builder_code);
- GenObjectBuilder(struct_def, &object_builder_name, &builder_code);
+ GenBuilder(struct_def, non_deprecated_fields, &builder_name, &builder_code);
+ GenObjectBuilder(struct_def, non_deprecated_fields, &object_builder_name,
+ &builder_code);
code += reader_code;
code += builder_code;
@@ -453,42 +469,46 @@
(*namespace_code)[object_namespace] += code;
}
- std::string NamespaceAliasFromUnionType(const std::string &in) {
- if (in.find('_') == std::string::npos) { return in; }
+ std::string NamespaceAliasFromUnionType(Namespace *root_namespace,
+ const Type &type) {
+ const std::vector<std::string> qualified_name_parts =
+ type.struct_def->defined_namespace->components;
+ if (std::equal(root_namespace->components.begin(),
+ root_namespace->components.end(),
+ qualified_name_parts.begin())) {
+ return type.struct_def->name;
+ }
- std::stringstream ss(in);
- std::string item;
- std::vector<std::string> parts;
std::string ns;
- while (std::getline(ss, item, '_')) { parts.push_back(item); }
-
- for (auto it = parts.begin(); it != parts.end() - 1; ++it) {
+ for (auto it = qualified_name_parts.begin();
+ it != qualified_name_parts.end(); ++it) {
auto &part = *it;
for (size_t i = 0; i < part.length(); i++) {
- if (i && !isdigit(part[i]) &&
- part[i] == static_cast<char>(toupper(part[i]))) {
+ if (i && !isdigit(part[i]) && part[i] == CharToUpper(part[i])) {
ns += "_";
- ns += static_cast<char>(tolower(part[i]));
+ ns += CharToLower(part[i]);
} else {
- ns += static_cast<char>(tolower(part[i]));
+ ns += CharToLower(part[i]);
}
}
- if (it != parts.end() - 2) { ns += "_"; }
+ if (it != qualified_name_parts.end() - 1) { ns += "_"; }
}
- return ns + "." + parts.back();
+ return ns + "." + type.struct_def->name;
}
- void GenImplementationGetters(const StructDef &struct_def,
- std::string *code_ptr) {
+ void GenImplementationGetters(
+ const StructDef &struct_def,
+ std::vector<std::pair<int, FieldDef *>> non_deprecated_fields,
+ std::string *code_ptr) {
auto &code = *code_ptr;
- for (auto it = struct_def.fields.vec.begin();
- it != struct_def.fields.vec.end(); ++it) {
- auto &field = **it;
- if (field.deprecated) continue;
+ for (auto it = non_deprecated_fields.begin();
+ it != non_deprecated_fields.end(); ++it) {
+ auto pair = *it;
+ auto &field = *pair.second;
std::string field_name = MakeCamel(field.name, false);
std::string type_name = GenDartTypeName(
@@ -505,7 +525,8 @@
en_it != enum_def.Vals().end(); ++en_it) {
auto &ev = **en_it;
- auto enum_name = NamespaceAliasFromUnionType(ev.name);
+ auto enum_name = NamespaceAliasFromUnionType(
+ enum_def.defined_namespace, ev.union_type);
code += " case " + enum_def.ToString(ev) + ": return " +
enum_name + ".reader.vTableGet(_bc, _bcOffset, " +
NumToString(field.value.offset) + ", null);\n";
@@ -534,6 +555,15 @@
if (!field.value.constant.empty() && field.value.constant != "0") {
if (IsBool(field.value.type.base_type)) {
code += "true";
+ } else if (field.value.constant == "nan" ||
+ field.value.constant == "+nan" ||
+ field.value.constant == "-nan") {
+ code += "double.nan";
+ } else if (field.value.constant == "inf" ||
+ field.value.constant == "+inf") {
+ code += "double.infinity";
+ } else if (field.value.constant == "-inf") {
+ code += "double.negativeInfinity";
} else {
code += field.value.constant;
}
@@ -561,13 +591,13 @@
code += " @override\n";
code += " String toString() {\n";
code += " return '" + struct_def.name + "{";
- for (auto it = struct_def.fields.vec.begin();
- it != struct_def.fields.vec.end(); ++it) {
- auto &field = **it;
- if (field.deprecated) continue;
+ for (auto it = non_deprecated_fields.begin();
+ it != non_deprecated_fields.end(); ++it) {
+ auto pair = *it;
+ auto &field = *pair.second;
code +=
MakeCamel(field.name, false) + ": $" + MakeCamel(field.name, false);
- if (it != struct_def.fields.vec.end() - 1) { code += ", "; }
+ if (it != non_deprecated_fields.end() - 1) { code += ", "; }
}
code += "}';\n";
code += " }\n";
@@ -599,9 +629,10 @@
code += "}\n\n";
}
- void GenBuilder(const StructDef &struct_def, std::string *builder_name_ptr,
- std::string *code_ptr) {
- if (struct_def.fields.vec.size() == 0) { return; }
+ void GenBuilder(const StructDef &struct_def,
+ std::vector<std::pair<int, FieldDef *>> non_deprecated_fields,
+ std::string *builder_name_ptr, std::string *code_ptr) {
+ if (non_deprecated_fields.size() == 0) { return; }
auto &code = *code_ptr;
auto &builder_name = *builder_name_ptr;
@@ -612,22 +643,25 @@
code += " final " + _kFb + ".Builder fbBuilder;\n\n";
if (struct_def.fixed) {
- StructBuilderBody(struct_def, code_ptr);
+ StructBuilderBody(struct_def, non_deprecated_fields, code_ptr);
} else {
- TableBuilderBody(struct_def, code_ptr);
+ TableBuilderBody(struct_def, non_deprecated_fields, code_ptr);
}
code += "}\n\n";
}
- void StructBuilderBody(const StructDef &struct_def, std::string *code_ptr) {
+ void StructBuilderBody(
+ const StructDef &struct_def,
+ std::vector<std::pair<int, FieldDef *>> non_deprecated_fields,
+ std::string *code_ptr) {
auto &code = *code_ptr;
code += " int finish(";
- for (auto it = struct_def.fields.vec.begin();
- it != struct_def.fields.vec.end(); ++it) {
- auto &field = **it;
- if (field.deprecated) continue;
+ for (auto it = non_deprecated_fields.begin();
+ it != non_deprecated_fields.end(); ++it) {
+ auto pair = *it;
+ auto &field = *pair.second;
if (IsStruct(field.value.type)) {
code += "fb.StructBuilder";
@@ -636,15 +670,14 @@
field);
}
code += " " + field.name;
- if (it != struct_def.fields.vec.end() - 1) { code += ", "; }
+ if (it != non_deprecated_fields.end() - 1) { code += ", "; }
}
code += ") {\n";
- for (auto it = struct_def.fields.vec.rbegin();
- it != struct_def.fields.vec.rend(); ++it) {
- auto &field = **it;
-
- if (field.deprecated) continue;
+ for (auto it = non_deprecated_fields.rbegin();
+ it != non_deprecated_fields.rend(); ++it) {
+ auto pair = *it;
+ auto &field = *pair.second;
if (field.padding) {
code += " fbBuilder.pad(" + NumToString(field.padding) + ");\n";
@@ -663,19 +696,21 @@
code += " }\n\n";
}
- void TableBuilderBody(const StructDef &struct_def, std::string *code_ptr) {
+ void TableBuilderBody(
+ const StructDef &struct_def,
+ std::vector<std::pair<int, FieldDef *>> non_deprecated_fields,
+ std::string *code_ptr) {
auto &code = *code_ptr;
code += " void begin() {\n";
code += " fbBuilder.startTable();\n";
code += " }\n\n";
- for (auto it = struct_def.fields.vec.begin();
- it != struct_def.fields.vec.end(); ++it) {
- auto &field = **it;
- if (field.deprecated) continue;
-
- auto offset = it - struct_def.fields.vec.begin();
+ for (auto it = non_deprecated_fields.begin();
+ it != non_deprecated_fields.end(); ++it) {
+ auto pair = *it;
+ auto &field = *pair.second;
+ auto offset = pair.first;
if (IsScalar(field.value.type.base_type)) {
code += " int add" + MakeCamel(field.name) + "(";
@@ -706,16 +741,19 @@
code += " }\n";
}
- void GenObjectBuilder(const StructDef &struct_def,
- std::string *builder_name_ptr, std::string *code_ptr) {
+ void GenObjectBuilder(
+ const StructDef &struct_def,
+ std::vector<std::pair<int, FieldDef *>> non_deprecated_fields,
+ std::string *builder_name_ptr, std::string *code_ptr) {
auto &code = *code_ptr;
auto &builder_name = *builder_name_ptr;
code += "class " + builder_name + " extends " + _kFb + ".ObjectBuilder {\n";
- for (auto it = struct_def.fields.vec.begin();
- it != struct_def.fields.vec.end(); ++it) {
- auto &field = **it;
- if (field.deprecated) continue;
+ for (auto it = non_deprecated_fields.begin();
+ it != non_deprecated_fields.end(); ++it) {
+ auto pair = *it;
+ auto &field = *pair.second;
+
code += " final " +
GenDartTypeName(field.value.type, struct_def.defined_namespace,
field, true) +
@@ -723,14 +761,14 @@
}
code += "\n";
code += " " + builder_name + "(";
- if (struct_def.fields.vec.size() != 0) {
- code +=
- "{\n";
- for (auto it = struct_def.fields.vec.begin();
- it != struct_def.fields.vec.end(); ++it) {
- auto &field = **it;
- if (field.deprecated) continue;
+ if (non_deprecated_fields.size() != 0) {
+ code += "{\n";
+ for (auto it = non_deprecated_fields.begin();
+ it != non_deprecated_fields.end(); ++it) {
+ auto pair = *it;
+ auto &field = *pair.second;
+
code += " " +
GenDartTypeName(field.value.type, struct_def.defined_namespace,
field, true) +
@@ -738,13 +776,14 @@
}
code += " })\n";
code += " : ";
- for (auto it = struct_def.fields.vec.begin();
- it != struct_def.fields.vec.end(); ++it) {
- auto &field = **it;
- if (field.deprecated) continue;
+ for (auto it = non_deprecated_fields.begin();
+ it != non_deprecated_fields.end(); ++it) {
+ auto pair = *it;
+ auto &field = *pair.second;
+
code += "_" + MakeCamel(field.name, false) + " = " +
MakeCamel(field.name, false);
- if (it == struct_def.fields.vec.end() - 1) {
+ if (it == non_deprecated_fields.end() - 1) {
code += ";\n\n";
} else {
code += ",\n ";
@@ -760,15 +799,16 @@
code += " " + _kFb + ".Builder fbBuilder) {\n";
code += " assert(fbBuilder != null);\n";
- for (auto it = struct_def.fields.vec.begin();
- it != struct_def.fields.vec.end(); ++it) {
- auto &field = **it;
- if (field.deprecated) continue;
+ for (auto it = non_deprecated_fields.begin();
+ it != non_deprecated_fields.end(); ++it) {
+ auto pair = *it;
+ auto &field = *pair.second;
+
if (IsScalar(field.value.type.base_type) || IsStruct(field.value.type))
continue;
code += " final int " + MakeCamel(field.name, false) + "Offset";
- if (field.value.type.base_type == BASE_TYPE_VECTOR) {
+ if (IsVector(field.value.type)) {
code +=
" = _" + MakeCamel(field.name, false) + "?.isNotEmpty == true\n";
code += " ? fbBuilder.writeList";
@@ -792,8 +832,9 @@
code += ")";
}
code += "\n : null;\n";
- } else if (field.value.type.base_type == BASE_TYPE_STRING) {
- code += " = fbBuilder.writeString(_" + MakeCamel(field.name, false) + ");\n";
+ } else if (IsString(field.value.type)) {
+ code += " = fbBuilder.writeString(_" + MakeCamel(field.name, false) +
+ ");\n";
} else {
code += " = _" + MakeCamel(field.name, false) +
"?.getOrCreateOffset(fbBuilder);\n";
@@ -802,9 +843,9 @@
code += "\n";
if (struct_def.fixed) {
- StructObjectBuilderBody(struct_def, code_ptr);
+ StructObjectBuilderBody(non_deprecated_fields, code_ptr);
} else {
- TableObjectBuilderBody(struct_def, code_ptr);
+ TableObjectBuilderBody(non_deprecated_fields, code_ptr);
}
code += " }\n\n";
@@ -819,16 +860,15 @@
code += "}\n";
}
- void StructObjectBuilderBody(const StructDef &struct_def,
- std::string *code_ptr,
- bool prependUnderscore = true) {
+ void StructObjectBuilderBody(
+ std::vector<std::pair<int, FieldDef *>> non_deprecated_fields,
+ std::string *code_ptr, bool prependUnderscore = true) {
auto &code = *code_ptr;
- for (auto it = struct_def.fields.vec.rbegin();
- it != struct_def.fields.vec.rend(); ++it) {
- auto &field = **it;
-
- if (field.deprecated) continue;
+ for (auto it = non_deprecated_fields.rbegin();
+ it != non_deprecated_fields.rend(); ++it) {
+ auto pair = *it;
+ auto &field = *pair.second;
if (field.padding) {
code += " fbBuilder.pad(" + NumToString(field.padding) + ");\n";
@@ -850,19 +890,18 @@
code += " return fbBuilder.offset;\n";
}
- void TableObjectBuilderBody(const StructDef &struct_def,
- std::string *code_ptr,
- bool prependUnderscore = true) {
+ void TableObjectBuilderBody(
+ std::vector<std::pair<int, FieldDef *>> non_deprecated_fields,
+ std::string *code_ptr, bool prependUnderscore = true) {
std::string &code = *code_ptr;
code += " fbBuilder.startTable();\n";
- for (auto it = struct_def.fields.vec.begin();
- it != struct_def.fields.vec.end(); ++it) {
- auto &field = **it;
+ for (auto it = non_deprecated_fields.begin();
+ it != non_deprecated_fields.end(); ++it) {
+ auto pair = *it;
+ auto &field = *pair.second;
+ auto offset = pair.first;
- if (field.deprecated) continue;
-
- auto offset = it - struct_def.fields.vec.begin();
if (IsScalar(field.value.type.base_type)) {
code += " fbBuilder.add" + GenType(field.value.type) + "(" +
NumToString(offset) + ", ";
@@ -902,7 +941,9 @@
auto filebase =
flatbuffers::StripPath(flatbuffers::StripExtension(file_name));
- auto make_rule = GeneratedFileName(path, filebase) + ": ";
+ dart::DartGenerator generator(parser, path, file_name);
+ auto make_rule =
+ generator.GeneratedFileName(path, file_name, parser.opts) + ": ";
auto included_files = parser.GetIncludedFilesRecursive(file_name);
for (auto it = included_files.begin(); it != included_files.end(); ++it) {
diff --git a/src/idl_gen_fbs.cpp b/src/idl_gen_fbs.cpp
index e5f3723..e6c8a4a 100644
--- a/src/idl_gen_fbs.cpp
+++ b/src/idl_gen_fbs.cpp
@@ -63,25 +63,35 @@
for (size_t i = 0; i < ns.from_table; i++) {
ns.components[ns.components.size() - 1 - i] += "_";
}
+
+ if (parser.opts.proto_mode && !parser.opts.proto_namespace_suffix.empty()) {
+ // Since we know that all these namespaces come from a .proto, and all are
+ // being converted, we can simply apply this suffix to all of them.
+ ns.components.insert(ns.components.end() - ns.from_table,
+ parser.opts.proto_namespace_suffix);
+ }
}
std::string schema;
schema += "// Generated from " + file_name + ".proto\n\n";
if (parser.opts.include_dependence_headers) {
// clang-format off
- #ifdef FBS_GEN_INCLUDES // TODO: currently all in one file.
int num_includes = 0;
for (auto it = parser.included_files_.begin();
it != parser.included_files_.end(); ++it) {
if (it->second.empty())
continue;
- auto basename = flatbuffers::StripPath(
- flatbuffers::StripExtension(it->second));
+ std::string basename;
+ if(parser.opts.keep_include_path) {
+ basename = flatbuffers::StripExtension(it->second);
+ } else {
+ basename = flatbuffers::StripPath(
+ flatbuffers::StripExtension(it->second));
+ }
schema += "include \"" + basename + ".fbs\";\n";
num_includes++;
}
if (num_includes) schema += "\n";
- #endif
// clang-format on
}
// Generate code for all the enum declarations.
@@ -89,6 +99,9 @@
for (auto enum_def_it = parser.enums_.vec.begin();
enum_def_it != parser.enums_.vec.end(); ++enum_def_it) {
EnumDef &enum_def = **enum_def_it;
+ if (parser.opts.include_dependence_headers && enum_def.generated) {
+ continue;
+ }
GenNameSpace(*enum_def.defined_namespace, &schema, &last_namespace);
GenComment(enum_def.doc_comment, &schema, nullptr);
if (enum_def.is_union)
@@ -110,6 +123,9 @@
for (auto it = parser.structs_.vec.begin(); it != parser.structs_.vec.end();
++it) {
StructDef &struct_def = **it;
+ if (parser.opts.include_dependence_headers && struct_def.generated) {
+ continue;
+ }
GenNameSpace(*struct_def.defined_namespace, &schema, &last_namespace);
GenComment(struct_def.doc_comment, &schema, nullptr);
schema += "table " + struct_def.name + " {\n";
diff --git a/src/idl_gen_general.cpp b/src/idl_gen_general.cpp
deleted file mode 100644
index 8dca792..0000000
--- a/src/idl_gen_general.cpp
+++ /dev/null
@@ -1,1667 +0,0 @@
-/*
- * Copyright 2014 Google Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// independent from idl_parser, since this code is not needed for most clients
-
-#include "flatbuffers/code_generators.h"
-#include "flatbuffers/flatbuffers.h"
-#include "flatbuffers/idl.h"
-#include "flatbuffers/util.h"
-
-#if defined(FLATBUFFERS_CPP98_STL)
-# include <cctype>
-#endif // defined(FLATBUFFERS_CPP98_STL)
-
-namespace flatbuffers {
-
-// These arrays need to correspond to the IDLOptions::k enum.
-
-struct LanguageParameters {
- IDLOptions::Language language;
- // Whether function names in the language typically start with uppercase.
- bool first_camel_upper;
- std::string file_extension;
- std::string string_type;
- std::string bool_type;
- std::string open_curly;
- std::string accessor_type;
- std::string const_decl;
- std::string unsubclassable_decl;
- std::string enum_decl;
- std::string enum_separator;
- std::string getter_prefix;
- std::string getter_suffix;
- std::string inheritance_marker;
- std::string namespace_ident;
- std::string namespace_begin;
- std::string namespace_end;
- std::string set_bb_byteorder;
- std::string get_bb_position;
- std::string get_fbb_offset;
- std::string accessor_prefix;
- std::string accessor_prefix_static;
- std::string optional_suffix;
- std::string includes;
- std::string class_annotation;
- std::string generated_type_annotation;
- CommentConfig comment_config;
- const FloatConstantGenerator *float_gen;
-};
-
-const LanguageParameters &GetLangParams(IDLOptions::Language lang) {
- static TypedFloatConstantGenerator CSharpFloatGen(
- "Double.", "Single.", "NaN", "PositiveInfinity", "NegativeInfinity");
-
- static TypedFloatConstantGenerator JavaFloatGen(
- "Double.", "Float.", "NaN", "POSITIVE_INFINITY", "NEGATIVE_INFINITY");
-
- static const LanguageParameters language_parameters[] = {
- {
- IDLOptions::kJava,
- false,
- ".java",
- "String",
- "boolean ",
- " {\n",
- "class ",
- " final ",
- "final ",
- "final class ",
- ";\n",
- "()",
- "",
- " extends ",
- "package ",
- ";",
- "",
- "_bb.order(ByteOrder.LITTLE_ENDIAN); ",
- "position()",
- "offset()",
- "",
- "",
- "",
- "import java.nio.*;\nimport java.lang.*;\nimport "
- "java.util.*;\nimport com.google.flatbuffers.*;\n",
- "\n@SuppressWarnings(\"unused\")\n",
- "\n@javax.annotation.Generated(value=\"flatc\")\n",
- {
- "/**",
- " *",
- " */",
- },
- &JavaFloatGen
- },
- {
- IDLOptions::kCSharp,
- true,
- ".cs",
- "string",
- "bool ",
- "\n{\n",
- "struct ",
- " readonly ",
- "",
- "enum ",
- ",\n",
- " { get",
- "} ",
- " : ",
- "namespace ",
- "\n{",
- "\n}\n",
- "",
- "Position",
- "Offset",
- "__p.",
- "Table.",
- "?",
- "using global::System;\nusing global::FlatBuffers;\n\n",
- "",
- "",
- {
- nullptr,
- "///",
- nullptr,
- },
- &CSharpFloatGen
- },
- };
-
- if (lang == IDLOptions::kJava) {
- return language_parameters[0];
- } else {
- FLATBUFFERS_ASSERT(lang == IDLOptions::kCSharp);
- return language_parameters[1];
- }
-}
-
-namespace general {
-class GeneralGenerator : public BaseGenerator {
- public:
- GeneralGenerator(const Parser &parser, const std::string &path,
- const std::string &file_name)
- : BaseGenerator(parser, path, file_name, "", "."),
- lang_(GetLangParams(parser_.opts.lang)),
- cur_name_space_(nullptr) {}
-
- GeneralGenerator &operator=(const GeneralGenerator &);
- bool generate() {
- std::string one_file_code;
- cur_name_space_ = parser_.current_namespace_;
-
- for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
- ++it) {
- std::string enumcode;
- auto &enum_def = **it;
- if (!parser_.opts.one_file) cur_name_space_ = enum_def.defined_namespace;
- GenEnum(enum_def, &enumcode);
- if (parser_.opts.one_file) {
- one_file_code += enumcode;
- } else {
- if (!SaveType(enum_def.name, *enum_def.defined_namespace, enumcode,
- false))
- return false;
- }
- }
-
- for (auto it = parser_.structs_.vec.begin();
- it != parser_.structs_.vec.end(); ++it) {
- std::string declcode;
- auto &struct_def = **it;
- if (!parser_.opts.one_file)
- cur_name_space_ = struct_def.defined_namespace;
- GenStruct(struct_def, &declcode);
- if (parser_.opts.one_file) {
- one_file_code += declcode;
- } else {
- if (!SaveType(struct_def.name, *struct_def.defined_namespace, declcode,
- true))
- return false;
- }
- }
-
- if (parser_.opts.one_file) {
- return SaveType(file_name_, *parser_.current_namespace_, one_file_code,
- true);
- }
- return true;
- }
-
- // Save out the generated code for a single class while adding
- // declaration boilerplate.
- bool SaveType(const std::string &defname, const Namespace &ns,
- const std::string &classcode, bool needs_includes) const {
- if (!classcode.length()) return true;
-
- std::string code;
- if (lang_.language == IDLOptions::kCSharp) {
- code =
- "// <auto-generated>\n"
- "// " +
- std::string(FlatBuffersGeneratedWarning()) +
- "\n"
- "// </auto-generated>\n\n";
- } else {
- code = "// " + std::string(FlatBuffersGeneratedWarning()) + "\n\n";
- }
-
- std::string namespace_name = FullNamespace(".", ns);
- if (!namespace_name.empty()) {
- code += lang_.namespace_ident + namespace_name + lang_.namespace_begin;
- code += "\n\n";
- }
- if (needs_includes) {
- code += lang_.includes;
- if (parser_.opts.gen_nullable) {
- code += "\nimport javax.annotation.Nullable;\n";
- }
- code += lang_.class_annotation;
- }
- if (parser_.opts.gen_generated) {
- code += lang_.generated_type_annotation;
- }
- code += classcode;
- if (!namespace_name.empty()) code += lang_.namespace_end;
- auto filename = NamespaceDir(ns) + defname + lang_.file_extension;
- return SaveFile(filename.c_str(), code, false);
- }
-
- const Namespace *CurrentNameSpace() const { return cur_name_space_; }
-
- std::string FunctionStart(char upper) const {
- return std::string() + (lang_.language == IDLOptions::kJava
- ? static_cast<char>(tolower(upper))
- : upper);
- }
-
- std::string GenNullableAnnotation(const Type &t) const {
- return lang_.language == IDLOptions::kJava && parser_.opts.gen_nullable &&
- !IsScalar(DestinationType(t, true).base_type)
- ? " @Nullable "
- : "";
- }
-
- std::string GenTypeBasic(const Type &type, bool enableLangOverrides) const {
- // clang-format off
- static const char * const java_typename[] = {
- #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
- CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \
- #JTYPE,
- FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
- #undef FLATBUFFERS_TD
- };
-
- static const char * const csharp_typename[] = {
- #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
- CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \
- #NTYPE,
- FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
- #undef FLATBUFFERS_TD
- };
- // clang-format on
-
- if (enableLangOverrides) {
- if (lang_.language == IDLOptions::kCSharp) {
- if (IsEnum(type)) return WrapInNameSpace(*type.enum_def);
- if (type.base_type == BASE_TYPE_STRUCT) {
- return "Offset<" + WrapInNameSpace(*type.struct_def) + ">";
- }
- }
- }
-
- if (lang_.language == IDLOptions::kJava) {
- return java_typename[type.base_type];
- } else {
- FLATBUFFERS_ASSERT(lang_.language == IDLOptions::kCSharp);
- return csharp_typename[type.base_type];
- }
- }
-
- std::string GenTypeBasic(const Type &type) const {
- return GenTypeBasic(type, true);
- }
-
- std::string GenTypePointer(const Type &type) const {
- switch (type.base_type) {
- case BASE_TYPE_STRING: return lang_.string_type;
- case BASE_TYPE_VECTOR: return GenTypeGet(type.VectorType());
- case BASE_TYPE_STRUCT: return WrapInNameSpace(*type.struct_def);
- case BASE_TYPE_UNION:
- // Unions in C# use a generic Table-derived type for better type safety
- if (lang_.language == IDLOptions::kCSharp) return "TTable";
- FLATBUFFERS_FALLTHROUGH(); // else fall thru
- default: return "Table";
- }
- }
-
- std::string GenTypeGet(const Type &type) const {
- return IsScalar(type.base_type)
- ? GenTypeBasic(type)
- : (IsArray(type) ? GenTypeGet(type.VectorType())
- : GenTypePointer(type));
- }
-
- // Find the destination type the user wants to receive the value in (e.g.
- // one size higher signed types for unsigned serialized values in Java).
- Type DestinationType(const Type &type, bool vectorelem) const {
- if (lang_.language != IDLOptions::kJava) return type;
- switch (type.base_type) {
- // We use int for both uchar/ushort, since that generally means less
- // casting than using short for uchar.
- case BASE_TYPE_UCHAR: return Type(BASE_TYPE_INT);
- case BASE_TYPE_USHORT: return Type(BASE_TYPE_INT);
- case BASE_TYPE_UINT: return Type(BASE_TYPE_LONG);
- case BASE_TYPE_ARRAY:
- case BASE_TYPE_VECTOR:
- if (vectorelem) return DestinationType(type.VectorType(), vectorelem);
- FLATBUFFERS_FALLTHROUGH(); // else fall thru
- default: return type;
- }
- }
-
- std::string GenOffsetType(const StructDef &struct_def) const {
- if (lang_.language == IDLOptions::kCSharp) {
- return "Offset<" + WrapInNameSpace(struct_def) + ">";
- } else {
- return "int";
- }
- }
-
- std::string GenOffsetConstruct(const StructDef &struct_def,
- const std::string &variable_name) const {
- if (lang_.language == IDLOptions::kCSharp) {
- return "new Offset<" + WrapInNameSpace(struct_def) + ">(" +
- variable_name + ")";
- }
- return variable_name;
- }
-
- std::string GenVectorOffsetType() const {
- if (lang_.language == IDLOptions::kCSharp) {
- return "VectorOffset";
- } else {
- return "int";
- }
- }
-
- // Generate destination type name
- std::string GenTypeNameDest(const Type &type) const {
- return GenTypeGet(DestinationType(type, true));
- }
-
- // Mask to turn serialized value into destination type value.
- std::string DestinationMask(const Type &type, bool vectorelem) const {
- if (lang_.language != IDLOptions::kJava) return "";
- switch (type.base_type) {
- case BASE_TYPE_UCHAR: return " & 0xFF";
- case BASE_TYPE_USHORT: return " & 0xFFFF";
- case BASE_TYPE_UINT: return " & 0xFFFFFFFFL";
- case BASE_TYPE_VECTOR:
- if (vectorelem) return DestinationMask(type.VectorType(), vectorelem);
- FLATBUFFERS_FALLTHROUGH(); // else fall thru
- default: return "";
- }
- }
-
- // Casts necessary to correctly read serialized data
- std::string DestinationCast(const Type &type) const {
- if (IsSeries(type)) {
- return DestinationCast(type.VectorType());
- } else {
- switch (lang_.language) {
- case IDLOptions::kJava:
- // Cast necessary to correctly read serialized unsigned values.
- if (type.base_type == BASE_TYPE_UINT) return "(long)";
- break;
-
- case IDLOptions::kCSharp:
- // Cast from raw integral types to enum.
- if (IsEnum(type)) return "(" + WrapInNameSpace(*type.enum_def) + ")";
- break;
-
- default: break;
- }
- }
- return "";
- }
-
- // Cast statements for mutator method parameters.
- // In Java, parameters representing unsigned numbers need to be cast down to
- // their respective type. For example, a long holding an unsigned int value
- // would be cast down to int before being put onto the buffer. In C#, one cast
- // directly cast an Enum to its underlying type, which is essential before
- // putting it onto the buffer.
- std::string SourceCast(const Type &type, bool castFromDest) const {
- if (IsSeries(type)) {
- return SourceCast(type.VectorType(), castFromDest);
- } else {
- switch (lang_.language) {
- case IDLOptions::kJava:
- if (castFromDest) {
- if (type.base_type == BASE_TYPE_UINT)
- return "(int)";
- else if (type.base_type == BASE_TYPE_USHORT)
- return "(short)";
- else if (type.base_type == BASE_TYPE_UCHAR)
- return "(byte)";
- }
- break;
- case IDLOptions::kCSharp:
- if (IsEnum(type)) return "(" + GenTypeBasic(type, false) + ")";
- break;
- default: break;
- }
- }
- return "";
- }
-
- std::string SourceCast(const Type &type) const { return SourceCast(type, true); }
-
- std::string SourceCastBasic(const Type &type, bool castFromDest) const {
- return IsScalar(type.base_type) ? SourceCast(type, castFromDest) : "";
- }
-
- std::string SourceCastBasic(const Type &type) const {
- return SourceCastBasic(type, true);
- }
-
- std::string GenEnumDefaultValue(const FieldDef &field) const {
- auto &value = field.value;
- FLATBUFFERS_ASSERT(value.type.enum_def);
- auto &enum_def = *value.type.enum_def;
- auto enum_val = enum_def.FindByValue(value.constant);
- return enum_val ? (WrapInNameSpace(enum_def) + "." + enum_val->name)
- : value.constant;
- }
-
- std::string GenDefaultValue(const FieldDef &field, bool enableLangOverrides) const {
- auto& value = field.value;
- if (enableLangOverrides) {
- // handles both enum case and vector of enum case
- if (lang_.language == IDLOptions::kCSharp &&
- value.type.enum_def != nullptr &&
- value.type.base_type != BASE_TYPE_UNION) {
- return GenEnumDefaultValue(field);
- }
- }
-
- auto longSuffix = lang_.language == IDLOptions::kJava ? "L" : "";
- switch (value.type.base_type) {
- case BASE_TYPE_BOOL: return value.constant == "0" ? "false" : "true";
- case BASE_TYPE_ULONG: {
- if (lang_.language != IDLOptions::kJava) return value.constant;
- // Converts the ulong into its bits signed equivalent
- uint64_t defaultValue = StringToUInt(value.constant.c_str());
- return NumToString(static_cast<int64_t>(defaultValue)) + longSuffix;
- }
- case BASE_TYPE_UINT:
- case BASE_TYPE_LONG: return value.constant + longSuffix;
- default:
- if(IsFloat(value.type.base_type))
- return lang_.float_gen->GenFloatConstant(field);
- else
- return value.constant;
- }
- }
-
- std::string GenDefaultValue(const FieldDef &field) const {
- return GenDefaultValue(field, true);
- }
-
- std::string GenDefaultValueBasic(const FieldDef &field,
- bool enableLangOverrides) const {
- auto& value = field.value;
- if (!IsScalar(value.type.base_type)) {
- if (enableLangOverrides) {
- if (lang_.language == IDLOptions::kCSharp) {
- switch (value.type.base_type) {
- case BASE_TYPE_STRING: return "default(StringOffset)";
- case BASE_TYPE_STRUCT:
- return "default(Offset<" +
- WrapInNameSpace(*value.type.struct_def) + ">)";
- case BASE_TYPE_VECTOR: return "default(VectorOffset)";
- default: break;
- }
- }
- }
- return "0";
- }
- return GenDefaultValue(field, enableLangOverrides);
- }
-
- std::string GenDefaultValueBasic(const FieldDef &field) const {
- return GenDefaultValueBasic(field, true);
- }
-
- void GenEnum(EnumDef &enum_def, std::string *code_ptr) const {
- std::string &code = *code_ptr;
- if (enum_def.generated) return;
-
- // Generate enum definitions of the form:
- // public static (final) int name = value;
- // In Java, we use ints rather than the Enum feature, because we want them
- // to map directly to how they're used in C/C++ and file formats.
- // That, and Java Enums are expensive, and not universally liked.
- GenComment(enum_def.doc_comment, code_ptr, &lang_.comment_config);
-
- // In C# this indicates enumeration values can be treated as bit flags.
- if (lang_.language == IDLOptions::kCSharp && enum_def.attributes.Lookup("bit_flags")) {
- code += "[System.FlagsAttribute]\n";
- }
- if (enum_def.attributes.Lookup("private")) {
- // For Java, we leave the enum unmarked to indicate package-private
- // For C# we mark the enum as internal
- if (lang_.language == IDLOptions::kCSharp) {
- code += "internal ";
- }
- } else {
- code += "public ";
- }
- code += lang_.enum_decl + enum_def.name;
- if (lang_.language == IDLOptions::kCSharp) {
- code += lang_.inheritance_marker +
- GenTypeBasic(enum_def.underlying_type, false);
- }
- code += lang_.open_curly;
- if (lang_.language == IDLOptions::kJava) {
- code += " private " + enum_def.name + "() { }\n";
- }
- for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
- auto &ev = **it;
- GenComment(ev.doc_comment, code_ptr, &lang_.comment_config, " ");
- if (lang_.language != IDLOptions::kCSharp) {
- code += " public static";
- code += lang_.const_decl;
- code += GenTypeBasic(enum_def.underlying_type, false);
- }
- code += (lang_.language == IDLOptions::kJava) ? " " : " ";
- code += ev.name + " = ";
- code += enum_def.ToString(ev);
- code += lang_.enum_separator;
- }
-
- // Generate a generate string table for enum values.
- // We do not do that for C# where this functionality is native.
- if (lang_.language != IDLOptions::kCSharp) {
- // Problem is, if values are very sparse that could generate really big
- // tables. Ideally in that case we generate a map lookup instead, but for
- // the moment we simply don't output a table at all.
- auto range = enum_def.Distance();
- // Average distance between values above which we consider a table
- // "too sparse". Change at will.
- static const uint64_t kMaxSparseness = 5;
- if (range / static_cast<uint64_t>(enum_def.size()) < kMaxSparseness) {
- code += "\n public static";
- code += lang_.const_decl;
- code += lang_.string_type;
- code += "[] names = { ";
- auto val = enum_def.Vals().front();
- for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
- ++it) {
- auto ev = *it;
- for (auto k = enum_def.Distance(val, ev); k > 1; --k)
- code += "\"\", ";
- val = ev;
- code += "\"" + (*it)->name + "\", ";
- }
- code += "};\n\n";
- code += " public static ";
- code += lang_.string_type;
- code += " " + MakeCamel("name", lang_.first_camel_upper);
- code += "(int e) { return names[e";
- if (enum_def.MinValue()->IsNonZero())
- code += " - " + enum_def.MinValue()->name;
- code += "]; }\n";
- }
- }
-
- // Close the class
- code += "}";
- // Java does not need the closing semi-colon on class definitions.
- code += (lang_.language != IDLOptions::kJava) ? ";" : "";
- code += "\n\n";
- }
-
- // Returns the function name that is able to read a value of the given type.
- std::string GenGetter(const Type &type) const {
- switch (type.base_type) {
- case BASE_TYPE_STRING: return lang_.accessor_prefix + "__string";
- case BASE_TYPE_STRUCT: return lang_.accessor_prefix + "__struct";
- case BASE_TYPE_UNION: return lang_.accessor_prefix + "__union";
- case BASE_TYPE_VECTOR: return GenGetter(type.VectorType());
- case BASE_TYPE_ARRAY: return GenGetter(type.VectorType());
- default: {
- std::string getter =
- lang_.accessor_prefix + "bb." + FunctionStart('G') + "et";
- if (type.base_type == BASE_TYPE_BOOL) {
- getter = "0!=" + getter;
- } else if (GenTypeBasic(type, false) != "byte") {
- getter += MakeCamel(GenTypeBasic(type, false));
- }
- return getter;
- }
- }
- }
-
- // Returns the function name that is able to read a value of the given type.
- std::string GenGetterForLookupByKey(flatbuffers::FieldDef *key_field,
- const std::string &data_buffer,
- const char *num = nullptr) const {
- auto type = key_field->value.type;
- auto dest_mask = DestinationMask(type, true);
- auto dest_cast = DestinationCast(type);
- auto getter = data_buffer + "." + FunctionStart('G') + "et";
- if (GenTypeBasic(type, false) != "byte") {
- getter += MakeCamel(GenTypeBasic(type, false));
- }
- getter = dest_cast + getter + "(" + GenOffsetGetter(key_field, num) + ")" +
- dest_mask;
- return getter;
- }
-
- // Direct mutation is only allowed for scalar fields.
- // Hence a setter method will only be generated for such fields.
- std::string GenSetter(const Type &type) const {
- if (IsScalar(type.base_type)) {
- std::string setter =
- lang_.accessor_prefix + "bb." + FunctionStart('P') + "ut";
- if (GenTypeBasic(type, false) != "byte" &&
- type.base_type != BASE_TYPE_BOOL) {
- setter += MakeCamel(GenTypeBasic(type, false));
- }
- return setter;
- } else {
- return "";
- }
- }
-
- // Returns the method name for use with add/put calls.
- std::string GenMethod(const Type &type) const {
- return IsScalar(type.base_type) ? MakeCamel(GenTypeBasic(type, false))
- : (IsStruct(type) ? "Struct" : "Offset");
- }
-
- // Recursively generate arguments for a constructor, to deal with nested
- // structs.
- void GenStructArgs(const StructDef &struct_def, std::string *code_ptr,
- const char *nameprefix, size_t array_count = 0) const {
- std::string &code = *code_ptr;
- for (auto it = struct_def.fields.vec.begin();
- it != struct_def.fields.vec.end(); ++it) {
- auto &field = **it;
- const auto &field_type = field.value.type;
- const auto array_field = IsArray(field_type);
- const auto &type = array_field ? field_type.VectorType()
- : DestinationType(field_type, false);
- const auto array_cnt = array_field ? (array_count + 1) : array_count;
- if (IsStruct(type)) {
- // Generate arguments for a struct inside a struct. To ensure names
- // don't clash, and to make it obvious these arguments are constructing
- // a nested struct, prefix the name with the field name.
- GenStructArgs(*field_type.struct_def, code_ptr,
- (nameprefix + (field.name + "_")).c_str(), array_cnt);
- } else {
- code += ", ";
- code += GenTypeBasic(type);
- if (lang_.language == IDLOptions::kJava) {
- for (size_t i = 0; i < array_cnt; i++) code += "[]";
- } else if (lang_.language == IDLOptions::kCSharp) {
- if (array_cnt > 0) {
- code += "[";
- for (size_t i = 1; i < array_cnt; i++) code += ",";
- code += "]";
- }
- } else {
- FLATBUFFERS_ASSERT(0);
- }
- code += " ";
- code += nameprefix;
- code += MakeCamel(field.name, lang_.first_camel_upper);
- }
- }
- }
-
- // Recusively generate struct construction statements of the form:
- // builder.putType(name);
- // and insert manual padding.
- void GenStructBody(const StructDef &struct_def, std::string *code_ptr,
- const char *nameprefix, size_t index = 0,
- bool in_array = false) const {
- std::string &code = *code_ptr;
- std::string indent((index + 1) * 2, ' ');
- code += indent + " builder." + FunctionStart('P') + "rep(";
- code += NumToString(struct_def.minalign) + ", ";
- code += NumToString(struct_def.bytesize) + ");\n";
- for (auto it = struct_def.fields.vec.rbegin();
- it != struct_def.fields.vec.rend(); ++it) {
- auto &field = **it;
- const auto &field_type = field.value.type;
- if (field.padding) {
- code += indent + " builder." + FunctionStart('P') + "ad(";
- code += NumToString(field.padding) + ");\n";
- }
- if (IsStruct(field_type)) {
- GenStructBody(*field_type.struct_def, code_ptr,
- (nameprefix + (field.name + "_")).c_str(), index,
- in_array);
- } else {
- const auto &type =
- IsArray(field_type) ? field_type.VectorType() : field_type;
- const auto index_var = "_idx" + NumToString(index);
- if (IsArray(field_type)) {
- code += indent + " for (int " + index_var + " = ";
- code += NumToString(field_type.fixed_length);
- code += "; " + index_var + " > 0; " + index_var + "--) {\n";
- in_array = true;
- }
- if (IsStruct(type)) {
- GenStructBody(*field_type.struct_def, code_ptr,
- (nameprefix + (field.name + "_")).c_str(), index + 1,
- in_array);
- } else {
- code += IsArray(field_type) ? " " : "";
- code += indent + " builder." + FunctionStart('P') + "ut";
- code += GenMethod(type) + "(";
- code += SourceCast(type);
- auto argname =
- nameprefix + MakeCamel(field.name, lang_.first_camel_upper);
- code += argname;
- size_t array_cnt = index + (IsArray(field_type) ? 1 : 0);
- if (lang_.language == IDLOptions::kJava) {
- for (size_t i = 0; in_array && i < array_cnt; i++) {
- code += "[_idx" + NumToString(i) + "-1]";
- }
- } else if (lang_.language == IDLOptions::kCSharp) {
- if (array_cnt > 0) {
- code += "[";
- for (size_t i = 0; in_array && i < array_cnt; i++) {
- code += "_idx" + NumToString(i) + "-1";
- if (i != (array_cnt - 1)) code += ",";
- }
- code += "]";
- }
- } else {
- FLATBUFFERS_ASSERT(0);
- }
- code += ");\n";
- }
- if (IsArray(field_type)) { code += indent + " }\n"; }
- }
- }
- }
-
- std::string GenByteBufferLength(const char *bb_name) const {
- std::string bb_len = bb_name;
- if (lang_.language == IDLOptions::kCSharp)
- bb_len += ".Length";
- else
- bb_len += ".capacity()";
- return bb_len;
- }
-
- std::string GenOffsetGetter(flatbuffers::FieldDef *key_field,
- const char *num = nullptr) const {
- std::string key_offset = "";
- key_offset += lang_.accessor_prefix_static + "__offset(" +
- NumToString(key_field->value.offset) + ", ";
- if (num) {
- key_offset += num;
- key_offset +=
- (lang_.language == IDLOptions::kCSharp ? ".Value, builder.DataBuffer)"
- : ", _bb)");
- } else {
- key_offset += GenByteBufferLength("bb");
- key_offset += " - tableOffset, bb)";
- }
- return key_offset;
- }
-
- std::string GenLookupKeyGetter(flatbuffers::FieldDef *key_field) const {
- std::string key_getter = " ";
- key_getter += "int tableOffset = " + lang_.accessor_prefix_static;
- key_getter += "__indirect(vectorLocation + 4 * (start + middle)";
- key_getter += ", bb);\n ";
- if (key_field->value.type.base_type == BASE_TYPE_STRING) {
- key_getter += "int comp = " + lang_.accessor_prefix_static;
- key_getter += FunctionStart('C') + "ompareStrings(";
- key_getter += GenOffsetGetter(key_field);
- key_getter += ", byteKey, bb);\n";
- } else {
- auto get_val = GenGetterForLookupByKey(key_field, "bb");
- if (lang_.language == IDLOptions::kCSharp) {
- key_getter += "int comp = " + get_val + ".CompareTo(key);\n";
- } else {
- key_getter += GenTypeNameDest(key_field->value.type) + " val = ";
- key_getter += get_val + ";\n";
- key_getter += " int comp = val > key ? 1 : val < key ? -1 : 0;\n";
- }
- }
- return key_getter;
- }
-
- std::string GenKeyGetter(flatbuffers::FieldDef *key_field) const {
- std::string key_getter = "";
- auto data_buffer =
- (lang_.language == IDLOptions::kCSharp) ? "builder.DataBuffer" : "_bb";
- if (key_field->value.type.base_type == BASE_TYPE_STRING) {
- if (lang_.language == IDLOptions::kJava) key_getter += " return ";
- key_getter += lang_.accessor_prefix_static;
- key_getter += FunctionStart('C') + "ompareStrings(";
- key_getter += GenOffsetGetter(key_field, "o1") + ", ";
- key_getter += GenOffsetGetter(key_field, "o2") + ", " + data_buffer + ")";
- if (lang_.language == IDLOptions::kJava) key_getter += ";";
- } else {
- auto field_getter = GenGetterForLookupByKey(key_field, data_buffer, "o1");
- if (lang_.language == IDLOptions::kCSharp) {
- key_getter += field_getter;
- field_getter = GenGetterForLookupByKey(key_field, data_buffer, "o2");
- key_getter += ".CompareTo(" + field_getter + ")";
- } else {
- key_getter +=
- "\n " + GenTypeNameDest(key_field->value.type) + " val_1 = ";
- key_getter +=
- field_getter + ";\n " + GenTypeNameDest(key_field->value.type);
- key_getter += " val_2 = ";
- field_getter = GenGetterForLookupByKey(key_field, data_buffer, "o2");
- key_getter += field_getter + ";\n";
- key_getter +=
- " return val_1 > val_2 ? 1 : val_1 < val_2 ? -1 : 0;\n ";
- }
- }
- return key_getter;
- }
-
- void GenStruct(StructDef &struct_def, std::string *code_ptr) const {
- if (struct_def.generated) return;
- std::string &code = *code_ptr;
-
- // Generate a struct accessor class, with methods of the form:
- // public type name() { return bb.getType(i + offset); }
- // or for tables of the form:
- // public type name() {
- // int o = __offset(offset); return o != 0 ? bb.getType(o + i) : default;
- // }
- GenComment(struct_def.doc_comment, code_ptr, &lang_.comment_config);
- if (struct_def.attributes.Lookup("private")) {
- // For Java, we leave the struct unmarked to indicate package-private
- // For C# we mark the struct as internal
- if (lang_.language == IDLOptions::kCSharp) {
- code += "internal ";
- }
- } else {
- code += "public ";
- }
- if (lang_.language == IDLOptions::kCSharp &&
- struct_def.attributes.Lookup("csharp_partial")) {
- // generate a partial class for this C# struct/table
- code += "partial ";
- } else {
- code += lang_.unsubclassable_decl;
- }
- code += lang_.accessor_type + struct_def.name;
- if (lang_.language == IDLOptions::kCSharp) {
- code += " : IFlatbufferObject";
- code += lang_.open_curly;
- code += " private ";
- code += struct_def.fixed ? "Struct" : "Table";
- code += " __p;\n";
-
- if (lang_.language == IDLOptions::kCSharp) {
- code += " public ByteBuffer ByteBuffer { get { return __p.bb; } }\n";
- }
-
- } else {
- code += lang_.inheritance_marker;
- code += struct_def.fixed ? "Struct" : "Table";
- code += lang_.open_curly;
- }
-
- if (!struct_def.fixed) {
- // Generate verson check method.
- // Force compile time error if not using the same version runtime.
- code += " public static void ValidateVersion() {";
- if (lang_.language == IDLOptions::kCSharp)
- code += " FlatBufferConstants.";
- else
- code += " Constants.";
- code += "FLATBUFFERS_1_11_1(); ";
- code += "}\n";
-
- // Generate a special accessor for the table that when used as the root
- // of a FlatBuffer
- std::string method_name =
- FunctionStart('G') + "etRootAs" + struct_def.name;
- std::string method_signature =
- " public static " + struct_def.name + " " + method_name;
-
- // create convenience method that doesn't require an existing object
- code += method_signature + "(ByteBuffer _bb) ";
- code += "{ return " + method_name + "(_bb, new " + struct_def.name +
- "()); }\n";
-
- // create method that allows object reuse
- code +=
- method_signature + "(ByteBuffer _bb, " + struct_def.name + " obj) { ";
- code += lang_.set_bb_byteorder;
- code += "return (obj.__assign(_bb." + FunctionStart('G') + "etInt(_bb.";
- code += lang_.get_bb_position;
- code += ") + _bb.";
- code += lang_.get_bb_position;
- code += ", _bb)); }\n";
- if (parser_.root_struct_def_ == &struct_def) {
- if (parser_.file_identifier_.length()) {
- // Check if a buffer has the identifier.
- code += " public static ";
- code += lang_.bool_type + struct_def.name;
- code += "BufferHasIdentifier(ByteBuffer _bb) { return ";
- code += lang_.accessor_prefix_static + "__has_identifier(_bb, \"";
- code += parser_.file_identifier_;
- code += "\"); }\n";
- }
- }
- }
- // Generate the __init method that sets the field in a pre-existing
- // accessor object. This is to allow object reuse.
- code += " public void __init(int _i, ByteBuffer _bb) ";
- code += "{ ";
- if (lang_.language == IDLOptions::kCSharp) {
- code += "__p = new ";
- code += struct_def.fixed ? "Struct" : "Table";
- code += "(_i, _bb); ";
- } else {
- code += "__reset(_i, _bb); ";
- }
- code += "}\n";
- code +=
- " public " + struct_def.name + " __assign(int _i, ByteBuffer _bb) ";
- code += "{ __init(_i, _bb); return this; }\n\n";
- for (auto it = struct_def.fields.vec.begin();
- it != struct_def.fields.vec.end(); ++it) {
- auto &field = **it;
- if (field.deprecated) continue;
- GenComment(field.doc_comment, code_ptr, &lang_.comment_config, " ");
- std::string type_name = GenTypeGet(field.value.type);
- std::string type_name_dest = GenTypeNameDest(field.value.type);
- std::string conditional_cast = "";
- std::string optional = "";
- if (lang_.language == IDLOptions::kCSharp && !struct_def.fixed &&
- (field.value.type.base_type == BASE_TYPE_STRUCT ||
- field.value.type.base_type == BASE_TYPE_UNION ||
- (field.value.type.base_type == BASE_TYPE_VECTOR &&
- (field.value.type.element == BASE_TYPE_STRUCT ||
- field.value.type.element == BASE_TYPE_UNION)))) {
- optional = lang_.optional_suffix;
- conditional_cast = "(" + type_name_dest + optional + ")";
- }
- std::string dest_mask = DestinationMask(field.value.type, true);
- std::string dest_cast = DestinationCast(field.value.type);
- std::string src_cast = SourceCast(field.value.type);
- std::string method_start = " public " +
- (field.required ? "" : GenNullableAnnotation(field.value.type)) +
- type_name_dest + optional + " " +
- MakeCamel(field.name, lang_.first_camel_upper);
- std::string obj = lang_.language == IDLOptions::kCSharp
- ? "(new " + type_name + "())"
- : "obj";
-
- // Most field accessors need to retrieve and test the field offset first,
- // this is the prefix code for that:
- auto offset_prefix =
- IsArray(field.value.type)
- ? " { return "
- : (" { int o = " + lang_.accessor_prefix + "__offset(" +
- NumToString(field.value.offset) + "); return o != 0 ? ");
- // Generate the accessors that don't do object reuse.
- if (field.value.type.base_type == BASE_TYPE_STRUCT) {
- // Calls the accessor that takes an accessor object with a new object.
- if (lang_.language != IDLOptions::kCSharp) {
- code += method_start + "() { return ";
- code += MakeCamel(field.name, lang_.first_camel_upper);
- code += "(new ";
- code += type_name + "()); }\n";
- }
- } else if (field.value.type.base_type == BASE_TYPE_VECTOR &&
- field.value.type.element == BASE_TYPE_STRUCT) {
- // Accessors for vectors of structs also take accessor objects, this
- // generates a variant without that argument.
- if (lang_.language != IDLOptions::kCSharp) {
- code += method_start + "(int j) { return ";
- code += MakeCamel(field.name, lang_.first_camel_upper);
- code += "(new " + type_name + "(), j); }\n";
- }
- } else if (field.value.type.base_type == BASE_TYPE_UNION ||
- (field.value.type.base_type == BASE_TYPE_VECTOR &&
- field.value.type.VectorType().base_type == BASE_TYPE_UNION)) {
- if (lang_.language == IDLOptions::kCSharp) {
- // Union types in C# use generic Table-derived type for better type
- // safety.
- method_start += "<TTable>";
- type_name = type_name_dest;
- }
- }
- std::string getter = dest_cast + GenGetter(field.value.type);
- code += method_start;
- std::string default_cast = "";
- // only create default casts for c# scalars or vectors of scalars
- if (lang_.language == IDLOptions::kCSharp &&
- (IsScalar(field.value.type.base_type) ||
- (field.value.type.base_type == BASE_TYPE_VECTOR &&
- IsScalar(field.value.type.element)))) {
- // For scalars, default value will be returned by GetDefaultValue().
- // If the scalar is an enum, GetDefaultValue() returns an actual c# enum
- // that doesn't need to be casted. However, default values for enum
- // elements of vectors are integer literals ("0") and are still casted
- // for clarity.
- if (field.value.type.enum_def == nullptr ||
- field.value.type.base_type == BASE_TYPE_VECTOR) {
- default_cast = "(" + type_name_dest + ")";
- }
- }
- std::string member_suffix = "; ";
- if (IsScalar(field.value.type.base_type)) {
- code += lang_.getter_prefix;
- member_suffix += lang_.getter_suffix;
- if (struct_def.fixed) {
- code += " { return " + getter;
- code += "(" + lang_.accessor_prefix + "bb_pos + ";
- code += NumToString(field.value.offset) + ")";
- code += dest_mask;
- } else {
- code += offset_prefix + getter;
- code += "(o + " + lang_.accessor_prefix + "bb_pos)" + dest_mask;
- code += " : " + default_cast;
- code += GenDefaultValue(field);
- }
- } else {
- switch (field.value.type.base_type) {
- case BASE_TYPE_STRUCT:
- if (lang_.language != IDLOptions::kCSharp) {
- code += "(" + type_name + " obj" + ")";
- } else {
- code += lang_.getter_prefix;
- member_suffix += lang_.getter_suffix;
- }
- if (struct_def.fixed) {
- code += " { return " + obj + ".__assign(" + lang_.accessor_prefix;
- code += "bb_pos + " + NumToString(field.value.offset) + ", ";
- code += lang_.accessor_prefix + "bb)";
- } else {
- code += offset_prefix + conditional_cast;
- code += obj + ".__assign(";
- code += field.value.type.struct_def->fixed
- ? "o + " + lang_.accessor_prefix + "bb_pos"
- : lang_.accessor_prefix + "__indirect(o + " +
- lang_.accessor_prefix + "bb_pos)";
- code += ", " + lang_.accessor_prefix + "bb) : null";
- }
- break;
- case BASE_TYPE_STRING:
- code += lang_.getter_prefix;
- member_suffix += lang_.getter_suffix;
- code += offset_prefix + getter + "(o + " + lang_.accessor_prefix;
- code += "bb_pos) : null";
- break;
- case BASE_TYPE_ARRAY: FLATBUFFERS_FALLTHROUGH(); // fall thru
- case BASE_TYPE_VECTOR: {
- auto vectortype = field.value.type.VectorType();
- if (vectortype.base_type == BASE_TYPE_UNION &&
- lang_.language == IDLOptions::kCSharp) {
- conditional_cast = "(TTable?)";
- getter += "<TTable>";
- }
- code += "(";
- if (vectortype.base_type == BASE_TYPE_STRUCT) {
- if (lang_.language != IDLOptions::kCSharp)
- code += type_name + " obj, ";
- getter = obj + ".__assign";
- } else if (vectortype.base_type == BASE_TYPE_UNION) {
- if (lang_.language != IDLOptions::kCSharp)
- code += type_name + " obj, ";
- }
- code += "int j)";
- const auto body = offset_prefix + conditional_cast + getter + "(";
- if (vectortype.base_type == BASE_TYPE_UNION) {
- if (lang_.language != IDLOptions::kCSharp)
- code += body + "obj, ";
- else
- code += " where TTable : struct, IFlatbufferObject" + body;
- } else {
- code += body;
- }
- auto index = lang_.accessor_prefix;
- if (IsArray(field.value.type)) {
- index += "bb_pos + " + NumToString(field.value.offset) + " + ";
- } else {
- index += "__vector(o) + ";
- }
- index += "j * " + NumToString(InlineSize(vectortype));
- if (vectortype.base_type == BASE_TYPE_STRUCT) {
- code += vectortype.struct_def->fixed
- ? index
- : lang_.accessor_prefix + "__indirect(" + index + ")";
- code += ", " + lang_.accessor_prefix + "bb";
- } else if (vectortype.base_type == BASE_TYPE_UNION) {
- code += index + " - " + lang_.accessor_prefix + "bb_pos";
- } else {
- code += index;
- }
- code += ")" + dest_mask;
- if (!IsArray(field.value.type)) {
- code += " : ";
- code +=
- field.value.type.element == BASE_TYPE_BOOL
- ? "false"
- : (IsScalar(field.value.type.element) ? default_cast + "0"
- : "null");
- }
-
- break;
- }
- case BASE_TYPE_UNION:
- if (lang_.language == IDLOptions::kCSharp) {
- code += "() where TTable : struct, IFlatbufferObject";
- code += offset_prefix + "(TTable?)" + getter;
- code += "<TTable>(o) : null";
- } else {
- code += "(" + type_name + " obj)" + offset_prefix + getter;
- code += "(obj, o) : null";
- }
- break;
- default: FLATBUFFERS_ASSERT(0);
- }
- }
- code += member_suffix;
- code += "}\n";
- if (field.value.type.base_type == BASE_TYPE_VECTOR) {
- code +=
- " public int " + MakeCamel(field.name, lang_.first_camel_upper);
- code += "Length";
- code += lang_.getter_prefix;
- code += offset_prefix;
- code += lang_.accessor_prefix + "__vector_len(o) : 0; ";
- code += lang_.getter_suffix;
- code += "}\n";
- // See if we should generate a by-key accessor.
- if (field.value.type.element == BASE_TYPE_STRUCT &&
- !field.value.type.struct_def->fixed) {
- auto &sd = *field.value.type.struct_def;
- auto &fields = sd.fields.vec;
- for (auto kit = fields.begin(); kit != fields.end(); ++kit) {
- auto &key_field = **kit;
- if (key_field.key) {
- auto qualified_name = WrapInNameSpace(sd);
- code += " public " + qualified_name + lang_.optional_suffix + " ";
- code += MakeCamel(field.name, lang_.first_camel_upper) + "ByKey(";
- code += GenTypeNameDest(key_field.value.type) + " key)";
- code += offset_prefix;
- code += qualified_name + ".__lookup_by_key(";
- if (lang_.language == IDLOptions::kJava)
- code += "null, ";
- code += lang_.accessor_prefix + "__vector(o), key, ";
- code += lang_.accessor_prefix + "bb) : null; ";
- code += "}\n";
- if (lang_.language == IDLOptions::kJava) {
- code += " public " + qualified_name + lang_.optional_suffix + " ";
- code += MakeCamel(field.name, lang_.first_camel_upper) + "ByKey(";
- code += qualified_name + lang_.optional_suffix + " obj, ";
- code += GenTypeNameDest(key_field.value.type) + " key)";
- code += offset_prefix;
- code += qualified_name + ".__lookup_by_key(obj, ";
- code += lang_.accessor_prefix + "__vector(o), key, ";
- code += lang_.accessor_prefix + "bb) : null; ";
- code += "}\n";
- }
- break;
- }
- }
- }
- }
- // Generate a ByteBuffer accessor for strings & vectors of scalars.
- if ((field.value.type.base_type == BASE_TYPE_VECTOR &&
- IsScalar(field.value.type.VectorType().base_type)) ||
- field.value.type.base_type == BASE_TYPE_STRING) {
- switch (lang_.language) {
- case IDLOptions::kJava:
- code += " public ByteBuffer ";
- code += MakeCamel(field.name, lang_.first_camel_upper);
- code += "AsByteBuffer() { return ";
- code += lang_.accessor_prefix + "__vector_as_bytebuffer(";
- code += NumToString(field.value.offset) + ", ";
- code +=
- NumToString(field.value.type.base_type == BASE_TYPE_STRING
- ? 1
- : InlineSize(field.value.type.VectorType()));
- code += "); }\n";
- code += " public ByteBuffer ";
- code += MakeCamel(field.name, lang_.first_camel_upper);
- code += "InByteBuffer(ByteBuffer _bb) { return ";
- code += lang_.accessor_prefix + "__vector_in_bytebuffer(_bb, ";
- code += NumToString(field.value.offset) + ", ";
- code +=
- NumToString(field.value.type.base_type == BASE_TYPE_STRING
- ? 1
- : InlineSize(field.value.type.VectorType()));
- code += "); }\n";
- break;
- case IDLOptions::kCSharp:
- code += "#if ENABLE_SPAN_T\n";
- code += " public Span<byte> Get";
- code += MakeCamel(field.name, lang_.first_camel_upper);
- code += "Bytes() { return ";
- code += lang_.accessor_prefix + "__vector_as_span(";
- code += NumToString(field.value.offset);
- code += "); }\n";
- code += "#else\n";
- code += " public ArraySegment<byte>? Get";
- code += MakeCamel(field.name, lang_.first_camel_upper);
- code += "Bytes() { return ";
- code += lang_.accessor_prefix + "__vector_as_arraysegment(";
- code += NumToString(field.value.offset);
- code += "); }\n";
- code += "#endif\n";
-
- // For direct blockcopying the data into a typed array
- code += " public ";
- code += GenTypeBasic(field.value.type.VectorType());
- code += "[] Get";
- code += MakeCamel(field.name, lang_.first_camel_upper);
- code += "Array() { return ";
- code += lang_.accessor_prefix + "__vector_as_array<";
- code += GenTypeBasic(field.value.type.VectorType());
- code += ">(";
- code += NumToString(field.value.offset);
- code += "); }\n";
- break;
- default: break;
- }
- }
- // generate object accessors if is nested_flatbuffer
- if (field.nested_flatbuffer) {
- auto nested_type_name = WrapInNameSpace(*field.nested_flatbuffer);
- auto nested_method_name =
- MakeCamel(field.name, lang_.first_camel_upper) + "As" +
- field.nested_flatbuffer->name;
- auto get_nested_method_name = nested_method_name;
- if (lang_.language == IDLOptions::kCSharp) {
- get_nested_method_name = "Get" + nested_method_name;
- conditional_cast =
- "(" + nested_type_name + lang_.optional_suffix + ")";
- }
- if (lang_.language != IDLOptions::kCSharp) {
- code += " public " + nested_type_name + lang_.optional_suffix + " ";
- code += nested_method_name + "() { return ";
- code +=
- get_nested_method_name + "(new " + nested_type_name + "()); }\n";
- } else {
- obj = "(new " + nested_type_name + "())";
- }
- code += " public " + nested_type_name + lang_.optional_suffix + " ";
- code += get_nested_method_name + "(";
- if (lang_.language != IDLOptions::kCSharp)
- code += nested_type_name + " obj";
- code += ") { int o = " + lang_.accessor_prefix + "__offset(";
- code += NumToString(field.value.offset) + "); ";
- code += "return o != 0 ? " + conditional_cast + obj + ".__assign(";
- code += lang_.accessor_prefix;
- code += "__indirect(" + lang_.accessor_prefix + "__vector(o)), ";
- code += lang_.accessor_prefix + "bb) : null; }\n";
- }
- // Generate mutators for scalar fields or vectors of scalars.
- if (parser_.opts.mutable_buffer) {
- auto is_series = (IsSeries(field.value.type));
- const auto &underlying_type =
- is_series ? field.value.type.VectorType() : field.value.type;
- // Boolean parameters have to be explicitly converted to byte
- // representation.
- auto setter_parameter = underlying_type.base_type == BASE_TYPE_BOOL
- ? "(byte)(" + field.name + " ? 1 : 0)"
- : field.name;
- auto mutator_prefix = MakeCamel("mutate", lang_.first_camel_upper);
- // A vector mutator also needs the index of the vector element it should
- // mutate.
- auto mutator_params = (is_series ? "(int j, " : "(") +
- GenTypeNameDest(underlying_type) + " " +
- field.name + ") { ";
- auto setter_index =
- is_series
- ? lang_.accessor_prefix +
- (IsArray(field.value.type)
- ? "bb_pos + " + NumToString(field.value.offset)
- : "__vector(o)") +
- +" + j * " + NumToString(InlineSize(underlying_type))
- : (struct_def.fixed
- ? lang_.accessor_prefix + "bb_pos + " +
- NumToString(field.value.offset)
- : "o + " + lang_.accessor_prefix + "bb_pos");
- if (IsScalar(underlying_type.base_type)) {
- code += " public ";
- code += struct_def.fixed ? "void " : lang_.bool_type;
- code += mutator_prefix + MakeCamel(field.name, true);
- code += mutator_params;
- if (struct_def.fixed) {
- code += GenSetter(underlying_type) + "(" + setter_index + ", ";
- code += src_cast + setter_parameter + "); }\n";
- } else {
- code += "int o = " + lang_.accessor_prefix + "__offset(";
- code += NumToString(field.value.offset) + ");";
- code += " if (o != 0) { " + GenSetter(underlying_type);
- code += "(" + setter_index + ", " + src_cast + setter_parameter +
- "); return true; } else { return false; } }\n";
- }
- }
- }
- }
- code += "\n";
- flatbuffers::FieldDef *key_field = nullptr;
- if (struct_def.fixed) {
- // create a struct constructor function
- code += " public static " + GenOffsetType(struct_def) + " ";
- code += FunctionStart('C') + "reate";
- code += struct_def.name + "(FlatBufferBuilder builder";
- GenStructArgs(struct_def, code_ptr, "");
- code += ") {\n";
- GenStructBody(struct_def, code_ptr, "");
- code += " return ";
- code += GenOffsetConstruct(
- struct_def, "builder." + std::string(lang_.get_fbb_offset));
- code += ";\n }\n";
- } else {
- // Generate a method that creates a table in one go. This is only possible
- // when the table has no struct fields, since those have to be created
- // inline, and there's no way to do so in Java.
- bool has_no_struct_fields = true;
- int num_fields = 0;
- for (auto it = struct_def.fields.vec.begin();
- it != struct_def.fields.vec.end(); ++it) {
- auto &field = **it;
- if (field.deprecated) continue;
- if (IsStruct(field.value.type)) {
- has_no_struct_fields = false;
- } else {
- num_fields++;
- }
- }
- // JVM specifications restrict default constructor params to be < 255.
- // Longs and doubles take up 2 units, so we set the limit to be < 127.
- if (has_no_struct_fields && num_fields && num_fields < 127) {
- // Generate a table constructor of the form:
- // public static int createName(FlatBufferBuilder builder, args...)
- code += " public static " + GenOffsetType(struct_def) + " ";
- code += FunctionStart('C') + "reate" + struct_def.name;
- code += "(FlatBufferBuilder builder";
- for (auto it = struct_def.fields.vec.begin();
- it != struct_def.fields.vec.end(); ++it) {
- auto &field = **it;
- if (field.deprecated) continue;
- code += ",\n ";
- code += GenTypeBasic(DestinationType(field.value.type, false));
- code += " ";
- code += field.name;
- if (!IsScalar(field.value.type.base_type)) code += "Offset";
-
- // Java doesn't have defaults, which means this method must always
- // supply all arguments, and thus won't compile when fields are added.
- if (lang_.language != IDLOptions::kJava) {
- code += " = ";
- code += GenDefaultValueBasic(field);
- }
- }
- code += ") {\n builder.";
- code += FunctionStart('S') + "tartTable(";
- code += NumToString(struct_def.fields.vec.size()) + ");\n";
- for (size_t size = struct_def.sortbysize ? sizeof(largest_scalar_t) : 1;
- size; size /= 2) {
- for (auto it = struct_def.fields.vec.rbegin();
- it != struct_def.fields.vec.rend(); ++it) {
- auto &field = **it;
- if (!field.deprecated &&
- (!struct_def.sortbysize ||
- size == SizeOf(field.value.type.base_type))) {
- code += " " + struct_def.name + ".";
- code += FunctionStart('A') + "dd";
- code += MakeCamel(field.name) + "(builder, " + field.name;
- if (!IsScalar(field.value.type.base_type)) code += "Offset";
- code += ");\n";
- }
- }
- }
- code += " return " + struct_def.name + ".";
- code += FunctionStart('E') + "nd" + struct_def.name;
- code += "(builder);\n }\n\n";
- }
- // Generate a set of static methods that allow table construction,
- // of the form:
- // public static void addName(FlatBufferBuilder builder, short name)
- // { builder.addShort(id, name, default); }
- // Unlike the Create function, these always work.
- code += " public static void " + FunctionStart('S') + "tart";
- code += struct_def.name;
- code += "(FlatBufferBuilder builder) { builder.";
- code += FunctionStart('S') + "tartTable(";
- code += NumToString(struct_def.fields.vec.size()) + "); }\n";
- for (auto it = struct_def.fields.vec.begin();
- it != struct_def.fields.vec.end(); ++it) {
- auto &field = **it;
- if (field.deprecated) continue;
- if (field.key) key_field = &field;
- code += " public static void " + FunctionStart('A') + "dd";
- code += MakeCamel(field.name);
- code += "(FlatBufferBuilder builder, ";
- code += GenTypeBasic(DestinationType(field.value.type, false));
- auto argname = MakeCamel(field.name, false);
- if (!IsScalar(field.value.type.base_type)) argname += "Offset";
- code += " " + argname + ") { builder." + FunctionStart('A') + "dd";
- code += GenMethod(field.value.type) + "(";
- code += NumToString(it - struct_def.fields.vec.begin()) + ", ";
- code += SourceCastBasic(field.value.type);
- code += argname;
- if (!IsScalar(field.value.type.base_type) &&
- field.value.type.base_type != BASE_TYPE_UNION &&
- lang_.language == IDLOptions::kCSharp) {
- code += ".Value";
- }
- code += ", ";
- if (lang_.language == IDLOptions::kJava)
- code += SourceCastBasic(field.value.type);
- code += GenDefaultValue(field, false);
- code += "); }\n";
- if (field.value.type.base_type == BASE_TYPE_VECTOR) {
- auto vector_type = field.value.type.VectorType();
- auto alignment = InlineAlignment(vector_type);
- auto elem_size = InlineSize(vector_type);
- if (!IsStruct(vector_type)) {
- // Generate a method to create a vector from a Java array.
- code += " public static " + GenVectorOffsetType() + " ";
- code += FunctionStart('C') + "reate";
- code += MakeCamel(field.name);
- code += "Vector(FlatBufferBuilder builder, ";
- code += GenTypeBasic(vector_type) + "[] data) ";
- code += "{ builder." + FunctionStart('S') + "tartVector(";
- code += NumToString(elem_size);
- code += ", data." + FunctionStart('L') + "ength, ";
- code += NumToString(alignment);
- code += "); for (int i = data.";
- code += FunctionStart('L') + "ength - 1; i >= 0; i--) builder.";
- code += FunctionStart('A') + "dd";
- code += GenMethod(vector_type);
- code += "(";
- code += SourceCastBasic(vector_type, false);
- code += "data[i]";
- if (lang_.language == IDLOptions::kCSharp &&
- (vector_type.base_type == BASE_TYPE_STRUCT ||
- vector_type.base_type == BASE_TYPE_STRING))
- code += ".Value";
- code += "); return ";
- code += "builder." + FunctionStart('E') + "ndVector(); }\n";
- // For C#, include a block copy method signature.
- if (lang_.language == IDLOptions::kCSharp) {
- code += " public static " + GenVectorOffsetType() + " ";
- code += FunctionStart('C') + "reate";
- code += MakeCamel(field.name);
- code += "VectorBlock(FlatBufferBuilder builder, ";
- code += GenTypeBasic(vector_type) + "[] data) ";
- code += "{ builder." + FunctionStart('S') + "tartVector(";
- code += NumToString(elem_size);
- code += ", data." + FunctionStart('L') + "ength, ";
- code += NumToString(alignment);
- code += "); builder.Add(data); return builder.EndVector(); }\n";
- }
- }
- // Generate a method to start a vector, data to be added manually
- // after.
- code += " public static void " + FunctionStart('S') + "tart";
- code += MakeCamel(field.name);
- code += "Vector(FlatBufferBuilder builder, int numElems) ";
- code += "{ builder." + FunctionStart('S') + "tartVector(";
- code += NumToString(elem_size);
- code += ", numElems, " + NumToString(alignment);
- code += "); }\n";
- }
- }
- code += " public static " + GenOffsetType(struct_def) + " ";
- code += FunctionStart('E') + "nd" + struct_def.name;
- code += "(FlatBufferBuilder builder) {\n int o = builder.";
- code += FunctionStart('E') + "ndTable();\n";
- for (auto it = struct_def.fields.vec.begin();
- it != struct_def.fields.vec.end(); ++it) {
- auto &field = **it;
- if (!field.deprecated && field.required) {
- code += " builder." + FunctionStart('R') + "equired(o, ";
- code += NumToString(field.value.offset);
- code += "); // " + field.name + "\n";
- }
- }
- code += " return " + GenOffsetConstruct(struct_def, "o") + ";\n }\n";
- if (parser_.root_struct_def_ == &struct_def) {
- std::string size_prefix[] = { "", "SizePrefixed" };
- for (int i = 0; i < 2; ++i) {
- code += " public static void ";
- code += FunctionStart('F') + "inish" + size_prefix[i] +
- struct_def.name;
- code += "Buffer(FlatBufferBuilder builder, " +
- GenOffsetType(struct_def);
- code += " offset) {";
- code += " builder." + FunctionStart('F') + "inish" + size_prefix[i] +
- "(offset";
- if (lang_.language == IDLOptions::kCSharp) { code += ".Value"; }
-
- if (parser_.file_identifier_.length())
- code += ", \"" + parser_.file_identifier_ + "\"";
- code += "); }\n";
- }
- }
- }
- // Only generate key compare function for table,
- // because `key_field` is not set for struct
- if (struct_def.has_key && !struct_def.fixed) {
- FLATBUFFERS_ASSERT(key_field);
- if (lang_.language == IDLOptions::kJava) {
- code += "\n @Override\n protected int keysCompare(";
- code += "Integer o1, Integer o2, ByteBuffer _bb) {";
- code += GenKeyGetter(key_field);
- code += " }\n";
- } else {
- code += "\n public static VectorOffset ";
- code += "CreateSortedVectorOf" + struct_def.name;
- code += "(FlatBufferBuilder builder, ";
- code += "Offset<" + struct_def.name + ">";
- code += "[] offsets) {\n";
- code += " Array.Sort(offsets, (Offset<" + struct_def.name +
- "> o1, Offset<" + struct_def.name + "> o2) => " +
- GenKeyGetter(key_field);
- code += ");\n";
- code += " return builder.CreateVectorOfTables(offsets);\n }\n";
- }
-
- code += "\n public static " + struct_def.name + lang_.optional_suffix;
- code += " __lookup_by_key(";
- if (lang_.language == IDLOptions::kJava)
- code += struct_def.name + " obj, ";
- code += "int vectorLocation, ";
- code += GenTypeNameDest(key_field->value.type);
- code += " key, ByteBuffer bb) {\n";
- if (key_field->value.type.base_type == BASE_TYPE_STRING) {
- code += " byte[] byteKey = ";
- if (lang_.language == IDLOptions::kJava)
- code += "key.getBytes(Table.UTF8_CHARSET.get());\n";
- else
- code += "System.Text.Encoding.UTF8.GetBytes(key);\n";
- }
- code += " int span = ";
- code += "bb." + FunctionStart('G') + "etInt(vectorLocation - 4);\n";
- code += " int start = 0;\n";
- code += " while (span != 0) {\n";
- code += " int middle = span / 2;\n";
- code += GenLookupKeyGetter(key_field);
- code += " if (comp > 0) {\n";
- code += " span = middle;\n";
- code += " } else if (comp < 0) {\n";
- code += " middle++;\n";
- code += " start += middle;\n";
- code += " span -= middle;\n";
- code += " } else {\n";
- code += " return ";
- if (lang_.language == IDLOptions::kJava)
- code += "(obj == null ? new " + struct_def.name + "() : obj)";
- else
- code += "new " + struct_def.name + "()";
- code += ".__assign(tableOffset, bb);\n";
- code += " }\n }\n";
- code += " return null;\n";
- code += " }\n";
- }
- code += "}";
- // Java does not need the closing semi-colon on class definitions.
- code += (lang_.language != IDLOptions::kJava) ? ";" : "";
- code += "\n\n";
- }
- const LanguageParameters &lang_;
- // This tracks the current namespace used to determine if a type need to be
- // prefixed by its namespace
- const Namespace *cur_name_space_;
-};
-} // namespace general
-
-bool GenerateGeneral(const Parser &parser, const std::string &path,
- const std::string &file_name) {
- general::GeneralGenerator generator(parser, path, file_name);
- return generator.generate();
-}
-
-std::string GeneralMakeRule(const Parser &parser, const std::string &path,
- const std::string &file_name) {
- FLATBUFFERS_ASSERT(parser.opts.lang <= IDLOptions::kMAX);
- const auto &lang = GetLangParams(parser.opts.lang);
-
- std::string make_rule;
-
- for (auto it = parser.enums_.vec.begin(); it != parser.enums_.vec.end();
- ++it) {
- auto &enum_def = **it;
- if (!make_rule.empty()) make_rule += " ";
- std::string directory =
- BaseGenerator::NamespaceDir(parser, path, *enum_def.defined_namespace);
- make_rule += directory + enum_def.name + lang.file_extension;
- }
-
- for (auto it = parser.structs_.vec.begin(); it != parser.structs_.vec.end();
- ++it) {
- auto &struct_def = **it;
- if (!make_rule.empty()) make_rule += " ";
- std::string directory = BaseGenerator::NamespaceDir(
- parser, path, *struct_def.defined_namespace);
- make_rule += directory + struct_def.name + lang.file_extension;
- }
-
- make_rule += ": ";
- auto included_files = parser.GetIncludedFilesRecursive(file_name);
- for (auto it = included_files.begin(); it != included_files.end(); ++it) {
- make_rule += " " + *it;
- }
- return make_rule;
-}
-
-std::string BinaryFileName(const Parser &parser, const std::string &path,
- const std::string &file_name) {
- auto ext = parser.file_extension_.length() ? parser.file_extension_ : "bin";
- return path + file_name + "." + ext;
-}
-
-bool GenerateBinary(const Parser &parser, const std::string &path,
- const std::string &file_name) {
- return !parser.builder_.GetSize() ||
- flatbuffers::SaveFile(
- BinaryFileName(parser, path, file_name).c_str(),
- reinterpret_cast<char *>(parser.builder_.GetBufferPointer()),
- parser.builder_.GetSize(), true);
-}
-
-std::string BinaryMakeRule(const Parser &parser, const std::string &path,
- const std::string &file_name) {
- if (!parser.builder_.GetSize()) return "";
- std::string filebase =
- flatbuffers::StripPath(flatbuffers::StripExtension(file_name));
- std::string make_rule =
- BinaryFileName(parser, path, filebase) + ": " + file_name;
- auto included_files =
- parser.GetIncludedFilesRecursive(parser.root_struct_def_->file);
- for (auto it = included_files.begin(); it != included_files.end(); ++it) {
- make_rule += " " + *it;
- }
- return make_rule;
-}
-
-} // namespace flatbuffers
diff --git a/src/idl_gen_go.cpp b/src/idl_gen_go.cpp
index 5e62b61..68cc01f 100644
--- a/src/idl_gen_go.cpp
+++ b/src/idl_gen_go.cpp
@@ -35,15 +35,10 @@
namespace flatbuffers {
-static std::string GeneratedFileName(const std::string &path,
- const std::string &file_name) {
- return path + file_name + "_generated.go";
-}
-
namespace go {
// see https://golang.org/ref/spec#Keywords
-static const char * const g_golang_keywords[] = {
+static const char *const g_golang_keywords[] = {
"break", "default", "func", "interface", "select", "case", "defer",
"go", "map", "struct", "chan", "else", "goto", "package",
"switch", "const", "fallthrough", "if", "range", "type", "continue",
@@ -64,7 +59,7 @@
GoGenerator(const Parser &parser, const std::string &path,
const std::string &file_name, const std::string &go_namespace)
: BaseGenerator(parser, path, file_name, "" /* not used*/,
- "" /* not used */),
+ "" /* not used */, "go"),
cur_name_space_(nullptr) {
std::istringstream iss(go_namespace);
std::string component;
@@ -75,15 +70,23 @@
bool generate() {
std::string one_file_code;
+ bool needs_imports = false;
for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
++it) {
tracked_imported_namespaces_.clear();
+ needs_imports = false;
std::string enumcode;
GenEnum(**it, &enumcode);
+ if ((*it)->is_union && parser_.opts.generate_object_based_api) {
+ GenNativeUnion(**it, &enumcode);
+ GenNativeUnionPack(**it, &enumcode);
+ GenNativeUnionUnPack(**it, &enumcode);
+ needs_imports = true;
+ }
if (parser_.opts.one_file) {
one_file_code += enumcode;
} else {
- if (!SaveType(**it, enumcode, false, true)) return false;
+ if (!SaveType(**it, enumcode, needs_imports, true)) return false;
}
}
@@ -104,7 +107,8 @@
const bool is_enum = !parser_.enums_.vec.empty();
BeginFile(LastNamespacePart(go_namespace_), true, is_enum, &code);
code += one_file_code;
- const std::string filename = GeneratedFileName(path_, file_name_);
+ const std::string filename =
+ GeneratedFileName(path_, file_name_, parser_.opts);
return SaveFile(filename.c_str(), code, false);
}
@@ -143,7 +147,8 @@
// Construct the name of the type for this enum.
std::string GetEnumTypeName(const EnumDef &enum_def) {
- return WrapInNameSpaceAndTrack(enum_def.defined_namespace, GoIdentity(enum_def.name));
+ return WrapInNameSpaceAndTrack(enum_def.defined_namespace,
+ GoIdentity(enum_def.name));
}
// Create a type for the enum values.
@@ -214,7 +219,7 @@
code += "\tif s, ok := EnumNames" + enum_def.name + "[v]; ok {\n";
code += "\t\treturn s\n";
code += "\t}\n";
- code += "\treturn \""+ enum_def.name;
+ code += "\treturn \"" + enum_def.name;
code += "(\" + strconv.FormatInt(int64(v), 10) + \")\"\n";
code += "}\n\n";
}
@@ -250,17 +255,28 @@
void NewRootTypeFromBuffer(const StructDef &struct_def,
std::string *code_ptr) {
std::string &code = *code_ptr;
+ std::string size_prefix[] = { "", "SizePrefixed" };
- code += "func GetRootAs";
- code += struct_def.name;
- code += "(buf []byte, offset flatbuffers.UOffsetT) ";
- code += "*" + struct_def.name + "";
- code += " {\n";
- code += "\tn := flatbuffers.GetUOffsetT(buf[offset:])\n";
- code += "\tx := &" + struct_def.name + "{}\n";
- code += "\tx.Init(buf, n+offset)\n";
- code += "\treturn x\n";
- code += "}\n\n";
+ for (int i = 0; i < 2; i++) {
+ code += "func Get" + size_prefix[i] + "RootAs";
+ code += struct_def.name;
+ code += "(buf []byte, offset flatbuffers.UOffsetT) ";
+ code += "*" + struct_def.name + "";
+ code += " {\n";
+ if (i == 0) {
+ code += "\tn := flatbuffers.GetUOffsetT(buf[offset:])\n";
+ } else {
+ code += "\tn := flatbuffers.GetUOffsetT(buf[offset+flatbuffers.SizeUint32:])\n";
+ }
+ code += "\tx := &" + struct_def.name + "{}\n";
+ if (i == 0) {
+ code += "\tx.Init(buf, n+offset)\n";
+ } else {
+ code += "\tx.Init(buf, n+offset+flatbuffers.SizeUint32)\n";
+ }
+ code += "\treturn x\n";
+ code += "}\n\n";
+ }
}
// Initialize an existing object with other data, to avoid an allocation.
@@ -317,23 +333,21 @@
// Get the value of a struct's scalar.
void GetScalarFieldOfStruct(const StructDef &struct_def,
- const FieldDef &field,
- std::string *code_ptr) {
+ const FieldDef &field, std::string *code_ptr) {
std::string &code = *code_ptr;
std::string getter = GenGetter(field.value.type);
GenReceiver(struct_def, code_ptr);
code += " " + MakeCamel(field.name);
code += "() " + TypeName(field) + " {\n";
- code += "\treturn " + CastToEnum(
- field.value.type,
- getter + "(rcv._tab.Pos + flatbuffers.UOffsetT(" +
- NumToString(field.value.offset) + "))");
+ code += "\treturn " +
+ CastToEnum(field.value.type,
+ getter + "(rcv._tab.Pos + flatbuffers.UOffsetT(" +
+ NumToString(field.value.offset) + "))");
code += "\n}\n";
}
// Get the value of a table's scalar.
- void GetScalarFieldOfTable(const StructDef &struct_def,
- const FieldDef &field,
+ void GetScalarFieldOfTable(const StructDef &struct_def, const FieldDef &field,
std::string *code_ptr) {
std::string &code = *code_ptr;
std::string getter = GenGetter(field.value.type);
@@ -350,8 +364,7 @@
// Get a struct by initializing an existing struct.
// Specific to Struct.
void GetStructFieldOfStruct(const StructDef &struct_def,
- const FieldDef &field,
- std::string *code_ptr) {
+ const FieldDef &field, std::string *code_ptr) {
std::string &code = *code_ptr;
GenReceiver(struct_def, code_ptr);
code += " " + MakeCamel(field.name);
@@ -369,8 +382,7 @@
// Get a struct by initializing an existing struct.
// Specific to Table.
- void GetStructFieldOfTable(const StructDef &struct_def,
- const FieldDef &field,
+ void GetStructFieldOfTable(const StructDef &struct_def, const FieldDef &field,
std::string *code_ptr) {
std::string &code = *code_ptr;
GenReceiver(struct_def, code_ptr);
@@ -392,8 +404,7 @@
}
// Get the value of a string.
- void GetStringField(const StructDef &struct_def,
- const FieldDef &field,
+ void GetStringField(const StructDef &struct_def, const FieldDef &field,
std::string *code_ptr) {
std::string &code = *code_ptr;
GenReceiver(struct_def, code_ptr);
@@ -420,8 +431,7 @@
// Get the value of a vector's struct member.
void GetMemberOfVectorOfStruct(const StructDef &struct_def,
- const FieldDef &field,
- std::string *code_ptr) {
+ const FieldDef &field, std::string *code_ptr) {
std::string &code = *code_ptr;
auto vectortype = field.value.type.VectorType();
@@ -453,12 +463,13 @@
code += "(j int) " + TypeName(field) + " ";
code += OffsetPrefix(field);
code += "\t\ta := rcv._tab.Vector(o)\n";
- code += "\t\treturn " + CastToEnum(
- field.value.type,
- GenGetter(field.value.type) + "(a + flatbuffers.UOffsetT(j*" +
- NumToString(InlineSize(vectortype)) + "))");
+ code += "\t\treturn " +
+ CastToEnum(field.value.type,
+ GenGetter(field.value.type) +
+ "(a + flatbuffers.UOffsetT(j*" +
+ NumToString(InlineSize(vectortype)) + "))");
code += "\n\t}\n";
- if (vectortype.base_type == BASE_TYPE_STRING) {
+ if (IsString(vectortype)) {
code += "\treturn nil\n";
} else if (vectortype.base_type == BASE_TYPE_BOOL) {
code += "\treturn false\n";
@@ -510,8 +521,8 @@
// Recursively generate struct construction statements and instert manual
// padding.
- void StructBuilderBody(const StructDef &struct_def,
- const char *nameprefix, std::string *code_ptr) {
+ void StructBuilderBody(const StructDef &struct_def, const char *nameprefix,
+ std::string *code_ptr) {
std::string &code = *code_ptr;
code += "\tbuilder.Prep(" + NumToString(struct_def.minalign) + ", ";
code += NumToString(struct_def.bytesize) + ")\n";
@@ -525,7 +536,9 @@
(nameprefix + (field.name + "_")).c_str(), code_ptr);
} else {
code += "\tbuilder.Prepend" + GenMethod(field) + "(";
- code += CastToBaseType(field.value.type, nameprefix + GoIdentity(field.name)) + ")\n";
+ code += CastToBaseType(field.value.type,
+ nameprefix + GoIdentity(field.name)) +
+ ")\n";
}
}
}
@@ -574,8 +587,8 @@
}
// Set the value of one of the members of a table's vector.
- void BuildVectorOfTable(const StructDef &struct_def,
- const FieldDef &field, std::string *code_ptr) {
+ void BuildVectorOfTable(const StructDef &struct_def, const FieldDef &field,
+ std::string *code_ptr) {
std::string &code = *code_ptr;
code += "func " + struct_def.name + "Start";
code += MakeCamel(field.name);
@@ -604,8 +617,8 @@
}
// Generate a struct field getter, conditioned on its child type(s).
- void GenStructAccessor(const StructDef &struct_def,
- const FieldDef &field, std::string *code_ptr) {
+ void GenStructAccessor(const StructDef &struct_def, const FieldDef &field,
+ std::string *code_ptr) {
GenComment(field.doc_comment, code_ptr, nullptr, "");
if (IsScalar(field.value.type.base_type)) {
if (struct_def.fixed) {
@@ -622,7 +635,9 @@
GetStructFieldOfTable(struct_def, field, code_ptr);
}
break;
- case BASE_TYPE_STRING: GetStringField(struct_def, field, code_ptr); break;
+ case BASE_TYPE_STRING:
+ GetStringField(struct_def, field, code_ptr);
+ break;
case BASE_TYPE_VECTOR: {
auto vectortype = field.value.type.VectorType();
if (vectortype.base_type == BASE_TYPE_STRUCT) {
@@ -636,7 +651,7 @@
default: FLATBUFFERS_ASSERT(0);
}
}
- if (field.value.type.base_type == BASE_TYPE_VECTOR) {
+ if (IsVector(field.value.type)) {
GetVectorLen(struct_def, field, code_ptr);
if (field.value.type.element == BASE_TYPE_UCHAR) {
GetUByteSlice(struct_def, field, code_ptr);
@@ -646,8 +661,7 @@
// Mutate the value of a struct's scalar.
void MutateScalarFieldOfStruct(const StructDef &struct_def,
- const FieldDef &field,
- std::string *code_ptr) {
+ const FieldDef &field, std::string *code_ptr) {
std::string &code = *code_ptr;
std::string type = MakeCamel(GenTypeBasic(field.value.type));
std::string setter = "rcv._tab.Mutate" + type;
@@ -661,8 +675,7 @@
// Mutate the value of a table's scalar.
void MutateScalarFieldOfTable(const StructDef &struct_def,
- const FieldDef &field,
- std::string *code_ptr) {
+ const FieldDef &field, std::string *code_ptr) {
std::string &code = *code_ptr;
std::string type = MakeCamel(GenTypeBasic(field.value.type));
std::string setter = "rcv._tab.Mutate" + type + "Slot";
@@ -706,7 +719,7 @@
} else {
MutateScalarFieldOfTable(struct_def, field, code_ptr);
}
- } else if (field.value.type.base_type == BASE_TYPE_VECTOR) {
+ } else if (IsVector(field.value.type)) {
if (IsScalar(field.value.type.element)) {
MutateElementOfVectorOfNonStruct(struct_def, field, code_ptr);
}
@@ -724,7 +737,7 @@
auto offset = it - struct_def.fields.vec.begin();
BuildFieldOfTable(struct_def, field, offset, code_ptr);
- if (field.value.type.base_type == BASE_TYPE_VECTOR) {
+ if (IsVector(field.value.type)) {
BuildVectorOfTable(struct_def, field, code_ptr);
}
}
@@ -739,6 +752,9 @@
cur_name_space_ = struct_def.defined_namespace;
GenComment(struct_def.doc_comment, code_ptr, nullptr);
+ if (parser_.opts.generate_object_based_api) {
+ GenNativeStruct(struct_def, code_ptr);
+ }
BeginClass(struct_def, code_ptr);
if (!struct_def.fixed) {
// Generate a special accessor for the table that has been declared as
@@ -771,6 +787,327 @@
}
}
+ void GenNativeStruct(const StructDef &struct_def, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+ code += "type " + NativeName(struct_def) + " struct {\n";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ const FieldDef &field = **it;
+ if (field.deprecated) continue;
+ if (IsScalar(field.value.type.base_type) &&
+ field.value.type.enum_def != nullptr &&
+ field.value.type.enum_def->is_union)
+ continue;
+ code += "\t" + MakeCamel(field.name) + " " +
+ NativeType(field.value.type) + "\n";
+ }
+ code += "}\n\n";
+
+ if (!struct_def.fixed) {
+ GenNativeTablePack(struct_def, code_ptr);
+ GenNativeTableUnPack(struct_def, code_ptr);
+ } else {
+ GenNativeStructPack(struct_def, code_ptr);
+ GenNativeStructUnPack(struct_def, code_ptr);
+ }
+ }
+
+ void GenNativeUnion(const EnumDef &enum_def, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "type " + NativeName(enum_def) + " struct {\n";
+ code += "\tType " + enum_def.name + "\n";
+ code += "\tValue interface{}\n";
+ code += "}\n\n";
+ }
+
+ void GenNativeUnionPack(const EnumDef &enum_def, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "func (t *" + NativeName(enum_def) +
+ ") Pack(builder *flatbuffers.Builder) flatbuffers.UOffsetT {\n";
+ code += "\tif t == nil {\n\t\treturn 0\n\t}\n";
+
+ code += "\tswitch t.Type {\n";
+ for (auto it2 = enum_def.Vals().begin(); it2 != enum_def.Vals().end();
+ ++it2) {
+ const EnumVal &ev = **it2;
+ if (ev.IsZero()) continue;
+ code += "\tcase " + enum_def.name + ev.name + ":\n";
+ code += "\t\treturn t.Value.(" + NativeType(ev.union_type) +
+ ").Pack(builder)\n";
+ }
+ code += "\t}\n";
+ code += "\treturn 0\n";
+ code += "}\n\n";
+ }
+
+ void GenNativeUnionUnPack(const EnumDef &enum_def, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+ code += "func (rcv " + enum_def.name +
+ ") UnPack(table flatbuffers.Table) *" + NativeName(enum_def) +
+ " {\n";
+ code += "\tswitch rcv {\n";
+
+ for (auto it2 = enum_def.Vals().begin(); it2 != enum_def.Vals().end();
+ ++it2) {
+ const EnumVal &ev = **it2;
+ if (ev.IsZero()) continue;
+ code += "\tcase " + enum_def.name + ev.name + ":\n";
+ code += "\t\tx := " + ev.union_type.struct_def->name + "{_tab: table}\n";
+
+ code += "\t\treturn &" +
+ WrapInNameSpaceAndTrack(enum_def.defined_namespace,
+ NativeName(enum_def)) +
+ "{ Type: " + enum_def.name + ev.name + ", Value: x.UnPack() }\n";
+ }
+ code += "\t}\n";
+ code += "\treturn nil\n";
+ code += "}\n\n";
+ }
+
+ void GenNativeTablePack(const StructDef &struct_def, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+ code += "func (t *" + NativeName(struct_def) +
+ ") Pack(builder *flatbuffers.Builder) flatbuffers.UOffsetT {\n";
+ code += "\tif t == nil { return 0 }\n";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ const FieldDef &field = **it;
+ if (field.deprecated) continue;
+ if (IsScalar(field.value.type.base_type)) continue;
+
+ std::string offset = MakeCamel(field.name, false) + "Offset";
+
+ if (IsString(field.value.type)) {
+ code += "\t" + offset + " := builder.CreateString(t." +
+ MakeCamel(field.name) + ")\n";
+ } else if (IsVector(field.value.type) &&
+ field.value.type.element == BASE_TYPE_UCHAR &&
+ field.value.type.enum_def == nullptr) {
+ code += "\t" + offset + " := flatbuffers.UOffsetT(0)\n";
+ code += "\tif t." + MakeCamel(field.name) + " != nil {\n";
+ code += "\t\t" + offset + " = builder.CreateByteString(t." +
+ MakeCamel(field.name) + ")\n";
+ code += "\t}\n";
+ } else if (IsVector(field.value.type)) {
+ code += "\t" + offset + " := flatbuffers.UOffsetT(0)\n";
+ code += "\tif t." + MakeCamel(field.name) + " != nil {\n";
+ std::string length = MakeCamel(field.name, false) + "Length";
+ std::string offsets = MakeCamel(field.name, false) + "Offsets";
+ code += "\t\t" + length + " := len(t." + MakeCamel(field.name) + ")\n";
+ if (field.value.type.element == BASE_TYPE_STRING) {
+ code += "\t\t" + offsets + " := make([]flatbuffers.UOffsetT, " +
+ length + ")\n";
+ code += "\t\tfor j := 0; j < " + length + "; j++ {\n";
+ code += "\t\t\t" + offsets + "[j] = builder.CreateString(t." +
+ MakeCamel(field.name) + "[j])\n";
+ code += "\t\t}\n";
+ } else if (field.value.type.element == BASE_TYPE_STRUCT &&
+ !field.value.type.struct_def->fixed) {
+ code += "\t\t" + offsets + " := make([]flatbuffers.UOffsetT, " +
+ length + ")\n";
+ code += "\t\tfor j := 0; j < " + length + "; j++ {\n";
+ code += "\t\t\t" + offsets + "[j] = t." + MakeCamel(field.name) +
+ "[j].Pack(builder)\n";
+ code += "\t\t}\n";
+ }
+ code += "\t\t" + struct_def.name + "Start" + MakeCamel(field.name) +
+ "Vector(builder, " + length + ")\n";
+ code += "\t\tfor j := " + length + " - 1; j >= 0; j-- {\n";
+ if (IsScalar(field.value.type.element)) {
+ code += "\t\t\tbuilder.Prepend" +
+ MakeCamel(GenTypeBasic(field.value.type.VectorType())) + "(" +
+ CastToBaseType(field.value.type.VectorType(),
+ "t." + MakeCamel(field.name) + "[j]") +
+ ")\n";
+ } else if (field.value.type.element == BASE_TYPE_STRUCT &&
+ field.value.type.struct_def->fixed) {
+ code += "\t\t\tt." + MakeCamel(field.name) + "[j].Pack(builder)\n";
+ } else {
+ code += "\t\t\tbuilder.PrependUOffsetT(" + offsets + "[j])\n";
+ }
+ code += "\t\t}\n";
+ code += "\t\t" + offset + " = builder.EndVector(" + length + ")\n";
+ code += "\t}\n";
+ } else if (field.value.type.base_type == BASE_TYPE_STRUCT) {
+ if (field.value.type.struct_def->fixed) continue;
+ code += "\t" + offset + " := t." + MakeCamel(field.name) +
+ ".Pack(builder)\n";
+ } else if (field.value.type.base_type == BASE_TYPE_UNION) {
+ code += "\t" + offset + " := t." + MakeCamel(field.name) +
+ ".Pack(builder)\n";
+ code += "\t\n";
+ } else {
+ FLATBUFFERS_ASSERT(0);
+ }
+ }
+ code += "\t" + struct_def.name + "Start(builder)\n";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ const FieldDef &field = **it;
+ if (field.deprecated) continue;
+
+ std::string offset = MakeCamel(field.name, false) + "Offset";
+ if (IsScalar(field.value.type.base_type)) {
+ if (field.value.type.enum_def == nullptr ||
+ !field.value.type.enum_def->is_union) {
+ code += "\t" + struct_def.name + "Add" + MakeCamel(field.name) +
+ "(builder, t." + MakeCamel(field.name) + ")\n";
+ }
+ } else {
+ if (field.value.type.base_type == BASE_TYPE_STRUCT &&
+ field.value.type.struct_def->fixed) {
+ code += "\t" + offset + " := t." + MakeCamel(field.name) +
+ ".Pack(builder)\n";
+ } else if (field.value.type.enum_def != nullptr &&
+ field.value.type.enum_def->is_union) {
+ code += "\tif t." + MakeCamel(field.name) + " != nil {\n";
+ code += "\t\t" + struct_def.name + "Add" +
+ MakeCamel(field.name + UnionTypeFieldSuffix()) +
+ "(builder, t." + MakeCamel(field.name) + ".Type)\n";
+ code += "\t}\n";
+ }
+ code += "\t" + struct_def.name + "Add" + MakeCamel(field.name) +
+ "(builder, " + offset + ")\n";
+ }
+ }
+ code += "\treturn " + struct_def.name + "End(builder)\n";
+ code += "}\n\n";
+ }
+
+ void GenNativeTableUnPack(const StructDef &struct_def,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+ code += "func (rcv *" + struct_def.name + ") UnPackTo(t *" +
+ NativeName(struct_def) + ") {\n";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ const FieldDef &field = **it;
+ if (field.deprecated) continue;
+ std::string field_name_camel = MakeCamel(field.name);
+ std::string length = MakeCamel(field.name, false) + "Length";
+ if (IsScalar(field.value.type.base_type)) {
+ if (field.value.type.enum_def != nullptr &&
+ field.value.type.enum_def->is_union)
+ continue;
+ code +=
+ "\tt." + field_name_camel + " = rcv." + field_name_camel + "()\n";
+ } else if (IsString(field.value.type)) {
+ code += "\tt." + field_name_camel + " = string(rcv." +
+ field_name_camel + "())\n";
+ } else if (IsVector(field.value.type) &&
+ field.value.type.element == BASE_TYPE_UCHAR &&
+ field.value.type.enum_def == nullptr) {
+ code += "\tt." + field_name_camel + " = rcv." + field_name_camel +
+ "Bytes()\n";
+ } else if (IsVector(field.value.type)) {
+ code += "\t" + length + " := rcv." + field_name_camel + "Length()\n";
+ code += "\tt." + field_name_camel + " = make(" +
+ NativeType(field.value.type) + ", " + length + ")\n";
+ code += "\tfor j := 0; j < " + length + "; j++ {\n";
+ if (field.value.type.element == BASE_TYPE_STRUCT) {
+ code += "\t\tx := " + field.value.type.struct_def->name + "{}\n";
+ code += "\t\trcv." + field_name_camel + "(&x, j)\n";
+ }
+ code += "\t\tt." + field_name_camel + "[j] = ";
+ if (IsScalar(field.value.type.element)) {
+ code += "rcv." + field_name_camel + "(j)";
+ } else if (field.value.type.element == BASE_TYPE_STRING) {
+ code += "string(rcv." + field_name_camel + "(j))";
+ } else if (field.value.type.element == BASE_TYPE_STRUCT) {
+ code += "x.UnPack()";
+ } else {
+ // TODO(iceboy): Support vector of unions.
+ FLATBUFFERS_ASSERT(0);
+ }
+ code += "\n";
+ code += "\t}\n";
+ } else if (field.value.type.base_type == BASE_TYPE_STRUCT) {
+ code += "\tt." + field_name_camel + " = rcv." + field_name_camel +
+ "(nil).UnPack()\n";
+ } else if (field.value.type.base_type == BASE_TYPE_UNION) {
+ std::string field_table = MakeCamel(field.name, false) + "Table";
+ code += "\t" + field_table + " := flatbuffers.Table{}\n";
+ code +=
+ "\tif rcv." + MakeCamel(field.name) + "(&" + field_table + ") {\n";
+ code += "\t\tt." + field_name_camel + " = rcv." +
+ MakeCamel(field.name + UnionTypeFieldSuffix()) + "().UnPack(" +
+ field_table + ")\n";
+ code += "\t}\n";
+ } else {
+ FLATBUFFERS_ASSERT(0);
+ }
+ }
+ code += "}\n\n";
+
+ code += "func (rcv *" + struct_def.name + ") UnPack() *" +
+ NativeName(struct_def) + " {\n";
+ code += "\tif rcv == nil { return nil }\n";
+ code += "\tt := &" + NativeName(struct_def) + "{}\n";
+ code += "\trcv.UnPackTo(t)\n";
+ code += "\treturn t\n";
+ code += "}\n\n";
+ }
+
+ void GenNativeStructPack(const StructDef &struct_def, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+ code += "func (t *" + NativeName(struct_def) +
+ ") Pack(builder *flatbuffers.Builder) flatbuffers.UOffsetT {\n";
+ code += "\tif t == nil { return 0 }\n";
+ code += "\treturn Create" + struct_def.name + "(builder";
+ StructPackArgs(struct_def, "", code_ptr);
+ code += ")\n";
+ code += "}\n";
+ }
+
+ void StructPackArgs(const StructDef &struct_def, const char *nameprefix,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ const FieldDef &field = **it;
+ if (field.value.type.base_type == BASE_TYPE_STRUCT) {
+ StructPackArgs(*field.value.type.struct_def,
+ (nameprefix + MakeCamel(field.name) + ".").c_str(),
+ code_ptr);
+ } else {
+ code += std::string(", t.") + nameprefix + MakeCamel(field.name);
+ }
+ }
+ }
+
+ void GenNativeStructUnPack(const StructDef &struct_def,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+ code += "func (rcv *" + struct_def.name + ") UnPackTo(t *" +
+ NativeName(struct_def) + ") {\n";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ const FieldDef &field = **it;
+ if (field.value.type.base_type == BASE_TYPE_STRUCT) {
+ code += "\tt." + MakeCamel(field.name) + " = rcv." +
+ MakeCamel(field.name) + "(nil).UnPack()\n";
+ } else {
+ code += "\tt." + MakeCamel(field.name) + " = rcv." +
+ MakeCamel(field.name) + "()\n";
+ }
+ }
+ code += "}\n\n";
+
+ code += "func (rcv *" + struct_def.name + ") UnPack() *" +
+ NativeName(struct_def) + " {\n";
+ code += "\tif rcv == nil { return nil }\n";
+ code += "\tt := &" + NativeName(struct_def) + "{}\n";
+ code += "\trcv.UnPackTo(t)\n";
+ code += "\treturn t\n";
+ code += "}\n\n";
+ }
+
// Generate enum declarations.
void GenEnum(const EnumDef &enum_def, std::string *code_ptr) {
if (enum_def.generated) return;
@@ -782,7 +1119,7 @@
GenEnumType(enum_def, code_ptr);
BeginEnum(code_ptr);
for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
- auto &ev = **it;
+ const EnumVal &ev = **it;
GenComment(ev.doc_comment, code_ptr, nullptr, "\t");
EnumMember(enum_def, ev, max_name_length, code_ptr);
}
@@ -790,14 +1127,13 @@
BeginEnumNames(enum_def, code_ptr);
for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
- auto &ev = **it;
+ const EnumVal &ev = **it;
EnumNameMember(enum_def, ev, max_name_length, code_ptr);
}
EndEnumNames(code_ptr);
BeginEnumValues(enum_def, code_ptr);
- for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
- ++it) {
+ for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
auto &ev = **it;
EnumValueMember(enum_def, ev, max_name_length, code_ptr);
}
@@ -824,15 +1160,14 @@
}
std::string GenTypeBasic(const Type &type) {
- static const char *ctypename[] = {
// clang-format off
- #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
- CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \
+ static const char *ctypename[] = {
+ #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, ...) \
#GTYPE,
FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
#undef FLATBUFFERS_TD
- // clang-format on
};
+ // clang-format on
return ctypename[type.base_type];
}
@@ -848,9 +1183,7 @@
}
std::string GenTypeGet(const Type &type) {
- if (type.enum_def != nullptr) {
- return GetEnumTypeName(*type.enum_def);
- }
+ if (type.enum_def != nullptr) { return GetEnumTypeName(*type.enum_def); }
return IsScalar(type.base_type) ? GenTypeBasic(type) : GenTypePointer(type);
}
@@ -880,11 +1213,44 @@
std::string GenConstant(const FieldDef &field) {
switch (field.value.type.base_type) {
- case BASE_TYPE_BOOL: return field.value.constant == "0" ? "false" : "true";;
+ case BASE_TYPE_BOOL:
+ return field.value.constant == "0" ? "false" : "true";
default: return field.value.constant;
}
}
+ std::string NativeName(const StructDef &struct_def) {
+ return parser_.opts.object_prefix + struct_def.name +
+ parser_.opts.object_suffix;
+ }
+
+ std::string NativeName(const EnumDef &enum_def) {
+ return parser_.opts.object_prefix + enum_def.name +
+ parser_.opts.object_suffix;
+ }
+
+ std::string NativeType(const Type &type) {
+ if (IsScalar(type.base_type)) {
+ if (type.enum_def == nullptr) {
+ return GenTypeBasic(type);
+ } else {
+ return GetEnumTypeName(*type.enum_def);
+ }
+ } else if (IsString(type)) {
+ return "string";
+ } else if (IsVector(type)) {
+ return "[]" + NativeType(type.VectorType());
+ } else if (type.base_type == BASE_TYPE_STRUCT) {
+ return "*" + WrapInNameSpaceAndTrack(type.struct_def->defined_namespace,
+ NativeName(*type.struct_def));
+ } else if (type.base_type == BASE_TYPE_UNION) {
+ return "*" + WrapInNameSpaceAndTrack(type.enum_def->defined_namespace,
+ NativeName(*type.enum_def));
+ }
+ FLATBUFFERS_ASSERT(0);
+ return std::string();
+ }
+
// Create a struct with a builder and the struct's arguments.
void GenStructBuilder(const StructDef &struct_def, std::string *code_ptr) {
BeginBuilderArgs(struct_def, code_ptr);
@@ -898,13 +1264,12 @@
void BeginFile(const std::string &name_space_name, const bool needs_imports,
const bool is_enum, std::string *code_ptr) {
std::string &code = *code_ptr;
- code = code + "// Code generated by the FlatBuffers compiler. DO NOT EDIT.\n\n";
+ code = code +
+ "// Code generated by the FlatBuffers compiler. DO NOT EDIT.\n\n";
code += "package " + name_space_name + "\n\n";
if (needs_imports) {
code += "import (\n";
- if (is_enum) {
- code += "\t\"strconv\"\n\n";
- }
+ if (is_enum) { code += "\t\"strconv\"\n\n"; }
if (!parser_.opts.go_import.empty()) {
code += "\tflatbuffers \"" + parser_.opts.go_import + "\"\n";
} else {
@@ -913,17 +1278,14 @@
if (tracked_imported_namespaces_.size() > 0) {
code += "\n";
for (auto it = tracked_imported_namespaces_.begin();
- it != tracked_imported_namespaces_.end();
- ++it) {
- code += "\t" + NamespaceImportName(*it) + " \"" + \
- NamespaceImportPath(*it) + "\"\n";
+ it != tracked_imported_namespaces_.end(); ++it) {
+ code += "\t" + NamespaceImportName(*it) + " \"" +
+ NamespaceImportPath(*it) + "\"\n";
}
}
code += ")\n\n";
} else {
- if (is_enum) {
- code += "import \"strconv\"\n\n";
- }
+ if (is_enum) { code += "import \"strconv\"\n\n"; }
}
}
@@ -991,8 +1353,7 @@
static size_t MaxNameLength(const EnumDef &enum_def) {
size_t max = 0;
- for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
- ++it) {
+ for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
max = std::max((*it)->name.length(), max);
}
return max;
diff --git a/src/idl_gen_grpc.cpp b/src/idl_gen_grpc.cpp
index 1d5e8e5..394ebe3 100644
--- a/src/idl_gen_grpc.cpp
+++ b/src/idl_gen_grpc.cpp
@@ -20,10 +20,13 @@
#include "flatbuffers/flatbuffers.h"
#include "flatbuffers/idl.h"
#include "flatbuffers/util.h"
-
#include "src/compiler/cpp_generator.h"
#include "src/compiler/go_generator.h"
#include "src/compiler/java_generator.h"
+#include "src/compiler/python_generator.h"
+#include "src/compiler/python_private_generator.h"
+#include "src/compiler/swift_generator.h"
+#include "src/compiler/ts_generator.h"
#if defined(_MSC_VER)
# pragma warning(push)
@@ -35,9 +38,7 @@
class FlatBufMethod : public grpc_generator::Method {
public:
- enum Streaming {
- kNone, kClient, kServer, kBiDi
- };
+ enum Streaming { kNone, kClient, kServer, kBiDi };
FlatBufMethod(const RPCCall *method) : method_(method) {
streaming_ = kNone;
@@ -59,12 +60,22 @@
std::string name() const { return method_->name; }
+ // TODO: This method need to incorporate namespace for C++ side. Other
+ // language bindings simply don't use this method.
std::string GRPCType(const StructDef &sd) const {
return "flatbuffers::grpc::Message<" + sd.name + ">";
}
+ std::vector<std::string> get_input_namespace_parts() const {
+ return (*method_->request).defined_namespace->components;
+ }
+
std::string get_input_type_name() const { return (*method_->request).name; }
+ std::vector<std::string> get_output_namespace_parts() const {
+ return (*method_->response).defined_namespace->components;
+ }
+
std::string get_output_type_name() const { return (*method_->response).name; }
bool get_module_and_message_path_input(grpc::string * /*str*/,
@@ -80,6 +91,8 @@
return true;
}
+ std::string get_fb_builder() const { return "builder"; }
+
std::string input_type_name() const { return GRPCType(*method_->request); }
std::string output_type_name() const { return GRPCType(*method_->response); }
@@ -109,7 +122,14 @@
return service_->doc_comment;
}
+ std::vector<grpc::string> namespace_parts() const {
+ return service_->defined_namespace->components;
+ }
+
std::string name() const { return service_->name; }
+ bool is_internal() const {
+ return service_->Definition::attributes.Lookup("private") ? true : false;
+ }
int method_count() const {
return static_cast<int>(service_->calls.vec.size());
@@ -171,7 +191,7 @@
void Outdent() {
indent_--;
- FLATBUFFERS_ASSERT(indent_ >= 0);
+ FLATBUFFERS_ASSERT(indent_ >= 0);
}
private:
@@ -183,7 +203,12 @@
class FlatBufFile : public grpc_generator::File {
public:
enum Language {
- kLanguageGo, kLanguageCpp, kLanguageJava
+ kLanguageGo,
+ kLanguageCpp,
+ kLanguageJava,
+ kLanguagePython,
+ kLanguageSwift,
+ kLanguageTS
};
FlatBufFile(const Parser &parser, const std::string &file_name,
@@ -229,6 +254,15 @@
case kLanguageJava: {
return "import com.google.flatbuffers.grpc.FlatbuffersUtils;";
}
+ case kLanguagePython: {
+ return "";
+ }
+ case kLanguageSwift: {
+ return "";
+ }
+ case kLanguageTS: {
+ return "";
+ }
}
return "";
}
@@ -257,7 +291,7 @@
public:
GoGRPCGenerator(const Parser &parser, const std::string &path,
const std::string &file_name)
- : BaseGenerator(parser, path, file_name, "", "" /*Unused*/),
+ : BaseGenerator(parser, path, file_name, "", "" /*Unused*/, "go"),
parser_(parser),
path_(path),
file_name_(file_name) {}
@@ -270,7 +304,8 @@
auto service = file.service(i);
const Definition *def = parser_.services_.vec[i];
p.package_name = LastNamespacePart(*(def->defined_namespace));
- p.service_prefix = def->defined_namespace->GetFullyQualifiedName(""); // file.package();
+ p.service_prefix =
+ def->defined_namespace->GetFullyQualifiedName(""); // file.package();
std::string output =
grpc_go_generator::GenerateServiceSource(&file, service.get(), &p);
std::string filename =
@@ -313,27 +348,27 @@
std::string header_code =
grpc_cpp_generator::GetHeaderPrologue(&fbfile, generator_parameters) +
- grpc_cpp_generator::GetHeaderIncludes(&fbfile, generator_parameters) +
- grpc_cpp_generator::GetHeaderServices(&fbfile, generator_parameters) +
- grpc_cpp_generator::GetHeaderEpilogue(&fbfile, generator_parameters);
+ grpc_cpp_generator::GetHeaderIncludes(&fbfile, generator_parameters) +
+ grpc_cpp_generator::GetHeaderServices(&fbfile, generator_parameters) +
+ grpc_cpp_generator::GetHeaderEpilogue(&fbfile, generator_parameters);
std::string source_code =
grpc_cpp_generator::GetSourcePrologue(&fbfile, generator_parameters) +
- grpc_cpp_generator::GetSourceIncludes(&fbfile, generator_parameters) +
- grpc_cpp_generator::GetSourceServices(&fbfile, generator_parameters) +
- grpc_cpp_generator::GetSourceEpilogue(&fbfile, generator_parameters);
+ grpc_cpp_generator::GetSourceIncludes(&fbfile, generator_parameters) +
+ grpc_cpp_generator::GetSourceServices(&fbfile, generator_parameters) +
+ grpc_cpp_generator::GetSourceEpilogue(&fbfile, generator_parameters);
return flatbuffers::SaveFile((path + file_name + ".grpc.fb.h").c_str(),
header_code, false) &&
- flatbuffers::SaveFile((path + file_name + ".grpc.fb.cc").c_str(),
- source_code, false);
+ flatbuffers::SaveFile((path + file_name + ".grpc.fb.cc").c_str(),
+ source_code, false);
}
class JavaGRPCGenerator : public flatbuffers::BaseGenerator {
public:
JavaGRPCGenerator(const Parser &parser, const std::string &path,
const std::string &file_name)
- : BaseGenerator(parser, path, file_name, "", "." /*separator*/) {}
+ : BaseGenerator(parser, path, file_name, "", "." /*separator*/, "java") {}
bool generate() {
FlatBufFile file(parser_, file_name_, FlatBufFile::kLanguageJava);
@@ -364,6 +399,127 @@
return JavaGRPCGenerator(parser, path, file_name).generate();
}
+bool GeneratePythonGRPC(const Parser &parser, const std::string & /*path*/,
+ const std::string &file_name) {
+ int nservices = 0;
+ for (auto it = parser.services_.vec.begin(); it != parser.services_.vec.end();
+ ++it) {
+ if (!(*it)->generated) nservices++;
+ }
+ if (!nservices) return true;
+
+ grpc_python_generator::GeneratorConfiguration config;
+ config.grpc_package_root = "grpc";
+ config.beta_package_root = "grpc.beta";
+ config.import_prefix = "";
+
+ FlatBufFile fbfile(parser, file_name, FlatBufFile::kLanguagePython);
+
+ grpc_python_generator::PrivateGenerator generator(config, &fbfile);
+
+ std::string code = generator.GetGrpcServices();
+ std::string namespace_dir;
+ auto &namespaces = parser.namespaces_.back()->components;
+ for (auto it = namespaces.begin(); it != namespaces.end(); ++it) {
+ if (it != namespaces.begin()) namespace_dir += kPathSeparator;
+ namespace_dir += *it;
+ }
+
+ std::string grpc_py_filename = namespace_dir;
+ if (!namespace_dir.empty()) grpc_py_filename += kPathSeparator;
+ grpc_py_filename += file_name + "_grpc_fb.py";
+
+ return flatbuffers::SaveFile(grpc_py_filename.c_str(), code, false);
+}
+
+class SwiftGRPCGenerator : public flatbuffers::BaseGenerator {
+ private:
+ CodeWriter code_;
+
+ public:
+ SwiftGRPCGenerator(const Parser &parser, const std::string &path,
+ const std::string &filename)
+ : BaseGenerator(parser, path, filename, "", "" /*Unused*/, "swift") {}
+
+ bool generate() {
+ code_.Clear();
+ code_ += "// Generated GRPC code for FlatBuffers swift!";
+ code_ += grpc_swift_generator::GenerateHeader();
+ FlatBufFile file(parser_, file_name_, FlatBufFile::kLanguageSwift);
+ for (int i = 0; i < file.service_count(); i++) {
+ auto service = file.service(i);
+ code_ += grpc_swift_generator::Generate(&file, service.get());
+ }
+ const auto final_code = code_.ToString();
+ const auto filename = GeneratedFileName(path_, file_name_);
+ return SaveFile(filename.c_str(), final_code, false);
+ }
+
+ static std::string GeneratedFileName(const std::string &path,
+ const std::string &file_name) {
+ return path + file_name + ".grpc.swift";
+ }
+};
+
+bool GenerateSwiftGRPC(const Parser &parser, const std::string &path,
+ const std::string &file_name) {
+ int nservices = 0;
+ for (auto it = parser.services_.vec.begin(); it != parser.services_.vec.end();
+ ++it) {
+ if (!(*it)->generated) nservices++;
+ }
+ if (!nservices) return true;
+ return SwiftGRPCGenerator(parser, path, file_name).generate();
+}
+
+class TSGRPCGenerator : public flatbuffers::BaseGenerator {
+ private:
+ CodeWriter code_;
+
+ public:
+ TSGRPCGenerator(const Parser &parser, const std::string &path,
+ const std::string &filename)
+ : BaseGenerator(parser, path, filename, "", "" /*Unused*/, "ts") {}
+
+ bool generate() {
+ code_.Clear();
+ FlatBufFile file(parser_, file_name_, FlatBufFile::kLanguageTS);
+
+ for (int i = 0; i < file.service_count(); i++) {
+ auto service = file.service(i);
+ code_ += grpc_ts_generator::Generate(&file, service.get(), file_name_);
+ const auto ts_name = GeneratedFileName(path_, file_name_);
+ if (!SaveFile(ts_name.c_str(), code_.ToString(), false)) return false;
+
+ code_.Clear();
+ code_ += grpc_ts_generator::GenerateInterface(&file, service.get(),
+ file_name_);
+ const auto ts_interface_name = GeneratedFileName(path_, file_name_, true);
+ if (!SaveFile(ts_interface_name.c_str(), code_.ToString(), false))
+ return false;
+ }
+ return true;
+ }
+
+ static std::string GeneratedFileName(const std::string &path,
+ const std::string &file_name,
+ const bool is_interface = false) {
+ if (is_interface) return path + file_name + "_grpc.d.ts";
+ return path + file_name + "_grpc.js";
+ }
+};
+
+bool GenerateTSGRPC(const Parser &parser, const std::string &path,
+ const std::string &file_name) {
+ int nservices = 0;
+ for (auto it = parser.services_.vec.begin(); it != parser.services_.vec.end();
+ ++it) {
+ if (!(*it)->generated) nservices++;
+ }
+ if (!nservices) return true;
+ return TSGRPCGenerator(parser, path, file_name).generate();
+}
+
} // namespace flatbuffers
#if defined(_MSC_VER)
diff --git a/src/idl_gen_java.cpp b/src/idl_gen_java.cpp
new file mode 100644
index 0000000..c51f7bc
--- /dev/null
+++ b/src/idl_gen_java.cpp
@@ -0,0 +1,1244 @@
+/*
+ * Copyright 2014 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// independent from idl_parser, since this code is not needed for most clients
+
+#include "flatbuffers/code_generators.h"
+#include "flatbuffers/flatbuffers.h"
+#include "flatbuffers/idl.h"
+#include "flatbuffers/util.h"
+
+#if defined(FLATBUFFERS_CPP98_STL)
+# include <cctype>
+#endif // defined(FLATBUFFERS_CPP98_STL)
+
+namespace flatbuffers {
+namespace java {
+
+static TypedFloatConstantGenerator JavaFloatGen("Double.", "Float.", "NaN",
+ "POSITIVE_INFINITY",
+ "NEGATIVE_INFINITY");
+
+static CommentConfig comment_config = {
+ "/**",
+ " *",
+ " */",
+};
+
+class JavaGenerator : public BaseGenerator {
+ public:
+ JavaGenerator(const Parser &parser, const std::string &path,
+ const std::string &file_name)
+ : BaseGenerator(parser, path, file_name, "", ".", "java"),
+ cur_name_space_(nullptr) {}
+
+ JavaGenerator &operator=(const JavaGenerator &);
+ bool generate() {
+ std::string one_file_code;
+ cur_name_space_ = parser_.current_namespace_;
+
+ for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
+ ++it) {
+ std::string enumcode;
+ auto &enum_def = **it;
+ if (!parser_.opts.one_file) cur_name_space_ = enum_def.defined_namespace;
+ GenEnum(enum_def, &enumcode);
+ if (parser_.opts.one_file) {
+ one_file_code += enumcode;
+ } else {
+ if (!SaveType(enum_def.name, *enum_def.defined_namespace, enumcode,
+ /* needs_includes= */ false))
+ return false;
+ }
+ }
+
+ for (auto it = parser_.structs_.vec.begin();
+ it != parser_.structs_.vec.end(); ++it) {
+ std::string declcode;
+ auto &struct_def = **it;
+ if (!parser_.opts.one_file)
+ cur_name_space_ = struct_def.defined_namespace;
+ GenStruct(struct_def, &declcode);
+ if (parser_.opts.one_file) {
+ one_file_code += declcode;
+ } else {
+ if (!SaveType(struct_def.name, *struct_def.defined_namespace, declcode,
+ /* needs_includes= */ true))
+ return false;
+ }
+ }
+
+ if (parser_.opts.one_file) {
+ return SaveType(file_name_, *parser_.current_namespace_, one_file_code,
+ /* needs_includes= */ true);
+ }
+ return true;
+ }
+
+ // Save out the generated code for a single class while adding
+ // declaration boilerplate.
+ bool SaveType(const std::string &defname, const Namespace &ns,
+ const std::string &classcode, bool needs_includes) const {
+ if (!classcode.length()) return true;
+
+ std::string code;
+ code = "// " + std::string(FlatBuffersGeneratedWarning()) + "\n\n";
+
+ std::string namespace_name = FullNamespace(".", ns);
+ if (!namespace_name.empty()) {
+ code += "package " + namespace_name + ";";
+ code += "\n\n";
+ }
+ if (needs_includes) {
+ code +=
+ "import java.nio.*;\nimport java.lang.*;\nimport "
+ "java.util.*;\nimport com.google.flatbuffers.*;\n";
+ if (parser_.opts.gen_nullable) {
+ code += "\nimport javax.annotation.Nullable;\n";
+ }
+ if (parser_.opts.java_checkerframework) {
+ code += "\nimport org.checkerframework.dataflow.qual.Pure;\n";
+ }
+ code += "\n";
+ }
+
+ code += classcode;
+ if (!namespace_name.empty()) code += "";
+ auto filename = NamespaceDir(ns) + defname + ".java";
+ return SaveFile(filename.c_str(), code, false);
+ }
+
+ const Namespace *CurrentNameSpace() const { return cur_name_space_; }
+
+ std::string GenNullableAnnotation(const Type &t) const {
+ return parser_.opts.gen_nullable &&
+ !IsScalar(DestinationType(t, true).base_type) &&
+ t.base_type != BASE_TYPE_VECTOR
+ ? " @Nullable "
+ : "";
+ }
+
+ std::string GenPureAnnotation(const Type &t) const {
+ return parser_.opts.java_checkerframework &&
+ !IsScalar(DestinationType(t, true).base_type)
+ ? " @Pure "
+ : "";
+ }
+
+ std::string GenTypeBasic(const Type &type) const {
+ // clang-format off
+ static const char * const java_typename[] = {
+ #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, ...) \
+ #JTYPE,
+ FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
+ #undef FLATBUFFERS_TD
+ };
+ // clang-format on
+ return java_typename[type.base_type];
+ }
+
+ std::string GenTypePointer(const Type &type) const {
+ switch (type.base_type) {
+ case BASE_TYPE_STRING: return "String";
+ case BASE_TYPE_VECTOR: return GenTypeGet(type.VectorType());
+ case BASE_TYPE_STRUCT: return WrapInNameSpace(*type.struct_def);
+ case BASE_TYPE_UNION: FLATBUFFERS_FALLTHROUGH(); // else fall thru
+ default: return "Table";
+ }
+ }
+
+ std::string GenTypeGet(const Type &type) const {
+ return IsScalar(type.base_type)
+ ? GenTypeBasic(type)
+ : (IsArray(type) ? GenTypeGet(type.VectorType())
+ : GenTypePointer(type));
+ }
+
+ // Find the destination type the user wants to receive the value in (e.g.
+ // one size higher signed types for unsigned serialized values in Java).
+ Type DestinationType(const Type &type, bool vectorelem) const {
+ switch (type.base_type) {
+ // We use int for both uchar/ushort, since that generally means less
+ // casting than using short for uchar.
+ case BASE_TYPE_UCHAR: return Type(BASE_TYPE_INT);
+ case BASE_TYPE_USHORT: return Type(BASE_TYPE_INT);
+ case BASE_TYPE_UINT: return Type(BASE_TYPE_LONG);
+ case BASE_TYPE_ARRAY:
+ case BASE_TYPE_VECTOR:
+ if (vectorelem) return DestinationType(type.VectorType(), vectorelem);
+ FLATBUFFERS_FALLTHROUGH(); // else fall thru
+ default: return type;
+ }
+ }
+
+ std::string GenOffsetType() const { return "int"; }
+
+ std::string GenOffsetConstruct(const std::string &variable_name) const {
+ return variable_name;
+ }
+
+ std::string GenVectorOffsetType() const { return "int"; }
+
+ // Generate destination type name
+ std::string GenTypeNameDest(const Type &type) const {
+ return GenTypeGet(DestinationType(type, true));
+ }
+
+ // Mask to turn serialized value into destination type value.
+ std::string DestinationMask(const Type &type, bool vectorelem) const {
+ switch (type.base_type) {
+ case BASE_TYPE_UCHAR: return " & 0xFF";
+ case BASE_TYPE_USHORT: return " & 0xFFFF";
+ case BASE_TYPE_UINT: return " & 0xFFFFFFFFL";
+ case BASE_TYPE_VECTOR:
+ if (vectorelem) return DestinationMask(type.VectorType(), vectorelem);
+ FLATBUFFERS_FALLTHROUGH(); // else fall thru
+ default: return "";
+ }
+ }
+
+ // Casts necessary to correctly read serialized data
+ std::string DestinationCast(const Type &type) const {
+ if (IsSeries(type)) {
+ return DestinationCast(type.VectorType());
+ } else {
+ // Cast necessary to correctly read serialized unsigned values.
+ if (type.base_type == BASE_TYPE_UINT) return "(long)";
+ }
+ return "";
+ }
+
+ // Cast statements for mutator method parameters.
+ // In Java, parameters representing unsigned numbers need to be cast down to
+ // their respective type. For example, a long holding an unsigned int value
+ // would be cast down to int before being put onto the buffer.
+ std::string SourceCast(const Type &type, bool castFromDest) const {
+ if (IsSeries(type)) {
+ return SourceCast(type.VectorType(), castFromDest);
+ } else {
+ if (castFromDest) {
+ if (type.base_type == BASE_TYPE_UINT)
+ return "(int)";
+ else if (type.base_type == BASE_TYPE_USHORT)
+ return "(short)";
+ else if (type.base_type == BASE_TYPE_UCHAR)
+ return "(byte)";
+ }
+ }
+ return "";
+ }
+
+ std::string SourceCast(const Type &type) const {
+ return SourceCast(type, true);
+ }
+
+ std::string SourceCastBasic(const Type &type, bool castFromDest) const {
+ return IsScalar(type.base_type) ? SourceCast(type, castFromDest) : "";
+ }
+
+ std::string SourceCastBasic(const Type &type) const {
+ return SourceCastBasic(type, true);
+ }
+
+ std::string GenEnumDefaultValue(const FieldDef &field) const {
+ auto &value = field.value;
+ FLATBUFFERS_ASSERT(value.type.enum_def);
+ auto &enum_def = *value.type.enum_def;
+ auto enum_val = enum_def.FindByValue(value.constant);
+ return enum_val ? (WrapInNameSpace(enum_def) + "." + enum_val->name)
+ : value.constant;
+ }
+
+ std::string GenDefaultValue(const FieldDef &field) const {
+ auto &value = field.value;
+ auto constant = field.IsScalarOptional() ? "0" : value.constant;
+ auto longSuffix = "L";
+ switch (value.type.base_type) {
+ case BASE_TYPE_BOOL: return constant == "0" ? "false" : "true";
+ case BASE_TYPE_ULONG: {
+ // Converts the ulong into its bits signed equivalent
+ uint64_t defaultValue = StringToUInt(constant.c_str());
+ return NumToString(static_cast<int64_t>(defaultValue)) + longSuffix;
+ }
+ case BASE_TYPE_UINT:
+ case BASE_TYPE_LONG: return constant + longSuffix;
+ default:
+ if (IsFloat(value.type.base_type)) {
+ if (field.IsScalarOptional()) {
+ return value.type.base_type == BASE_TYPE_DOUBLE ? "0.0" : "0f";
+ }
+ return JavaFloatGen.GenFloatConstant(field);
+ } else {
+ return constant;
+ }
+ }
+ }
+
+ std::string GenDefaultValueBasic(const FieldDef &field) const {
+ auto &value = field.value;
+ if (!IsScalar(value.type.base_type)) { return "0"; }
+ return GenDefaultValue(field);
+ }
+
+ void GenEnum(EnumDef &enum_def, std::string *code_ptr) const {
+ std::string &code = *code_ptr;
+ if (enum_def.generated) return;
+
+ // Generate enum definitions of the form:
+ // public static (final) int name = value;
+ // In Java, we use ints rather than the Enum feature, because we want them
+ // to map directly to how they're used in C/C++ and file formats.
+ // That, and Java Enums are expensive, and not universally liked.
+ GenComment(enum_def.doc_comment, code_ptr, &comment_config);
+
+ if (enum_def.attributes.Lookup("private")) {
+ // For Java, we leave the enum unmarked to indicate package-private
+ } else {
+ code += "public ";
+ }
+ code += "final class " + enum_def.name;
+ code += " {\n";
+ code += " private " + enum_def.name + "() { }\n";
+ for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
+ auto &ev = **it;
+ GenComment(ev.doc_comment, code_ptr, &comment_config, " ");
+ code += " public static final ";
+ code += GenTypeBasic(enum_def.underlying_type);
+ code += " ";
+ code += ev.name + " = ";
+ code += enum_def.ToString(ev);
+ code += ";\n";
+ }
+
+ // Generate a generate string table for enum values.
+ // Problem is, if values are very sparse that could generate really big
+ // tables. Ideally in that case we generate a map lookup instead, but for
+ // the moment we simply don't output a table at all.
+ auto range = enum_def.Distance();
+ // Average distance between values above which we consider a table
+ // "too sparse". Change at will.
+ static const uint64_t kMaxSparseness = 5;
+ if (range / static_cast<uint64_t>(enum_def.size()) < kMaxSparseness) {
+ code += "\n public static final String";
+ code += "[] names = { ";
+ auto val = enum_def.Vals().front();
+ for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
+ ++it) {
+ auto ev = *it;
+ for (auto k = enum_def.Distance(val, ev); k > 1; --k) code += "\"\", ";
+ val = ev;
+ code += "\"" + (*it)->name + "\", ";
+ }
+ code += "};\n\n";
+ code += " public static ";
+ code += "String";
+ code += " " + MakeCamel("name", false);
+ code += "(int e) { return names[e";
+ if (enum_def.MinValue()->IsNonZero())
+ code += " - " + enum_def.MinValue()->name;
+ code += "]; }\n";
+ }
+
+ // Close the class
+ code += "}\n\n";
+ }
+
+ // Returns the function name that is able to read a value of the given type.
+ std::string GenGetter(const Type &type) const {
+ switch (type.base_type) {
+ case BASE_TYPE_STRING: return "__string";
+ case BASE_TYPE_STRUCT: return "__struct";
+ case BASE_TYPE_UNION: return "__union";
+ case BASE_TYPE_VECTOR: return GenGetter(type.VectorType());
+ case BASE_TYPE_ARRAY: return GenGetter(type.VectorType());
+ default: {
+ std::string getter = "bb.get";
+ if (type.base_type == BASE_TYPE_BOOL) {
+ getter = "0!=" + getter;
+ } else if (GenTypeBasic(type) != "byte") {
+ getter += MakeCamel(GenTypeBasic(type));
+ }
+ return getter;
+ }
+ }
+ }
+
+ // Returns the function name that is able to read a value of the given type.
+ std::string GenGetterForLookupByKey(flatbuffers::FieldDef *key_field,
+ const std::string &data_buffer,
+ const char *num = nullptr) const {
+ auto type = key_field->value.type;
+ auto dest_mask = DestinationMask(type, true);
+ auto dest_cast = DestinationCast(type);
+ auto getter = data_buffer + ".get";
+ if (GenTypeBasic(type) != "byte") {
+ getter += MakeCamel(GenTypeBasic(type));
+ }
+ getter = dest_cast + getter + "(" + GenOffsetGetter(key_field, num) + ")" +
+ dest_mask;
+ return getter;
+ }
+
+ // Direct mutation is only allowed for scalar fields.
+ // Hence a setter method will only be generated for such fields.
+ std::string GenSetter(const Type &type) const {
+ if (IsScalar(type.base_type)) {
+ std::string setter = "bb.put";
+ if (GenTypeBasic(type) != "byte" && type.base_type != BASE_TYPE_BOOL) {
+ setter += MakeCamel(GenTypeBasic(type));
+ }
+ return setter;
+ } else {
+ return "";
+ }
+ }
+
+ // Returns the method name for use with add/put calls.
+ std::string GenMethod(const Type &type) const {
+ return IsScalar(type.base_type) ? MakeCamel(GenTypeBasic(type))
+ : (IsStruct(type) ? "Struct" : "Offset");
+ }
+
+ // Recursively generate arguments for a constructor, to deal with nested
+ // structs.
+ void GenStructArgs(const StructDef &struct_def, std::string *code_ptr,
+ const char *nameprefix, size_t array_count = 0) const {
+ std::string &code = *code_ptr;
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ const auto &field_type = field.value.type;
+ const auto array_field = IsArray(field_type);
+ const auto &type = array_field ? field_type.VectorType()
+ : DestinationType(field_type, false);
+ const auto array_cnt = array_field ? (array_count + 1) : array_count;
+ if (IsStruct(type)) {
+ // Generate arguments for a struct inside a struct. To ensure names
+ // don't clash, and to make it obvious these arguments are constructing
+ // a nested struct, prefix the name with the field name.
+ GenStructArgs(*field_type.struct_def, code_ptr,
+ (nameprefix + (field.name + "_")).c_str(), array_cnt);
+ } else {
+ code += ", ";
+ code += GenTypeBasic(type);
+ for (size_t i = 0; i < array_cnt; i++) code += "[]";
+ code += " ";
+ code += nameprefix;
+ code += MakeCamel(field.name, false);
+ }
+ }
+ }
+
+ // Recusively generate struct construction statements of the form:
+ // builder.putType(name);
+ // and insert manual padding.
+ void GenStructBody(const StructDef &struct_def, std::string *code_ptr,
+ const char *nameprefix, size_t index = 0,
+ bool in_array = false) const {
+ std::string &code = *code_ptr;
+ std::string indent((index + 1) * 2, ' ');
+ code += indent + " builder.prep(";
+ code += NumToString(struct_def.minalign) + ", ";
+ code += NumToString(struct_def.bytesize) + ");\n";
+ for (auto it = struct_def.fields.vec.rbegin();
+ it != struct_def.fields.vec.rend(); ++it) {
+ auto &field = **it;
+ const auto &field_type = field.value.type;
+ if (field.padding) {
+ code += indent + " builder.pad(";
+ code += NumToString(field.padding) + ");\n";
+ }
+ if (IsStruct(field_type)) {
+ GenStructBody(*field_type.struct_def, code_ptr,
+ (nameprefix + (field.name + "_")).c_str(), index,
+ in_array);
+ } else {
+ const auto &type =
+ IsArray(field_type) ? field_type.VectorType() : field_type;
+ const auto index_var = "_idx" + NumToString(index);
+ if (IsArray(field_type)) {
+ code += indent + " for (int " + index_var + " = ";
+ code += NumToString(field_type.fixed_length);
+ code += "; " + index_var + " > 0; " + index_var + "--) {\n";
+ in_array = true;
+ }
+ if (IsStruct(type)) {
+ GenStructBody(*field_type.struct_def, code_ptr,
+ (nameprefix + (field.name + "_")).c_str(), index + 1,
+ in_array);
+ } else {
+ code += IsArray(field_type) ? " " : "";
+ code += indent + " builder.put";
+ code += GenMethod(type) + "(";
+ code += SourceCast(type);
+ auto argname = nameprefix + MakeCamel(field.name, false);
+ code += argname;
+ size_t array_cnt = index + (IsArray(field_type) ? 1 : 0);
+ for (size_t i = 0; in_array && i < array_cnt; i++) {
+ code += "[_idx" + NumToString(i) + "-1]";
+ }
+ code += ");\n";
+ }
+ if (IsArray(field_type)) { code += indent + " }\n"; }
+ }
+ }
+ }
+
+ std::string GenByteBufferLength(const char *bb_name) const {
+ std::string bb_len = bb_name;
+ bb_len += ".capacity()";
+ return bb_len;
+ }
+
+ std::string GenOffsetGetter(flatbuffers::FieldDef *key_field,
+ const char *num = nullptr) const {
+ std::string key_offset = "";
+ key_offset += "__offset(" + NumToString(key_field->value.offset) + ", ";
+ if (num) {
+ key_offset += num;
+ key_offset += ", _bb)";
+ } else {
+ key_offset += GenByteBufferLength("bb");
+ key_offset += " - tableOffset, bb)";
+ }
+ return key_offset;
+ }
+
+ std::string GenLookupKeyGetter(flatbuffers::FieldDef *key_field) const {
+ std::string key_getter = " ";
+ key_getter += "int tableOffset = ";
+ key_getter += "__indirect(vectorLocation + 4 * (start + middle)";
+ key_getter += ", bb);\n ";
+ if (IsString(key_field->value.type)) {
+ key_getter += "int comp = ";
+ key_getter += "compareStrings(";
+ key_getter += GenOffsetGetter(key_field);
+ key_getter += ", byteKey, bb);\n";
+ } else {
+ auto get_val = GenGetterForLookupByKey(key_field, "bb");
+ key_getter += GenTypeNameDest(key_field->value.type) + " val = ";
+ key_getter += get_val + ";\n";
+ key_getter += " int comp = val > key ? 1 : val < key ? -1 : 0;\n";
+ }
+ return key_getter;
+ }
+
+ std::string GenKeyGetter(flatbuffers::FieldDef *key_field) const {
+ std::string key_getter = "";
+ auto data_buffer = "_bb";
+ if (IsString(key_field->value.type)) {
+ key_getter += " return ";
+ key_getter += "";
+ key_getter += "compareStrings(";
+ key_getter += GenOffsetGetter(key_field, "o1") + ", ";
+ key_getter += GenOffsetGetter(key_field, "o2") + ", " + data_buffer + ")";
+ key_getter += ";";
+ } else {
+ auto field_getter = GenGetterForLookupByKey(key_field, data_buffer, "o1");
+ key_getter +=
+ "\n " + GenTypeNameDest(key_field->value.type) + " val_1 = ";
+ key_getter +=
+ field_getter + ";\n " + GenTypeNameDest(key_field->value.type);
+ key_getter += " val_2 = ";
+ field_getter = GenGetterForLookupByKey(key_field, data_buffer, "o2");
+ key_getter += field_getter + ";\n";
+ key_getter += " return val_1 > val_2 ? 1 : val_1 < val_2 ? -1 : 0;\n ";
+ }
+ return key_getter;
+ }
+
+ void GenStruct(StructDef &struct_def, std::string *code_ptr) const {
+ if (struct_def.generated) return;
+ std::string &code = *code_ptr;
+
+ // Generate a struct accessor class, with methods of the form:
+ // public type name() { return bb.getType(i + offset); }
+ // or for tables of the form:
+ // public type name() {
+ // int o = __offset(offset); return o != 0 ? bb.getType(o + i) : default;
+ // }
+ GenComment(struct_def.doc_comment, code_ptr, &comment_config);
+
+ if (parser_.opts.gen_generated) {
+ code += "@javax.annotation.Generated(value=\"flatc\")\n";
+ }
+ code += "@SuppressWarnings(\"unused\")\n";
+ if (struct_def.attributes.Lookup("private")) {
+ // For Java, we leave the struct unmarked to indicate package-private
+ } else {
+ code += "public ";
+ }
+ code += "final class " + struct_def.name;
+ code += " extends ";
+ code += struct_def.fixed ? "Struct" : "Table";
+ code += " {\n";
+
+ if (!struct_def.fixed) {
+ // Generate verson check method.
+ // Force compile time error if not using the same version runtime.
+ code += " public static void ValidateVersion() {";
+ code += " Constants.";
+ code += "FLATBUFFERS_1_12_0(); ";
+ code += "}\n";
+
+ // Generate a special accessor for the table that when used as the root
+ // of a FlatBuffer
+ std::string method_name = "getRootAs" + struct_def.name;
+ std::string method_signature =
+ " public static " + struct_def.name + " " + method_name;
+
+ // create convenience method that doesn't require an existing object
+ code += method_signature + "(ByteBuffer _bb) ";
+ code += "{ return " + method_name + "(_bb, new " + struct_def.name +
+ "()); }\n";
+
+ // create method that allows object reuse
+ code +=
+ method_signature + "(ByteBuffer _bb, " + struct_def.name + " obj) { ";
+ code += "_bb.order(ByteOrder.LITTLE_ENDIAN); ";
+ code += "return (obj.__assign(_bb.getInt(_bb.";
+ code += "position()";
+ code += ") + _bb.";
+ code += "position()";
+ code += ", _bb)); }\n";
+ if (parser_.root_struct_def_ == &struct_def) {
+ if (parser_.file_identifier_.length()) {
+ // Check if a buffer has the identifier.
+ code += " public static ";
+ code += "boolean " + struct_def.name;
+ code += "BufferHasIdentifier(ByteBuffer _bb) { return ";
+ code += "__has_identifier(_bb, \"";
+ code += parser_.file_identifier_;
+ code += "\"); }\n";
+ }
+ }
+ }
+ // Generate the __init method that sets the field in a pre-existing
+ // accessor object. This is to allow object reuse.
+ code += " public void __init(int _i, ByteBuffer _bb) ";
+ code += "{ ";
+ code += "__reset(_i, _bb); ";
+ code += "}\n";
+ code +=
+ " public " + struct_def.name + " __assign(int _i, ByteBuffer _bb) ";
+ code += "{ __init(_i, _bb); return this; }\n\n";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+ GenComment(field.doc_comment, code_ptr, &comment_config, " ");
+ std::string type_name = GenTypeGet(field.value.type);
+ std::string type_name_dest = GenTypeNameDest(field.value.type);
+ std::string conditional_cast = "";
+ std::string optional = "";
+ std::string dest_mask = DestinationMask(field.value.type, true);
+ std::string dest_cast = DestinationCast(field.value.type);
+ std::string src_cast = SourceCast(field.value.type);
+ std::string method_start =
+ " public " +
+ (field.required ? "" : GenNullableAnnotation(field.value.type)) +
+ GenPureAnnotation(field.value.type) + type_name_dest + optional +
+ " " + MakeCamel(field.name, false);
+ std::string obj = "obj";
+
+ // Most field accessors need to retrieve and test the field offset first,
+ // this is the prefix code for that:
+ auto offset_prefix =
+ IsArray(field.value.type)
+ ? " { return "
+ : (" { int o = __offset(" + NumToString(field.value.offset) +
+ "); return o != 0 ? ");
+ // Generate the accessors that don't do object reuse.
+ if (field.value.type.base_type == BASE_TYPE_STRUCT) {
+ // Calls the accessor that takes an accessor object with a new object.
+ code += method_start + "() { return ";
+ code += MakeCamel(field.name, false);
+ code += "(new ";
+ code += type_name + "()); }\n";
+ } else if (IsVector(field.value.type) &&
+ field.value.type.element == BASE_TYPE_STRUCT) {
+ // Accessors for vectors of structs also take accessor objects, this
+ // generates a variant without that argument.
+ code += method_start + "(int j) { return ";
+ code += MakeCamel(field.name, false);
+ code += "(new " + type_name + "(), j); }\n";
+ }
+
+ if (field.IsScalarOptional()) { code += GenOptionalScalarCheck(field); }
+ std::string getter = dest_cast + GenGetter(field.value.type);
+ code += method_start;
+ std::string default_cast = "";
+ std::string member_suffix = "; ";
+ if (IsScalar(field.value.type.base_type)) {
+ code += "()";
+ member_suffix += "";
+ if (struct_def.fixed) {
+ code += " { return " + getter;
+ code += "(bb_pos + ";
+ code += NumToString(field.value.offset) + ")";
+ code += dest_mask;
+ } else {
+ code += offset_prefix + getter;
+ code += "(o + bb_pos)" + dest_mask;
+ code += " : " + default_cast;
+ code += GenDefaultValue(field);
+ }
+ } else {
+ switch (field.value.type.base_type) {
+ case BASE_TYPE_STRUCT:
+ code += "(" + type_name + " obj)";
+ if (struct_def.fixed) {
+ code += " { return " + obj + ".__assign(";
+ code += "bb_pos + " + NumToString(field.value.offset) + ", ";
+ code += "bb)";
+ } else {
+ code += offset_prefix + conditional_cast;
+ code += obj + ".__assign(";
+ code += field.value.type.struct_def->fixed
+ ? "o + bb_pos"
+ : "__indirect(o + bb_pos)";
+ code += ", bb) : null";
+ }
+ break;
+ case BASE_TYPE_STRING:
+ code += "()";
+ member_suffix += "";
+ code += offset_prefix + getter + "(o + ";
+ code += "bb_pos) : null";
+ break;
+ case BASE_TYPE_ARRAY: FLATBUFFERS_FALLTHROUGH(); // fall thru
+ case BASE_TYPE_VECTOR: {
+ auto vectortype = field.value.type.VectorType();
+ code += "(";
+ if (vectortype.base_type == BASE_TYPE_STRUCT) {
+ code += type_name + " obj, ";
+ getter = obj + ".__assign";
+ } else if (vectortype.base_type == BASE_TYPE_UNION) {
+ code += type_name + " obj, ";
+ }
+ code += "int j)";
+ const auto body = offset_prefix + conditional_cast + getter + "(";
+ if (vectortype.base_type == BASE_TYPE_UNION) {
+ code += body + "obj, ";
+ } else {
+ code += body;
+ }
+ std::string index;
+ if (IsArray(field.value.type)) {
+ index += "bb_pos + " + NumToString(field.value.offset) + " + ";
+ } else {
+ index += "__vector(o) + ";
+ }
+ index += "j * " + NumToString(InlineSize(vectortype));
+ if (vectortype.base_type == BASE_TYPE_STRUCT) {
+ code += vectortype.struct_def->fixed
+ ? index
+ : "__indirect(" + index + ")";
+ code += ", bb";
+ } else {
+ code += index;
+ }
+ code += ")" + dest_mask;
+ if (!IsArray(field.value.type)) {
+ code += " : ";
+ code +=
+ field.value.type.element == BASE_TYPE_BOOL
+ ? "false"
+ : (IsScalar(field.value.type.element) ? default_cast + "0"
+ : "null");
+ }
+
+ break;
+ }
+ case BASE_TYPE_UNION:
+ code += "(" + type_name + " obj)" + offset_prefix + getter;
+ code += "(obj, o + bb_pos) : null";
+ break;
+ default: FLATBUFFERS_ASSERT(0);
+ }
+ }
+ code += member_suffix;
+ code += "}\n";
+ if (IsVector(field.value.type)) {
+ code += " public int " + MakeCamel(field.name, false);
+ code += "Length";
+ code += "()";
+ code += offset_prefix;
+ code += "__vector_len(o) : 0; ";
+ code += "";
+ code += "}\n";
+ // See if we should generate a by-key accessor.
+ if (field.value.type.element == BASE_TYPE_STRUCT &&
+ !field.value.type.struct_def->fixed) {
+ auto &sd = *field.value.type.struct_def;
+ auto &fields = sd.fields.vec;
+ for (auto kit = fields.begin(); kit != fields.end(); ++kit) {
+ auto &key_field = **kit;
+ if (key_field.key) {
+ auto qualified_name = WrapInNameSpace(sd);
+ code += " public " + qualified_name + " ";
+ code += MakeCamel(field.name, false) + "ByKey(";
+ code += GenTypeNameDest(key_field.value.type) + " key)";
+ code += offset_prefix;
+ code += qualified_name + ".__lookup_by_key(";
+ code += "null, ";
+ code += "__vector(o), key, ";
+ code += "bb) : null; ";
+ code += "}\n";
+ code += " public " + qualified_name + " ";
+ code += MakeCamel(field.name, false) + "ByKey(";
+ code += qualified_name + " obj, ";
+ code += GenTypeNameDest(key_field.value.type) + " key)";
+ code += offset_prefix;
+ code += qualified_name + ".__lookup_by_key(obj, ";
+ code += "__vector(o), key, ";
+ code += "bb) : null; ";
+ code += "}\n";
+ break;
+ }
+ }
+ }
+ }
+ // Generate the accessors for vector of structs with vector access object
+ if (IsVector(field.value.type)) {
+ std::string vector_type_name;
+ const auto &element_base_type = field.value.type.VectorType().base_type;
+ if (IsScalar(element_base_type)) {
+ vector_type_name = MakeCamel(type_name, true) + "Vector";
+ } else if (element_base_type == BASE_TYPE_STRING) {
+ vector_type_name = "StringVector";
+ } else if (element_base_type == BASE_TYPE_UNION) {
+ vector_type_name = "UnionVector";
+ } else {
+ vector_type_name = type_name + ".Vector";
+ }
+ auto vector_method_start = GenNullableAnnotation(field.value.type) +
+ " public " + vector_type_name + optional +
+ " " + MakeCamel(field.name, false) +
+ "Vector";
+ code += vector_method_start + "() { return ";
+ code += MakeCamel(field.name, false) + "Vector";
+ code += "(new " + vector_type_name + "()); }\n";
+ code += vector_method_start + "(" + vector_type_name + " obj)";
+ code += offset_prefix + conditional_cast + obj + ".__assign(";
+ code += "__vector(o), ";
+ if (!IsScalar(element_base_type)) {
+ auto vectortype = field.value.type.VectorType();
+ code += NumToString(InlineSize(vectortype)) + ", ";
+ }
+ code += "bb) : null" + member_suffix + "}\n";
+ }
+ // Generate a ByteBuffer accessor for strings & vectors of scalars.
+ if ((IsVector(field.value.type) &&
+ IsScalar(field.value.type.VectorType().base_type)) ||
+ IsString(field.value.type)) {
+ code += " public ByteBuffer ";
+ code += MakeCamel(field.name, false);
+ code += "AsByteBuffer() { return ";
+ code += "__vector_as_bytebuffer(";
+ code += NumToString(field.value.offset) + ", ";
+ code += NumToString(IsString(field.value.type)
+ ? 1
+ : InlineSize(field.value.type.VectorType()));
+ code += "); }\n";
+ code += " public ByteBuffer ";
+ code += MakeCamel(field.name, false);
+ code += "InByteBuffer(ByteBuffer _bb) { return ";
+ code += "__vector_in_bytebuffer(_bb, ";
+ code += NumToString(field.value.offset) + ", ";
+ code += NumToString(IsString(field.value.type)
+ ? 1
+ : InlineSize(field.value.type.VectorType()));
+ code += "); }\n";
+ }
+ // generate object accessors if is nested_flatbuffer
+ if (field.nested_flatbuffer) {
+ auto nested_type_name = WrapInNameSpace(*field.nested_flatbuffer);
+ auto nested_method_name =
+ MakeCamel(field.name, false) + "As" + field.nested_flatbuffer->name;
+ auto get_nested_method_name = nested_method_name;
+ code += " public " + nested_type_name + " ";
+ code += nested_method_name + "() { return ";
+ code +=
+ get_nested_method_name + "(new " + nested_type_name + "()); }\n";
+ code += " public " + nested_type_name + " ";
+ code += get_nested_method_name + "(";
+ code += nested_type_name + " obj";
+ code += ") { int o = __offset(";
+ code += NumToString(field.value.offset) + "); ";
+ code += "return o != 0 ? " + conditional_cast + obj + ".__assign(";
+ code += "";
+ code += "__indirect(__vector(o)), ";
+ code += "bb) : null; }\n";
+ }
+ // Generate mutators for scalar fields or vectors of scalars.
+ if (parser_.opts.mutable_buffer) {
+ auto is_series = (IsSeries(field.value.type));
+ const auto &underlying_type =
+ is_series ? field.value.type.VectorType() : field.value.type;
+ // Boolean parameters have to be explicitly converted to byte
+ // representation.
+ auto setter_parameter = underlying_type.base_type == BASE_TYPE_BOOL
+ ? "(byte)(" + field.name + " ? 1 : 0)"
+ : field.name;
+ auto mutator_prefix = MakeCamel("mutate", false);
+ // A vector mutator also needs the index of the vector element it should
+ // mutate.
+ auto mutator_params = (is_series ? "(int j, " : "(") +
+ GenTypeNameDest(underlying_type) + " " +
+ field.name + ") { ";
+ auto setter_index =
+ is_series
+ ? (IsArray(field.value.type)
+ ? "bb_pos + " + NumToString(field.value.offset)
+ : "__vector(o)") +
+ +" + j * " + NumToString(InlineSize(underlying_type))
+ : (struct_def.fixed
+ ? "bb_pos + " + NumToString(field.value.offset)
+ : "o + bb_pos");
+ if (IsScalar(underlying_type.base_type) && !IsUnion(field.value.type)) {
+ code += " public ";
+ code += struct_def.fixed ? "void " : "boolean ";
+ code += mutator_prefix + MakeCamel(field.name, true);
+ code += mutator_params;
+ if (struct_def.fixed) {
+ code += GenSetter(underlying_type) + "(" + setter_index + ", ";
+ code += src_cast + setter_parameter + "); }\n";
+ } else {
+ code += "int o = __offset(";
+ code += NumToString(field.value.offset) + ");";
+ code += " if (o != 0) { " + GenSetter(underlying_type);
+ code += "(" + setter_index + ", " + src_cast + setter_parameter +
+ "); return true; } else { return false; } }\n";
+ }
+ }
+ }
+ if (parser_.opts.java_primitive_has_method &&
+ IsScalar(field.value.type.base_type) && !struct_def.fixed) {
+ auto vt_offset_constant = " public static final int VT_" +
+ MakeScreamingCamel(field.name) + " = " +
+ NumToString(field.value.offset) + ";";
+
+ code += vt_offset_constant;
+ code += "\n";
+ }
+ }
+ code += "\n";
+ flatbuffers::FieldDef *key_field = nullptr;
+ if (struct_def.fixed) {
+ // create a struct constructor function
+ code += " public static " + GenOffsetType() + " ";
+ code += "create";
+ code += struct_def.name + "(FlatBufferBuilder builder";
+ GenStructArgs(struct_def, code_ptr, "");
+ code += ") {\n";
+ GenStructBody(struct_def, code_ptr, "");
+ code += " return ";
+ code += GenOffsetConstruct("builder." + std::string("offset()"));
+ code += ";\n }\n";
+ } else {
+ // Generate a method that creates a table in one go. This is only possible
+ // when the table has no struct fields, since those have to be created
+ // inline, and there's no way to do so in Java.
+ bool has_no_struct_fields = true;
+ int num_fields = 0;
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+ if (IsStruct(field.value.type)) {
+ has_no_struct_fields = false;
+ } else {
+ num_fields++;
+ }
+ }
+ // JVM specifications restrict default constructor params to be < 255.
+ // Longs and doubles take up 2 units, so we set the limit to be < 127.
+ if (has_no_struct_fields && num_fields && num_fields < 127) {
+ // Generate a table constructor of the form:
+ // public static int createName(FlatBufferBuilder builder, args...)
+ code += " public static " + GenOffsetType() + " ";
+ code += "create" + struct_def.name;
+ code += "(FlatBufferBuilder builder";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+ code += ",\n ";
+ code += GenTypeBasic(DestinationType(field.value.type, false));
+ code += " ";
+ code += field.name;
+ if (!IsScalar(field.value.type.base_type)) code += "Offset";
+ }
+ code += ") {\n builder.";
+ code += "startTable(";
+ code += NumToString(struct_def.fields.vec.size()) + ");\n";
+ for (size_t size = struct_def.sortbysize ? sizeof(largest_scalar_t) : 1;
+ size; size /= 2) {
+ for (auto it = struct_def.fields.vec.rbegin();
+ it != struct_def.fields.vec.rend(); ++it) {
+ auto &field = **it;
+ if (!field.deprecated &&
+ (!struct_def.sortbysize ||
+ size == SizeOf(field.value.type.base_type))) {
+ code += " " + struct_def.name + ".";
+ code += "add";
+ code += MakeCamel(field.name) + "(builder, " + field.name;
+ if (!IsScalar(field.value.type.base_type)) code += "Offset";
+ code += ");\n";
+ }
+ }
+ }
+ code += " return " + struct_def.name + ".";
+ code += "end" + struct_def.name;
+ code += "(builder);\n }\n\n";
+ }
+ // Generate a set of static methods that allow table construction,
+ // of the form:
+ // public static void addName(FlatBufferBuilder builder, short name)
+ // { builder.addShort(id, name, default); }
+ // Unlike the Create function, these always work.
+ code += " public static void start";
+ code += struct_def.name;
+ code += "(FlatBufferBuilder builder) { builder.";
+ code += "startTable(";
+ code += NumToString(struct_def.fields.vec.size()) + "); }\n";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+ if (field.key) key_field = &field;
+ code += " public static void add";
+ code += MakeCamel(field.name);
+ code += "(FlatBufferBuilder builder, ";
+ code += GenTypeBasic(DestinationType(field.value.type, false));
+ auto argname = MakeCamel(field.name, false);
+ if (!IsScalar(field.value.type.base_type)) argname += "Offset";
+ code += " " + argname + ") { builder.add";
+ code += GenMethod(field.value.type) + "(";
+ code += NumToString(it - struct_def.fields.vec.begin()) + ", ";
+ code += SourceCastBasic(field.value.type);
+ code += argname;
+ code += ", ";
+ code += SourceCastBasic(field.value.type);
+ code += GenDefaultValue(field);
+ code += "); }\n";
+ if (IsVector(field.value.type)) {
+ auto vector_type = field.value.type.VectorType();
+ auto alignment = InlineAlignment(vector_type);
+ auto elem_size = InlineSize(vector_type);
+ if (!IsStruct(vector_type)) {
+ // generate a method to create a vector from a java array.
+ if ((vector_type.base_type == BASE_TYPE_CHAR ||
+ vector_type.base_type == BASE_TYPE_UCHAR)) {
+ // Handle byte[] and ByteBuffers separately for Java
+ code += " public static " + GenVectorOffsetType() + " ";
+ code += "create";
+ code += MakeCamel(field.name);
+ code += "Vector(FlatBufferBuilder builder, byte[] data) ";
+ code += "{ return builder.createByteVector(data); }\n";
+
+ code += " public static " + GenVectorOffsetType() + " ";
+ code += "create";
+ code += MakeCamel(field.name);
+ code += "Vector(FlatBufferBuilder builder, ByteBuffer data) ";
+ code += "{ return builder.createByteVector(data); }\n";
+ } else {
+ code += " public static " + GenVectorOffsetType() + " ";
+ code += "create";
+ code += MakeCamel(field.name);
+ code += "Vector(FlatBufferBuilder builder, ";
+ code += GenTypeBasic(vector_type) + "[] data) ";
+ code += "{ builder.startVector(";
+ code += NumToString(elem_size);
+ code += ", data.length, ";
+ code += NumToString(alignment);
+ code += "); for (int i = data.";
+ code += "length - 1; i >= 0; i--) builder.";
+ code += "add";
+ code += GenMethod(vector_type);
+ code += "(";
+ code += SourceCastBasic(vector_type, false);
+ code += "data[i]";
+ code += "); return ";
+ code += "builder.endVector(); }\n";
+ }
+ }
+ // Generate a method to start a vector, data to be added manually
+ // after.
+ code += " public static void start";
+ code += MakeCamel(field.name);
+ code += "Vector(FlatBufferBuilder builder, int numElems) ";
+ code += "{ builder.startVector(";
+ code += NumToString(elem_size);
+ code += ", numElems, " + NumToString(alignment);
+ code += "); }\n";
+ }
+ }
+ code += " public static " + GenOffsetType() + " ";
+ code += "end" + struct_def.name;
+ code += "(FlatBufferBuilder builder) {\n int o = builder.";
+ code += "endTable();\n";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (!field.deprecated && field.required) {
+ code += " builder.required(o, ";
+ code += NumToString(field.value.offset);
+ code += "); // " + field.name + "\n";
+ }
+ }
+ code += " return " + GenOffsetConstruct("o") + ";\n }\n";
+ if (parser_.root_struct_def_ == &struct_def) {
+ std::string size_prefix[] = { "", "SizePrefixed" };
+ for (int i = 0; i < 2; ++i) {
+ code += " public static void ";
+ code += "finish" + size_prefix[i] + struct_def.name;
+ code += "Buffer(FlatBufferBuilder builder, " + GenOffsetType();
+ code += " offset) {";
+ code += " builder.finish" + size_prefix[i] + "(offset";
+
+ if (parser_.file_identifier_.length())
+ code += ", \"" + parser_.file_identifier_ + "\"";
+ code += "); }\n";
+ }
+ }
+ }
+ // Only generate key compare function for table,
+ // because `key_field` is not set for struct
+ if (struct_def.has_key && !struct_def.fixed) {
+ FLATBUFFERS_ASSERT(key_field);
+ code += "\n @Override\n protected int keysCompare(";
+ code += "Integer o1, Integer o2, ByteBuffer _bb) {";
+ code += GenKeyGetter(key_field);
+ code += " }\n";
+
+ code += "\n public static " + struct_def.name;
+ code += " __lookup_by_key(";
+ code += struct_def.name + " obj, ";
+ code += "int vectorLocation, ";
+ code += GenTypeNameDest(key_field->value.type);
+ code += " key, ByteBuffer bb) {\n";
+ if (IsString(key_field->value.type)) {
+ code += " byte[] byteKey = ";
+ code += "key.getBytes(java.nio.charset.StandardCharsets.UTF_8);\n";
+ }
+ code += " int span = ";
+ code += "bb.getInt(vectorLocation - 4);\n";
+ code += " int start = 0;\n";
+ code += " while (span != 0) {\n";
+ code += " int middle = span / 2;\n";
+ code += GenLookupKeyGetter(key_field);
+ code += " if (comp > 0) {\n";
+ code += " span = middle;\n";
+ code += " } else if (comp < 0) {\n";
+ code += " middle++;\n";
+ code += " start += middle;\n";
+ code += " span -= middle;\n";
+ code += " } else {\n";
+ code += " return ";
+ code += "(obj == null ? new " + struct_def.name + "() : obj)";
+ code += ".__assign(tableOffset, bb);\n";
+ code += " }\n }\n";
+ code += " return null;\n";
+ code += " }\n";
+ }
+ GenVectorAccessObject(struct_def, code_ptr);
+ code += "}";
+ code += "\n\n";
+ }
+
+ std::string GenOptionalScalarCheck(FieldDef &field) const {
+ if (!field.IsScalarOptional()) return "";
+ return " public boolean has" + MakeCamel(field.name, true) +
+ "() { return 0 != __offset(" + NumToString(field.value.offset) +
+ "); }\n";
+ }
+
+ void GenVectorAccessObject(StructDef &struct_def,
+ std::string *code_ptr) const {
+ auto &code = *code_ptr;
+ // Generate a vector of structs accessor class.
+ code += "\n";
+ code += " ";
+ if (!struct_def.attributes.Lookup("private")) code += "public ";
+ code += "static ";
+ code += "final ";
+ code += "class Vector extends ";
+ code += "BaseVector {\n";
+
+ // Generate the __assign method that sets the field in a pre-existing
+ // accessor object. This is to allow object reuse.
+ std::string method_indent = " ";
+ code += method_indent + "public Vector ";
+ code += "__assign(int _vector, int _element_size, ByteBuffer _bb) { ";
+ code += "__reset(_vector, _element_size, _bb); return this; }\n\n";
+
+ auto type_name = struct_def.name;
+ auto method_start = method_indent + "public " + type_name + " get";
+ // Generate the accessors that don't do object reuse.
+ code += method_start + "(int j) { return get";
+ code += "(new " + type_name + "(), j); }\n";
+ code += method_start + "(" + type_name + " obj, int j) { ";
+ code += " return obj.__assign(";
+ std::string index = "__element(j)";
+ code += struct_def.fixed ? index : "__indirect(" + index + ", bb)";
+ code += ", bb); }\n";
+ // See if we should generate a by-key accessor.
+ if (!struct_def.fixed) {
+ auto &fields = struct_def.fields.vec;
+ for (auto kit = fields.begin(); kit != fields.end(); ++kit) {
+ auto &key_field = **kit;
+ if (key_field.key) {
+ auto nullable_annotation =
+ parser_.opts.gen_nullable ? "@Nullable " : "";
+ code += method_indent + nullable_annotation;
+ code += "public " + type_name + " ";
+ code += "getByKey(";
+ code += GenTypeNameDest(key_field.value.type) + " key) { ";
+ code += " return __lookup_by_key(null, ";
+ code += "__vector(), key, ";
+ code += "bb); ";
+ code += "}\n";
+ code += method_indent + nullable_annotation;
+ code += "public " + type_name + " ";
+ code += "getByKey(";
+ code += type_name + " obj, ";
+ code += GenTypeNameDest(key_field.value.type) + " key) { ";
+ code += " return __lookup_by_key(obj, ";
+ code += "__vector(), key, ";
+ code += "bb); ";
+ code += "}\n";
+ break;
+ }
+ }
+ }
+ code += " }\n";
+ }
+
+ // This tracks the current namespace used to determine if a type need to be
+ // prefixed by its namespace
+ const Namespace *cur_name_space_;
+};
+} // namespace java
+
+bool GenerateJava(const Parser &parser, const std::string &path,
+ const std::string &file_name) {
+ java::JavaGenerator generator(parser, path, file_name);
+ return generator.generate();
+}
+
+} // namespace flatbuffers
diff --git a/src/idl_gen_js_ts.cpp b/src/idl_gen_js_ts.cpp
index 9c89c1a..0240f51 100644
--- a/src/idl_gen_js_ts.cpp
+++ b/src/idl_gen_js_ts.cpp
@@ -15,6 +15,7 @@
*/
// independent from idl_parser, since this code is not needed for most clients
+#include <algorithm>
#include <cassert>
#include <unordered_map>
#include <unordered_set>
@@ -26,8 +27,6 @@
namespace flatbuffers {
-const std::string kGeneratedFileNamePostfix = "_generated";
-
struct JsTsLanguageParameters {
IDLOptions::Language language;
std::string file_extension;
@@ -61,12 +60,6 @@
}
}
-static std::string GeneratedFileName(const std::string &path,
- const std::string &file_name,
- const JsTsLanguageParameters &lang) {
- return path + file_name + kGeneratedFileNamePostfix + lang.file_extension;
-}
-
namespace jsts {
// Iterate through all definitions we haven't generate code for (enums, structs,
// and tables) and output them to a single file.
@@ -78,7 +71,8 @@
JsTsGenerator(const Parser &parser, const std::string &path,
const std::string &file_name)
- : BaseGenerator(parser, path, file_name, "", "."),
+ : BaseGenerator(parser, path, file_name, "", ".",
+ parser.opts.lang == IDLOptions::kJs ? "js" : "ts"),
lang_(GetJsLangParams(parser_.opts.lang)) {}
// Iterate through all definitions we haven't generate code for (enums,
// structs, and tables) and output them to a single file.
@@ -87,7 +81,7 @@
reexport_map reexports;
std::string enum_code, struct_code, import_code, exports_code, code;
- generateEnums(&enum_code, &exports_code, reexports);
+ generateEnums(&enum_code, &exports_code, reexports, imported_files);
generateStructs(&struct_code, &exports_code, imported_files);
generateImportDependencies(&import_code, imported_files);
generateReexports(&import_code, reexports, imported_files);
@@ -112,8 +106,8 @@
code += exports_code;
}
- return SaveFile(GeneratedFileName(path_, file_name_, lang_).c_str(), code,
- false);
+ return SaveFile(GeneratedFileName(path_, file_name_, parser_.opts).c_str(),
+ code, false);
}
private:
@@ -127,9 +121,7 @@
const auto &file = *it;
const auto basename =
flatbuffers::StripPath(flatbuffers::StripExtension(file));
- if (basename != file_name_) {
- code += GenPrefixedImport(file, basename);
- }
+ if (basename != file_name_) { code += GenPrefixedImport(file, basename); }
}
}
@@ -142,34 +134,47 @@
return;
}
+ std::unordered_set<std::string> imported;
+
std::string &code = *code_ptr;
for (auto it = reexports.begin(); it != reexports.end(); ++it) {
const auto &file = *it;
const auto basename =
flatbuffers::StripPath(flatbuffers::StripExtension(file.first));
- if (basename != file_name_) {
+ if (basename != file_name_ &&
+ imported.find(file.second.symbol) == imported.end()) {
if (imported_files.find(file.first) == imported_files.end()) {
code += GenPrefixedImport(file.first, basename);
imported_files.emplace(file.first);
}
- code += "export namespace " + file.second.target_namespace + " { \n";
+ if (!file.second.target_namespace.empty()) {
+ code += "export namespace " + file.second.target_namespace + " { \n";
+ }
code += "export import " + file.second.symbol + " = ";
- code += GenFileNamespacePrefix(file.first) + "." +
- file.second.source_namespace + "." + file.second.symbol +
- "; }\n";
+ code += GenFileNamespacePrefix(file.first) + ".";
+ if (!file.second.source_namespace.empty()) {
+ code += file.second.source_namespace + ".";
+ }
+ code += file.second.symbol + ";\n";
+ if (!file.second.target_namespace.empty()) { code += "}\n"; }
+
+ imported.emplace(file.second.symbol);
}
}
}
// Generate code for all enums.
void generateEnums(std::string *enum_code_ptr, std::string *exports_code_ptr,
- reexport_map &reexports) {
+ reexport_map &reexports,
+ imported_fileset &imported_files) {
for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
++it) {
auto &enum_def = **it;
- GenEnum(enum_def, enum_code_ptr, exports_code_ptr, reexports, false);
- GenEnum(enum_def, enum_code_ptr, exports_code_ptr, reexports, true);
+ GenEnum(enum_def, enum_code_ptr, exports_code_ptr, reexports,
+ imported_files, false);
+ GenEnum(enum_def, enum_code_ptr, exports_code_ptr, reexports,
+ imported_files, true);
}
}
@@ -213,13 +218,15 @@
// Emit namespaces in a form that Closure Compiler can optimize
std::string &code = *code_ptr;
std::string &exports = *exports_ptr;
+
+ if (lang_.language == IDLOptions::kTs) {
+ code += "import * as flatbuffers from 'flatbuffers';\n";
+ }
+
for (auto it = sorted_namespaces.begin(); it != sorted_namespaces.end();
++it) {
if (lang_.language == IDLOptions::kTs) {
- if (it->find('.') == std::string::npos) {
- code += "import { flatbuffers } from \"./flatbuffers\"\n";
- break;
- }
+ if (it->find('.') == std::string::npos) { break; }
} else {
code += "/**\n * @const\n * @namespace\n */\n";
if (it->find('.') == std::string::npos) {
@@ -309,14 +316,12 @@
result += " " + type_name;
break;
}
- default: { result += " {" + type_name + "}"; }
+ default: {
+ result += " {" + type_name + "}";
+ }
}
- if (!arg_name.empty()) {
- result += " " + arg_name;
- }
- if (include_newline) {
- result += "\n";
- }
+ if (!arg_name.empty()) { result += " " + arg_name; }
+ if (include_newline) { result += "\n"; }
return result;
}
@@ -324,7 +329,7 @@
// Generate an enum declaration and an enum string lookup table.
void GenEnum(EnumDef &enum_def, std::string *code_ptr,
std::string *exports_ptr, reexport_map &reexports,
- bool reverse) {
+ imported_fileset &imported_files, bool reverse) {
if (enum_def.generated) return;
if (reverse && lang_.language == IDLOptions::kTs) return; // FIXME.
std::string &code = *code_ptr;
@@ -359,7 +364,7 @@
// Generate mapping between EnumName: EnumValue(int)
if (reverse) {
- code += " " + enum_def.ToString(ev);
+ code += " '" + enum_def.ToString(ev) + "'";
code += lang_.language == IDLOptions::kTs ? "= " : ": ";
code += "'" + ev.name + "'";
} else {
@@ -371,16 +376,23 @@
code += (it + 1) != enum_def.Vals().end() ? ",\n" : "\n";
if (ev.union_type.struct_def) {
- ReexportDescription desc = { ev.name,
+ ReexportDescription desc = { ev.union_type.struct_def->name,
GetNameSpace(*ev.union_type.struct_def),
GetNameSpace(enum_def) };
reexports.insert(
std::make_pair(ev.union_type.struct_def->file, std::move(desc)));
}
}
+ code += "};";
- if (lang_.language == IDLOptions::kTs && !ns.empty()) { code += "}"; }
- code += "};\n\n";
+ if (lang_.language == IDLOptions::kTs) {
+ if (enum_def.is_union) {
+ code += GenUnionConvFunc(enum_def.underlying_type, imported_files);
+ }
+ if (!ns.empty()) { code += "\n}"; }
+ }
+
+ code += "\n\n";
}
static std::string GenType(const Type &type) {
@@ -408,7 +420,12 @@
switch (type.base_type) {
case BASE_TYPE_STRING: return GenBBAccess() + ".__string" + arguments;
case BASE_TYPE_STRUCT: return GenBBAccess() + ".__struct" + arguments;
- case BASE_TYPE_UNION: return GenBBAccess() + ".__union" + arguments;
+ case BASE_TYPE_UNION:
+ if (!UnionHasStringType(*type.enum_def) ||
+ lang_.language == IDLOptions::kJs) {
+ return GenBBAccess() + ".__union" + arguments;
+ }
+ return GenBBAccess() + ".__union_with_string" + arguments;
case BASE_TYPE_VECTOR: return GenGetter(type.VectorType(), arguments);
default: {
auto getter =
@@ -425,12 +442,18 @@
}
}
- std::string GenBBAccess() {
+ std::string GenBBAccess() const {
return lang_.language == IDLOptions::kTs ? "this.bb!" : "this.bb";
}
- std::string GenDefaultValue(const Value &value, const std::string &context) {
- if (value.type.enum_def) {
+ std::string GenDefaultValue(const FieldDef &field, const std::string &context) {
+ if (field.IsScalarOptional()) {
+ return "null";
+ }
+
+ const auto &value = field.value;
+ if (value.type.enum_def && value.type.base_type != BASE_TYPE_UNION &&
+ value.type.base_type != BASE_TYPE_VECTOR) {
if (auto val = value.type.enum_def->FindByValue(value.constant)) {
if (lang_.language == IDLOptions::kTs) {
return GenPrefixedTypeName(WrapInNameSpace(*value.type.enum_def),
@@ -450,7 +473,13 @@
switch (value.type.base_type) {
case BASE_TYPE_BOOL: return value.constant == "0" ? "false" : "true";
- case BASE_TYPE_STRING: return "null";
+ case BASE_TYPE_STRING:
+ case BASE_TYPE_UNION:
+ case BASE_TYPE_STRUCT: {
+ return "null";
+ }
+
+ case BASE_TYPE_VECTOR: return "[]";
case BASE_TYPE_LONG:
case BASE_TYPE_ULONG: {
@@ -467,10 +496,9 @@
std::string GenTypeName(const Type &type, bool input,
bool allowNull = false) {
if (!input) {
- if (type.base_type == BASE_TYPE_STRING ||
- type.base_type == BASE_TYPE_STRUCT) {
+ if (IsString(type) || type.base_type == BASE_TYPE_STRUCT) {
std::string name;
- if (type.base_type == BASE_TYPE_STRING) {
+ if (IsString(type)) {
name = "string|Uint8Array";
} else {
name = WrapInNameSpace(*type.struct_def);
@@ -480,13 +508,17 @@
}
switch (type.base_type) {
- case BASE_TYPE_BOOL: return "boolean";
+ case BASE_TYPE_BOOL: return (allowNull) ? ("boolean|null") : ("boolean");
case BASE_TYPE_LONG:
- case BASE_TYPE_ULONG: return "flatbuffers.Long";
+ case BASE_TYPE_ULONG: return (allowNull) ? ("flatbuffers.Long|null") : ("flatbuffers.Long");
default:
if (IsScalar(type.base_type)) {
- if (type.enum_def) { return WrapInNameSpace(*type.enum_def); }
- return "number";
+ if (type.enum_def) {
+ const auto enum_name = WrapInNameSpace(*type.enum_def);
+ return (allowNull) ? (enum_name + "|null") : (enum_name);
+ }
+
+ return (allowNull) ? ("number|null") : ("number");
}
return "flatbuffers.Offset";
}
@@ -528,10 +560,10 @@
if (parser_.opts.keep_include_path) {
auto it = parser_.included_files_.find(full_file_name);
FLATBUFFERS_ASSERT(it != parser_.included_files_.end());
- path =
- flatbuffers::StripExtension(it->second) + kGeneratedFileNamePostfix;
+ path = flatbuffers::StripExtension(it->second) +
+ parser_.opts.filename_suffix;
} else {
- path = base_name + kGeneratedFileNamePostfix;
+ path = base_name + parser_.opts.filename_suffix;
}
// Add the include prefix and make the path always relative
@@ -566,11 +598,11 @@
nameprefix + field.name + "_");
} else {
*annotations +=
- GenTypeAnnotation(kParam, GenTypeName(field.value.type, true),
+ GenTypeAnnotation(kParam, GenTypeName(field.value.type, true, field.optional),
nameprefix + field.name);
if (lang_.language == IDLOptions::kTs) {
*arguments += ", " + nameprefix + field.name + ": " +
- GenTypeName(field.value.type, true);
+ GenTypeName(field.value.type, true, field.optional);
} else {
*arguments += ", " + nameprefix + field.name;
}
@@ -604,8 +636,14 @@
}
}
+ std::string GenerateNewExpression(const std::string &object_name) {
+ return "new " + object_name +
+ (lang_.language == IDLOptions::kTs ? "()" : "");
+ }
+
void GenerateRootAccessor(StructDef &struct_def, std::string *code_ptr,
- std::string &code, std::string &object_name, bool size_prefixed) {
+ std::string &code, std::string &object_name,
+ bool size_prefixed) {
if (!struct_def.fixed) {
GenDocComment(code_ptr,
GenTypeAnnotation(kParam, "flatbuffers.ByteBuffer", "bb") +
@@ -613,35 +651,43 @@
GenTypeAnnotation(kReturns, object_name, "", false));
std::string sizePrefixed("SizePrefixed");
if (lang_.language == IDLOptions::kTs) {
- code += "static get" + (size_prefixed ? sizePrefixed : "") + "Root" + Verbose(struct_def, "As");
+ code += "static get" + (size_prefixed ? sizePrefixed : "") + "Root" +
+ Verbose(struct_def, "As");
code += "(bb:flatbuffers.ByteBuffer, obj?:" + object_name +
"):" + object_name + " {\n";
} else {
- code += object_name + ".get" + (size_prefixed ? sizePrefixed : "") + "Root" + Verbose(struct_def, "As");
+ code += object_name + ".get" + (size_prefixed ? sizePrefixed : "") +
+ "Root" + Verbose(struct_def, "As");
code += " = function(bb, obj) {\n";
}
- code += " return (obj || new " + object_name;
+ if (size_prefixed) {
+ code +=
+ " bb.setPosition(bb.position() + "
+ "flatbuffers.SIZE_PREFIX_LENGTH);\n";
+ }
+ code += " return (obj || " + GenerateNewExpression(object_name);
code += ").__init(bb.readInt32(bb.position()) + bb.position(), bb);\n";
code += "};\n\n";
}
}
void GenerateFinisher(StructDef &struct_def, std::string *code_ptr,
- std::string &code, std::string &object_name, bool size_prefixed) {
+ std::string &code, std::string &object_name,
+ bool size_prefixed) {
if (parser_.root_struct_def_ == &struct_def) {
std::string sizePrefixed("SizePrefixed");
GenDocComment(
code_ptr,
GenTypeAnnotation(kParam, "flatbuffers.Builder", "builder") +
- GenTypeAnnotation(kParam, "flatbuffers.Offset", "offset",
- false));
+ GenTypeAnnotation(kParam, "flatbuffers.Offset", "offset", false));
if (lang_.language == IDLOptions::kTs) {
- code += "static finish" + (size_prefixed ? sizePrefixed : "") + Verbose(struct_def) + "Buffer";
- code +=
- "(builder:flatbuffers.Builder, offset:flatbuffers.Offset) {\n";
+ code += "static finish" + (size_prefixed ? sizePrefixed : "") +
+ Verbose(struct_def) + "Buffer";
+ code += "(builder:flatbuffers.Builder, offset:flatbuffers.Offset) {\n";
} else {
- code += object_name + ".finish" + (size_prefixed ? sizePrefixed : "") + Verbose(struct_def) + "Buffer";
+ code += object_name + ".finish" + (size_prefixed ? sizePrefixed : "") +
+ Verbose(struct_def) + "Buffer";
code += " = function(builder, offset) {\n";
}
@@ -650,9 +696,7 @@
code += ", '" + parser_.file_identifier_ + "'";
}
if (size_prefixed) {
- if (parser_.file_identifier_.empty()) {
- code += ", undefined";
- }
+ if (parser_.file_identifier_.empty()) { code += ", undefined"; }
code += ", true";
}
code += ");\n";
@@ -660,6 +704,602 @@
}
}
+ static std::string GetObjApiClassName(const StructDef &sd,
+ const IDLOptions &opts) {
+ return GetObjApiClassName(sd.name, opts);
+ }
+
+ static std::string GetObjApiClassName(const std::string &name,
+ const IDLOptions &opts) {
+ return opts.object_prefix + name + opts.object_suffix;
+ }
+
+ bool UnionHasStringType(const EnumDef &union_enum) {
+ return std::any_of(union_enum.Vals().begin(), union_enum.Vals().end(),
+ [](const EnumVal *ev) {
+ return !(ev->IsZero()) &&
+ (IsString(ev->union_type));
+ });
+ }
+
+ std::string GenUnionGenericTypeTS(const EnumDef &union_enum) {
+ return std::string("T") + (UnionHasStringType(union_enum) ? "|string" : "");
+ }
+
+ std::string GenUnionTypeTS(const EnumDef &union_enum,
+ imported_fileset &imported_files) {
+ std::string ret;
+ std::set<std::string> type_list;
+
+ for (auto it = union_enum.Vals().begin(); it != union_enum.Vals().end();
+ ++it) {
+ const auto &ev = **it;
+ if (ev.IsZero()) { continue; }
+
+ std::string type = "";
+ if (IsString(ev.union_type)) {
+ type = "string"; // no need to wrap string type in namespace
+ } else if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
+ if (!parser_.opts.generate_all) {
+ imported_files.insert(ev.union_type.struct_def->file);
+ }
+
+ type = GenPrefixedTypeName(WrapInNameSpace(*(ev.union_type.struct_def)),
+ ev.union_type.struct_def->file);
+ } else {
+ FLATBUFFERS_ASSERT(false);
+ }
+ type_list.insert(type);
+ }
+
+ for (auto it = type_list.begin(); it != type_list.end(); ++it) {
+ ret += *it + ((std::next(it) == type_list.end()) ? "" : "|");
+ }
+
+ return ret;
+ }
+
+ // Generate a TS union type based on a union's enum
+ std::string GenObjApiUnionTypeTS(const IDLOptions &opts,
+ const EnumDef &union_enum) {
+ std::string ret = "";
+ std::set<std::string> type_list;
+
+ for (auto it = union_enum.Vals().begin(); it != union_enum.Vals().end();
+ ++it) {
+ const auto &ev = **it;
+ if (ev.IsZero()) { continue; }
+
+ std::string type = "";
+ if (IsString(ev.union_type)) {
+ type = "string"; // no need to wrap string type in namespace
+ } else if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
+ type = GenPrefixedTypeName(
+ GetObjApiClassName(WrapInNameSpace(*(ev.union_type.struct_def)),
+ opts),
+ union_enum.file);
+ } else {
+ FLATBUFFERS_ASSERT(false);
+ }
+ type_list.insert(type);
+ }
+
+ size_t totalPrinted = 0;
+ for (auto it = type_list.begin(); it != type_list.end(); ++it) {
+ ++totalPrinted;
+ ret += *it + ((totalPrinted == type_list.size()) ? "" : "|");
+ }
+
+ return ret;
+ }
+
+ std::string GenUnionConvFuncName(const EnumDef &enum_def) {
+ return "unionTo" + enum_def.name;
+ }
+
+ std::string GenUnionListConvFuncName(const EnumDef &enum_def) {
+ return "unionListTo" + enum_def.name;
+ }
+
+ std::string GenUnionConvFunc(const Type &union_type,
+ imported_fileset &imported_files) {
+ if (union_type.enum_def) {
+ const auto &enum_def = *union_type.enum_def;
+
+ const auto valid_union_type = GenUnionTypeTS(enum_def, imported_files);
+ const auto valid_union_type_with_null = valid_union_type + "|null";
+
+ auto ret = "\n\nexport function " + GenUnionConvFuncName(enum_def) +
+ "(\n type: " + enum_def.name +
+ ",\n accessor: (obj:" + valid_union_type + ") => " +
+ valid_union_type_with_null +
+ "\n): " + valid_union_type_with_null + " {\n";
+
+ if (!parser_.opts.generate_all) {
+ imported_files.insert(union_type.enum_def->file);
+ }
+
+ const auto enum_type = GenPrefixedTypeName(
+ WrapInNameSpace(*(union_type.enum_def)), union_type.enum_def->file);
+ const auto &union_enum = *(union_type.enum_def);
+
+ const auto union_enum_loop = [&](const std::string &accessor_str) {
+ ret += " switch(" + enum_type + "[type]) {\n";
+ ret += " case 'NONE': return null; \n";
+
+ for (auto it = union_enum.Vals().begin(); it != union_enum.Vals().end();
+ ++it) {
+ const auto &ev = **it;
+ if (ev.IsZero()) { continue; }
+
+ ret += " case '" + ev.name + "': ";
+
+ if (IsString(ev.union_type)) {
+ ret += "return " + accessor_str + "'') as string;";
+ } else if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
+ const auto type = GenPrefixedTypeName(
+ WrapInNameSpace(*(ev.union_type.struct_def)),
+ ev.union_type.struct_def->file);
+ ret += "return " + accessor_str + "new " + type + "())! as " +
+ type + ";";
+ } else {
+ FLATBUFFERS_ASSERT(false);
+ }
+ ret += "\n";
+ }
+
+ ret += " default: return null;\n";
+ ret += " }\n";
+ };
+
+ union_enum_loop("accessor(");
+ ret += "}";
+
+ ret += "\n\nexport function " + GenUnionListConvFuncName(enum_def) +
+ "(\n type: " + enum_def.name +
+ ", \n accessor: (index: number, obj:" + valid_union_type +
+ ") => " + valid_union_type_with_null +
+ ", \n index: number\n): " + valid_union_type_with_null + " {\n";
+ union_enum_loop("accessor(index, ");
+ ret += "}";
+
+ return ret;
+ }
+ FLATBUFFERS_ASSERT(0);
+ return "";
+ }
+
+ // Used for generating a short function that returns the correct class
+ // based on union enum type. Assume the context is inside the non object api
+ // type
+ std::string GenUnionValTS(const std::string &field_name,
+ const Type &union_type,
+ const bool is_array = false) {
+ if (union_type.enum_def) {
+ const auto &enum_def = *union_type.enum_def;
+ const auto enum_type =
+ GenPrefixedTypeName(WrapInNameSpace(enum_def), enum_def.file);
+ const std::string union_accessor = "this." + field_name;
+
+ const auto union_has_string = UnionHasStringType(enum_def);
+ const auto field_binded_method = "this." + field_name + ".bind(this)";
+
+ std::string ret;
+
+ if (!is_array) {
+ const auto conversion_function =
+ GenPrefixedTypeName(WrapInNameSpace(enum_def.defined_namespace,
+ GenUnionConvFuncName(enum_def)),
+ enum_def.file);
+ const auto target_enum = "this." + field_name + "Type()";
+
+ ret = "(() => {\n";
+ ret += " let temp = " + conversion_function + "(" + target_enum +
+ ", " + field_binded_method + ");\n";
+ ret += " if(temp === null) { return null; }\n";
+ ret += union_has_string
+ ? " if(typeof temp === 'string') { return temp; }\n"
+ : "";
+ ret += " return temp.unpack()\n";
+ ret += " })()";
+ } else {
+ const auto conversion_function = GenPrefixedTypeName(
+ WrapInNameSpace(enum_def.defined_namespace,
+ GenUnionListConvFuncName(enum_def)),
+ enum_def.file);
+ const auto target_enum_accesor = "this." + field_name + "Type";
+ const auto target_enum_length = target_enum_accesor + "Length()";
+
+ ret = "(() => {\n";
+ ret += " let ret = [];\n";
+ ret += " for(let targetEnumIndex = 0; targetEnumIndex < " +
+ target_enum_length +
+ "; "
+ "++targetEnumIndex) {\n";
+ ret += " let targetEnum = " + target_enum_accesor +
+ "(targetEnumIndex);\n";
+ ret += " if(targetEnum === null || " + enum_type +
+ "[targetEnum!] === 'NONE') { "
+ "continue; }\n\n";
+ ret += " let temp = " + conversion_function + "(targetEnum, " +
+ field_binded_method + ", targetEnumIndex);\n";
+ ret += " if(temp === null) { continue; }\n";
+ ret += union_has_string ? " if(typeof temp === 'string') { "
+ "ret.push(temp); continue; }\n"
+ : "";
+ ret += " ret.push(temp.unpack());\n";
+ ret += " }\n";
+ ret += " return ret;\n";
+ ret += " })()";
+ }
+
+ return ret;
+ }
+
+ FLATBUFFERS_ASSERT(0);
+ return "";
+ }
+
+ static std::string GenNullCheckConditional(const std::string &nullCheckVar,
+ const std::string &trueVal,
+ const std::string &falseVal = "null") {
+ return "(" + nullCheckVar + " !== null ? " + trueVal + " : " + falseVal +
+ ")";
+ }
+
+ std::string GenStructMemberValueTS(const StructDef &struct_def,
+ const std::string &prefix,
+ const std::string &delimiter,
+ const bool nullCheck = true) {
+ std::string ret;
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+
+ const auto curr_member_accessor =
+ prefix + "." + MakeCamel(field.name, false);
+ if (IsStruct(field.value.type)) {
+ ret += GenStructMemberValueTS(*field.value.type.struct_def,
+ curr_member_accessor, delimiter);
+ } else {
+ if (nullCheck) {
+ ret +=
+ "(" + prefix + " === null ? 0 : " + curr_member_accessor + "!)";
+ } else {
+ ret += curr_member_accessor;
+ }
+ }
+
+ if (std::next(it) != struct_def.fields.vec.end()) { ret += delimiter; }
+ }
+
+ return ret;
+ }
+
+ void GenObjApi(const Parser &parser, StructDef &struct_def,
+ std::string &obj_api_unpack_func, std::string &obj_api_class,
+ imported_fileset &imported_files) {
+ const auto class_name = GetObjApiClassName(struct_def, parser.opts);
+
+ std::string unpack_func =
+ "\n/**\n * " + GenTypeAnnotation(kReturns, class_name, "") +
+ " */\nunpack(): " + class_name + " {\n return new " + class_name +
+ "(" + (struct_def.fields.vec.empty() ? "" : "\n");
+ std::string unpack_to_func =
+ "/**\n * " + GenTypeAnnotation(kParam, class_name, "_o") +
+ " */\nunpackTo(_o: " + class_name + "): void {" +
+ +(struct_def.fields.vec.empty() ? "" : "\n");
+
+ std::string constructor_annotation = "/**\n * @constructor";
+ constructor_annotation += (struct_def.fields.vec.empty() ? "" : "\n");
+ std::string constructor_func = "constructor(";
+ constructor_func += (struct_def.fields.vec.empty() ? "" : "\n");
+
+ const auto has_create =
+ struct_def.fixed || CanCreateFactoryMethod(struct_def);
+
+ std::string pack_func_prototype =
+ "/**\n * " +
+ GenTypeAnnotation(kParam, "flatbuffers.Builder", "builder") + " * " +
+ GenTypeAnnotation(kReturns, "flatbuffers.Offset", "") +
+ " */\npack(builder:flatbuffers.Builder): flatbuffers.Offset {\n";
+
+ std::string pack_func_offset_decl;
+ std::string pack_func_create_call;
+
+ const auto struct_name =
+ GenPrefixedTypeName(WrapInNameSpace(struct_def), struct_def.file);
+
+ if (has_create) {
+ pack_func_create_call = " return " + struct_name + ".create" +
+ Verbose(struct_def) + "(builder" +
+ (struct_def.fields.vec.empty() ? "" : ",\n ");
+ } else {
+ pack_func_create_call = " " + struct_name + ".start(builder);\n";
+ }
+
+ if (struct_def.fixed) {
+ // when packing struct, nested struct's members instead of the struct's
+ // offset are used
+ pack_func_create_call +=
+ GenStructMemberValueTS(struct_def, "this", ",\n ", false) + "\n ";
+ }
+
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+
+ const auto field_name = MakeCamel(field.name, false);
+ const std::string field_binded_method =
+ "this." + field_name + ".bind(this)";
+
+ std::string field_val;
+ std::string field_type;
+ // a string that declares a variable containing the
+ // offset for things that can't be generated inline
+ // empty otw
+ std::string field_offset_decl;
+ // a string that contains values for things that can be created inline or
+ // the variable name from field_offset_decl
+ std::string field_offset_val;
+ const auto field_default_val =
+ GenDefaultValue(field, "flatbuffers");
+
+ // Emit a scalar field
+ const auto is_string = IsString(field.value.type);
+ if (IsScalar(field.value.type.base_type) || is_string) {
+ const auto has_null_default = is_string || HasNullDefault(field);
+
+ if (field.value.type.enum_def) {
+ if (!parser_.opts.generate_all) {
+ imported_files.insert(field.value.type.enum_def->file);
+ }
+
+ field_type +=
+ GenPrefixedTypeName(GenTypeName(field.value.type, false, has_null_default),
+ field.value.type.enum_def->file);
+ } else {
+ field_type += GenTypeName(field.value.type, false, has_null_default);
+ }
+ field_val = "this." + field_name + "()";
+
+ if (field.value.type.base_type != BASE_TYPE_STRING) {
+ field_offset_val = "this." + field_name;
+ } else {
+ field_offset_decl = GenNullCheckConditional(
+ "this." + field_name,
+ "builder.createString(this." + field_name + "!)", "0");
+ }
+ }
+
+ // Emit an object field
+ else {
+ auto is_vector = false;
+ switch (field.value.type.base_type) {
+ case BASE_TYPE_STRUCT: {
+ const auto &sd = *field.value.type.struct_def;
+ field_type += GenPrefixedTypeName(
+ WrapInNameSpace(sd.defined_namespace,
+ GetObjApiClassName(sd, parser.opts)),
+ field.value.type.struct_def->file);
+
+ const std::string field_accessor = "this." + field_name + "()";
+ field_val = GenNullCheckConditional(field_accessor,
+ field_accessor + "!.unpack()");
+ field_offset_val = GenNullCheckConditional(
+ "this." + field_name, "this." + field_name + "!.pack(builder)",
+ "0");
+
+ break;
+ }
+
+ case BASE_TYPE_VECTOR: {
+ auto vectortype = field.value.type.VectorType();
+ auto vectortypename = GenTypeName(vectortype, false);
+ is_vector = true;
+
+ field_type = "(";
+
+ switch (vectortype.base_type) {
+ case BASE_TYPE_STRUCT: {
+ const auto &sd = *field.value.type.struct_def;
+ field_type += GenPrefixedTypeName(
+ WrapInNameSpace(sd.defined_namespace,
+ GetObjApiClassName(sd, parser.opts)),
+ field.value.type.struct_def->file);
+ field_type += ")[]";
+
+ field_val = GenBBAccess() + ".createObjList(" +
+ field_binded_method + ", this." + field_name +
+ "Length())";
+
+ if (sd.fixed) {
+ field_offset_decl =
+ "builder.createStructOffsetList(this." + field_name +
+ ", " +
+ GenPrefixedTypeName(WrapInNameSpace(struct_def),
+ struct_def.file) +
+ ".start" + MakeCamel(field_name) + "Vector)";
+ } else {
+ field_offset_decl =
+ GenPrefixedTypeName(WrapInNameSpace(struct_def),
+ struct_def.file) +
+ ".create" + MakeCamel(field_name) +
+ "Vector(builder, builder.createObjectOffsetList(" +
+ "this." + field_name + "))";
+ }
+
+ break;
+ }
+
+ case BASE_TYPE_STRING: {
+ field_type += "string)[]";
+ field_val = GenBBAccess() + ".createStringList(" +
+ field_binded_method + ", this." + field_name +
+ "Length())";
+ field_offset_decl =
+ GenPrefixedTypeName(WrapInNameSpace(struct_def),
+ struct_def.file) +
+ ".create" + MakeCamel(field_name) +
+ "Vector(builder, builder.createObjectOffsetList(" +
+ "this." + field_name + "))";
+ break;
+ }
+
+ case BASE_TYPE_UNION: {
+ field_type +=
+ GenObjApiUnionTypeTS(parser.opts, *(vectortype.enum_def));
+ field_type += ")[]";
+ field_val = GenUnionValTS(field_name, vectortype, true);
+
+ field_offset_decl =
+ GenPrefixedTypeName(WrapInNameSpace(struct_def),
+ struct_def.file) +
+ ".create" + MakeCamel(field_name) +
+ "Vector(builder, builder.createObjectOffsetList(" +
+ "this." + field_name + "))";
+
+ break;
+ }
+ default: {
+ if (vectortype.enum_def) {
+ if (!parser_.opts.generate_all) {
+ imported_files.insert(vectortype.enum_def->file);
+ }
+
+ field_type +=
+ GenPrefixedTypeName(GenTypeName(vectortype, false, HasNullDefault(field)),
+ vectortype.enum_def->file);
+ } else {
+ field_type += vectortypename;
+ }
+ field_type += ")[]";
+ field_val = GenBBAccess() + ".createScalarList(" +
+ field_binded_method + ", this." + field_name +
+ "Length())";
+
+ field_offset_decl =
+ GenPrefixedTypeName(WrapInNameSpace(struct_def),
+ struct_def.file) +
+ ".create" + MakeCamel(field_name) +
+ "Vector(builder, this." + field_name + ")";
+
+ break;
+ }
+ }
+
+ break;
+ }
+
+ case BASE_TYPE_UNION: {
+ if (!parser_.opts.generate_all) {
+ imported_files.insert(field.value.type.enum_def->file);
+ }
+
+ field_type +=
+ GenObjApiUnionTypeTS(parser.opts, *(field.value.type.enum_def));
+
+ field_val = GenUnionValTS(field_name, field.value.type);
+ field_offset_decl =
+ "builder.createObjectOffset(this." + field_name + ")";
+ break;
+ }
+
+ default: FLATBUFFERS_ASSERT(0); break;
+ }
+
+ // length 0 vector is simply empty instead of null
+ field_type += is_vector ? "" : "|null";
+ }
+
+ if (!field_offset_decl.empty()) {
+ field_offset_decl =
+ " const " + field_name + " = " + field_offset_decl + ";";
+ }
+ if (field_offset_val.empty()) { field_offset_val = field_name; }
+
+ unpack_func += " " + field_val;
+ unpack_to_func += " _o." + field_name + " = " + field_val + ";";
+
+ constructor_annotation +=
+ " * " + GenTypeAnnotation(kParam, field_type, field_name, false);
+ constructor_func += " public " + field_name + ": " + field_type + " = " +
+ field_default_val;
+
+ if (!struct_def.fixed) {
+ if (!field_offset_decl.empty()) {
+ pack_func_offset_decl += field_offset_decl + "\n";
+ }
+
+ if (has_create) {
+ pack_func_create_call += field_offset_val;
+ } else {
+ pack_func_create_call += " " + struct_name + ".add" +
+ MakeCamel(field.name) + "(builder, " +
+ field_offset_val + ");\n";
+ }
+ }
+
+ if (std::next(it) != struct_def.fields.vec.end()) {
+ constructor_annotation += "\n";
+ constructor_func += ",\n";
+
+ if (!struct_def.fixed && has_create) {
+ pack_func_create_call += ",\n ";
+ }
+
+ unpack_func += ",\n";
+ unpack_to_func += "\n";
+ } else {
+ constructor_func += "\n";
+ if (!struct_def.fixed) {
+ pack_func_offset_decl += (pack_func_offset_decl.empty() ? "" : "\n");
+ pack_func_create_call += "\n ";
+ }
+
+ unpack_func += "\n ";
+ unpack_to_func += "\n";
+ }
+ }
+
+ constructor_annotation += "\n */\n";
+ constructor_func += "){};\n\n";
+
+ if (has_create) {
+ pack_func_create_call += ");";
+ } else {
+ pack_func_create_call += "return " + struct_name + ".end(builder);";
+ }
+
+ obj_api_class = "\nexport class " +
+ GetObjApiClassName(struct_def, parser.opts) + " {\n";
+
+ obj_api_class += constructor_annotation + constructor_func;
+
+ obj_api_class += pack_func_prototype + pack_func_offset_decl +
+ pack_func_create_call + "\n};";
+
+ obj_api_class += "\n}\n";
+
+ unpack_func += ");\n};";
+ unpack_to_func += "};\n";
+
+ obj_api_unpack_func = unpack_func + "\n\n" + unpack_to_func;
+ }
+
+ static bool CanCreateFactoryMethod(const StructDef &struct_def) {
+ // to preserve backwards compatibility, we allow the first field to be a
+ // struct
+ return struct_def.fields.vec.size() < 2 ||
+ std::all_of(std::begin(struct_def.fields.vec) + 1,
+ std::end(struct_def.fields.vec),
+ [](const FieldDef *f) -> bool {
+ FLATBUFFERS_ASSERT(f != nullptr);
+ return f->value.type.base_type != BASE_TYPE_STRUCT;
+ });
+ }
+
// Generate an accessor struct with constructor for a flatbuffers struct.
void GenStruct(const Parser &parser, StructDef &struct_def,
std::string *code_ptr, std::string *exports_ptr,
@@ -682,7 +1322,8 @@
code += " {\n";
if (lang_.language != IDLOptions::kTs) {
code += " /**\n";
- code += " * " + GenTypeAnnotation(kType, "flatbuffers.ByteBuffer", "");
+ code +=
+ " * " + GenTypeAnnotation(kType, "flatbuffers.ByteBuffer", "");
code += " */\n";
}
code += " bb: flatbuffers.ByteBuffer|null = null;\n";
@@ -752,10 +1393,9 @@
// Generate the identifier check method
if (!struct_def.fixed && parser_.root_struct_def_ == &struct_def &&
!parser_.file_identifier_.empty()) {
- GenDocComment(
- code_ptr,
- GenTypeAnnotation(kParam, "flatbuffers.ByteBuffer", "bb") +
- GenTypeAnnotation(kReturns, "boolean", "", false));
+ GenDocComment(code_ptr,
+ GenTypeAnnotation(kParam, "flatbuffers.ByteBuffer", "bb") +
+ GenTypeAnnotation(kReturns, "boolean", "", false));
if (lang_.language == IDLOptions::kTs) {
code +=
"static bufferHasIdentifier(bb:flatbuffers.ByteBuffer):boolean "
@@ -778,20 +1418,22 @@
NumToString(field.value.offset) + ");\n return offset ? ";
// Emit a scalar field
- if (IsScalar(field.value.type.base_type) ||
- field.value.type.base_type == BASE_TYPE_STRING) {
+ const auto is_string = IsString(field.value.type);
+ if (IsScalar(field.value.type.base_type) || is_string) {
+ const auto has_null_default = is_string || HasNullDefault(field);
+
GenDocComment(
field.doc_comment, code_ptr,
- std::string(field.value.type.base_type == BASE_TYPE_STRING
+ std::string(is_string
? GenTypeAnnotation(kParam, "flatbuffers.Encoding=",
"optionalEncoding")
: "") +
GenTypeAnnotation(kReturns,
- GenTypeName(field.value.type, false, true),
+ GenTypeName(field.value.type, false, has_null_default),
"", false));
if (lang_.language == IDLOptions::kTs) {
std::string prefix = MakeCamel(field.name, false) + "(";
- if (field.value.type.base_type == BASE_TYPE_STRING) {
+ if (is_string) {
code += prefix + "):string|null\n";
code += prefix + "optionalEncoding:flatbuffers.Encoding" +
"):" + GenTypeName(field.value.type, false, true) + "\n";
@@ -802,7 +1444,7 @@
if (field.value.type.enum_def) {
code +=
"):" +
- GenPrefixedTypeName(GenTypeName(field.value.type, false, true),
+ GenPrefixedTypeName(GenTypeName(field.value.type, false, field.optional),
field.value.type.enum_def->file) +
" {\n";
@@ -810,12 +1452,12 @@
imported_files.insert(field.value.type.enum_def->file);
}
} else {
- code += "):" + GenTypeName(field.value.type, false, true) + " {\n";
+ code += "):" + GenTypeName(field.value.type, false, has_null_default) + " {\n";
}
} else {
code += object_name + ".prototype." + MakeCamel(field.name, false);
code += " = function(";
- if (field.value.type.base_type == BASE_TYPE_STRING) {
+ if (is_string) {
code += "optionalEncoding";
}
code += ") {\n";
@@ -829,12 +1471,12 @@
";\n";
} else {
std::string index = "this.bb_pos + offset";
- if (field.value.type.base_type == BASE_TYPE_STRING) {
+ if (is_string) {
index += ", optionalEncoding";
}
code += offset_prefix +
GenGetter(field.value.type, "(" + index + ")") + " : " +
- GenDefaultValue(field.value, GenBBAccess());
+ GenDefaultValue(field, GenBBAccess());
code += ";\n";
}
}
@@ -860,19 +1502,21 @@
}
if (struct_def.fixed) {
- code += " return (obj || new " + type;
+ code += " return (obj || " + GenerateNewExpression(type);
code += ").__init(this.bb_pos";
code +=
MaybeAdd(field.value.offset) + ", " + GenBBAccess() + ");\n";
} else {
- code += offset_prefix + "(obj || new " + type + ").__init(";
+ code += offset_prefix + "(obj || " + GenerateNewExpression(type) +
+ ").__init(";
code += field.value.type.struct_def->fixed
? "this.bb_pos + offset"
: GenBBAccess() + ".__indirect(this.bb_pos + offset)";
code += ", " + GenBBAccess() + ") : null;\n";
}
- if (lang_.language == IDLOptions::kTs && !parser_.opts.generate_all) {
+ if (lang_.language == IDLOptions::kTs &&
+ !parser_.opts.generate_all) {
imported_files.insert(field.value.type.struct_def->file);
}
@@ -882,6 +1526,12 @@
case BASE_TYPE_VECTOR: {
auto vectortype = field.value.type.VectorType();
auto vectortypename = GenTypeName(vectortype, false);
+
+ if (vectortype.enum_def) {
+ vectortypename = GenPrefixedTypeName(vectortypename,
+ vectortype.enum_def->file);
+ }
+
auto inline_size = InlineSize(vectortype);
auto index = GenBBAccess() +
".__vector(this.bb_pos + offset) + index" +
@@ -914,8 +1564,11 @@
if (is_union) { prefix += "<T extends flatbuffers.Table>"; }
prefix += "(index: number";
if (is_union) {
- vectortypename = "T";
- code += prefix + ", obj:T";
+ const auto union_type =
+ GenUnionGenericTypeTS(*(field.value.type.enum_def));
+
+ vectortypename = union_type;
+ code += prefix + ", obj:" + union_type;
} else if (vectortype.base_type == BASE_TYPE_STRUCT) {
vectortypename = GenPrefixedTypeName(
vectortypename, vectortype.struct_def->file);
@@ -924,13 +1577,17 @@
if (!parser_.opts.generate_all) {
imported_files.insert(vectortype.struct_def->file);
}
- } else if (vectortype.base_type == BASE_TYPE_STRING) {
+ } else if (IsString(vectortype)) {
code += prefix + "):string\n";
code += prefix + ",optionalEncoding:flatbuffers.Encoding" +
"):" + vectortypename + "\n";
code += prefix + ",optionalEncoding?:any";
} else {
code += prefix;
+
+ if (vectortype.enum_def && !parser_.opts.generate_all) {
+ imported_files.insert(vectortype.enum_def->file);
+ }
}
code += "):" + vectortypename + "|null {\n";
} else {
@@ -939,14 +1596,15 @@
code += " = function(index";
if (vectortype.base_type == BASE_TYPE_STRUCT || is_union) {
code += ", obj";
- } else if (vectortype.base_type == BASE_TYPE_STRING) {
+ } else if (IsString(vectortype)) {
code += ", optionalEncoding";
}
code += ") {\n";
}
if (vectortype.base_type == BASE_TYPE_STRUCT) {
- code += offset_prefix + "(obj || new " + vectortypename;
+ code += offset_prefix + "(obj || " +
+ GenerateNewExpression(vectortypename);
code += ").__init(";
code += vectortype.struct_def->fixed
? index
@@ -955,7 +1613,7 @@
} else {
if (is_union) {
index = "obj, " + index;
- } else if (vectortype.base_type == BASE_TYPE_STRING) {
+ } else if (IsString(vectortype)) {
index += ", optionalEncoding";
}
code += offset_prefix + GenGetter(vectortype, "(" + index + ")");
@@ -991,7 +1649,13 @@
false));
if (lang_.language == IDLOptions::kTs) {
code += MakeCamel(field.name, false);
- code += "<T extends flatbuffers.Table>(obj:T):T|null {\n";
+
+ const auto &union_enum = *(field.value.type.enum_def);
+ const auto union_type = GenUnionGenericTypeTS(union_enum);
+ code += "<T extends flatbuffers.Table>(obj:" + union_type +
+ "):" + union_type +
+ "|null "
+ "{\n";
} else {
code +=
object_name + ".prototype." + MakeCamel(field.name, false);
@@ -1015,7 +1679,8 @@
}
// Adds the mutable scalar value to the output
- if (IsScalar(field.value.type.base_type) && parser.opts.mutable_buffer) {
+ if (IsScalar(field.value.type.base_type) && parser.opts.mutable_buffer &&
+ !IsUnion(field.value.type)) {
std::string annotations = GenTypeAnnotation(
kParam, GenTypeName(field.value.type, true), "value");
GenDocComment(
@@ -1025,6 +1690,10 @@
if (lang_.language == IDLOptions::kTs) {
std::string type;
if (field.value.type.enum_def) {
+ if (!parser_.opts.generate_all) {
+ imported_files.insert(field.value.type.enum_def->file);
+ }
+
type = GenPrefixedTypeName(GenTypeName(field.value.type, true),
field.value.type.enum_def->file);
} else {
@@ -1037,19 +1706,26 @@
" = function(value) {\n";
}
- code += " var offset = " + GenBBAccess() + ".__offset(this.bb_pos, " +
- NumToString(field.value.offset) + ");\n\n";
- code += " if (offset === 0) {\n";
- code += " return false;\n";
- code += " }\n\n";
+ if (struct_def.fixed) {
+ code += " " + GenBBAccess() + ".write" +
+ MakeCamel(GenType(field.value.type)) + "(this.bb_pos + " +
+ NumToString(field.value.offset) + ", ";
+ } else {
+ code += " var offset = " + GenBBAccess() +
+ ".__offset(this.bb_pos, " + NumToString(field.value.offset) +
+ ");\n\n";
+ code += " if (offset === 0) {\n";
+ code += " return false;\n";
+ code += " }\n\n";
- // special case for bools, which are treated as uint8
- code += " " + GenBBAccess() + ".write" +
- MakeCamel(GenType(field.value.type)) +
- "(this.bb_pos + offset, ";
- if (field.value.type.base_type == BASE_TYPE_BOOL &&
- lang_.language == IDLOptions::kTs) {
- code += "+";
+ // special case for bools, which are treated as uint8
+ code += " " + GenBBAccess() + ".write" +
+ MakeCamel(GenType(field.value.type)) +
+ "(this.bb_pos + offset, ";
+ if (field.value.type.base_type == BASE_TYPE_BOOL &&
+ lang_.language == IDLOptions::kTs) {
+ code += "+";
+ }
}
code += "value);\n";
@@ -1064,7 +1740,7 @@
}
// Emit vector helpers
- if (field.value.type.base_type == BASE_TYPE_VECTOR) {
+ if (IsVector(field.value.type)) {
// Emit a length helper
GenDocComment(code_ptr,
GenTypeAnnotation(kReturns, "number", "", false));
@@ -1118,6 +1794,30 @@
}
}
+ // Emit the fully qualified name
+ if (parser_.opts.generate_name_strings) {
+ GenDocComment(code_ptr, GenTypeAnnotation(kReturns, "string", "", false));
+ if (lang_.language == IDLOptions::kTs) {
+ code += "static getFullyQualifiedName():string {\n";
+ } else {
+ code += object_name + ".getFullyQualifiedName = function() {\n";
+ }
+ code += " return '" + WrapInNameSpace(struct_def) + "';\n";
+ code += "}\n\n";
+ }
+
+ // Emit the size of the struct.
+ if (struct_def.fixed) {
+ GenDocComment(code_ptr, GenTypeAnnotation(kReturns, "number", "", false));
+ if (lang_.language == IDLOptions::kTs) {
+ code += "static sizeOf():number {\n";
+ } else {
+ code += object_name + ".sizeOf = function() {\n";
+ }
+ code += " return " + NumToString(struct_def.bytesize) + ";\n";
+ code += "}\n\n";
+ }
+
// Emit a factory constructor
if (struct_def.fixed) {
std::string annotations =
@@ -1174,7 +1874,7 @@
if (lang_.language == IDLOptions::kTs) {
code += "static add" + MakeCamel(field.name);
code += "(builder:flatbuffers.Builder, " + argname + ":" +
- GetArgType(field) + ") {\n";
+ GetArgType(field, false) + ") {\n";
} else {
code += object_name + ".add" + MakeCamel(field.name);
code += " = function(builder, " + argname + ") {\n";
@@ -1186,13 +1886,19 @@
code += argname + ", ";
if (!IsScalar(field.value.type.base_type)) {
code += "0";
+ } else if (HasNullDefault(field)) {
+ if (IsLong(field.value.type.base_type)) {
+ code += "builder.createLong(0, 0)";
+ } else {
+ code += "0";
+ }
} else {
if (field.value.type.base_type == BASE_TYPE_BOOL) { code += "+"; }
- code += GenDefaultValue(field.value, "builder");
+ code += GenDefaultValue(field, "builder");
}
code += ");\n};\n\n";
- if (field.value.type.base_type == BASE_TYPE_VECTOR) {
+ if (IsVector(field.value.type)) {
auto vector_type = field.value.type.VectorType();
auto alignment = InlineAlignment(vector_type);
auto elem_size = InlineSize(vector_type);
@@ -1210,11 +1916,37 @@
false));
if (lang_.language == IDLOptions::kTs) {
- code += "static create" + MakeCamel(field.name);
+ const std::string sig_begin =
+ "static create" + MakeCamel(field.name) +
+ "Vector(builder:flatbuffers.Builder, data:";
+ const std::string sig_end = "):flatbuffers.Offset";
std::string type = GenTypeName(vector_type, true) + "[]";
- if (type == "number[]") { type += " | Uint8Array"; }
- code += "Vector(builder:flatbuffers.Builder, data:" + type +
- "):flatbuffers.Offset {\n";
+ if (type == "number[]") {
+ const auto &array_type = GenType(vector_type);
+ // the old type should be deprecated in the future
+ std::string type_old = "number[]|Uint8Array";
+ std::string type_new = "number[]|" + array_type + "Array";
+ if (type_old == type_new) {
+ type = type_new;
+ } else {
+ // add function overloads
+ code += sig_begin + type_new + sig_end + ";\n";
+ code +=
+ "/**\n * @deprecated This Uint8Array overload will "
+ "be removed in the future.\n */\n";
+ code += sig_begin + type_old + sig_end + ";\n";
+ type = type_new + "|Uint8Array";
+ }
+ } else {
+ if (vector_type.enum_def) {
+ if (!parser_.opts.generate_all) {
+ imported_files.insert(vector_type.enum_def->file);
+ }
+
+ type = GenPrefixedTypeName(type, vector_type.enum_def->file);
+ }
+ }
+ code += sig_begin + type + sig_end + " {\n";
} else {
code += object_name + ".create" + MakeCamel(field.name);
code += "Vector = function(builder, data) {\n";
@@ -1284,85 +2016,120 @@
GenerateFinisher(struct_def, code_ptr, code, object_name, true);
// Generate a convenient CreateX function
- if (lang_.language == IDLOptions::kJs) {
- std::string paramDoc =
- GenTypeAnnotation(kParam, "flatbuffers.Builder", "builder");
+ if (CanCreateFactoryMethod(struct_def)) {
+ if (lang_.language == IDLOptions::kJs) {
+ std::string paramDoc =
+ GenTypeAnnotation(kParam, "flatbuffers.Builder", "builder");
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ const auto &field = **it;
+ if (field.deprecated) continue;
+ paramDoc +=
+ GenTypeAnnotation(kParam, GetArgType(field, true), GetArgName(field));
+ }
+ paramDoc +=
+ GenTypeAnnotation(kReturns, "flatbuffers.Offset", "", false);
+
+ GenDocComment(code_ptr, paramDoc);
+ }
+
+ if (lang_.language == IDLOptions::kTs) {
+ code += "static create" + Verbose(struct_def);
+ code += "(builder:flatbuffers.Builder";
+ } else {
+ code += object_name + ".create" + Verbose(struct_def);
+ code += " = function(builder";
+ }
for (auto it = struct_def.fields.vec.begin();
it != struct_def.fields.vec.end(); ++it) {
const auto &field = **it;
- if (field.deprecated)
- continue;
- paramDoc +=
- GenTypeAnnotation(kParam, GetArgType(field), GetArgName(field));
+ if (field.deprecated) continue;
+
+ if (lang_.language == IDLOptions::kTs) {
+ code += ", " + GetArgName(field) + ":" + GetArgType(field, true);
+ } else {
+ code += ", " + GetArgName(field);
+ }
}
- paramDoc +=
- GenTypeAnnotation(kReturns, "flatbuffers.Offset", "", false);
-
- GenDocComment(code_ptr, paramDoc);
- }
-
- if (lang_.language == IDLOptions::kTs) {
- code += "static create" + Verbose(struct_def);
- code += "(builder:flatbuffers.Builder";
- } else {
- code += object_name + ".create" + Verbose(struct_def);
- code += " = function(builder";
- }
- for (auto it = struct_def.fields.vec.begin();
- it != struct_def.fields.vec.end(); ++it) {
- const auto &field = **it;
- if (field.deprecated)
- continue;
if (lang_.language == IDLOptions::kTs) {
- code += ", " + GetArgName(field) + ":" + GetArgType(field);
+ code += "):flatbuffers.Offset {\n";
+ code += " " + struct_def.name + ".start" + Verbose(struct_def) +
+ "(builder);\n";
} else {
- code += ", " + GetArgName(field);
+ code += ") {\n";
+ code += " " + object_name + ".start" + Verbose(struct_def) +
+ "(builder);\n";
}
- }
- if (lang_.language == IDLOptions::kTs) {
- code += "):flatbuffers.Offset {\n";
- code += " " + struct_def.name + ".start" + Verbose(struct_def) +
+ std::string methodPrefix =
+ lang_.language == IDLOptions::kTs ? struct_def.name : object_name;
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ const auto &field = **it;
+ if (field.deprecated) continue;
+
+ const auto arg_name = GetArgName(field);
+
+ if (field.IsScalarOptional()) {
+ code += " if (" + arg_name + " !== null)\n ";
+ }
+
+ code += " " + methodPrefix + ".add" + MakeCamel(field.name) + "(";
+ code += "builder, " + arg_name + ");\n";
+ }
+
+ code += " return " + methodPrefix + ".end" + Verbose(struct_def) +
"(builder);\n";
- } else {
- code += ") {\n";
- code += " " + object_name + ".start" + Verbose(struct_def) +
- "(builder);\n";
+ code += "}\n";
+ if (lang_.language == IDLOptions::kJs) code += "\n";
}
+ }
- std::string methodPrefix =
- lang_.language == IDLOptions::kTs ? struct_def.name : object_name;
- for (auto it = struct_def.fields.vec.begin();
- it != struct_def.fields.vec.end(); ++it) {
- const auto &field = **it;
- if (field.deprecated)
- continue;
-
- code += " " + methodPrefix + ".add" + MakeCamel(field.name) + "(";
- code += "builder, " + GetArgName(field) + ");\n";
- }
-
- code += " return " + methodPrefix + ".end" + Verbose(struct_def) +
- "(builder);\n";
+ if (!struct_def.fixed && parser_.services_.vec.size() != 0 &&
+ lang_.language == IDLOptions::kTs) {
+ auto name = Verbose(struct_def, "");
+ code += "\n";
+ code += "serialize():Uint8Array {\n";
+ code += " return this.bb!.bytes();\n";
code += "}\n";
- if (lang_.language == IDLOptions::kJs)
- code += "\n";
+
+ code += "\n";
+ code += "static deserialize(buffer: Uint8Array):"+ name +" {\n";
+ code += " return " + name + ".getRootAs" + name +
+ "(new flatbuffers.ByteBuffer(buffer))\n";
+ code += "}\n";
}
if (lang_.language == IDLOptions::kTs) {
- if (!object_namespace.empty()) {
+ if (parser_.opts.generate_object_based_api) {
+ std::string obj_api_class;
+ std::string obj_api_unpack_func;
+ GenObjApi(parser_, struct_def, obj_api_unpack_func, obj_api_class,
+ imported_files);
+
+ code += obj_api_unpack_func + "}\n" + obj_api_class;
+ } else {
code += "}\n";
}
- code += "}\n";
+ if (!object_namespace.empty()) { code += "}\n"; }
}
}
+
+ static bool HasNullDefault(const FieldDef &field) {
+ return field.optional && field.value.constant == "null";
+ }
- std::string GetArgType(const FieldDef &field) {
- if (field.value.type.enum_def)
- return GenPrefixedTypeName(GenTypeName(field.value.type, true),
- field.value.type.enum_def->file);
- return GenTypeName(field.value.type, true);
+ std::string GetArgType(const FieldDef &field, bool allowNull) {
+ auto type_name = GenTypeName(field.value.type, true, allowNull && field.optional);
+
+ if (field.value.type.enum_def) {
+ if (IsScalar(field.value.type.base_type)) {
+ return GenPrefixedTypeName(type_name, field.value.type.enum_def->file);
+ }
+ }
+
+ return type_name;
}
static std::string GetArgName(const FieldDef &field) {
@@ -1372,12 +2139,10 @@
return argname;
}
- std::string Verbose(const StructDef &struct_def,
- const char* prefix = "")
- {
+ std::string Verbose(const StructDef &struct_def, const char *prefix = "") {
return parser_.opts.js_ts_short_names ? "" : prefix + struct_def.name;
}
-};
+}; // namespace jsts
} // namespace jsts
bool GenerateJSTS(const Parser &parser, const std::string &path,
@@ -1389,11 +2154,12 @@
std::string JSTSMakeRule(const Parser &parser, const std::string &path,
const std::string &file_name) {
FLATBUFFERS_ASSERT(parser.opts.lang <= IDLOptions::kMAX);
- const auto &lang = GetJsLangParams(parser.opts.lang);
std::string filebase =
flatbuffers::StripPath(flatbuffers::StripExtension(file_name));
- std::string make_rule = GeneratedFileName(path, filebase, lang) + ": ";
+ jsts::JsTsGenerator generator(parser, path, file_name);
+ std::string make_rule =
+ generator.GeneratedFileName(path, filebase, parser.opts) + ": ";
auto included_files = parser.GetIncludedFilesRecursive(file_name);
for (auto it = included_files.begin(); it != included_files.end(); ++it) {
diff --git a/src/idl_gen_json_schema.cpp b/src/idl_gen_json_schema.cpp
index 27e2cd4..a321b89 100644
--- a/src/idl_gen_json_schema.cpp
+++ b/src/idl_gen_json_schema.cpp
@@ -15,38 +15,15 @@
*/
#include <iostream>
+
#include "flatbuffers/code_generators.h"
#include "flatbuffers/idl.h"
#include "flatbuffers/util.h"
namespace flatbuffers {
-static std::string GeneratedFileName(const std::string &path,
- const std::string &file_name) {
- return path + file_name + ".schema.json";
-}
-
namespace jsons {
-std::string GenNativeType(BaseType type) {
- switch (type) {
- case BASE_TYPE_BOOL: return "boolean";
- case BASE_TYPE_CHAR:
- case BASE_TYPE_UCHAR:
- case BASE_TYPE_SHORT:
- case BASE_TYPE_USHORT:
- case BASE_TYPE_INT:
- case BASE_TYPE_UINT:
- case BASE_TYPE_LONG:
- case BASE_TYPE_ULONG:
- case BASE_TYPE_FLOAT:
- case BASE_TYPE_DOUBLE: return "number";
- case BASE_TYPE_STRING: return "string";
- case BASE_TYPE_ARRAY: return "array";
- default: return "";
- }
-}
-
template<class T> std::string GenFullName(const T *enum_def) {
std::string full_name;
const auto &name_spaces = enum_def->defined_namespace->components;
@@ -65,23 +42,62 @@
return "\"type\" : \"" + name + "\"";
}
-std::string GenType(const Type &type) {
- if (type.enum_def != nullptr && !type.enum_def->is_union) {
- // it is a reference to an enum type
- return GenTypeRef(type.enum_def);
+std::string GenType(BaseType type) {
+ switch (type) {
+ case BASE_TYPE_BOOL: return "\"type\" : \"boolean\"";
+ case BASE_TYPE_CHAR:
+ return "\"type\" : \"integer\", \"minimum\" : " +
+ NumToString(std::numeric_limits<int8_t>::min()) +
+ ", \"maximum\" : " +
+ NumToString(std::numeric_limits<int8_t>::max()) + "\"";
+ case BASE_TYPE_UCHAR:
+ return "\"type\" : \"integer\", \"minimum\" : 0, \"maximum\" :" +
+ NumToString(std::numeric_limits<uint8_t>::max()) + "\"";
+ case BASE_TYPE_SHORT:
+ return "\"type\" : \"integer\", \"minimum\" : " +
+ NumToString(std::numeric_limits<int16_t>::min()) +
+ ", \"maximum\" : " +
+ NumToString(std::numeric_limits<int16_t>::max());
+ case BASE_TYPE_USHORT:
+ return "\"type\" : \"integer\", \"minimum\" : 0, \"maximum\" : " +
+ NumToString(std::numeric_limits<uint16_t>::max());
+ case BASE_TYPE_INT:
+ return "\"type\" : \"integer\", \"minimum\" : " +
+ NumToString(std::numeric_limits<int32_t>::min()) +
+ ", \"maximum\" : " +
+ NumToString(std::numeric_limits<int32_t>::max());
+ case BASE_TYPE_UINT:
+ return "\"type\" : \"integer\", \"minimum\" : 0, \"maximum\" : " +
+ NumToString(std::numeric_limits<uint32_t>::max());
+ case BASE_TYPE_LONG:
+ return "\"type\" : \"integer\", \"minimum\" : " +
+ NumToString(std::numeric_limits<int64_t>::min()) +
+ ", \"maximum\" : " +
+ NumToString(std::numeric_limits<int64_t>::max());
+ case BASE_TYPE_ULONG:
+ return "\"type\" : \"integer\", \"minimum\" : 0, \"maximum\" : " +
+ NumToString(std::numeric_limits<uint64_t>::max());
+ case BASE_TYPE_FLOAT:
+ case BASE_TYPE_DOUBLE: return "\"type\" : \"number\"";
+ case BASE_TYPE_STRING: return "\"type\" : \"string\"";
+ default: return "";
}
+}
+
+std::string GenBaseType(const Type &type) {
+ if (type.struct_def != nullptr) { return GenTypeRef(type.struct_def); }
+ if (type.enum_def != nullptr) { return GenTypeRef(type.enum_def); }
+ if (IsArray(type) || IsVector(type)) {
+ return "\"type\" : \"array\", \"items\" : {" + GenType(type.element) + "}";
+ }
+ return GenType(type.base_type);
+}
+
+std::string GenType(const Type &type) {
switch (type.base_type) {
case BASE_TYPE_ARRAY: FLATBUFFERS_FALLTHROUGH(); // fall thru
case BASE_TYPE_VECTOR: {
- std::string typeline;
- typeline.append("\"type\" : \"array\", \"items\" : { ");
- if (type.element == BASE_TYPE_STRUCT) {
- typeline.append(GenTypeRef(type.struct_def));
- } else {
- typeline.append(GenType(GenNativeType(type.element)));
- }
- typeline.append(" }");
- return typeline;
+ return GenBaseType(type);
}
case BASE_TYPE_STRUCT: {
return GenTypeRef(type.struct_def);
@@ -90,7 +106,7 @@
std::string union_type_string("\"anyOf\": [");
const auto &union_types = type.enum_def->Vals();
for (auto ut = union_types.cbegin(); ut < union_types.cend(); ++ut) {
- auto &union_type = *ut;
+ const auto &union_type = *ut;
if (union_type->union_type.base_type == BASE_TYPE_NONE) { continue; }
if (union_type->union_type.base_type == BASE_TYPE_STRUCT) {
union_type_string.append(
@@ -104,46 +120,69 @@
return union_type_string;
}
case BASE_TYPE_UTYPE: return GenTypeRef(type.enum_def);
- default: return GenType(GenNativeType(type.base_type));
+ default: {
+ return GenBaseType(type);
+ }
}
}
class JsonSchemaGenerator : public BaseGenerator {
private:
- CodeWriter code_;
+ std::string code_;
public:
JsonSchemaGenerator(const Parser &parser, const std::string &path,
const std::string &file_name)
- : BaseGenerator(parser, path, file_name, "", "") {}
+ : BaseGenerator(parser, path, file_name, "", "", "json") {}
explicit JsonSchemaGenerator(const BaseGenerator &base_generator)
: BaseGenerator(base_generator) {}
+ std::string GeneratedFileName(const std::string &path,
+ const std::string &file_name,
+ const IDLOptions &options /* unused */) const {
+ (void)options;
+ return path + file_name + ".schema.json";
+ }
+
+ // If indentation is less than 0, that indicates we don't want any newlines
+ // either.
+ const std::string NewLine() {
+ return parser_.opts.indent_step >= 0 ? "\n" : "";
+ }
+
+ const std::string Indent(int indent) {
+ std::string indentation = "";
+ return indentation.append(indent * std::max(parser_.opts.indent_step, 0), ' ');
+ }
+
bool generate() {
- code_.Clear();
- code_ += "{";
- code_ += " \"$schema\": \"http://json-schema.org/draft-04/schema#\",";
- code_ += " \"definitions\": {";
+ code_ = "";
+ if (parser_.root_struct_def_ == nullptr) { return false; }
+ code_ += "{" + NewLine();
+ code_ += Indent(1) +
+ "\"$schema\": \"https://json-schema.org/draft/2019-09/schema\"," +
+ NewLine();
+ code_ += Indent(1) + "\"definitions\": {" + NewLine();
for (auto e = parser_.enums_.vec.cbegin(); e != parser_.enums_.vec.cend();
++e) {
- code_ += " \"" + GenFullName(*e) + "\" : {";
- code_ += " " + GenType("string") + ",";
- std::string enumdef(" \"enum\": [");
+ code_ += Indent(2) + "\"" + GenFullName(*e) + "\" : {" + NewLine();
+ code_ += Indent(3) + GenType("string") + "," + NewLine();
+ std::string enumdef(Indent(3) + "\"enum\": [");
for (auto enum_value = (*e)->Vals().begin();
enum_value != (*e)->Vals().end(); ++enum_value) {
enumdef.append("\"" + (*enum_value)->name + "\"");
if (*enum_value != (*e)->Vals().back()) { enumdef.append(", "); }
}
enumdef.append("]");
- code_ += enumdef;
- code_ += " },"; // close type
+ code_ += enumdef + NewLine();
+ code_ += Indent(2) + "}," + NewLine(); // close type
}
for (auto s = parser_.structs_.vec.cbegin();
s != parser_.structs_.vec.cend(); ++s) {
const auto &structure = *s;
- code_ += " \"" + GenFullName(structure) + "\" : {";
- code_ += " " + GenType("object") + ",";
+ code_ += Indent(2) + "\"" + GenFullName(structure) + "\" : {" + NewLine();
+ code_ += Indent(3) + GenType("object") + "," + NewLine();
std::string comment;
const auto &comment_lines = structure->doc_comment;
for (auto comment_line = comment_lines.cbegin();
@@ -151,34 +190,47 @@
comment.append(*comment_line);
}
if (comment.size() > 0) {
- code_ += " \"description\" : \"" + comment + "\",";
+ std::string description;
+ if (!EscapeString(comment.c_str(), comment.length(), &description, true,
+ true)) {
+ return false;
+ }
+ code_ +=
+ Indent(3) + "\"description\" : " + description + "," + NewLine();
}
- code_ += " \"properties\" : {";
+ code_ += Indent(3) + "\"properties\" : {" + NewLine();
const auto &properties = structure->fields.vec;
for (auto prop = properties.cbegin(); prop != properties.cend(); ++prop) {
const auto &property = *prop;
std::string arrayInfo = "";
if (IsArray(property->value.type)) {
- arrayInfo = ",\n \"minItems\": " +
+ arrayInfo = "," + NewLine() + Indent(8) + "\"minItems\": " +
NumToString(property->value.type.fixed_length) +
- ",\n \"maxItems\": " +
+ "," + NewLine() + Indent(8) + "\"maxItems\": " +
NumToString(property->value.type.fixed_length);
}
- std::string typeLine =
- " \"" + property->name + "\" : {\n" + " " +
- GenType(property->value.type) + arrayInfo + "\n }";
+ std::string deprecated_info = "";
+ if (property->deprecated) {
+ deprecated_info = "," + NewLine() + Indent(8) + "\"deprecated\" : true,";
+ }
+ std::string typeLine = Indent(4) + "\"" + property->name + "\"";
+ typeLine += " : {" + NewLine() + Indent(8);
+ typeLine += GenType(property->value.type);
+ typeLine += arrayInfo;
+ typeLine += deprecated_info;
+ typeLine += NewLine() + Indent(7) + "}";
if (property != properties.back()) { typeLine.append(","); }
- code_ += typeLine;
+ code_ += typeLine + NewLine();
}
- code_ += " },"; // close properties
+ code_ += Indent(3) + "}," + NewLine(); // close properties
std::vector<FieldDef *> requiredProperties;
std::copy_if(properties.begin(), properties.end(),
back_inserter(requiredProperties),
[](FieldDef const *prop) { return prop->required; });
if (requiredProperties.size() > 0) {
- std::string required_string(" \"required\" : [");
+ std::string required_string(Indent(3) + "\"required\" : [");
for (auto req_prop = requiredProperties.cbegin();
req_prop != requiredProperties.cend(); ++req_prop) {
required_string.append("\"" + (*req_prop)->name + "\"");
@@ -187,23 +239,31 @@
}
}
required_string.append("],");
- code_ += required_string;
+ code_ += required_string + NewLine();
}
- code_ += " \"additionalProperties\" : false";
- std::string closeType(" }");
+ code_ += Indent(3) + "\"additionalProperties\" : false" + NewLine();
+ std::string closeType(Indent(2) + "}");
if (*s != parser_.structs_.vec.back()) { closeType.append(","); }
- code_ += closeType; // close type
+ code_ += closeType + NewLine(); // close type
}
- code_ += " },"; // close definitions
+ code_ += Indent(1) + "}," + NewLine(); // close definitions
// mark root type
- code_ += " \"$ref\" : \"#/definitions/" +
- GenFullName(parser_.root_struct_def_) + "\"";
+ code_ += Indent(1) + "\"$ref\" : \"#/definitions/" +
+ GenFullName(parser_.root_struct_def_) + "\"" + NewLine();
- code_ += "}"; // close schema root
- const std::string file_path = GeneratedFileName(path_, file_name_);
- const std::string final_code = code_.ToString();
- return SaveFile(file_path.c_str(), final_code, false);
+ code_ += "}" + NewLine(); // close schema root
+ return true;
+ }
+
+ bool save() {
+ const std::string file_path =
+ GeneratedFileName(path_, file_name_, parser_.opts);
+ return SaveFile(file_path.c_str(), code_, false);
+ }
+
+ const std::string getJson() {
+ return code_;
}
};
} // namespace jsons
@@ -211,6 +271,14 @@
bool GenerateJsonSchema(const Parser &parser, const std::string &path,
const std::string &file_name) {
jsons::JsonSchemaGenerator generator(parser, path, file_name);
- return generator.generate();
+ if (!generator.generate()) { return false; }
+ return generator.save();
+}
+
+bool GenerateJsonSchema(const Parser &parser, std::string *json) {
+ jsons::JsonSchemaGenerator generator(parser, "", "");
+ if (!generator.generate()) { return false; }
+ *json = generator.getJson();
+ return true;
}
} // namespace flatbuffers
diff --git a/src/idl_gen_kotlin.cpp b/src/idl_gen_kotlin.cpp
index 3ced7b3..ed85b2c 100644
--- a/src/idl_gen_kotlin.cpp
+++ b/src/idl_gen_kotlin.cpp
@@ -18,12 +18,13 @@
#include <functional>
#include <unordered_set>
+
#include "flatbuffers/code_generators.h"
#include "flatbuffers/flatbuffers.h"
#include "flatbuffers/idl.h"
#include "flatbuffers/util.h"
#if defined(FLATBUFFERS_CPP98_STL)
-#include <cctype>
+# include <cctype>
#endif // defined(FLATBUFFERS_CPP98_STL)
namespace flatbuffers {
@@ -35,21 +36,20 @@
"POSITIVE_INFINITY",
"NEGATIVE_INFINITY");
-static const CommentConfig comment_config = {"/**", " *", " */"};
+static const CommentConfig comment_config = { "/**", " *", " */" };
static const std::string ident_pad = " ";
static const char *keywords[] = {
- "package", "as", "typealias", "class", "this", "super",
- "val", "var", "fun", "for", "null", "true",
- "false", "is", "in", "throw", "return", "break",
- "continue", "object", "if", "try", "else", "while",
- "do", "when", "interface", "typeof", "Any", "Character"};
+ "package", "as", "typealias", "class", "this", "super",
+ "val", "var", "fun", "for", "null", "true",
+ "false", "is", "in", "throw", "return", "break",
+ "continue", "object", "if", "try", "else", "while",
+ "do", "when", "interface", "typeof", "Any", "Character"
+};
// Escape Keywords
static std::string Esc(const std::string &name) {
for (size_t i = 0; i < sizeof(keywords) / sizeof(keywords[0]); i++) {
- if (name == keywords[i]) {
- return MakeCamel(name + "_", false);
- }
+ if (name == keywords[i]) { return MakeCamel(name + "_", false); }
}
return MakeCamel(name, false);
@@ -59,7 +59,7 @@
public:
KotlinGenerator(const Parser &parser, const std::string &path,
const std::string &file_name)
- : BaseGenerator(parser, path, file_name, "", "."),
+ : BaseGenerator(parser, path, file_name, "", ".", "kt"),
cur_name_space_(nullptr) {}
KotlinGenerator &operator=(const KotlinGenerator &);
@@ -88,7 +88,7 @@
auto &struct_def = **it;
if (!parser_.opts.one_file)
cur_name_space_ = struct_def.defined_namespace;
- GenStruct(struct_def, structWriter);
+ GenStruct(struct_def, structWriter, parser_.opts);
if (parser_.opts.one_file) {
one_file_code += structWriter.ToString();
} else {
@@ -139,1389 +139,1389 @@
static std::string GenTypeBasic(const BaseType &type) {
// clang-format off
- static const char * const kotlin_typename[] = {
- #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
- CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \
- #KTYPE,
+ static const char * const kotlin_typename[] = {
+ #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
+ CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE, ...) \
+ #KTYPE,
FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
- #undef FLATBUFFERS_TD
- };
- return kotlin_typename[type];
+ #undef FLATBUFFERS_TD
+ };
+ // clang-format on
+ return kotlin_typename[type];
+ }
+ std::string GenTypePointer(const Type &type) const {
+ switch (type.base_type) {
+ case BASE_TYPE_STRING: return "String";
+ case BASE_TYPE_VECTOR: return GenTypeGet(type.VectorType());
+ case BASE_TYPE_STRUCT: return WrapInNameSpace(*type.struct_def);
+ default: return "Table";
}
+ }
- std::string GenTypePointer(const Type &type) const {
- switch (type.base_type) {
- case BASE_TYPE_STRING:
- return "String";
- case BASE_TYPE_VECTOR:
- return GenTypeGet(type.VectorType());
- case BASE_TYPE_STRUCT:
- return WrapInNameSpace(*type.struct_def);
- default:
- return "Table";
- }
+ // with the addition of optional scalar types,
+ // we are adding the nullable '?' operator to return type of a field.
+ std::string GetterReturnType(const FieldDef &field) const {
+ auto base_type = field.value.type.base_type;
+
+ auto r_type = GenTypeGet(field.value.type);
+ if (field.IsScalarOptional() ||
+ // string, structs and unions
+ (base_type == BASE_TYPE_STRING || base_type == BASE_TYPE_STRUCT ||
+ base_type == BASE_TYPE_UNION) ||
+ // vector of anything not scalar
+ (base_type == BASE_TYPE_VECTOR &&
+ !IsScalar(field.value.type.VectorType().base_type))) {
+ r_type += "?";
}
+ return r_type;
+ }
- std::string GenTypeGet(const Type &type) const {
- return IsScalar(type.base_type) ? GenTypeBasic(type.base_type)
- : GenTypePointer(type);
- }
+ std::string GenTypeGet(const Type &type) const {
+ return IsScalar(type.base_type) ? GenTypeBasic(type.base_type)
+ : GenTypePointer(type);
+ }
- std::string GenEnumDefaultValue(const FieldDef &field) const {
- auto &value = field.value;
- FLATBUFFERS_ASSERT(value.type.enum_def);
- auto &enum_def = *value.type.enum_def;
- auto enum_val = enum_def.FindByValue(value.constant);
- return enum_val ? (WrapInNameSpace(enum_def) + "." + enum_val->name)
- : value.constant;
- }
+ std::string GenEnumDefaultValue(const FieldDef &field) const {
+ auto &value = field.value;
+ FLATBUFFERS_ASSERT(value.type.enum_def);
+ auto &enum_def = *value.type.enum_def;
+ auto enum_val = enum_def.FindByValue(value.constant);
+ return enum_val ? (WrapInNameSpace(enum_def) + "." + enum_val->name)
+ : value.constant;
+ }
-
- // Generate default values to compare against a default value when
- // `force_defaults` is `false`.
- // Main differences are:
- // - Floats are upcasted to doubles
- // - Unsigned are casted to signed
- std::string GenFBBDefaultValue(const FieldDef &field) const {
- auto out = GenDefaultValue(field, true);
- // All FlatBufferBuilder default floating point values are doubles
- if (field.value.type.base_type == BASE_TYPE_FLOAT) {
- if (out.find("Float") != std::string::npos) {
- out.replace(0, 5, "Double");
- }
- }
- //Guarantee all values are doubles
- if (out.back() == 'f')
- out.pop_back();
- return out;
- }
-
-
- // FlatBufferBuilder only store signed types, so this function
- // returns a cast for unsigned values
- std::string GenFBBValueCast(const FieldDef &field) const {
- if (IsUnsigned(field.value.type.base_type)) {
- return CastToSigned(field.value.type);
- }
- return "";
- }
-
- std::string GenDefaultValue(const FieldDef &field,
- bool force_signed = false) const {
- auto &value = field.value;
- auto base_type = field.value.type.base_type;
- if (IsFloat(base_type)) {
- auto val = KotlinFloatGen.GenFloatConstant(field);
- if (base_type == BASE_TYPE_DOUBLE &&
- val.back() == 'f') {
- val.pop_back();
- }
- return val;
- }
-
- if (base_type == BASE_TYPE_BOOL) {
- return value.constant == "0" ? "false" : "true";
- }
-
- std::string suffix = "";
-
- if (base_type == BASE_TYPE_LONG || !force_signed) {
- suffix = LiteralSuffix(base_type);
- }
- return value.constant + suffix;
- }
-
- void GenEnum(EnumDef &enum_def, CodeWriter &writer) const {
- if (enum_def.generated) return;
-
- GenerateComment(enum_def.doc_comment, writer, &comment_config);
-
- writer += "@Suppress(\"unused\")";
- writer += "@ExperimentalUnsignedTypes";
- writer += "class " + Esc(enum_def.name) + " private constructor() {";
- writer.IncrementIdentLevel();
-
- GenerateCompanionObject(writer, [&](){
- // Write all properties
- auto vals = enum_def.Vals();
- for (auto it = vals.begin(); it != vals.end(); ++it) {
- auto &ev = **it;
- auto field_type = GenTypeBasic(enum_def.underlying_type.base_type);
- auto val = enum_def.ToString(ev);
- auto suffix = LiteralSuffix(enum_def.underlying_type.base_type);
- writer.SetValue("name", Esc(ev.name));
- writer.SetValue("type", field_type);
- writer.SetValue("val", val + suffix);
- GenerateComment(ev.doc_comment, writer, &comment_config);
- writer += "const val {{name}}: {{type}} = {{val}}";
- }
-
- // Generate a generate string table for enum values.
- // Problem is, if values are very sparse that could generate really
- // big tables. Ideally in that case we generate a map lookup
- // instead, but for the moment we simply don't output a table at all.
- auto range = enum_def.Distance();
- // Average distance between values above which we consider a table
- // "too sparse". Change at will.
- static const uint64_t kMaxSparseness = 5;
- if (range / static_cast<uint64_t>(enum_def.size()) < kMaxSparseness) {
- GeneratePropertyOneLine(writer, "names", "Array<String>",
- [&](){
- writer += "arrayOf(\\";
- auto val = enum_def.Vals().front();
- for (auto it = vals.begin(); it != vals.end(); ++it) {
- auto ev = *it;
- for (auto k = enum_def.Distance(val, ev); k > 1; --k)
- writer += "\"\", \\";
- val = ev;
- writer += "\"" + (*it)->name + "\"\\";
- if (it+1 != vals.end()) {
- writer += ", \\";
- }
- }
- writer += ")";
- });
- GenerateFunOneLine(writer, "name", "e: Int", "String", [&](){
- writer += "names[e\\";
- if (enum_def.MinValue()->IsNonZero())
- writer += " - " + enum_def.MinValue()->name + ".toInt()\\";
- writer += "]";
- });
- }
- });
- writer.DecrementIdentLevel();
- writer += "}";
- }
-
- // Returns the function name that is able to read a value of the given type.
- std::string ByteBufferGetter(const Type &type, std::string bb_var_name) const {
- switch (type.base_type) {
- case BASE_TYPE_STRING:
- return "__string";
- case BASE_TYPE_STRUCT:
- return "__struct";
- case BASE_TYPE_UNION:
- return "__union";
- case BASE_TYPE_VECTOR:
- return ByteBufferGetter(type.VectorType(), bb_var_name);
- case BASE_TYPE_INT:
- case BASE_TYPE_UINT:
- return bb_var_name + ".getInt";
- case BASE_TYPE_SHORT:
- case BASE_TYPE_USHORT:
- return bb_var_name + ".getShort";
- case BASE_TYPE_ULONG:
- case BASE_TYPE_LONG:
- return bb_var_name + ".getLong";
- case BASE_TYPE_FLOAT:
- return bb_var_name + ".getFloat";
+ // Generate default values to compare against a default value when
+ // `force_defaults` is `false`.
+ // Main differences are:
+ // - Floats are upcasted to doubles
+ // - Unsigned are casted to signed
+ std::string GenFBBDefaultValue(const FieldDef &field) const {
+ if (field.IsScalarOptional()) {
+ // although default value is null, java API forces us to present a real
+ // default value for scalars, while adding a field to the buffer. This is
+ // not a problem because the default can be representing just by not
+ // calling builder.addMyField()
+ switch (field.value.type.base_type) {
case BASE_TYPE_DOUBLE:
- return bb_var_name + ".getDouble";
+ case BASE_TYPE_FLOAT: return "0.0";
+ case BASE_TYPE_BOOL: return "false";
+ default: return "0";
+ }
+ }
+ auto out = GenDefaultValue(field, true);
+ // All FlatBufferBuilder default floating point values are doubles
+ if (field.value.type.base_type == BASE_TYPE_FLOAT) {
+ if (out.find("Float") != std::string::npos) {
+ out.replace(0, 5, "Double");
+ }
+ }
+ // Guarantee all values are doubles
+ if (out.back() == 'f') out.pop_back();
+ return out;
+ }
+
+ // FlatBufferBuilder only store signed types, so this function
+ // returns a cast for unsigned values
+ std::string GenFBBValueCast(const FieldDef &field) const {
+ if (IsUnsigned(field.value.type.base_type)) {
+ return CastToSigned(field.value.type);
+ }
+ return "";
+ }
+
+ std::string GenDefaultValue(const FieldDef &field,
+ bool force_signed = false) const {
+ auto &value = field.value;
+ auto base_type = field.value.type.base_type;
+
+ if (field.IsScalarOptional()) { return "null"; }
+ if (IsFloat(base_type)) {
+ auto val = KotlinFloatGen.GenFloatConstant(field);
+ if (base_type == BASE_TYPE_DOUBLE && val.back() == 'f') {
+ val.pop_back();
+ }
+ return val;
+ }
+
+ if (base_type == BASE_TYPE_BOOL) {
+ return value.constant == "0" ? "false" : "true";
+ }
+
+ std::string suffix = "";
+
+ if (base_type == BASE_TYPE_LONG || !force_signed) {
+ suffix = LiteralSuffix(base_type);
+ }
+ return value.constant + suffix;
+ }
+
+ void GenEnum(EnumDef &enum_def, CodeWriter &writer) const {
+ if (enum_def.generated) return;
+
+ GenerateComment(enum_def.doc_comment, writer, &comment_config);
+
+ writer += "@Suppress(\"unused\")";
+ writer += "@ExperimentalUnsignedTypes";
+ writer += "class " + Esc(enum_def.name) + " private constructor() {";
+ writer.IncrementIdentLevel();
+
+ GenerateCompanionObject(writer, [&]() {
+ // Write all properties
+ auto vals = enum_def.Vals();
+ for (auto it = vals.begin(); it != vals.end(); ++it) {
+ auto &ev = **it;
+ auto field_type = GenTypeBasic(enum_def.underlying_type.base_type);
+ auto val = enum_def.ToString(ev);
+ auto suffix = LiteralSuffix(enum_def.underlying_type.base_type);
+ writer.SetValue("name", Esc(ev.name));
+ writer.SetValue("type", field_type);
+ writer.SetValue("val", val + suffix);
+ GenerateComment(ev.doc_comment, writer, &comment_config);
+ writer += "const val {{name}}: {{type}} = {{val}}";
+ }
+
+ // Generate a generate string table for enum values.
+ // Problem is, if values are very sparse that could generate really
+ // big tables. Ideally in that case we generate a map lookup
+ // instead, but for the moment we simply don't output a table at all.
+ auto range = enum_def.Distance();
+ // Average distance between values above which we consider a table
+ // "too sparse". Change at will.
+ static const uint64_t kMaxSparseness = 5;
+ if (range / static_cast<uint64_t>(enum_def.size()) < kMaxSparseness) {
+ GeneratePropertyOneLine(writer, "names", "Array<String>", [&]() {
+ writer += "arrayOf(\\";
+ auto val = enum_def.Vals().front();
+ for (auto it = vals.begin(); it != vals.end(); ++it) {
+ auto ev = *it;
+ for (auto k = enum_def.Distance(val, ev); k > 1; --k)
+ writer += "\"\", \\";
+ val = ev;
+ writer += "\"" + (*it)->name + "\"\\";
+ if (it + 1 != vals.end()) { writer += ", \\"; }
+ }
+ writer += ")";
+ });
+ GenerateFunOneLine(
+ writer, "name", "e: Int", "String",
+ [&]() {
+ writer += "names[e\\";
+ if (enum_def.MinValue()->IsNonZero())
+ writer += " - " + enum_def.MinValue()->name + ".toInt()\\";
+ writer += "]";
+ },
+ parser_.opts.gen_jvmstatic);
+ }
+ });
+ writer.DecrementIdentLevel();
+ writer += "}";
+ }
+
+ // Returns the function name that is able to read a value of the given type.
+ std::string ByteBufferGetter(const Type &type,
+ std::string bb_var_name) const {
+ switch (type.base_type) {
+ case BASE_TYPE_STRING: return "__string";
+ case BASE_TYPE_STRUCT: return "__struct";
+ case BASE_TYPE_UNION: return "__union";
+ case BASE_TYPE_VECTOR:
+ return ByteBufferGetter(type.VectorType(), bb_var_name);
+ case BASE_TYPE_INT:
+ case BASE_TYPE_UINT: return bb_var_name + ".getInt";
+ case BASE_TYPE_SHORT:
+ case BASE_TYPE_USHORT: return bb_var_name + ".getShort";
+ case BASE_TYPE_ULONG:
+ case BASE_TYPE_LONG: return bb_var_name + ".getLong";
+ case BASE_TYPE_FLOAT: return bb_var_name + ".getFloat";
+ case BASE_TYPE_DOUBLE: return bb_var_name + ".getDouble";
+ case BASE_TYPE_CHAR:
+ case BASE_TYPE_UCHAR:
+ case BASE_TYPE_NONE:
+ case BASE_TYPE_UTYPE: return bb_var_name + ".get";
+ case BASE_TYPE_BOOL: return "0.toByte() != " + bb_var_name + ".get";
+ default:
+ return bb_var_name + ".get" + MakeCamel(GenTypeBasic(type.base_type));
+ }
+ }
+
+ std::string ByteBufferSetter(const Type &type) const {
+ if (IsScalar(type.base_type)) {
+ switch (type.base_type) {
+ case BASE_TYPE_INT:
+ case BASE_TYPE_UINT: return "bb.putInt";
+ case BASE_TYPE_SHORT:
+ case BASE_TYPE_USHORT: return "bb.putShort";
+ case BASE_TYPE_ULONG:
+ case BASE_TYPE_LONG: return "bb.putLong";
+ case BASE_TYPE_FLOAT: return "bb.putFloat";
+ case BASE_TYPE_DOUBLE: return "bb.putDouble";
case BASE_TYPE_CHAR:
case BASE_TYPE_UCHAR:
- case BASE_TYPE_NONE:
- case BASE_TYPE_UTYPE:
- return bb_var_name + ".get";
case BASE_TYPE_BOOL:
- return "0.toByte() != " + bb_var_name + ".get";
- default:
- return bb_var_name + ".get" + MakeCamel(GenTypeBasic(type.base_type));
- }
- }
-
- std::string ByteBufferSetter(const Type &type) const {
- if (IsScalar(type.base_type)) {
- switch (type.base_type) {
- case BASE_TYPE_INT:
- case BASE_TYPE_UINT:
- return "bb.putInt";
- case BASE_TYPE_SHORT:
- case BASE_TYPE_USHORT:
- return "bb.putShort";
- case BASE_TYPE_ULONG:
- case BASE_TYPE_LONG:
- return "bb.putLong";
- case BASE_TYPE_FLOAT:
- return "bb.putFloat";
- case BASE_TYPE_DOUBLE:
- return "bb.putDouble";
- case BASE_TYPE_CHAR:
- case BASE_TYPE_UCHAR:
- case BASE_TYPE_BOOL:
- case BASE_TYPE_NONE:
- case BASE_TYPE_UTYPE:
- return "bb.put";
- default:
- return "bb.put" + MakeCamel(GenTypeBasic(type.base_type));
- }
- }
- return "";
- }
-
- // Returns the function name that is able to read a value of the given type.
- std::string GenLookupByKey(flatbuffers::FieldDef *key_field,
- const std::string &bb_var_name,
- const char *num = nullptr) const {
- auto type = key_field->value.type;
- return ByteBufferGetter(type, bb_var_name) + "(" + GenOffsetGetter(key_field, num) + ")";
-
- }
-
- // Returns the method name for use with add/put calls.
- static std::string GenMethod(const Type &type) {
- return IsScalar(type.base_type) ? ToSignedType(type)
- : (IsStruct(type) ? "Struct" : "Offset");
- }
-
- // Recursively generate arguments for a constructor, to deal with nested
- // structs.
- static void GenStructArgs(const StructDef &struct_def, CodeWriter &writer,
- const char *nameprefix) {
- for (auto it = struct_def.fields.vec.begin();
- it != struct_def.fields.vec.end(); ++it) {
- auto &field = **it;
- if (IsStruct(field.value.type)) {
- // Generate arguments for a struct inside a struct. To ensure
- // names don't clash, and to make it obvious these arguments are
- // constructing a nested struct, prefix the name with the field
- // name.
- GenStructArgs(*field.value.type.struct_def, writer,
- (nameprefix + (field.name + "_")).c_str());
- } else {
- writer += std::string(", ") + nameprefix + "\\";
- writer += MakeCamel(field.name) + ": \\";
- writer += GenTypeBasic(field.value.type.base_type) + "\\";
- }
- }
- }
-
- // Recusively generate struct construction statements of the form:
- // builder.putType(name);
- // and insert manual padding.
- static void GenStructBody(const StructDef &struct_def, CodeWriter &writer,
- const char *nameprefix) {
- writer.SetValue("align", NumToString(struct_def.minalign));
- writer.SetValue("size", NumToString(struct_def.bytesize));
- writer += "builder.prep({{align}}, {{size}})";
- auto fields_vec = struct_def.fields.vec;
- for (auto it = fields_vec.rbegin(); it != fields_vec.rend(); ++it) {
- auto &field = **it;
-
- if (field.padding) {
- writer.SetValue("pad", NumToString(field.padding));
- writer += "builder.pad({{pad}})";
- }
- if (IsStruct(field.value.type)) {
- GenStructBody(*field.value.type.struct_def, writer,
- (nameprefix + (field.name + "_")).c_str());
- } else {
- writer.SetValue("type", GenMethod(field.value.type));
- writer.SetValue("argname", nameprefix +
- MakeCamel(field.name, false));
- writer.SetValue("cast", CastToSigned(field.value.type));
- writer += "builder.put{{type}}({{argname}}{{cast}})";
- }
- }
- }
-
- std::string GenByteBufferLength(const char *bb_name) const {
- std::string bb_len = bb_name;
- bb_len += ".capacity()";
- return bb_len;
- }
-
- std::string GenOffsetGetter(flatbuffers::FieldDef *key_field,
- const char *num = nullptr) const {
- std::string key_offset = "__offset(" +
- NumToString(key_field->value.offset) + ", ";
- if (num) {
- key_offset += num;
- key_offset += ", _bb)";
- } else {
- key_offset += GenByteBufferLength("bb");
- key_offset += " - tableOffset, bb)";
- }
- return key_offset;
- }
-
- void GenStruct(StructDef &struct_def, CodeWriter &writer) const {
- if (struct_def.generated) return;
-
- GenerateComment(struct_def.doc_comment, writer, &comment_config);
- auto fixed = struct_def.fixed;
-
- writer.SetValue("struct_name", Esc(struct_def.name));
- writer.SetValue("superclass", fixed ? "Struct" : "Table");
-
- writer += "@Suppress(\"unused\")";
- writer += "@ExperimentalUnsignedTypes";
- writer += "class {{struct_name}} : {{superclass}}() {\n";
-
- writer.IncrementIdentLevel();
-
- {
- // Generate the __init() method that sets the field in a pre-existing
- // accessor object. This is to allow object reuse.
- GenerateFun(writer, "__init", "_i: Int, _bb: ByteBuffer", "", [&]() {
- writer += "__reset(_i, _bb)";
- });
-
- // Generate assign method
- GenerateFun(writer, "__assign", "_i: Int, _bb: ByteBuffer",
- Esc(struct_def.name), [&]() {
- writer += "__init(_i, _bb)";
- writer += "return this";
- });
-
- // Generate all getters
- GenerateStructGetters(struct_def, writer);
-
- // Generate Static Fields
- GenerateCompanionObject(writer, [&](){
-
- if (!struct_def.fixed) {
- FieldDef *key_field = nullptr;
-
- // Generate verson check method.
- // Force compile time error if not using the same version
- // runtime.
- GenerateFunOneLine(writer, "validateVersion", "", "", [&](){
- writer += "Constants.FLATBUFFERS_1_11_1()";
- });
-
- GenerateGetRootAsAccessors(Esc(struct_def.name), writer);
- GenerateBufferHasIdentifier(struct_def, writer);
- GenerateTableCreator(struct_def, writer);
-
- GenerateStartStructMethod(struct_def, writer);
-
- // Static Add for fields
- auto fields = struct_def.fields.vec;
- int field_pos = -1;
- for (auto it = fields.begin(); it != fields.end(); ++it) {
- auto &field = **it;
- field_pos++;
- if (field.deprecated) continue;
- if (field.key) key_field = &field;
- GenerateAddField(NumToString(field_pos), field, writer);
-
- if (field.value.type.base_type == BASE_TYPE_VECTOR) {
- auto vector_type = field.value.type.VectorType();
- if (!IsStruct(vector_type)) {
- GenerateCreateVectorField(field, writer);
- }
- GenerateStartVectorField(field, writer);
- }
- }
-
- GenerateEndStructMethod(struct_def, writer);
- auto file_identifier = parser_.file_identifier_;
- if (parser_.root_struct_def_ == &struct_def) {
- GenerateFinishStructBuffer(struct_def,
- file_identifier,
- writer);
- GenerateFinishSizePrefixed(struct_def,
- file_identifier,
- writer);
- }
-
- if (struct_def.has_key) {
- GenerateLookupByKey(key_field, struct_def, writer);
- }
- } else {
- GenerateStaticConstructor(struct_def, writer);
- }
- });
- }
-
- // class closing
- writer.DecrementIdentLevel();
- writer += "}";
- }
-
- // TODO: move key_field to reference instead of pointer
- void GenerateLookupByKey(FieldDef *key_field, StructDef &struct_def,
- CodeWriter &writer) const {
- std::stringstream params;
- params << "obj: " << Esc(struct_def.name) << "?" << ", ";
- params << "vectorLocation: Int, ";
- params << "key: " << GenTypeGet(key_field->value.type) << ", ";
- params << "bb: ByteBuffer";
-
- auto statements = [&]() {
- auto base_type = key_field->value.type.base_type;
- writer.SetValue("struct_name", Esc(struct_def.name));
- if (base_type == BASE_TYPE_STRING) {
- writer += "val byteKey = key."
- "toByteArray(Table.UTF8_CHARSET.get()!!)";
- }
- writer += "var span = bb.getInt(vectorLocation - 4)";
- writer += "var start = 0";
- writer += "while (span != 0) {";
- writer.IncrementIdentLevel();
- writer += "var middle = span / 2";
- writer += "val tableOffset = __indirect(vector"
- "Location + 4 * (start + middle), bb)";
- if (key_field->value.type.base_type == BASE_TYPE_STRING) {
- writer += "val comp = compareStrings(\\";
- writer += GenOffsetGetter(key_field) + "\\";
- writer += ", byteKey, bb)";
- } else {
- auto cast = CastToUsigned(key_field->value.type);
- auto get_val = GenLookupByKey(key_field, "bb");
- writer += "val value = " + get_val + cast;
- writer += "val comp = value.compareTo(key)";
- }
- writer += "when {";
- writer.IncrementIdentLevel();
- writer += "comp > 0 -> span = middle";
- writer += "comp < 0 -> {";
- writer.IncrementIdentLevel();
- writer += "middle++";
- writer += "start += middle";
- writer += "span -= middle";
- writer.DecrementIdentLevel();
- writer += "}"; // end comp < 0
- writer += "else -> {";
- writer.IncrementIdentLevel();
- writer += "return (obj ?: {{struct_name}}()).__assign(tableOffset, bb)";
- writer.DecrementIdentLevel();
- writer += "}"; // end else
- writer.DecrementIdentLevel();
- writer += "}"; // end when
- writer.DecrementIdentLevel();
- writer += "}"; // end while
- writer += "return null";
- };
- GenerateFun(writer, "__lookup_by_key",
- params.str(),
- Esc(struct_def.name) + "?",
- statements);
- }
-
- void GenerateFinishSizePrefixed(StructDef &struct_def,
- const std::string &identifier,
- CodeWriter &writer) const {
- auto id = identifier.length() > 0 ? ", \"" + identifier + "\"" : "";
- auto params = "builder: FlatBufferBuilder, offset: Int";
- auto method_name = "finishSizePrefixed" + Esc(struct_def.name) + "Buffer";
- GenerateFunOneLine(writer, method_name, params, "", [&]() {
- writer += "builder.finishSizePrefixed(offset" + id + ")";
- });
- }
- void GenerateFinishStructBuffer(StructDef &struct_def,
- const std::string &identifier,
- CodeWriter &writer) const {
- auto id = identifier.length() > 0 ? ", \"" + identifier + "\"" : "";
- auto params = "builder: FlatBufferBuilder, offset: Int";
- auto method_name = "finish" + Esc(struct_def.name) + "Buffer";
- GenerateFunOneLine(writer, method_name, params, "", [&]() {
- writer += "builder.finish(offset" + id + ")";
- });
- }
-
- void GenerateEndStructMethod(StructDef &struct_def, CodeWriter &writer) const {
- // Generate end{{TableName}}(builder: FlatBufferBuilder) method
- auto name = "end" + Esc(struct_def.name);
- auto params = "builder: FlatBufferBuilder";
- auto returns = "Int";
- auto field_vec = struct_def.fields.vec;
-
- GenerateFun(writer, name, params, returns, [&](){
- writer += "val o = builder.endTable()";
- writer.IncrementIdentLevel();
- for (auto it = field_vec.begin(); it != field_vec.end(); ++it) {
- auto &field = **it;
- if (field.deprecated || !field.required) {
- continue;
- }
- writer.SetValue("offset", NumToString(field.value.offset));
- writer += "builder.required(o, {{offset}})";
- }
- writer.DecrementIdentLevel();
- writer += "return o";
- });
- }
-
- // Generate a method to create a vector from a Kotlin array.
- void GenerateCreateVectorField(FieldDef &field, CodeWriter &writer) const {
- auto vector_type = field.value.type.VectorType();
- auto method_name = "create" + MakeCamel(Esc(field.name)) + "Vector";
- auto params = "builder: FlatBufferBuilder, data: " +
- GenTypeBasic(vector_type.base_type) + "Array";
- writer.SetValue("size", NumToString(InlineSize(vector_type)));
- writer.SetValue("align", NumToString(InlineAlignment(vector_type)));
- writer.SetValue("root", GenMethod(vector_type));
- writer.SetValue("cast", CastToSigned(vector_type));
-
- GenerateFun(writer, method_name, params, "Int", [&](){
- writer += "builder.startVector({{size}}, data.size, {{align}})";
- writer += "for (i in data.size - 1 downTo 0) {";
- writer.IncrementIdentLevel();
- writer += "builder.add{{root}}(data[i]{{cast}})";
- writer.DecrementIdentLevel();
- writer += "}";
- writer += "return builder.endVector()";
- });
- }
-
- void GenerateStartVectorField(FieldDef &field, CodeWriter &writer) const {
- // Generate a method to start a vector, data to be added manually
- // after.
- auto vector_type = field.value.type.VectorType();
- auto params = "builder: FlatBufferBuilder, numElems: Int";
- writer.SetValue("size", NumToString(InlineSize(vector_type)));
- writer.SetValue("align", NumToString(InlineAlignment(vector_type)));
-
- GenerateFunOneLine(writer,
- "start" + MakeCamel(Esc(field.name) + "Vector", true),
- params,
- "",
- [&]() {
- writer += "builder.startVector({{size}}, numElems, {{align}})";
- });
- }
-
- void GenerateAddField(std::string field_pos, FieldDef &field,
- CodeWriter &writer) const {
- auto field_type = GenTypeBasic(field.value.type.base_type);
- auto secondArg = MakeCamel(Esc(field.name), false) + ": " + field_type;
- GenerateFunOneLine(writer, "add" + MakeCamel(Esc(field.name), true),
- "builder: FlatBufferBuilder, " + secondArg, "", [&](){
- auto method = GenMethod(field.value.type);
- writer.SetValue("field_name", MakeCamel(Esc(field.name), false));
- writer.SetValue("method_name", method);
- writer.SetValue("pos", field_pos);
- writer.SetValue("default", GenFBBDefaultValue(field));
- writer.SetValue("cast", GenFBBValueCast(field));
-
- writer += "builder.add{{method_name}}({{pos}}, \\";
- writer += "{{field_name}}{{cast}}, {{default}})";
- });
- }
-
- static std::string ToSignedType(const Type & type) {
- switch(type.base_type) {
- case BASE_TYPE_UINT:
- return GenTypeBasic(BASE_TYPE_INT);
- case BASE_TYPE_ULONG:
- return GenTypeBasic(BASE_TYPE_LONG);
- case BASE_TYPE_UCHAR:
case BASE_TYPE_NONE:
- case BASE_TYPE_UTYPE:
- return GenTypeBasic(BASE_TYPE_CHAR);
- case BASE_TYPE_USHORT:
- return GenTypeBasic(BASE_TYPE_SHORT);
- case BASE_TYPE_VECTOR:
- return ToSignedType(type.VectorType());
- default:
- return GenTypeBasic(type.base_type);
- }
+ case BASE_TYPE_UTYPE: return "bb.put";
+ default: return "bb.put" + MakeCamel(GenTypeBasic(type.base_type));
+ }
}
+ return "";
+ }
- static std::string FlexBufferBuilderCast(const std::string &method,
- FieldDef &field,
- bool isFirst) {
- auto field_type = GenTypeBasic(field.value.type.base_type);
- std::string to_type;
- if (method == "Boolean")
- to_type = "Boolean";
- else if (method == "Long")
- to_type = "Long";
- else if (method == "Int" || method == "Offset" || method == "Struct")
- to_type = "Int";
- else if (method == "Byte" || method.empty())
- to_type = isFirst ? "Byte" : "Int";
- else if (method == "Short")
- to_type = isFirst ? "Short" : "Int";
- else if (method == "Double")
- to_type = "Double";
- else if (method == "Float")
- to_type = isFirst ? "Float" : "Double";
- else if (method == "UByte")
+ // Returns the function name that is able to read a value of the given type.
+ std::string GenLookupByKey(flatbuffers::FieldDef *key_field,
+ const std::string &bb_var_name,
+ const char *num = nullptr) const {
+ auto type = key_field->value.type;
+ return ByteBufferGetter(type, bb_var_name) + "(" +
+ GenOffsetGetter(key_field, num) + ")";
+ }
- if (field_type != to_type)
- return ".to" + to_type + "()";
- return "";
+ // Returns the method name for use with add/put calls.
+ static std::string GenMethod(const Type &type) {
+ return IsScalar(type.base_type) ? ToSignedType(type)
+ : (IsStruct(type) ? "Struct" : "Offset");
+ }
+
+ // Recursively generate arguments for a constructor, to deal with nested
+ // structs.
+ static void GenStructArgs(const StructDef &struct_def, CodeWriter &writer,
+ const char *nameprefix) {
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (IsStruct(field.value.type)) {
+ // Generate arguments for a struct inside a struct. To ensure
+ // names don't clash, and to make it obvious these arguments are
+ // constructing a nested struct, prefix the name with the field
+ // name.
+ GenStructArgs(*field.value.type.struct_def, writer,
+ (nameprefix + (field.name + "_")).c_str());
+ } else {
+ writer += std::string(", ") + nameprefix + "\\";
+ writer += MakeCamel(field.name) + ": \\";
+ writer += GenTypeBasic(field.value.type.base_type) + "\\";
+ }
}
+ }
- // fun startMonster(builder: FlatBufferBuilder) = builder.startTable(11)
- void GenerateStartStructMethod(StructDef &struct_def, CodeWriter &code) const {
- GenerateFunOneLine(code, "start" + Esc(struct_def.name),
- "builder: FlatBufferBuilder", "", [&] () {
- code += "builder.startTable("+ NumToString(struct_def.fields.vec.size()) + ")";
- });
+ // Recusively generate struct construction statements of the form:
+ // builder.putType(name);
+ // and insert manual padding.
+ static void GenStructBody(const StructDef &struct_def, CodeWriter &writer,
+ const char *nameprefix) {
+ writer.SetValue("align", NumToString(struct_def.minalign));
+ writer.SetValue("size", NumToString(struct_def.bytesize));
+ writer += "builder.prep({{align}}, {{size}})";
+ auto fields_vec = struct_def.fields.vec;
+ for (auto it = fields_vec.rbegin(); it != fields_vec.rend(); ++it) {
+ auto &field = **it;
+
+ if (field.padding) {
+ writer.SetValue("pad", NumToString(field.padding));
+ writer += "builder.pad({{pad}})";
+ }
+ if (IsStruct(field.value.type)) {
+ GenStructBody(*field.value.type.struct_def, writer,
+ (nameprefix + (field.name + "_")).c_str());
+ } else {
+ writer.SetValue("type", GenMethod(field.value.type));
+ writer.SetValue("argname", nameprefix + MakeCamel(field.name, false));
+ writer.SetValue("cast", CastToSigned(field.value.type));
+ writer += "builder.put{{type}}({{argname}}{{cast}})";
+ }
}
+ }
- void GenerateTableCreator(StructDef &struct_def, CodeWriter &writer) const {
- // Generate a method that creates a table in one go. This is only possible
- // when the table has no struct fields, since those have to be created
- // inline, and there's no way to do so in Java.
- bool has_no_struct_fields = true;
- int num_fields = 0;
- auto fields_vec = struct_def.fields.vec;
+ std::string GenByteBufferLength(const char *bb_name) const {
+ std::string bb_len = bb_name;
+ bb_len += ".capacity()";
+ return bb_len;
+ }
- for (auto it = fields_vec.begin(); it != fields_vec.end(); ++it) {
+ std::string GenOffsetGetter(flatbuffers::FieldDef *key_field,
+ const char *num = nullptr) const {
+ std::string key_offset =
+ "__offset(" + NumToString(key_field->value.offset) + ", ";
+ if (num) {
+ key_offset += num;
+ key_offset += ", _bb)";
+ } else {
+ key_offset += GenByteBufferLength("bb");
+ key_offset += " - tableOffset, bb)";
+ }
+ return key_offset;
+ }
+
+ void GenStruct(StructDef &struct_def, CodeWriter &writer,
+ IDLOptions options) const {
+ if (struct_def.generated) return;
+
+ GenerateComment(struct_def.doc_comment, writer, &comment_config);
+ auto fixed = struct_def.fixed;
+
+ writer.SetValue("struct_name", Esc(struct_def.name));
+ writer.SetValue("superclass", fixed ? "Struct" : "Table");
+
+ writer += "@Suppress(\"unused\")";
+ writer += "@ExperimentalUnsignedTypes";
+ writer += "class {{struct_name}} : {{superclass}}() {\n";
+
+ writer.IncrementIdentLevel();
+
+ {
+ // Generate the __init() method that sets the field in a pre-existing
+ // accessor object. This is to allow object reuse.
+ GenerateFun(writer, "__init", "_i: Int, _bb: ByteBuffer", "",
+ [&]() { writer += "__reset(_i, _bb)"; });
+
+ // Generate assign method
+ GenerateFun(writer, "__assign", "_i: Int, _bb: ByteBuffer",
+ Esc(struct_def.name), [&]() {
+ writer += "__init(_i, _bb)";
+ writer += "return this";
+ });
+
+ // Generate all getters
+ GenerateStructGetters(struct_def, writer);
+
+ // Generate Static Fields
+ GenerateCompanionObject(writer, [&]() {
+ if (!struct_def.fixed) {
+ FieldDef *key_field = nullptr;
+
+ // Generate verson check method.
+ // Force compile time error if not using the same version
+ // runtime.
+ GenerateFunOneLine(
+ writer, "validateVersion", "", "",
+ [&]() { writer += "Constants.FLATBUFFERS_1_12_0()"; },
+ options.gen_jvmstatic);
+
+ GenerateGetRootAsAccessors(Esc(struct_def.name), writer, options);
+ GenerateBufferHasIdentifier(struct_def, writer, options);
+ GenerateTableCreator(struct_def, writer, options);
+
+ GenerateStartStructMethod(struct_def, writer, options);
+
+ // Static Add for fields
+ auto fields = struct_def.fields.vec;
+ int field_pos = -1;
+ for (auto it = fields.begin(); it != fields.end(); ++it) {
auto &field = **it;
- if (field.deprecated) continue;
- if (IsStruct(field.value.type)) {
- has_no_struct_fields = false;
- } else {
- num_fields++;
- }
- }
- // JVM specifications restrict default constructor params to be < 255.
- // Longs and doubles take up 2 units, so we set the limit to be < 127.
- if (has_no_struct_fields && num_fields && num_fields < 127) {
- // Generate a table constructor of the form:
- // public static int createName(FlatBufferBuilder builder, args...)
-
- auto name = "create" + Esc(struct_def.name);
- std::stringstream params;
- params << "builder: FlatBufferBuilder";
- for (auto it = fields_vec.begin(); it != fields_vec.end(); ++it) {
- auto &field = **it;
- if (field.deprecated) continue;
- params << ", " << MakeCamel(Esc(field.name), false);
- if (!IsScalar(field.value.type.base_type)){
- params << "Offset: ";
- } else {
- params << ": ";
- }
- params << GenTypeBasic(field.value.type.base_type);
- }
-
- GenerateFun(writer, name, params.str(), "Int", [&]() {
- writer.SetValue("vec_size", NumToString(fields_vec.size()));
-
- writer += "builder.startTable({{vec_size}})";
-
- auto sortbysize = struct_def.sortbysize;
- auto largest = sortbysize ? sizeof(largest_scalar_t) : 1;
- for (size_t size = largest; size; size /= 2) {
- for (auto it = fields_vec.rbegin(); it != fields_vec.rend();
- ++it) {
- auto &field = **it;
- auto base_type_size = SizeOf(field.value.type.base_type);
- if (!field.deprecated &&
- (!sortbysize || size == base_type_size)) {
- writer.SetValue("camel_field_name",
- MakeCamel(Esc(field.name), true));
- writer.SetValue("field_name",
- MakeCamel(Esc(field.name), false));
-
- writer += "add{{camel_field_name}}(builder, {{field_name}}\\";
- if (!IsScalar(field.value.type.base_type)){
- writer += "Offset\\";
- }
- writer += ")";
- }
- }
- }
- writer += "return end{{struct_name}}(builder)";
- });
- }
-
- }
- void GenerateBufferHasIdentifier(StructDef &struct_def,
- CodeWriter &writer) const {
- auto file_identifier = parser_.file_identifier_;
- // Check if a buffer has the identifier.
- if (parser_.root_struct_def_ != &struct_def || !file_identifier.length())
- return;
- auto name = MakeCamel(Esc(struct_def.name), false);
- GenerateFunOneLine(writer, name + "BufferHasIdentifier",
- "_bb: ByteBuffer",
- "Boolean",
- [&]() {
- writer += "__has_identifier(_bb, \"" + file_identifier + "\")";
- });
- }
-
- void GenerateStructGetters(StructDef &struct_def, CodeWriter &writer) const {
- auto fields_vec = struct_def.fields.vec;
- FieldDef *key_field = nullptr;
- for (auto it = fields_vec.begin(); it != fields_vec.end(); ++it) {
- auto &field = **it;
+ field_pos++;
if (field.deprecated) continue;
if (field.key) key_field = &field;
+ GenerateAddField(NumToString(field_pos), field, writer, options);
- GenerateComment(field.doc_comment, writer, &comment_config);
+ if (IsVector(field.value.type)) {
+ auto vector_type = field.value.type.VectorType();
+ if (!IsStruct(vector_type)) {
+ GenerateCreateVectorField(field, writer, options);
+ }
+ GenerateStartVectorField(field, writer, options);
+ }
+ }
- auto field_name = MakeCamel(Esc(field.name), false);
- auto field_type = GenTypeGet(field.value.type);
- auto field_default_value = GenDefaultValue(field);
- auto return_type = GenTypeGet(field.value.type);
- auto bbgetter = ByteBufferGetter(field.value.type, "bb");
- auto ucast = CastToUsigned(field);
- auto offset_val = NumToString(field.value.offset);
- auto offset_prefix = "val o = __offset(" + offset_val
- + "); return o != 0 ? ";
- auto value_base_type = field.value.type.base_type;
- // Most field accessors need to retrieve and test the field offset
- // first, this is the offset value for that:
+ GenerateEndStructMethod(struct_def, writer, options);
+ auto file_identifier = parser_.file_identifier_;
+ if (parser_.root_struct_def_ == &struct_def) {
+ GenerateFinishStructBuffer(struct_def, file_identifier, writer,
+ options);
+ GenerateFinishSizePrefixed(struct_def, file_identifier, writer,
+ options);
+ }
+
+ if (struct_def.has_key) {
+ GenerateLookupByKey(key_field, struct_def, writer, options);
+ }
+ } else {
+ GenerateStaticConstructor(struct_def, writer, options);
+ }
+ });
+ }
+
+ // class closing
+ writer.DecrementIdentLevel();
+ writer += "}";
+ }
+
+ // TODO: move key_field to reference instead of pointer
+ void GenerateLookupByKey(FieldDef *key_field, StructDef &struct_def,
+ CodeWriter &writer, const IDLOptions options) const {
+ std::stringstream params;
+ params << "obj: " << Esc(struct_def.name) << "?"
+ << ", ";
+ params << "vectorLocation: Int, ";
+ params << "key: " << GenTypeGet(key_field->value.type) << ", ";
+ params << "bb: ByteBuffer";
+
+ auto statements = [&]() {
+ auto base_type = key_field->value.type.base_type;
+ writer.SetValue("struct_name", Esc(struct_def.name));
+ if (base_type == BASE_TYPE_STRING) {
+ writer +=
+ "val byteKey = key."
+ "toByteArray(java.nio.charset.StandardCharsets.UTF_8)";
+ }
+ writer += "var span = bb.getInt(vectorLocation - 4)";
+ writer += "var start = 0";
+ writer += "while (span != 0) {";
+ writer.IncrementIdentLevel();
+ writer += "var middle = span / 2";
+ writer +=
+ "val tableOffset = __indirect(vector"
+ "Location + 4 * (start + middle), bb)";
+ if (IsString(key_field->value.type)) {
+ writer += "val comp = compareStrings(\\";
+ writer += GenOffsetGetter(key_field) + "\\";
+ writer += ", byteKey, bb)";
+ } else {
+ auto cast = CastToUsigned(key_field->value.type);
+ auto get_val = GenLookupByKey(key_field, "bb");
+ writer += "val value = " + get_val + cast;
+ writer += "val comp = value.compareTo(key)";
+ }
+ writer += "when {";
+ writer.IncrementIdentLevel();
+ writer += "comp > 0 -> span = middle";
+ writer += "comp < 0 -> {";
+ writer.IncrementIdentLevel();
+ writer += "middle++";
+ writer += "start += middle";
+ writer += "span -= middle";
+ writer.DecrementIdentLevel();
+ writer += "}"; // end comp < 0
+ writer += "else -> {";
+ writer.IncrementIdentLevel();
+ writer += "return (obj ?: {{struct_name}}()).__assign(tableOffset, bb)";
+ writer.DecrementIdentLevel();
+ writer += "}"; // end else
+ writer.DecrementIdentLevel();
+ writer += "}"; // end when
+ writer.DecrementIdentLevel();
+ writer += "}"; // end while
+ writer += "return null";
+ };
+ GenerateFun(writer, "__lookup_by_key", params.str(),
+ Esc(struct_def.name) + "?", statements, options.gen_jvmstatic);
+ }
+
+ void GenerateFinishSizePrefixed(StructDef &struct_def,
+ const std::string &identifier,
+ CodeWriter &writer,
+ const IDLOptions options) const {
+ auto id = identifier.length() > 0 ? ", \"" + identifier + "\"" : "";
+ auto params = "builder: FlatBufferBuilder, offset: Int";
+ auto method_name = "finishSizePrefixed" + Esc(struct_def.name) + "Buffer";
+ GenerateFunOneLine(
+ writer, method_name, params, "",
+ [&]() { writer += "builder.finishSizePrefixed(offset" + id + ")"; },
+ options.gen_jvmstatic);
+ }
+ void GenerateFinishStructBuffer(StructDef &struct_def,
+ const std::string &identifier,
+ CodeWriter &writer,
+ const IDLOptions options) const {
+ auto id = identifier.length() > 0 ? ", \"" + identifier + "\"" : "";
+ auto params = "builder: FlatBufferBuilder, offset: Int";
+ auto method_name = "finish" + Esc(struct_def.name) + "Buffer";
+ GenerateFunOneLine(
+ writer, method_name, params, "",
+ [&]() { writer += "builder.finish(offset" + id + ")"; },
+ options.gen_jvmstatic);
+ }
+
+ void GenerateEndStructMethod(StructDef &struct_def, CodeWriter &writer,
+ const IDLOptions options) const {
+ // Generate end{{TableName}}(builder: FlatBufferBuilder) method
+ auto name = "end" + Esc(struct_def.name);
+ auto params = "builder: FlatBufferBuilder";
+ auto returns = "Int";
+ auto field_vec = struct_def.fields.vec;
+
+ GenerateFun(
+ writer, name, params, returns,
+ [&]() {
+ writer += "val o = builder.endTable()";
+ writer.IncrementIdentLevel();
+ for (auto it = field_vec.begin(); it != field_vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated || !field.required) { continue; }
writer.SetValue("offset", NumToString(field.value.offset));
- writer.SetValue("return_type", return_type);
- writer.SetValue("field_type", field_type);
- writer.SetValue("field_name", field_name);
- writer.SetValue("field_default", field_default_value);
- writer.SetValue("bbgetter", bbgetter);
- writer.SetValue("ucast", ucast);
+ writer += "builder.required(o, {{offset}})";
+ }
+ writer.DecrementIdentLevel();
+ writer += "return o";
+ },
+ options.gen_jvmstatic);
+ }
- auto opt_ret_type = return_type + "?";
- // Generate the accessors that don't do object reuse.
- if (value_base_type == BASE_TYPE_STRUCT) {
- // Calls the accessor that takes an accessor object with a
- // new object.
- // val pos
- // get() = pos(Vec3())
- GenerateGetterOneLine(writer, field_name, opt_ret_type, [&](){
- writer += "{{field_name}}({{field_type}}())";
- });
- } else if (value_base_type == BASE_TYPE_VECTOR &&
- field.value.type.element == BASE_TYPE_STRUCT) {
- // Accessors for vectors of structs also take accessor objects,
- // this generates a variant without that argument.
- // ex: fun weapons(j: Int) = weapons(Weapon(), j)
- GenerateFunOneLine(writer, field_name, "j: Int", opt_ret_type, [&](){
- writer += "{{field_name}}({{return_type}}(), j)";
- });
+ // Generate a method to create a vector from a Kotlin array.
+ void GenerateCreateVectorField(FieldDef &field, CodeWriter &writer,
+ const IDLOptions options) const {
+ auto vector_type = field.value.type.VectorType();
+ auto method_name = "create" + MakeCamel(Esc(field.name)) + "Vector";
+ auto params = "builder: FlatBufferBuilder, data: " +
+ GenTypeBasic(vector_type.base_type) + "Array";
+ writer.SetValue("size", NumToString(InlineSize(vector_type)));
+ writer.SetValue("align", NumToString(InlineAlignment(vector_type)));
+ writer.SetValue("root", GenMethod(vector_type));
+ writer.SetValue("cast", CastToSigned(vector_type));
+
+ GenerateFun(
+ writer, method_name, params, "Int",
+ [&]() {
+ writer += "builder.startVector({{size}}, data.size, {{align}})";
+ writer += "for (i in data.size - 1 downTo 0) {";
+ writer.IncrementIdentLevel();
+ writer += "builder.add{{root}}(data[i]{{cast}})";
+ writer.DecrementIdentLevel();
+ writer += "}";
+ writer += "return builder.endVector()";
+ },
+ options.gen_jvmstatic);
+ }
+
+ void GenerateStartVectorField(FieldDef &field, CodeWriter &writer,
+ const IDLOptions options) const {
+ // Generate a method to start a vector, data to be added manually
+ // after.
+ auto vector_type = field.value.type.VectorType();
+ auto params = "builder: FlatBufferBuilder, numElems: Int";
+ writer.SetValue("size", NumToString(InlineSize(vector_type)));
+ writer.SetValue("align", NumToString(InlineAlignment(vector_type)));
+
+ GenerateFunOneLine(
+ writer, "start" + MakeCamel(Esc(field.name) + "Vector", true), params,
+ "",
+ [&]() {
+ writer += "builder.startVector({{size}}, numElems, {{align}})";
+ },
+ options.gen_jvmstatic);
+ }
+
+ void GenerateAddField(std::string field_pos, FieldDef &field,
+ CodeWriter &writer, const IDLOptions options) const {
+ auto field_type = GenTypeBasic(field.value.type.base_type);
+ auto secondArg = MakeCamel(Esc(field.name), false) + ": " + field_type;
+
+ GenerateFunOneLine(
+ writer, "add" + MakeCamel(Esc(field.name), true),
+ "builder: FlatBufferBuilder, " + secondArg, "",
+ [&]() {
+ auto method = GenMethod(field.value.type);
+ writer.SetValue("field_name", MakeCamel(Esc(field.name), false));
+ writer.SetValue("method_name", method);
+ writer.SetValue("pos", field_pos);
+ writer.SetValue("default", GenFBBDefaultValue(field));
+ writer.SetValue("cast", GenFBBValueCast(field));
+
+ writer += "builder.add{{method_name}}({{pos}}, \\";
+ writer += "{{field_name}}{{cast}}, {{default}})";
+ },
+ options.gen_jvmstatic);
+ }
+
+ static std::string ToSignedType(const Type &type) {
+ switch (type.base_type) {
+ case BASE_TYPE_UINT: return GenTypeBasic(BASE_TYPE_INT);
+ case BASE_TYPE_ULONG: return GenTypeBasic(BASE_TYPE_LONG);
+ case BASE_TYPE_UCHAR:
+ case BASE_TYPE_NONE:
+ case BASE_TYPE_UTYPE: return GenTypeBasic(BASE_TYPE_CHAR);
+ case BASE_TYPE_USHORT: return GenTypeBasic(BASE_TYPE_SHORT);
+ case BASE_TYPE_VECTOR: return ToSignedType(type.VectorType());
+ default: return GenTypeBasic(type.base_type);
+ }
+ }
+
+ static std::string FlexBufferBuilderCast(const std::string &method,
+ FieldDef &field, bool isFirst) {
+ auto field_type = GenTypeBasic(field.value.type.base_type);
+ std::string to_type;
+ if (method == "Boolean")
+ to_type = "Boolean";
+ else if (method == "Long")
+ to_type = "Long";
+ else if (method == "Int" || method == "Offset" || method == "Struct")
+ to_type = "Int";
+ else if (method == "Byte" || method.empty())
+ to_type = isFirst ? "Byte" : "Int";
+ else if (method == "Short")
+ to_type = isFirst ? "Short" : "Int";
+ else if (method == "Double")
+ to_type = "Double";
+ else if (method == "Float")
+ to_type = isFirst ? "Float" : "Double";
+ else if (method == "UByte")
+
+ if (field_type != to_type) return ".to" + to_type + "()";
+ return "";
+ }
+
+ // fun startMonster(builder: FlatBufferBuilder) = builder.startTable(11)
+ void GenerateStartStructMethod(StructDef &struct_def, CodeWriter &code,
+ const IDLOptions options) const {
+ GenerateFunOneLine(
+ code, "start" + Esc(struct_def.name), "builder: FlatBufferBuilder", "",
+ [&]() {
+ code += "builder.startTable(" +
+ NumToString(struct_def.fields.vec.size()) + ")";
+ },
+ options.gen_jvmstatic);
+ }
+
+ void GenerateTableCreator(StructDef &struct_def, CodeWriter &writer,
+ const IDLOptions options) const {
+ // Generate a method that creates a table in one go. This is only possible
+ // when the table has no struct fields, since those have to be created
+ // inline, and there's no way to do so in Java.
+ bool has_no_struct_fields = true;
+ int num_fields = 0;
+ auto fields_vec = struct_def.fields.vec;
+
+ for (auto it = fields_vec.begin(); it != fields_vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+ if (IsStruct(field.value.type)) {
+ has_no_struct_fields = false;
+ } else {
+ num_fields++;
+ }
+ }
+ // JVM specifications restrict default constructor params to be < 255.
+ // Longs and doubles take up 2 units, so we set the limit to be < 127.
+ if (has_no_struct_fields && num_fields && num_fields < 127) {
+ // Generate a table constructor of the form:
+ // public static int createName(FlatBufferBuilder builder, args...)
+
+ auto name = "create" + Esc(struct_def.name);
+ std::stringstream params;
+ params << "builder: FlatBufferBuilder";
+ for (auto it = fields_vec.begin(); it != fields_vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+ params << ", " << MakeCamel(Esc(field.name), false);
+ if (!IsScalar(field.value.type.base_type)) {
+ params << "Offset: ";
+ } else {
+ params << ": ";
+ }
+ auto optional = field.IsScalarOptional() ? "?" : "";
+ params << GenTypeBasic(field.value.type.base_type) << optional;
+ }
+
+ GenerateFun(
+ writer, name, params.str(), "Int",
+ [&]() {
+ writer.SetValue("vec_size", NumToString(fields_vec.size()));
+
+ writer += "builder.startTable({{vec_size}})";
+
+ auto sortbysize = struct_def.sortbysize;
+ auto largest = sortbysize ? sizeof(largest_scalar_t) : 1;
+ for (size_t size = largest; size; size /= 2) {
+ for (auto it = fields_vec.rbegin(); it != fields_vec.rend();
+ ++it) {
+ auto &field = **it;
+ auto base_type_size = SizeOf(field.value.type.base_type);
+ if (!field.deprecated &&
+ (!sortbysize || size == base_type_size)) {
+ writer.SetValue("camel_field_name",
+ MakeCamel(Esc(field.name), true));
+ writer.SetValue("field_name",
+ MakeCamel(Esc(field.name), false));
+
+ // we wrap on null check for scalar optionals
+ writer += field.IsScalarOptional()
+ ? "{{field_name}}?.run { \\"
+ : "\\";
+
+ writer += "add{{camel_field_name}}(builder, {{field_name}}\\";
+ if (!IsScalar(field.value.type.base_type)) {
+ writer += "Offset\\";
+ }
+ // we wrap on null check for scalar optionals
+ writer += field.IsScalarOptional() ? ") }" : ")";
+ }
+ }
+ }
+ writer += "return end{{struct_name}}(builder)";
+ },
+ options.gen_jvmstatic);
+ }
+ }
+ void GenerateBufferHasIdentifier(StructDef &struct_def, CodeWriter &writer,
+ IDLOptions options) const {
+ auto file_identifier = parser_.file_identifier_;
+ // Check if a buffer has the identifier.
+ if (parser_.root_struct_def_ != &struct_def || !file_identifier.length())
+ return;
+ auto name = MakeCamel(Esc(struct_def.name), false);
+ GenerateFunOneLine(
+ writer, name + "BufferHasIdentifier", "_bb: ByteBuffer", "Boolean",
+ [&]() {
+ writer += "__has_identifier(_bb, \"" + file_identifier + "\")";
+ },
+ options.gen_jvmstatic);
+ }
+
+ void GenerateStructGetters(StructDef &struct_def, CodeWriter &writer) const {
+ auto fields_vec = struct_def.fields.vec;
+ FieldDef *key_field = nullptr;
+ for (auto it = fields_vec.begin(); it != fields_vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+ if (field.key) key_field = &field;
+
+ GenerateComment(field.doc_comment, writer, &comment_config);
+
+ auto field_name = MakeCamel(Esc(field.name), false);
+ auto field_type = GenTypeGet(field.value.type);
+ auto field_default_value = GenDefaultValue(field);
+ auto return_type = GetterReturnType(field);
+ auto bbgetter = ByteBufferGetter(field.value.type, "bb");
+ auto ucast = CastToUsigned(field);
+ auto offset_val = NumToString(field.value.offset);
+ auto offset_prefix =
+ "val o = __offset(" + offset_val + "); return o != 0 ? ";
+ auto value_base_type = field.value.type.base_type;
+ // Most field accessors need to retrieve and test the field offset
+ // first, this is the offset value for that:
+ writer.SetValue("offset", NumToString(field.value.offset));
+ writer.SetValue("return_type", return_type);
+ writer.SetValue("field_type", field_type);
+ writer.SetValue("field_name", field_name);
+ writer.SetValue("field_default", field_default_value);
+ writer.SetValue("bbgetter", bbgetter);
+ writer.SetValue("ucast", ucast);
+
+ // Generate the accessors that don't do object reuse.
+ if (value_base_type == BASE_TYPE_STRUCT) {
+ // Calls the accessor that takes an accessor object with a
+ // new object.
+ // val pos
+ // get() = pos(Vec3())
+ GenerateGetterOneLine(writer, field_name, return_type, [&]() {
+ writer += "{{field_name}}({{field_type}}())";
+ });
+ } else if (value_base_type == BASE_TYPE_VECTOR &&
+ field.value.type.element == BASE_TYPE_STRUCT) {
+ // Accessors for vectors of structs also take accessor objects,
+ // this generates a variant without that argument.
+ // ex: fun weapons(j: Int) = weapons(Weapon(), j)
+ GenerateFunOneLine(writer, field_name, "j: Int", return_type, [&]() {
+ writer += "{{field_name}}({{field_type}}(), j)";
+ });
+ }
+
+ if (IsScalar(value_base_type)) {
+ if (struct_def.fixed) {
+ GenerateGetterOneLine(writer, field_name, return_type, [&]() {
+ writer += "{{bbgetter}}(bb_pos + {{offset}}){{ucast}}";
+ });
+ } else {
+ GenerateGetter(writer, field_name, return_type, [&]() {
+ writer += "val o = __offset({{offset}})";
+ writer +=
+ "return if(o != 0) {{bbgetter}}"
+ "(o + bb_pos){{ucast}} else "
+ "{{field_default}}";
+ });
+ }
+ } else {
+ switch (value_base_type) {
+ case BASE_TYPE_STRUCT:
+ if (struct_def.fixed) {
+ // create getter with object reuse
+ // ex:
+ // fun pos(obj: Vec3) : Vec3? = obj.__assign(bb_pos + 4, bb)
+ // ? adds nullability annotation
+ GenerateFunOneLine(
+ writer, field_name, "obj: " + field_type, return_type,
+ [&]() { writer += "obj.__assign(bb_pos + {{offset}}, bb)"; });
+ } else {
+ // create getter with object reuse
+ // ex:
+ // fun pos(obj: Vec3) : Vec3? {
+ // val o = __offset(4)
+ // return if(o != 0) {
+ // obj.__assign(o + bb_pos, bb)
+ // else {
+ // null
+ // }
+ // }
+ // ? adds nullability annotation
+ GenerateFun(
+ writer, field_name, "obj: " + field_type, return_type, [&]() {
+ auto fixed = field.value.type.struct_def->fixed;
+
+ writer.SetValue("seek", Indirect("o + bb_pos", fixed));
+ OffsetWrapper(
+ writer, offset_val,
+ [&]() { writer += "obj.__assign({{seek}}, bb)"; },
+ [&]() { writer += "null"; });
+ });
+ }
+ break;
+ case BASE_TYPE_STRING:
+ // create string getter
+ // e.g.
+ // val Name : String?
+ // get() = {
+ // val o = __offset(10)
+ // return if (o != 0) __string(o + bb_pos) else null
+ // }
+ // ? adds nullability annotation
+ GenerateGetter(writer, field_name, return_type, [&]() {
+ writer += "val o = __offset({{offset}})";
+ writer += "return if (o != 0) __string(o + bb_pos) else null";
+ });
+ break;
+ case BASE_TYPE_VECTOR: {
+ // e.g.
+ // fun inventory(j: Int) : UByte {
+ // val o = __offset(14)
+ // return if (o != 0) {
+ // bb.get(__vector(o) + j * 1).toUByte()
+ // } else {
+ // 0
+ // }
+ // }
+
+ auto vectortype = field.value.type.VectorType();
+ std::string params = "j: Int";
+
+ if (vectortype.base_type == BASE_TYPE_STRUCT ||
+ vectortype.base_type == BASE_TYPE_UNION) {
+ params = "obj: " + field_type + ", j: Int";
}
- if (IsScalar(value_base_type)) {
- if (struct_def.fixed) {
- GenerateGetterOneLine(writer, field_name, return_type, [&](){
- writer += "{{bbgetter}}(bb_pos + {{offset}}){{ucast}}";
- });
- } else {
- GenerateGetter(writer, field_name, return_type, [&](){
- writer += "val o = __offset({{offset}})";
- writer += "return if(o != 0) {{bbgetter}}"
- "(o + bb_pos){{ucast}} else "
- "{{field_default}}";
- });
- }
- } else {
- switch (value_base_type) {
- case BASE_TYPE_STRUCT:
- if (struct_def.fixed) {
- // create getter with object reuse
- // ex:
- // fun pos(obj: Vec3) : Vec3? = obj.__assign(bb_pos + 4, bb)
- // ? adds nullability annotation
- GenerateFunOneLine(writer,
- field_name, "obj: " + field_type ,
- return_type + "?", [&](){
- writer += "obj.__assign(bb_pos + {{offset}}, bb)";
- });
- } else {
- // create getter with object reuse
- // ex:
- // fun pos(obj: Vec3) : Vec3? {
- // val o = __offset(4)
- // return if(o != 0) {
- // obj.__assign(o + bb_pos, bb)
- // else {
- // null
- // }
- // }
- // ? adds nullability annotation
- GenerateFun(writer, field_name, "obj: " + field_type,
- return_type + "?", [&](){
- auto fixed = field.value.type.struct_def->fixed;
-
- writer.SetValue("seek", Indirect("o + bb_pos", fixed));
- OffsetWrapper(writer,
- offset_val,
- [&]() { writer += "obj.__assign({{seek}}, bb)"; },
- [&]() { writer += "null"; });
- });
- }
- break;
- case BASE_TYPE_STRING:
- // create string getter
- // e.g.
- // val Name : String?
- // get() = {
- // val o = __offset(10)
- // return if (o != 0) __string(o + bb_pos) else null
- // }
- // ? adds nullability annotation
- GenerateGetter(writer, field_name, return_type + "?", [&](){
-
- writer += "val o = __offset({{offset}})";
- writer += "return if (o != 0) __string(o + bb_pos) else null";
- });
- break;
- case BASE_TYPE_VECTOR: {
- // e.g.
- // fun inventory(j: Int) : UByte {
- // val o = __offset(14)
- // return if (o != 0) {
- // bb.get(__vector(o) + j * 1).toUByte()
- // } else {
- // 0
- // }
- // }
-
- auto vectortype = field.value.type.VectorType();
- std::string params = "j: Int";
- std::string nullable = IsScalar(vectortype.base_type) ? ""
- : "?";
-
- if (vectortype.base_type == BASE_TYPE_STRUCT ||
- vectortype.base_type == BASE_TYPE_UNION) {
- params = "obj: " + field_type + ", j: Int";
- }
-
-
- writer.SetValue("toType", "YYYYY");
-
- auto ret_type = return_type + nullable;
- GenerateFun(writer, field_name, params, ret_type, [&](){
- auto inline_size = NumToString(InlineSize(vectortype));
- auto index = "__vector(o) + j * " + inline_size;
- auto not_found = NotFoundReturn(field.value.type.element);
- auto found = "";
- writer.SetValue("index", index);
- switch(vectortype.base_type) {
- case BASE_TYPE_STRUCT: {
- bool fixed = vectortype.struct_def->fixed;
- writer.SetValue("index", Indirect(index, fixed));
- found = "obj.__assign({{index}}, bb)";
- break;
- }
- case BASE_TYPE_UNION:
- found = "{{bbgetter}}(obj, {{index}} - bb_pos){{ucast}}";
- break;
- default:
- found = "{{bbgetter}}({{index}}){{ucast}}";
- }
- OffsetWrapper(writer, offset_val,
- [&]() { writer += found; } ,
- [&]() { writer += not_found; });
- });
- break;
+ GenerateFun(writer, field_name, params, return_type, [&]() {
+ auto inline_size = NumToString(InlineSize(vectortype));
+ auto index = "__vector(o) + j * " + inline_size;
+ auto not_found = NotFoundReturn(field.value.type.element);
+ auto found = "";
+ writer.SetValue("index", index);
+ switch (vectortype.base_type) {
+ case BASE_TYPE_STRUCT: {
+ bool fixed = vectortype.struct_def->fixed;
+ writer.SetValue("index", Indirect(index, fixed));
+ found = "obj.__assign({{index}}, bb)";
+ break;
}
case BASE_TYPE_UNION:
- GenerateFun(writer, field_name, "obj: " + field_type,
- return_type + "?", [&](){
- writer += OffsetWrapperOneLine(offset_val,
- bbgetter + "(obj, o)",
- "null");
- });
- break;
- default:
- FLATBUFFERS_ASSERT(0);
- }
- }
-
- if (value_base_type == BASE_TYPE_VECTOR) {
- // Generate Lenght functions for vectors
- GenerateGetter(writer, field_name + "Length", "Int", [&](){
- writer += OffsetWrapperOneLine(offset_val,
- "__vector_len(o)", "0");
- });
-
- // See if we should generate a by-key accessor.
- if (field.value.type.element == BASE_TYPE_STRUCT &&
- !field.value.type.struct_def->fixed) {
- auto &sd = *field.value.type.struct_def;
- auto &fields = sd.fields.vec;
- for (auto kit = fields.begin(); kit != fields.end(); ++kit) {
- auto &kfield = **kit;
- if (kfield.key) {
- auto qualified_name = WrapInNameSpace(sd);
- auto name = MakeCamel(Esc(field.name), false) + "ByKey";
- auto params = "key: " + GenTypeGet(kfield.value.type);
- auto rtype = qualified_name + "?";
- GenerateFun(writer, name, params, rtype, [&] () {
- OffsetWrapper(writer, offset_val,
- [&] () {
- writer += qualified_name +
- ".__lookup_by_key(null, __vector(o), key, bb)";
- },
- [&] () {
- writer += "null";
- });
- });
-
- auto param2 = "obj: " + qualified_name +
- ", key: " +
- GenTypeGet(kfield.value.type);
- GenerateFun(writer, name, param2, rtype, [&](){
- OffsetWrapper(writer, offset_val,
- [&] () {
- writer += qualified_name +
- ".__lookup_by_key(obj, __vector(o), key, bb)";
- },
- [&]() { writer += "null"; });
- });
-
- break;
- }
- }
- }
- }
-
- if ((value_base_type == BASE_TYPE_VECTOR &&
- IsScalar(field.value.type.VectorType().base_type)) ||
- value_base_type == BASE_TYPE_STRING) {
-
- auto end_idx = NumToString(value_base_type == BASE_TYPE_STRING
- ? 1
- : InlineSize(field.value.type.VectorType()));
- // Generate a ByteBuffer accessor for strings & vectors of scalars.
- // e.g.
- // val inventoryByteBuffer: ByteBuffer
- // get = __vector_as_bytebuffer(14, 1)
-
- GenerateGetterOneLine(writer, field_name + "AsByteBuffer",
- "ByteBuffer", [&](){
- writer.SetValue("end", end_idx);
- writer += "__vector_as_bytebuffer({{offset}}, {{end}})";
- });
-
- // Generate a ByteBuffer accessor for strings & vectors of scalars.
- // e.g.
- // fun inventoryInByteBuffer(_bb: Bytebuffer):
- // ByteBuffer = __vector_as_bytebuffer(_bb, 14, 1)
- GenerateFunOneLine(writer, field_name + "InByteBuffer",
- "_bb: ByteBuffer", "ByteBuffer", [&](){
- writer.SetValue("end", end_idx);
- writer += "__vector_in_bytebuffer(_bb, {{offset}}, {{end}})";
- });
- }
-
- // generate object accessors if is nested_flatbuffer
- //fun testnestedflatbufferAsMonster() : Monster?
- //{ return testnestedflatbufferAsMonster(new Monster()); }
-
- if (field.nested_flatbuffer) {
- auto nested_type_name = WrapInNameSpace(*field.nested_flatbuffer);
- auto nested_method_name =
- field_name + "As" +
- field.nested_flatbuffer->name;
-
- GenerateGetterOneLine(writer,
- nested_method_name,
- nested_type_name + "?", [&](){
- writer += nested_method_name + "(" + nested_type_name + "())";
- });
-
- GenerateFun(writer,
- nested_method_name,
- "obj: " + nested_type_name,
- nested_type_name + "?", [&](){
- OffsetWrapper(writer, offset_val,
- [&]() { writer += "obj.__assign(__indirect(__vector(o)), bb)"; },
- [&]() { writer += "null";});
- });
- }
-
- // Generate mutators for scalar fields or vectors of scalars.
- if (parser_.opts.mutable_buffer) {
- auto value_type = field.value.type;
- auto underlying_type = value_base_type == BASE_TYPE_VECTOR
- ? value_type.VectorType()
- : value_type;
- auto name = "mutate" + MakeCamel(Esc(field.name), true);
- auto size = NumToString(InlineSize(underlying_type));
- auto params = Esc(field.name) + ": " + GenTypeGet(underlying_type);
- // A vector mutator also needs the index of the vector element it should
- // mutate.
- if (value_base_type == BASE_TYPE_VECTOR)
- params.insert(0, "j: Int, ");
-
- // Boolean parameters have to be explicitly converted to byte
- // representation.
- auto setter_parameter = underlying_type.base_type == BASE_TYPE_BOOL
- ? "(if(" + Esc(field.name) + ") 1 else 0).toByte()"
- : Esc(field.name);
-
- auto setter_index = value_base_type == BASE_TYPE_VECTOR
- ? "__vector(o) + j * " + size
- : (struct_def.fixed
- ? "bb_pos + " + offset_val
- : "o + bb_pos");
- if (IsScalar(value_base_type) || (value_base_type == BASE_TYPE_VECTOR &&
- IsScalar(value_type.VectorType().base_type))) {
-
- auto statements = [&] () {
- writer.SetValue("bbsetter", ByteBufferSetter(underlying_type));
- writer.SetValue("index", setter_index);
- writer.SetValue("params", setter_parameter);
- writer.SetValue("cast", CastToSigned(field));
- if (struct_def.fixed) {
- writer += "{{bbsetter}}({{index}}, {{params}}{{cast}})";
- } else {
- OffsetWrapper(writer, offset_val, [&](){
- writer += "{{bbsetter}}({{index}}, {{params}}{{cast}})";
- writer += "true";
- }, [&](){ writer += "false";});
- }
- };
-
- if (struct_def.fixed) {
- GenerateFunOneLine(writer, name, params, "ByteBuffer",
- statements);
- } else {
- GenerateFun(writer, name, params, "Boolean",
- statements);
- }
- }
- }
- }
- if (struct_def.has_key && !struct_def.fixed) {
- // Key Comparison method
- GenerateOverrideFun(
- writer,
- "keysCompare",
- "o1: Int, o2: Int, _bb: ByteBuffer", "Int", [&]() {
- if (key_field->value.type.base_type == BASE_TYPE_STRING) {
- writer.SetValue("offset", NumToString(key_field->value.offset));
- writer += " return compareStrings(__offset({{offset}}, o1, "
- "_bb), __offset({{offset}}, o2, _bb), _bb)";
-
- } else {
- auto getter1 = GenLookupByKey(key_field, "_bb", "o1");
- auto getter2 = GenLookupByKey(key_field, "_bb", "o2");
- writer += "val val_1 = " + getter1;
- writer += "val val_2 = " + getter2;
- writer += "return (val_1 - val_2).sign";
- }
+ found = "{{bbgetter}}(obj, {{index}}){{ucast}}";
+ break;
+ default: found = "{{bbgetter}}({{index}}){{ucast}}";
+ }
+ OffsetWrapper(
+ writer, offset_val, [&]() { writer += found; },
+ [&]() { writer += not_found; });
});
+ break;
+ }
+ case BASE_TYPE_UNION:
+ GenerateFun(
+ writer, field_name, "obj: " + field_type, return_type, [&]() {
+ writer += OffsetWrapperOneLine(
+ offset_val, bbgetter + "(obj, o + bb_pos)", "null");
+ });
+ break;
+ default: FLATBUFFERS_ASSERT(0);
}
- }
-
- static std::string CastToUsigned(const FieldDef &field) {
- return CastToUsigned(field.value.type);
- }
-
- static std::string CastToUsigned(const Type type) {
- switch (type.base_type) {
- case BASE_TYPE_UINT:
- return ".toUInt()";
- case BASE_TYPE_UCHAR:
- case BASE_TYPE_UTYPE:
- return ".toUByte()";
- case BASE_TYPE_USHORT:
- return ".toUShort()";
- case BASE_TYPE_ULONG:
- return ".toULong()";
- case BASE_TYPE_VECTOR:
- return CastToUsigned(type.VectorType());
- default:
- return "";
- }
- }
-
- static std::string CastToSigned(const FieldDef &field) {
- return CastToSigned(field.value.type);
- }
-
- static std::string CastToSigned(const Type type) {
- switch (type.base_type) {
- case BASE_TYPE_UINT:
- return ".toInt()";
- case BASE_TYPE_UCHAR:
- case BASE_TYPE_UTYPE:
- return ".toByte()";
- case BASE_TYPE_USHORT:
- return ".toShort()";
- case BASE_TYPE_ULONG:
- return ".toLong()";
- case BASE_TYPE_VECTOR:
- return CastToSigned(type.VectorType());
- default:
- return "";
- }
- }
-
- static std::string LiteralSuffix(const BaseType type) {
- switch (type) {
- case BASE_TYPE_UINT:
- case BASE_TYPE_UCHAR:
- case BASE_TYPE_UTYPE:
- case BASE_TYPE_USHORT:
- return "u";
- case BASE_TYPE_ULONG:
- return "UL";
- case BASE_TYPE_LONG:
- return "L";
- default:
- return "";
- }
- }
-
- void GenerateCompanionObject(CodeWriter &code,
- const std::function<void()> &callback) const {
- code += "companion object {";
- code.IncrementIdentLevel();
- callback();
- code.DecrementIdentLevel();
- code += "}";
- }
-
- // Generate a documentation comment, if available.
- void GenerateComment(const std::vector<std::string> &dc, CodeWriter &writer,
- const CommentConfig *config) const {
- if (dc.begin() == dc.end()) {
- // Don't output empty comment blocks with 0 lines of comment content.
- return;
}
- if (config != nullptr && config->first_line != nullptr) {
- writer += std::string(config->first_line);
- }
- std::string line_prefix =
- ((config != nullptr && config->content_line_prefix != nullptr)
- ? config->content_line_prefix
- : "///");
- for (auto it = dc.begin(); it != dc.end(); ++it) {
- writer += line_prefix + *it;
- }
- if (config != nullptr && config->last_line != nullptr) {
- writer += std::string(config->last_line);
- }
- }
-
- static void GenerateGetRootAsAccessors(const std::string &struct_name,
- CodeWriter &writer) {
- // Generate a special accessor for the table that when used as the root
- // ex: fun getRootAsMonster(_bb: ByteBuffer): Monster {...}
- writer.SetValue("gr_name", struct_name);
- writer.SetValue("gr_method", "getRootAs" + struct_name);
-
- // create convenience method that doesn't require an existing object
- writer += "fun {{gr_method}}(_bb: ByteBuffer): {{gr_name}} = \\";
- writer += "{{gr_method}}(_bb, {{gr_name}}())";
-
- // create method that allows object reuse
- // ex: fun Monster getRootAsMonster(_bb: ByteBuffer, obj: Monster) {...}
- writer += "fun {{gr_method}}"
- "(_bb: ByteBuffer, obj: {{gr_name}}): {{gr_name}} {";
- writer.IncrementIdentLevel();
- writer += "_bb.order(ByteOrder.LITTLE_ENDIAN)";
- writer += "return (obj.__assign(_bb.getInt(_bb.position())"
- " + _bb.position(), _bb))";
- writer.DecrementIdentLevel();
- writer += "}";
- }
-
- static void GenerateStaticConstructor(const StructDef &struct_def,
- CodeWriter &code) {
- // create a struct constructor function
- auto params = StructConstructorParams(struct_def);
- GenerateFun(code, "create" + Esc(struct_def.name), params, "Int", [&](){
- GenStructBody(struct_def, code, "");
- code += "return builder.offset()";
+ if (value_base_type == BASE_TYPE_VECTOR) {
+ // Generate Lenght functions for vectors
+ GenerateGetter(writer, field_name + "Length", "Int", [&]() {
+ writer += OffsetWrapperOneLine(offset_val, "__vector_len(o)", "0");
});
- }
- static std::string StructConstructorParams(const StructDef &struct_def,
- const std::string &prefix = "") {
- //builder: FlatBufferBuilder
- std::stringstream out;
- auto field_vec = struct_def.fields.vec;
- if (prefix.empty()) {
- out << "builder: FlatBufferBuilder";
- }
- for (auto it = field_vec.begin(); it != field_vec.end(); ++it) {
- auto &field = **it;
- if (IsStruct(field.value.type)) {
- // Generate arguments for a struct inside a struct. To ensure
- // names don't clash, and to make it obvious these arguments are
- // constructing a nested struct, prefix the name with the field
- // name.
- out << StructConstructorParams(*field.value.type.struct_def,
- prefix + (Esc(field.name) + "_"));
- } else {
- out << ", " << prefix << MakeCamel(Esc(field.name), false)
- << ": "
- << GenTypeBasic(field.value.type.base_type);
+ // See if we should generate a by-key accessor.
+ if (field.value.type.element == BASE_TYPE_STRUCT &&
+ !field.value.type.struct_def->fixed) {
+ auto &sd = *field.value.type.struct_def;
+ auto &fields = sd.fields.vec;
+ for (auto kit = fields.begin(); kit != fields.end(); ++kit) {
+ auto &kfield = **kit;
+ if (kfield.key) {
+ auto qualified_name = WrapInNameSpace(sd);
+ auto name = MakeCamel(Esc(field.name), false) + "ByKey";
+ auto params = "key: " + GenTypeGet(kfield.value.type);
+ auto rtype = qualified_name + "?";
+ GenerateFun(writer, name, params, rtype, [&]() {
+ OffsetWrapper(
+ writer, offset_val,
+ [&]() {
+ writer += qualified_name +
+ ".__lookup_by_key(null, __vector(o), key, bb)";
+ },
+ [&]() { writer += "null"; });
+ });
+
+ auto param2 = "obj: " + qualified_name +
+ ", key: " + GenTypeGet(kfield.value.type);
+ GenerateFun(writer, name, param2, rtype, [&]() {
+ OffsetWrapper(
+ writer, offset_val,
+ [&]() {
+ writer += qualified_name +
+ ".__lookup_by_key(obj, __vector(o), key, bb)";
+ },
+ [&]() { writer += "null"; });
+ });
+
+ break;
}
+ }
}
- return out.str();
- }
+ }
- static void GeneratePropertyOneLine(CodeWriter &writer,
- const std::string &name,
- const std::string &type,
- const std::function<void()> &body) {
- // Generates Kotlin getter for properties
- // e.g.:
- // val prop: Mytype = x
- writer.SetValue("_name", name);
- writer.SetValue("_type", type);
- writer += "val {{_name}} : {{_type}} = \\";
- body();
- }
- static void GenerateGetterOneLine(CodeWriter &writer,
- const std::string &name,
- const std::string &type,
- const std::function<void()> &body) {
- // Generates Kotlin getter for properties
- // e.g.:
- // val prop: Mytype get() = x
- writer.SetValue("_name", name);
- writer.SetValue("_type", type);
- writer += "val {{_name}} : {{_type}} get() = \\";
- body();
- }
+ if ((value_base_type == BASE_TYPE_VECTOR &&
+ IsScalar(field.value.type.VectorType().base_type)) ||
+ value_base_type == BASE_TYPE_STRING) {
+ auto end_idx =
+ NumToString(value_base_type == BASE_TYPE_STRING
+ ? 1
+ : InlineSize(field.value.type.VectorType()));
+ // Generate a ByteBuffer accessor for strings & vectors of scalars.
+ // e.g.
+ // val inventoryByteBuffer: ByteBuffer
+ // get = __vector_as_bytebuffer(14, 1)
- static void GenerateGetter(CodeWriter &writer,
- const std::string &name,
- const std::string &type,
- const std::function<void()> &body) {
- // Generates Kotlin getter for properties
- // e.g.:
- // val prop: Mytype
- // get() = {
- // return x
- // }
- writer.SetValue("name", name);
- writer.SetValue("type", type);
- writer += "val {{name}} : {{type}}";
- writer.IncrementIdentLevel();
- writer += "get() {";
- writer.IncrementIdentLevel();
- body();
- writer.DecrementIdentLevel();
- writer += "}";
- writer.DecrementIdentLevel();
- }
+ GenerateGetterOneLine(
+ writer, field_name + "AsByteBuffer", "ByteBuffer", [&]() {
+ writer.SetValue("end", end_idx);
+ writer += "__vector_as_bytebuffer({{offset}}, {{end}})";
+ });
- static void GenerateFun(CodeWriter &writer,
- const std::string &name,
- const std::string ¶ms,
- const std::string &returnType,
- const std::function<void()> &body) {
- // Generates Kotlin function
- // e.g.:
- // fun path(j: Int): Vec3 {
- // return path(Vec3(), j)
- // }
- auto noreturn = returnType.empty();
- writer.SetValue("name", name);
- writer.SetValue("params", params);
- writer.SetValue("return_type", noreturn ? "" : ": " + returnType);
- writer += "fun {{name}}({{params}}) {{return_type}} {";
- writer.IncrementIdentLevel();
- body();
- writer.DecrementIdentLevel();
- writer += "}";
- }
+ // Generate a ByteBuffer accessor for strings & vectors of scalars.
+ // e.g.
+ // fun inventoryInByteBuffer(_bb: Bytebuffer):
+ // ByteBuffer = __vector_as_bytebuffer(_bb, 14, 1)
+ GenerateFunOneLine(
+ writer, field_name + "InByteBuffer", "_bb: ByteBuffer",
+ "ByteBuffer", [&]() {
+ writer.SetValue("end", end_idx);
+ writer += "__vector_in_bytebuffer(_bb, {{offset}}, {{end}})";
+ });
+ }
- static void GenerateFunOneLine(CodeWriter &writer,
- const std::string &name,
- const std::string ¶ms,
- const std::string &returnType,
- const std::function<void()> &body) {
- // Generates Kotlin function
- // e.g.:
- // fun path(j: Int): Vec3 = return path(Vec3(), j)
- writer.SetValue("name", name);
- writer.SetValue("params", params);
- writer.SetValue("return_type_p", returnType.empty() ? "" :
- " : " + returnType);
- writer += "fun {{name}}({{params}}){{return_type_p}} = \\";
- body();
- }
+ // generate object accessors if is nested_flatbuffer
+ // fun testnestedflatbufferAsMonster() : Monster?
+ //{ return testnestedflatbufferAsMonster(new Monster()); }
- static void GenerateOverrideFun(CodeWriter &writer,
- const std::string &name,
- const std::string ¶ms,
- const std::string &returnType,
- const std::function<void()> &body) {
- // Generates Kotlin function
- // e.g.:
- // override fun path(j: Int): Vec3 = return path(Vec3(), j)
- writer += "override \\";
- GenerateFun(writer, name, params, returnType, body);
- }
+ if (field.nested_flatbuffer) {
+ auto nested_type_name = WrapInNameSpace(*field.nested_flatbuffer);
+ auto nested_method_name =
+ field_name + "As" + field.nested_flatbuffer->name;
- static void GenerateOverrideFunOneLine(CodeWriter &writer,
- const std::string &name,
- const std::string ¶ms,
- const std::string &returnType,
- const std::string &statement) {
- // Generates Kotlin function
- // e.g.:
- // override fun path(j: Int): Vec3 = return path(Vec3(), j)
- writer.SetValue("name", name);
- writer.SetValue("params", params);
- writer.SetValue("return_type", returnType.empty() ? "" :
- " : " + returnType);
- writer += "override fun {{name}}({{params}}){{return_type}} = \\";
- writer += statement;
- }
+ GenerateGetterOneLine(
+ writer, nested_method_name, nested_type_name + "?", [&]() {
+ writer += nested_method_name + "(" + nested_type_name + "())";
+ });
- static std::string OffsetWrapperOneLine(const std::string &offset,
- const std::string &found,
- const std::string ¬_found) {
- return "val o = __offset(" + offset + "); return if (o != 0) " + found +
- " else " + not_found;
- }
+ GenerateFun(writer, nested_method_name, "obj: " + nested_type_name,
+ nested_type_name + "?", [&]() {
+ OffsetWrapper(
+ writer, offset_val,
+ [&]() {
+ writer +=
+ "obj.__assign(__indirect(__vector(o)), bb)";
+ },
+ [&]() { writer += "null"; });
+ });
+ }
- static void OffsetWrapper(CodeWriter &code,
- const std::string &offset,
- const std::function<void()> &found,
- const std::function<void()> ¬_found) {
- code += "val o = __offset(" + offset + ")";
- code +="return if (o != 0) {";
- code.IncrementIdentLevel();
- found();
- code.DecrementIdentLevel();
- code += "} else {";
- code.IncrementIdentLevel();
- not_found();
- code.DecrementIdentLevel();
- code += "}";
- }
+ // Generate mutators for scalar fields or vectors of scalars.
+ if (parser_.opts.mutable_buffer) {
+ auto value_type = field.value.type;
+ auto underlying_type = value_base_type == BASE_TYPE_VECTOR
+ ? value_type.VectorType()
+ : value_type;
+ auto name = "mutate" + MakeCamel(Esc(field.name), true);
+ auto size = NumToString(InlineSize(underlying_type));
+ auto params = Esc(field.name) + ": " + GenTypeGet(underlying_type);
+ // A vector mutator also needs the index of the vector element it should
+ // mutate.
+ if (value_base_type == BASE_TYPE_VECTOR) params.insert(0, "j: Int, ");
- static std::string Indirect(const std::string &index, bool fixed) {
- // We apply __indirect() and struct is not fixed.
- if (!fixed)
- return "__indirect(" + index + ")";
- return index;
- }
+ // Boolean parameters have to be explicitly converted to byte
+ // representation.
+ auto setter_parameter =
+ underlying_type.base_type == BASE_TYPE_BOOL
+ ? "(if(" + Esc(field.name) + ") 1 else 0).toByte()"
+ : Esc(field.name);
- static std::string NotFoundReturn(BaseType el) {
- switch (el) {
- case BASE_TYPE_FLOAT:
- return "0.0f";
- case BASE_TYPE_DOUBLE:
- return "0.0";
- case BASE_TYPE_BOOL:
- return "false";
- case BASE_TYPE_LONG:
- case BASE_TYPE_INT:
- case BASE_TYPE_CHAR:
- case BASE_TYPE_SHORT:
- return "0";
- case BASE_TYPE_UINT:
- case BASE_TYPE_UCHAR:
- case BASE_TYPE_USHORT:
- case BASE_TYPE_UTYPE:
- return "0u";
- case BASE_TYPE_ULONG:
- return "0uL";
- default:
- return "null";
+ auto setter_index =
+ value_base_type == BASE_TYPE_VECTOR
+ ? "__vector(o) + j * " + size
+ : (struct_def.fixed ? "bb_pos + " + offset_val : "o + bb_pos");
+ if (IsScalar(value_base_type) ||
+ (value_base_type == BASE_TYPE_VECTOR &&
+ IsScalar(value_type.VectorType().base_type))) {
+ auto statements = [&]() {
+ writer.SetValue("bbsetter", ByteBufferSetter(underlying_type));
+ writer.SetValue("index", setter_index);
+ writer.SetValue("params", setter_parameter);
+ writer.SetValue("cast", CastToSigned(field));
+ if (struct_def.fixed) {
+ writer += "{{bbsetter}}({{index}}, {{params}}{{cast}})";
+ } else {
+ OffsetWrapper(
+ writer, offset_val,
+ [&]() {
+ writer += "{{bbsetter}}({{index}}, {{params}}{{cast}})";
+ writer += "true";
+ },
+ [&]() { writer += "false"; });
+ }
+ };
+
+ if (struct_def.fixed) {
+ GenerateFunOneLine(writer, name, params, "ByteBuffer", statements);
+ } else {
+ GenerateFun(writer, name, params, "Boolean", statements);
+ }
}
+ }
+ }
+ if (struct_def.has_key && !struct_def.fixed) {
+ // Key Comparison method
+ GenerateOverrideFun(
+ writer, "keysCompare", "o1: Int, o2: Int, _bb: ByteBuffer", "Int",
+ [&]() {
+ if (IsString(key_field->value.type)) {
+ writer.SetValue("offset", NumToString(key_field->value.offset));
+ writer +=
+ " return compareStrings(__offset({{offset}}, o1, "
+ "_bb), __offset({{offset}}, o2, _bb), _bb)";
+
+ } else {
+ auto getter1 = GenLookupByKey(key_field, "_bb", "o1");
+ auto getter2 = GenLookupByKey(key_field, "_bb", "o2");
+ writer += "val val_1 = " + getter1;
+ writer += "val val_2 = " + getter2;
+ writer += "return (val_1 - val_2).sign";
+ }
+ });
+ }
+ }
+
+ static std::string CastToUsigned(const FieldDef &field) {
+ return CastToUsigned(field.value.type);
+ }
+
+ static std::string CastToUsigned(const Type type) {
+ switch (type.base_type) {
+ case BASE_TYPE_UINT: return ".toUInt()";
+ case BASE_TYPE_UCHAR:
+ case BASE_TYPE_UTYPE: return ".toUByte()";
+ case BASE_TYPE_USHORT: return ".toUShort()";
+ case BASE_TYPE_ULONG: return ".toULong()";
+ case BASE_TYPE_VECTOR: return CastToUsigned(type.VectorType());
+ default: return "";
+ }
+ }
+
+ static std::string CastToSigned(const FieldDef &field) {
+ return CastToSigned(field.value.type);
+ }
+
+ static std::string CastToSigned(const Type type) {
+ switch (type.base_type) {
+ case BASE_TYPE_UINT: return ".toInt()";
+ case BASE_TYPE_UCHAR:
+ case BASE_TYPE_UTYPE: return ".toByte()";
+ case BASE_TYPE_USHORT: return ".toShort()";
+ case BASE_TYPE_ULONG: return ".toLong()";
+ case BASE_TYPE_VECTOR: return CastToSigned(type.VectorType());
+ default: return "";
+ }
+ }
+
+ static std::string LiteralSuffix(const BaseType type) {
+ switch (type) {
+ case BASE_TYPE_UINT:
+ case BASE_TYPE_UCHAR:
+ case BASE_TYPE_UTYPE:
+ case BASE_TYPE_USHORT: return "u";
+ case BASE_TYPE_ULONG: return "UL";
+ case BASE_TYPE_LONG: return "L";
+ default: return "";
+ }
+ }
+
+ void GenerateCompanionObject(CodeWriter &code,
+ const std::function<void()> &callback) const {
+ code += "companion object {";
+ code.IncrementIdentLevel();
+ callback();
+ code.DecrementIdentLevel();
+ code += "}";
+ }
+
+ // Generate a documentation comment, if available.
+ void GenerateComment(const std::vector<std::string> &dc, CodeWriter &writer,
+ const CommentConfig *config) const {
+ if (dc.begin() == dc.end()) {
+ // Don't output empty comment blocks with 0 lines of comment content.
+ return;
}
- // This tracks the current namespace used to determine if a type need to be
- // prefixed by its namespace
- const Namespace *cur_name_space_;
+ if (config != nullptr && config->first_line != nullptr) {
+ writer += std::string(config->first_line);
+ }
+ std::string line_prefix =
+ ((config != nullptr && config->content_line_prefix != nullptr)
+ ? config->content_line_prefix
+ : "///");
+ for (auto it = dc.begin(); it != dc.end(); ++it) {
+ writer += line_prefix + *it;
+ }
+ if (config != nullptr && config->last_line != nullptr) {
+ writer += std::string(config->last_line);
+ }
+ }
+
+ static void GenerateGetRootAsAccessors(const std::string &struct_name,
+ CodeWriter &writer,
+ IDLOptions options) {
+ // Generate a special accessor for the table that when used as the root
+ // ex: fun getRootAsMonster(_bb: ByteBuffer): Monster {...}
+ writer.SetValue("gr_name", struct_name);
+ writer.SetValue("gr_method", "getRootAs" + struct_name);
+
+ // create convenience method that doesn't require an existing object
+ GenerateJvmStaticAnnotation(writer, options.gen_jvmstatic);
+ writer += "fun {{gr_method}}(_bb: ByteBuffer): {{gr_name}} = \\";
+ writer += "{{gr_method}}(_bb, {{gr_name}}())";
+
+ // create method that allows object reuse
+ // ex: fun Monster getRootAsMonster(_bb: ByteBuffer, obj: Monster) {...}
+ GenerateJvmStaticAnnotation(writer, options.gen_jvmstatic);
+ writer +=
+ "fun {{gr_method}}"
+ "(_bb: ByteBuffer, obj: {{gr_name}}): {{gr_name}} {";
+ writer.IncrementIdentLevel();
+ writer += "_bb.order(ByteOrder.LITTLE_ENDIAN)";
+ writer +=
+ "return (obj.__assign(_bb.getInt(_bb.position())"
+ " + _bb.position(), _bb))";
+ writer.DecrementIdentLevel();
+ writer += "}";
+ }
+
+ static void GenerateStaticConstructor(const StructDef &struct_def,
+ CodeWriter &code,
+ const IDLOptions options) {
+ // create a struct constructor function
+ auto params = StructConstructorParams(struct_def);
+ GenerateFun(
+ code, "create" + Esc(struct_def.name), params, "Int",
+ [&]() {
+ GenStructBody(struct_def, code, "");
+ code += "return builder.offset()";
+ },
+ options.gen_jvmstatic);
+ }
+
+ static std::string StructConstructorParams(const StructDef &struct_def,
+ const std::string &prefix = "") {
+ // builder: FlatBufferBuilder
+ std::stringstream out;
+ auto field_vec = struct_def.fields.vec;
+ if (prefix.empty()) { out << "builder: FlatBufferBuilder"; }
+ for (auto it = field_vec.begin(); it != field_vec.end(); ++it) {
+ auto &field = **it;
+ if (IsStruct(field.value.type)) {
+ // Generate arguments for a struct inside a struct. To ensure
+ // names don't clash, and to make it obvious these arguments are
+ // constructing a nested struct, prefix the name with the field
+ // name.
+ out << StructConstructorParams(*field.value.type.struct_def,
+ prefix + (Esc(field.name) + "_"));
+ } else {
+ out << ", " << prefix << MakeCamel(Esc(field.name), false) << ": "
+ << GenTypeBasic(field.value.type.base_type);
+ }
+ }
+ return out.str();
+ }
+
+ static void GeneratePropertyOneLine(CodeWriter &writer,
+ const std::string &name,
+ const std::string &type,
+ const std::function<void()> &body) {
+ // Generates Kotlin getter for properties
+ // e.g.:
+ // val prop: Mytype = x
+ writer.SetValue("_name", name);
+ writer.SetValue("_type", type);
+ writer += "val {{_name}} : {{_type}} = \\";
+ body();
+ }
+ static void GenerateGetterOneLine(CodeWriter &writer, const std::string &name,
+ const std::string &type,
+ const std::function<void()> &body) {
+ // Generates Kotlin getter for properties
+ // e.g.:
+ // val prop: Mytype get() = x
+ writer.SetValue("_name", name);
+ writer.SetValue("_type", type);
+ writer += "val {{_name}} : {{_type}} get() = \\";
+ body();
+ }
+
+ static void GenerateGetter(CodeWriter &writer, const std::string &name,
+ const std::string &type,
+ const std::function<void()> &body) {
+ // Generates Kotlin getter for properties
+ // e.g.:
+ // val prop: Mytype
+ // get() = {
+ // return x
+ // }
+ writer.SetValue("name", name);
+ writer.SetValue("type", type);
+ writer += "val {{name}} : {{type}}";
+ writer.IncrementIdentLevel();
+ writer += "get() {";
+ writer.IncrementIdentLevel();
+ body();
+ writer.DecrementIdentLevel();
+ writer += "}";
+ writer.DecrementIdentLevel();
+ }
+
+ static void GenerateFun(CodeWriter &writer, const std::string &name,
+ const std::string ¶ms,
+ const std::string &returnType,
+ const std::function<void()> &body,
+ bool gen_jvmstatic = false) {
+ // Generates Kotlin function
+ // e.g.:
+ // fun path(j: Int): Vec3 {
+ // return path(Vec3(), j)
+ // }
+ auto noreturn = returnType.empty();
+ writer.SetValue("name", name);
+ writer.SetValue("params", params);
+ writer.SetValue("return_type", noreturn ? "" : ": " + returnType);
+ GenerateJvmStaticAnnotation(writer, gen_jvmstatic);
+ writer += "fun {{name}}({{params}}) {{return_type}} {";
+ writer.IncrementIdentLevel();
+ body();
+ writer.DecrementIdentLevel();
+ writer += "}";
+ }
+
+ static void GenerateFunOneLine(CodeWriter &writer, const std::string &name,
+ const std::string ¶ms,
+ const std::string &returnType,
+ const std::function<void()> &body,
+ bool gen_jvmstatic = false) {
+ // Generates Kotlin function
+ // e.g.:
+ // fun path(j: Int): Vec3 = return path(Vec3(), j)
+ writer.SetValue("name", name);
+ writer.SetValue("params", params);
+ writer.SetValue("return_type_p",
+ returnType.empty() ? "" : " : " + returnType);
+ GenerateJvmStaticAnnotation(writer, gen_jvmstatic);
+ writer += "fun {{name}}({{params}}){{return_type_p}} = \\";
+ body();
+ }
+
+ static void GenerateOverrideFun(CodeWriter &writer, const std::string &name,
+ const std::string ¶ms,
+ const std::string &returnType,
+ const std::function<void()> &body) {
+ // Generates Kotlin function
+ // e.g.:
+ // override fun path(j: Int): Vec3 = return path(Vec3(), j)
+ writer += "override \\";
+ GenerateFun(writer, name, params, returnType, body);
+ }
+
+ static void GenerateOverrideFunOneLine(CodeWriter &writer,
+ const std::string &name,
+ const std::string ¶ms,
+ const std::string &returnType,
+ const std::string &statement) {
+ // Generates Kotlin function
+ // e.g.:
+ // override fun path(j: Int): Vec3 = return path(Vec3(), j)
+ writer.SetValue("name", name);
+ writer.SetValue("params", params);
+ writer.SetValue("return_type",
+ returnType.empty() ? "" : " : " + returnType);
+ writer += "override fun {{name}}({{params}}){{return_type}} = \\";
+ writer += statement;
+ }
+
+ static std::string OffsetWrapperOneLine(const std::string &offset,
+ const std::string &found,
+ const std::string ¬_found) {
+ return "val o = __offset(" + offset + "); return if (o != 0) " + found +
+ " else " + not_found;
+ }
+
+ static void OffsetWrapper(CodeWriter &code, const std::string &offset,
+ const std::function<void()> &found,
+ const std::function<void()> ¬_found) {
+ code += "val o = __offset(" + offset + ")";
+ code += "return if (o != 0) {";
+ code.IncrementIdentLevel();
+ found();
+ code.DecrementIdentLevel();
+ code += "} else {";
+ code.IncrementIdentLevel();
+ not_found();
+ code.DecrementIdentLevel();
+ code += "}";
+ }
+
+ static std::string Indirect(const std::string &index, bool fixed) {
+ // We apply __indirect() and struct is not fixed.
+ if (!fixed) return "__indirect(" + index + ")";
+ return index;
+ }
+
+ static std::string NotFoundReturn(BaseType el) {
+ switch (el) {
+ case BASE_TYPE_FLOAT: return "0.0f";
+ case BASE_TYPE_DOUBLE: return "0.0";
+ case BASE_TYPE_BOOL: return "false";
+ case BASE_TYPE_LONG:
+ case BASE_TYPE_INT:
+ case BASE_TYPE_CHAR:
+ case BASE_TYPE_SHORT: return "0";
+ case BASE_TYPE_UINT:
+ case BASE_TYPE_UCHAR:
+ case BASE_TYPE_USHORT:
+ case BASE_TYPE_UTYPE: return "0u";
+ case BASE_TYPE_ULONG: return "0uL";
+ default: return "null";
+ }
+ }
+
+ // Prepend @JvmStatic to methods in companion object.
+ static void GenerateJvmStaticAnnotation(CodeWriter &code,
+ bool gen_jvmstatic) {
+ if (gen_jvmstatic) { code += "@JvmStatic"; }
+ }
+
+ // This tracks the current namespace used to determine if a type need to be
+ // prefixed by its namespace
+ const Namespace *cur_name_space_;
};
} // namespace kotlin
bool GenerateKotlin(const Parser &parser, const std::string &path,
const std::string &file_name) {
- kotlin::KotlinGenerator generator(parser, path, file_name);
- return generator.generate();
+ kotlin::KotlinGenerator generator(parser, path, file_name);
+ return generator.generate();
}
} // namespace flatbuffers
diff --git a/src/idl_gen_lobster.cpp b/src/idl_gen_lobster.cpp
index ef9e474..4ebf8ca 100644
--- a/src/idl_gen_lobster.cpp
+++ b/src/idl_gen_lobster.cpp
@@ -27,14 +27,17 @@
class LobsterGenerator : public BaseGenerator {
public:
- LobsterGenerator(const Parser &parser, const std::string &path,
- const std::string &file_name)
- : BaseGenerator(parser, path, file_name, "" /* not used */, "_") {
- static const char * const keywords[] = {
- "nil", "true", "false", "return", "struct", "class", "import", "int",
- "float", "string", "any", "def", "is", "from", "program", "private",
- "coroutine", "resource", "enum", "typeof", "var", "let", "pakfile",
- "switch", "case", "default", "namespace", "not", "and", "or", "bool",
+ LobsterGenerator(const Parser &parser, const std::string &path,
+ const std::string &file_name)
+ : BaseGenerator(parser, path, file_name, "" /* not used */, "_",
+ "lobster") {
+ static const char *const keywords[] = {
+ "nil", "true", "false", "return", "struct", "class",
+ "import", "int", "float", "string", "any", "def",
+ "is", "from", "program", "private", "coroutine", "resource",
+ "enum", "typeof", "var", "let", "pakfile", "switch",
+ "case", "default", "namespace", "not", "and", "or",
+ "bool",
};
keywords_.insert(std::begin(keywords), std::end(keywords));
}
@@ -59,14 +62,15 @@
auto bits = NumToString(SizeOf(type.base_type) * 8);
if (IsInteger(type.base_type)) return "int" + bits;
if (IsFloat(type.base_type)) return "float" + bits;
- if (type.base_type == BASE_TYPE_STRING) return "string";
+ if (IsString(type)) return "string";
if (type.base_type == BASE_TYPE_STRUCT) return "table";
return "none";
}
std::string LobsterType(const Type &type) {
if (IsFloat(type.base_type)) return "float";
- if (IsScalar(type.base_type) && type.enum_def) return NormalizedName(*type.enum_def);
+ if (IsScalar(type.base_type) && type.enum_def)
+ return NormalizedName(*type.enum_def);
if (!IsScalar(type.base_type)) return "flatbuffers_offset";
return "int";
}
@@ -74,27 +78,27 @@
// Returns the method name for use with add/put calls.
std::string GenMethod(const Type &type) {
return IsScalar(type.base_type)
- ? MakeCamel(GenTypeBasic(type))
- : (IsStruct(type) ? "Struct" : "UOffsetTRelative");
+ ? MakeCamel(GenTypeBasic(type))
+ : (IsStruct(type) ? "Struct" : "UOffsetTRelative");
}
// This uses Python names for now..
std::string GenTypeBasic(const Type &type) {
+ // clang-format off
static const char *ctypename[] = {
- // clang-format off
#define FLATBUFFERS_TD(ENUM, IDLTYPE, \
- CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \
+ CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, ...) \
#PTYPE,
- FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
+ FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
#undef FLATBUFFERS_TD
- // clang-format on
};
+ // clang-format on
return ctypename[type.base_type];
}
// Generate a struct field, conditioned on its child type(s).
- void GenStructAccessor(const StructDef &struct_def,
- const FieldDef &field, std::string *code_ptr) {
+ void GenStructAccessor(const StructDef &struct_def, const FieldDef &field,
+ std::string *code_ptr) {
GenComment(field.doc_comment, code_ptr, nullptr, " ");
std::string &code = *code_ptr;
auto offsets = NumToString(field.value.offset);
@@ -102,16 +106,18 @@
if (IsScalar(field.value.type.base_type)) {
std::string acc;
if (struct_def.fixed) {
- acc = "buf_.read_" + GenTypeName(field.value.type) +
- "_le(pos_ + " + offsets + ")";
+ acc = "buf_.read_" + GenTypeName(field.value.type) + "_le(pos_ + " +
+ offsets + ")";
} else {
- acc = "buf_.flatbuffers_field_" +
- GenTypeName(field.value.type) + "(pos_, " + offsets + ", " +
- field.value.constant + ")";
+ auto defval = field.optional ? "0" : field.value.constant;
+ acc = "buf_.flatbuffers_field_" + GenTypeName(field.value.type) +
+ "(pos_, " + offsets + ", " + defval + ")";
}
if (field.value.type.enum_def)
acc = NormalizedName(*field.value.type.enum_def) + "(" + acc + ")";
+ if (field.optional)
+ acc += ", buf_.flatbuffers_field_present(pos_, " + offsets + ")";
code += def + "():\n return " + acc + "\n";
return;
}
@@ -130,7 +136,8 @@
break;
}
case BASE_TYPE_STRING:
- code += def + "():\n return buf_.flatbuffers_field_string(pos_, " +
+ code += def +
+ "():\n return buf_.flatbuffers_field_string(pos_, " +
offsets + ")\n";
break;
case BASE_TYPE_VECTOR: {
@@ -145,7 +152,7 @@
code += NamespacedName(*field.value.type.struct_def) + " { buf_, " +
start + " }\n";
} else {
- if (vectortype.base_type == BASE_TYPE_STRING)
+ if (IsString(vectortype))
code += "buf_.flatbuffers_string";
else
code += "buf_.read_" + GenTypeName(vectortype) + "_le";
@@ -169,21 +176,22 @@
}
default: FLATBUFFERS_ASSERT(0);
}
- if (field.value.type.base_type == BASE_TYPE_VECTOR) {
+ if (IsVector(field.value.type)) {
code += def +
- "_length():\n return buf_.flatbuffers_field_vector_len(pos_, " +
+ "_length():\n return "
+ "buf_.flatbuffers_field_vector_len(pos_, " +
offsets + ")\n";
}
}
// Generate table constructors, conditioned on its members' types.
- void GenTableBuilders(const StructDef &struct_def,
- std::string *code_ptr) {
+ void GenTableBuilders(const StructDef &struct_def, std::string *code_ptr) {
std::string &code = *code_ptr;
code += "struct " + NormalizedName(struct_def) +
"Builder:\n b_:flatbuffers_builder\n";
code += " def start():\n b_.StartObject(" +
- NumToString(struct_def.fields.vec.size()) + ")\n return this\n";
+ NumToString(struct_def.fields.vec.size()) +
+ ")\n return this\n";
for (auto it = struct_def.fields.vec.begin();
it != struct_def.fields.vec.end(); ++it) {
auto &field = **it;
@@ -193,7 +201,7 @@
NormalizedName(field) + ":" + LobsterType(field.value.type) +
"):\n b_.Prepend" + GenMethod(field.value.type) + "Slot(" +
NumToString(offset) + ", " + NormalizedName(field);
- if (IsScalar(field.value.type.base_type))
+ if (IsScalar(field.value.type.base_type) && !field.optional)
code += ", " + field.value.constant;
code += ")\n return this\n";
}
@@ -202,15 +210,15 @@
it != struct_def.fields.vec.end(); ++it) {
auto &field = **it;
if (field.deprecated) continue;
- if (field.value.type.base_type == BASE_TYPE_VECTOR) {
+ if (IsVector(field.value.type)) {
code += "def " + NormalizedName(struct_def) + "Start" +
MakeCamel(NormalizedName(field)) +
"Vector(b_:flatbuffers_builder, n_:int):\n b_.StartVector(";
auto vector_type = field.value.type.VectorType();
auto alignment = InlineAlignment(vector_type);
auto elem_size = InlineSize(vector_type);
- code += NumToString(elem_size) + ", n_, " + NumToString(alignment) +
- ")\n";
+ code +=
+ NumToString(elem_size) + ", n_, " + NumToString(alignment) + ")\n";
if (vector_type.base_type != BASE_TYPE_STRUCT ||
!vector_type.struct_def->fixed) {
code += "def " + NormalizedName(struct_def) + "Create" +
@@ -218,8 +226,7 @@
"Vector(b_:flatbuffers_builder, v_:[" +
LobsterType(vector_type) + "]):\n b_.StartVector(" +
NumToString(elem_size) + ", v_.length, " +
- NumToString(alignment) +
- ")\n reverse(v_) e_: b_.Prepend" +
+ NumToString(alignment) + ")\n reverse(v_) e_: b_.Prepend" +
GenMethod(vector_type) +
"(e_)\n return b_.EndVector(v_.length)\n";
}
@@ -243,7 +250,7 @@
GenComment(struct_def.doc_comment, code_ptr, nullptr, "");
code += "class " + NormalizedName(struct_def) + " : flatbuffers_handle\n";
for (auto it = struct_def.fields.vec.begin();
- it != struct_def.fields.vec.end(); ++it) {
+ it != struct_def.fields.vec.end(); ++it) {
auto &field = **it;
if (field.deprecated) continue;
GenStructAccessor(struct_def, field, code_ptr);
@@ -252,8 +259,8 @@
if (!struct_def.fixed) {
// Generate a special accessor for the table that has been declared as
// the root type.
- code += "def GetRootAs" + NormalizedName(struct_def) + "(buf:string): return " +
- NormalizedName(struct_def) +
+ code += "def GetRootAs" + NormalizedName(struct_def) +
+ "(buf:string): return " + NormalizedName(struct_def) +
" { buf, buf.flatbuffers_indirect(0) }\n\n";
}
if (struct_def.fixed) {
@@ -283,8 +290,8 @@
// Recursively generate arguments for a constructor, to deal with nested
// structs.
- void StructBuilderArgs(const StructDef &struct_def,
- const char *nameprefix, std::string *code_ptr) {
+ void StructBuilderArgs(const StructDef &struct_def, const char *nameprefix,
+ std::string *code_ptr) {
for (auto it = struct_def.fields.vec.begin();
it != struct_def.fields.vec.end(); ++it) {
auto &field = **it;
@@ -293,7 +300,8 @@
// don't clash, and to make it obvious these arguments are constructing
// a nested struct, prefix the name with the field name.
StructBuilderArgs(*field.value.type.struct_def,
- (nameprefix + (NormalizedName(field) + "_")).c_str(), code_ptr);
+ (nameprefix + (NormalizedName(field) + "_")).c_str(),
+ code_ptr);
} else {
std::string &code = *code_ptr;
code += ", " + (nameprefix + NormalizedName(field)) + ":" +
@@ -304,8 +312,8 @@
// Recursively generate struct construction statements and instert manual
// padding.
- void StructBuilderBody(const StructDef &struct_def,
- const char *nameprefix, std::string *code_ptr) {
+ void StructBuilderBody(const StructDef &struct_def, const char *nameprefix,
+ std::string *code_ptr) {
std::string &code = *code_ptr;
code += " b_.Prep(" + NumToString(struct_def.minalign) + ", " +
NumToString(struct_def.bytesize) + ")\n";
@@ -316,7 +324,8 @@
code += " b_.Pad(" + NumToString(field.padding) + ")\n";
if (IsStruct(field.value.type)) {
StructBuilderBody(*field.value.type.struct_def,
- (nameprefix + (NormalizedName(field) + "_")).c_str(), code_ptr);
+ (nameprefix + (NormalizedName(field) + "_")).c_str(),
+ code_ptr);
} else {
code += " b_.Prepend" + GenMethod(field.value.type) + "(" +
nameprefix + NormalizedName(field) + ")\n";
@@ -325,11 +334,10 @@
}
// Create a struct with a builder and the struct's arguments.
- void GenStructBuilder(const StructDef &struct_def,
- std::string *code_ptr) {
+ void GenStructBuilder(const StructDef &struct_def, std::string *code_ptr) {
std::string &code = *code_ptr;
- code += "def Create" + NormalizedName(struct_def) +
- "(b_:flatbuffers_builder";
+ code +=
+ "def Create" + NormalizedName(struct_def) + "(b_:flatbuffers_builder";
StructBuilderArgs(struct_def, "", code_ptr);
code += "):\n";
StructBuilderBody(struct_def, "", code_ptr);
@@ -363,7 +371,7 @@
auto &struct_def = **it;
GenStruct(struct_def, &code);
}
- return SaveFile((path_ + file_name_ + "_generated.lobster").c_str(),
+ return SaveFile(GeneratedFileName(path_, file_name_, parser_.opts).c_str(),
code, false);
}
@@ -375,7 +383,7 @@
} // namespace lobster
bool GenerateLobster(const Parser &parser, const std::string &path,
- const std::string &file_name) {
+ const std::string &file_name) {
lobster::LobsterGenerator generator(parser, path, file_name);
return generator.generate();
}
diff --git a/src/idl_gen_lua.cpp b/src/idl_gen_lua.cpp
index 10df231..9788485 100644
--- a/src/idl_gen_lua.cpp
+++ b/src/idl_gen_lua.cpp
@@ -14,716 +14,710 @@
* limitations under the License.
*/
- // independent from idl_parser, since this code is not needed for most clients
+// independent from idl_parser, since this code is not needed for most clients
#include <string>
+#include <unordered_set>
#include "flatbuffers/code_generators.h"
#include "flatbuffers/flatbuffers.h"
#include "flatbuffers/idl.h"
#include "flatbuffers/util.h"
-#include <unordered_set>
-
namespace flatbuffers {
namespace lua {
- // Hardcode spaces per indentation.
- const CommentConfig def_comment = { nullptr, "--", nullptr };
- const char * Indent = " ";
- const char * Comment = "-- ";
- const char * End = "end\n";
- const char * EndFunc = "end\n";
- const char * SelfData = "self.view";
- const char * SelfDataPos = "self.view.pos";
- const char * SelfDataBytes = "self.view.bytes";
+// Hardcode spaces per indentation.
+const CommentConfig def_comment = { nullptr, "--", nullptr };
+const char *Indent = " ";
+const char *Comment = "-- ";
+const char *End = "end\n";
+const char *EndFunc = "end\n";
+const char *SelfData = "self.view";
+const char *SelfDataPos = "self.view.pos";
+const char *SelfDataBytes = "self.view.bytes";
- class LuaGenerator : public BaseGenerator {
- public:
- LuaGenerator(const Parser &parser, const std::string &path,
- const std::string &file_name)
+class LuaGenerator : public BaseGenerator {
+ public:
+ LuaGenerator(const Parser &parser, const std::string &path,
+ const std::string &file_name)
: BaseGenerator(parser, path, file_name, "" /* not used */,
- "" /* not used */) {
- static const char * const keywords[] = {
- "and",
- "break",
- "do",
- "else",
- "elseif",
- "end",
- "false",
- "for",
- "function",
- "goto",
- "if",
- "in",
- "local",
- "nil",
- "not",
- "or",
- "repeat",
- "return",
- "then",
- "true",
- "until",
- "while"
- };
- keywords_.insert(std::begin(keywords), std::end(keywords));
+ "" /* not used */, "lua") {
+ static const char *const keywords[] = {
+ "and", "break", "do", "else", "elseif", "end", "false", "for",
+ "function", "goto", "if", "in", "local", "nil", "not", "or",
+ "repeat", "return", "then", "true", "until", "while"
+ };
+ keywords_.insert(std::begin(keywords), std::end(keywords));
+ }
+
+ // Most field accessors need to retrieve and test the field offset first,
+ // this is the prefix code for that.
+ std::string OffsetPrefix(const FieldDef &field) {
+ return std::string(Indent) + "local o = " + SelfData + ":Offset(" +
+ NumToString(field.value.offset) + ")\n" + Indent +
+ "if o ~= 0 then\n";
+ }
+
+ // Begin a class declaration.
+ void BeginClass(const StructDef &struct_def, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "local " + NormalizedName(struct_def) + " = {} -- the module\n";
+ code += "local " + NormalizedMetaName(struct_def) +
+ " = {} -- the class metatable\n";
+ code += "\n";
+ }
+
+ // Begin enum code with a class declaration.
+ void BeginEnum(const std::string &class_name, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "local " + class_name + " = {\n";
+ }
+
+ std::string EscapeKeyword(const std::string &name) const {
+ return keywords_.find(name) == keywords_.end() ? name : "_" + name;
+ }
+
+ std::string NormalizedName(const Definition &definition) const {
+ return EscapeKeyword(definition.name);
+ }
+
+ std::string NormalizedName(const EnumVal &ev) const {
+ return EscapeKeyword(ev.name);
+ }
+
+ std::string NormalizedMetaName(const Definition &definition) const {
+ return EscapeKeyword(definition.name) + "_mt";
+ }
+
+ // A single enum member.
+ void EnumMember(const EnumDef &enum_def, const EnumVal &ev,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += std::string(Indent) + NormalizedName(ev) + " = " +
+ enum_def.ToString(ev) + ",\n";
+ }
+
+ // End enum code.
+ void EndEnum(std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "}\n";
+ }
+
+ void GenerateNewObjectPrototype(const StructDef &struct_def,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+ code += "function " + NormalizedName(struct_def) + ".New()\n";
+ code += std::string(Indent) + "local o = {}\n";
+ code += std::string(Indent) +
+ "setmetatable(o, {__index = " + NormalizedMetaName(struct_def) +
+ "})\n";
+ code += std::string(Indent) + "return o\n";
+ code += EndFunc;
+ }
+
+ // Initialize a new struct or table from existing data.
+ void NewRootTypeFromBuffer(const StructDef &struct_def,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+ code += "function " + NormalizedName(struct_def) + ".GetRootAs" +
+ NormalizedName(struct_def) + "(buf, offset)\n";
+ code += std::string(Indent) +
+ "local n = flatbuffers.N.UOffsetT:Unpack(buf, offset)\n";
+ code += std::string(Indent) + "local o = " + NormalizedName(struct_def) +
+ ".New()\n";
+ code += std::string(Indent) + "o:Init(buf, n + offset)\n";
+ code += std::string(Indent) + "return o\n";
+ code += EndFunc;
+ }
+
+ // Initialize an existing object with other data, to avoid an allocation.
+ void InitializeExisting(const StructDef &struct_def, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+ GenReceiver(struct_def, code_ptr);
+ code += "Init(buf, pos)\n";
+ code +=
+ std::string(Indent) + SelfData + " = flatbuffers.view.New(buf, pos)\n";
+ code += EndFunc;
+ }
+
+ // Get the length of a vector.
+ void GetVectorLen(const StructDef &struct_def, const FieldDef &field,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+ GenReceiver(struct_def, code_ptr);
+ code += MakeCamel(NormalizedName(field)) + "Length()\n";
+ code += OffsetPrefix(field);
+ code +=
+ std::string(Indent) + Indent + "return " + SelfData + ":VectorLen(o)\n";
+ code += std::string(Indent) + End;
+ code += std::string(Indent) + "return 0\n";
+ code += EndFunc;
+ }
+
+ // Get the value of a struct's scalar.
+ void GetScalarFieldOfStruct(const StructDef &struct_def,
+ const FieldDef &field, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ std::string getter = GenGetter(field.value.type);
+ GenReceiver(struct_def, code_ptr);
+ code += MakeCamel(NormalizedName(field));
+ code += "()\n";
+ code += std::string(Indent) + "return " + getter;
+ code += std::string(SelfDataPos) + " + " + NumToString(field.value.offset) +
+ ")\n";
+ code += EndFunc;
+ }
+
+ // Get the value of a table's scalar.
+ void GetScalarFieldOfTable(const StructDef &struct_def, const FieldDef &field,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ std::string getter = GenGetter(field.value.type);
+ GenReceiver(struct_def, code_ptr);
+ code += MakeCamel(NormalizedName(field));
+ code += "()\n";
+ code += OffsetPrefix(field);
+ getter += std::string("o + ") + SelfDataPos + ")";
+ auto is_bool = field.value.type.base_type == BASE_TYPE_BOOL;
+ if (is_bool) { getter = "(" + getter + " ~= 0)"; }
+ code += std::string(Indent) + Indent + "return " + getter + "\n";
+ code += std::string(Indent) + End;
+ std::string default_value;
+ if (is_bool) {
+ default_value = field.value.constant == "0" ? "false" : "true";
+ } else {
+ default_value = field.value.constant;
}
+ code += std::string(Indent) + "return " + default_value + "\n";
+ code += EndFunc;
+ }
- // Most field accessors need to retrieve and test the field offset first,
- // this is the prefix code for that.
- std::string OffsetPrefix(const FieldDef &field) {
- return std::string(Indent) +
- "local o = " + SelfData + ":Offset(" + NumToString(field.value.offset) + ")\n" +
- Indent + "if o ~= 0 then\n";
+ // Get a struct by initializing an existing struct.
+ // Specific to Struct.
+ void GetStructFieldOfStruct(const StructDef &struct_def,
+ const FieldDef &field, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ GenReceiver(struct_def, code_ptr);
+ code += MakeCamel(NormalizedName(field));
+ code += "(obj)\n";
+ code += std::string(Indent) + "obj:Init(" + SelfDataBytes + ", " +
+ SelfDataPos + " + ";
+ code += NumToString(field.value.offset) + ")\n";
+ code += std::string(Indent) + "return obj\n";
+ code += EndFunc;
+ }
+
+ // Get a struct by initializing an existing struct.
+ // Specific to Table.
+ void GetStructFieldOfTable(const StructDef &struct_def, const FieldDef &field,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ GenReceiver(struct_def, code_ptr);
+ code += MakeCamel(NormalizedName(field));
+ code += "()\n";
+ code += OffsetPrefix(field);
+ if (field.value.type.struct_def->fixed) {
+ code +=
+ std::string(Indent) + Indent + "local x = o + " + SelfDataPos + "\n";
+ } else {
+ code += std::string(Indent) + Indent + "local x = " + SelfData +
+ ":Indirect(o + " + SelfDataPos + ")\n";
}
+ code += std::string(Indent) + Indent + "local obj = require('" +
+ TypeNameWithNamespace(field) + "').New()\n";
+ code +=
+ std::string(Indent) + Indent + "obj:Init(" + SelfDataBytes + ", x)\n";
+ code += std::string(Indent) + Indent + "return obj\n";
+ code += std::string(Indent) + End;
+ code += EndFunc;
+ }
- // Begin a class declaration.
- void BeginClass(const StructDef &struct_def, std::string *code_ptr) {
- std::string &code = *code_ptr;
- code += "local " + NormalizedName(struct_def) + " = {} -- the module\n";
- code += "local " + NormalizedMetaName(struct_def) + " = {} -- the class metatable\n";
- code += "\n";
+ // Get the value of a string.
+ void GetStringField(const StructDef &struct_def, const FieldDef &field,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ GenReceiver(struct_def, code_ptr);
+ code += MakeCamel(NormalizedName(field));
+ code += "()\n";
+ code += OffsetPrefix(field);
+ code +=
+ std::string(Indent) + Indent + "return " + GenGetter(field.value.type);
+ code += std::string("o + ") + SelfDataPos + ")\n";
+ code += std::string(Indent) + End;
+ code += EndFunc;
+ }
+
+ // Get the value of a union from an object.
+ void GetUnionField(const StructDef &struct_def, const FieldDef &field,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ GenReceiver(struct_def, code_ptr);
+ code += MakeCamel(NormalizedName(field)) + "()\n";
+ code += OffsetPrefix(field);
+
+ // TODO(rw): this works and is not the good way to it:
+ // bool is_native_table = TypeName(field) == "*flatbuffers.Table";
+ // if (is_native_table) {
+ // code += std::string(Indent) + Indent + "from flatbuffers.table import
+ // Table\n";
+ //} else {
+ // code += std::string(Indent) + Indent +
+ // code += "from ." + TypeName(field) + " import " + TypeName(field) +
+ // "\n";
+ //}
+ code +=
+ std::string(Indent) + Indent +
+ "local obj = "
+ "flatbuffers.view.New(require('flatbuffers.binaryarray').New(0), 0)\n";
+ code += std::string(Indent) + Indent + GenGetter(field.value.type) +
+ "obj, o)\n";
+ code += std::string(Indent) + Indent + "return obj\n";
+ code += std::string(Indent) + End;
+ code += EndFunc;
+ }
+
+ // Get the value of a vector's struct member.
+ void GetMemberOfVectorOfStruct(const StructDef &struct_def,
+ const FieldDef &field, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ auto vectortype = field.value.type.VectorType();
+
+ GenReceiver(struct_def, code_ptr);
+ code += MakeCamel(NormalizedName(field));
+ code += "(j)\n";
+ code += OffsetPrefix(field);
+ code +=
+ std::string(Indent) + Indent + "local x = " + SelfData + ":Vector(o)\n";
+ code += std::string(Indent) + Indent + "x = x + ((j-1) * ";
+ code += NumToString(InlineSize(vectortype)) + ")\n";
+ if (!(vectortype.struct_def->fixed)) {
+ code +=
+ std::string(Indent) + Indent + "x = " + SelfData + ":Indirect(x)\n";
}
+ code += std::string(Indent) + Indent + "local obj = require('" +
+ TypeNameWithNamespace(field) + "').New()\n";
+ code +=
+ std::string(Indent) + Indent + "obj:Init(" + SelfDataBytes + ", x)\n";
+ code += std::string(Indent) + Indent + "return obj\n";
+ code += std::string(Indent) + End;
+ code += EndFunc;
+ }
- // Begin enum code with a class declaration.
- void BeginEnum(const std::string &class_name, std::string *code_ptr) {
- std::string &code = *code_ptr;
- code += "local " + class_name + " = {\n";
- }
+ // Get the value of a vector's non-struct member. Uses a named return
+ // argument to conveniently set the zero value for the result.
+ void GetMemberOfVectorOfNonStruct(const StructDef &struct_def,
+ const FieldDef &field,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ auto vectortype = field.value.type.VectorType();
- std::string EscapeKeyword(const std::string &name) const {
- return keywords_.find(name) == keywords_.end() ? name : "_" + name;
- }
-
- std::string NormalizedName(const Definition &definition) const {
- return EscapeKeyword(definition.name);
- }
-
- std::string NormalizedName(const EnumVal &ev) const {
- return EscapeKeyword(ev.name);
- }
-
- std::string NormalizedMetaName(const Definition &definition) const {
- return EscapeKeyword(definition.name) + "_mt";
- }
-
- // A single enum member.
- void EnumMember(const EnumDef &enum_def, const EnumVal &ev, std::string *code_ptr) {
- std::string &code = *code_ptr;
- code += std::string(Indent) + NormalizedName(ev) + " = " +
- enum_def.ToString(ev) + ",\n";
- }
-
- // End enum code.
- void EndEnum(std::string *code_ptr) {
- std::string &code = *code_ptr;
- code += "}\n";
- }
-
- void GenerateNewObjectPrototype(const StructDef &struct_def,
- std::string *code_ptr) {
- std::string &code = *code_ptr;
-
- code += "function " + NormalizedName(struct_def) + ".New()\n";
- code += std::string(Indent) + "local o = {}\n";
- code += std::string(Indent) + "setmetatable(o, {__index = " + NormalizedMetaName(struct_def) + "})\n";
- code += std::string(Indent) + "return o\n";
- code += EndFunc;
- }
-
- // Initialize a new struct or table from existing data.
- void NewRootTypeFromBuffer(const StructDef &struct_def,
- std::string *code_ptr) {
- std::string &code = *code_ptr;
-
- code += "function " + NormalizedName(struct_def) + ".GetRootAs" + NormalizedName(struct_def) + "(buf, offset)\n";
- code += std::string(Indent) + "local n = flatbuffers.N.UOffsetT:Unpack(buf, offset)\n";
- code += std::string(Indent) + "local o = " + NormalizedName(struct_def) + ".New()\n";
- code += std::string(Indent) + "o:Init(buf, n + offset)\n";
- code += std::string(Indent) + "return o\n";
- code += EndFunc;
- }
-
- // Initialize an existing object with other data, to avoid an allocation.
- void InitializeExisting(const StructDef &struct_def,
- std::string *code_ptr) {
- std::string &code = *code_ptr;
-
- GenReceiver(struct_def, code_ptr);
- code += "Init(buf, pos)\n";
- code += std::string(Indent) + SelfData + " = flatbuffers.view.New(buf, pos)\n";
- code += EndFunc;
- }
-
- // Get the length of a vector.
- void GetVectorLen(const StructDef &struct_def, const FieldDef &field,
- std::string *code_ptr) {
- std::string &code = *code_ptr;
-
- GenReceiver(struct_def, code_ptr);
- code += MakeCamel(NormalizedName(field)) + "Length()\n";
- code += OffsetPrefix(field);
- code += std::string(Indent) + Indent + "return " + SelfData + ":VectorLen(o)\n";
- code += std::string(Indent) + End;
+ GenReceiver(struct_def, code_ptr);
+ code += MakeCamel(NormalizedName(field));
+ code += "(j)\n";
+ code += OffsetPrefix(field);
+ code +=
+ std::string(Indent) + Indent + "local a = " + SelfData + ":Vector(o)\n";
+ code += std::string(Indent) + Indent;
+ code += "return " + GenGetter(field.value.type);
+ code += "a + ((j-1) * ";
+ code += NumToString(InlineSize(vectortype)) + "))\n";
+ code += std::string(Indent) + End;
+ if (IsString(vectortype)) {
+ code += std::string(Indent) + "return ''\n";
+ } else {
code += std::string(Indent) + "return 0\n";
- code += EndFunc;
}
+ code += EndFunc;
+ }
- // Get the value of a struct's scalar.
- void GetScalarFieldOfStruct(const StructDef &struct_def,
- const FieldDef &field,
- std::string *code_ptr) {
- std::string &code = *code_ptr;
- std::string getter = GenGetter(field.value.type);
- GenReceiver(struct_def, code_ptr);
- code += MakeCamel(NormalizedName(field));
- code += "()\n";
- code += std::string(Indent) + "return " + getter;
- code += std::string(SelfDataPos) + " + " + NumToString(field.value.offset) + ")\n";
- code += EndFunc;
- }
+ // Begin the creator function signature.
+ void BeginBuilderArgs(const StructDef &struct_def, std::string *code_ptr) {
+ std::string &code = *code_ptr;
- // Get the value of a table's scalar.
- void GetScalarFieldOfTable(const StructDef &struct_def,
- const FieldDef &field,
- std::string *code_ptr) {
- std::string &code = *code_ptr;
- std::string getter = GenGetter(field.value.type);
- GenReceiver(struct_def, code_ptr);
- code += MakeCamel(NormalizedName(field));
- code += "()\n";
- code += OffsetPrefix(field);
- getter += std::string("o + ") + SelfDataPos + ")";
- auto is_bool = field.value.type.base_type == BASE_TYPE_BOOL;
- if (is_bool) {
- getter = "(" + getter + " ~= 0)";
- }
- code += std::string(Indent) + Indent + "return " + getter + "\n";
- code += std::string(Indent) + End;
- std::string default_value;
- if (is_bool) {
- default_value = field.value.constant == "0" ? "false" : "true";
- }
- else {
- default_value = field.value.constant;
- }
- code += std::string(Indent) + "return " + default_value + "\n";
- code += EndFunc;
- }
+ code += "function " + NormalizedName(struct_def) + ".Create" +
+ NormalizedName(struct_def);
+ code += "(builder";
+ }
- // Get a struct by initializing an existing struct.
- // Specific to Struct.
- void GetStructFieldOfStruct(const StructDef &struct_def,
- const FieldDef &field,
- std::string *code_ptr) {
- std::string &code = *code_ptr;
- GenReceiver(struct_def, code_ptr);
- code += MakeCamel(NormalizedName(field));
- code += "(obj)\n";
- code += std::string(Indent) + "obj:Init(" + SelfDataBytes + ", " + SelfDataPos + " + ";
- code += NumToString(field.value.offset) + ")\n";
- code += std::string(Indent) + "return obj\n";
- code += EndFunc;
- }
-
- // Get a struct by initializing an existing struct.
- // Specific to Table.
- void GetStructFieldOfTable(const StructDef &struct_def,
- const FieldDef &field,
- std::string *code_ptr) {
- std::string &code = *code_ptr;
- GenReceiver(struct_def, code_ptr);
- code += MakeCamel(NormalizedName(field));
- code += "()\n";
- code += OffsetPrefix(field);
- if (field.value.type.struct_def->fixed) {
- code += std::string(Indent) + Indent + "local x = o + " + SelfDataPos + "\n";
- }
- else {
- code += std::string(Indent) + Indent + "local x = " + SelfData + ":Indirect(o + " + SelfDataPos + ")\n";
- }
- code += std::string(Indent) + Indent + "local obj = require('" + TypeNameWithNamespace(field) + "').New()\n";
- code += std::string(Indent) + Indent + "obj:Init(" + SelfDataBytes + ", x)\n";
- code += std::string(Indent) + Indent + "return obj\n";
- code += std::string(Indent) + End;
- code += EndFunc;
- }
-
- // Get the value of a string.
- void GetStringField(const StructDef &struct_def, const FieldDef &field,
- std::string *code_ptr) {
- std::string &code = *code_ptr;
- GenReceiver(struct_def, code_ptr);
- code += MakeCamel(NormalizedName(field));
- code += "()\n";
- code += OffsetPrefix(field);
- code += std::string(Indent) + Indent + "return " + GenGetter(field.value.type);
- code += std::string("o + ") + SelfDataPos + ")\n";
- code += std::string(Indent) + End;
- code += EndFunc;
- }
-
- // Get the value of a union from an object.
- void GetUnionField(const StructDef &struct_def, const FieldDef &field,
- std::string *code_ptr) {
- std::string &code = *code_ptr;
- GenReceiver(struct_def, code_ptr);
- code += MakeCamel(NormalizedName(field)) + "()\n";
- code += OffsetPrefix(field);
-
- // TODO(rw): this works and is not the good way to it:
- //bool is_native_table = TypeName(field) == "*flatbuffers.Table";
- //if (is_native_table) {
- // code += std::string(Indent) + Indent + "from flatbuffers.table import Table\n";
- //} else {
- // code += std::string(Indent) + Indent +
- // code += "from ." + TypeName(field) + " import " + TypeName(field) + "\n";
- //}
- code += std::string(Indent) + Indent + "local obj = flatbuffers.view.New(require('flatbuffers.binaryarray').New(0), 0)\n";
- code += std::string(Indent) + Indent + GenGetter(field.value.type) + "obj, o)\n";
- code += std::string(Indent) + Indent + "return obj\n";
- code += std::string(Indent) + End;
- code += EndFunc;
- }
-
- // Get the value of a vector's struct member.
- void GetMemberOfVectorOfStruct(const StructDef &struct_def,
- const FieldDef &field,
- std::string *code_ptr) {
- std::string &code = *code_ptr;
- auto vectortype = field.value.type.VectorType();
-
- GenReceiver(struct_def, code_ptr);
- code += MakeCamel(NormalizedName(field));
- code += "(j)\n";
- code += OffsetPrefix(field);
- code += std::string(Indent) + Indent + "local x = " + SelfData + ":Vector(o)\n";
- code += std::string(Indent) + Indent + "x = x + ((j-1) * ";
- code += NumToString(InlineSize(vectortype)) + ")\n";
- if (!(vectortype.struct_def->fixed)) {
- code += std::string(Indent) + Indent + "x = " + SelfData + ":Indirect(x)\n";
- }
- code += std::string(Indent) + Indent + "local obj = require('" + TypeNameWithNamespace(field) + "').New()\n";
- code += std::string(Indent) + Indent + "obj:Init(" + SelfDataBytes + ", x)\n";
- code += std::string(Indent) + Indent + "return obj\n";
- code += std::string(Indent) + End;
- code += EndFunc;
- }
-
- // Get the value of a vector's non-struct member. Uses a named return
- // argument to conveniently set the zero value for the result.
- void GetMemberOfVectorOfNonStruct(const StructDef &struct_def,
- const FieldDef &field,
- std::string *code_ptr) {
- std::string &code = *code_ptr;
- auto vectortype = field.value.type.VectorType();
-
- GenReceiver(struct_def, code_ptr);
- code += MakeCamel(NormalizedName(field));
- code += "(j)\n";
- code += OffsetPrefix(field);
- code += std::string(Indent) + Indent + "local a = " + SelfData + ":Vector(o)\n";
- code += std::string(Indent) + Indent;
- code += "return " + GenGetter(field.value.type);
- code += "a + ((j-1) * ";
- code += NumToString(InlineSize(vectortype)) + "))\n";
- code += std::string(Indent) + End;
- if (vectortype.base_type == BASE_TYPE_STRING) {
- code += std::string(Indent) + "return ''\n";
- }
- else {
- code += std::string(Indent) + "return 0\n";
- }
- code += EndFunc;
- }
-
- // Begin the creator function signature.
- void BeginBuilderArgs(const StructDef &struct_def,
- std::string *code_ptr) {
- std::string &code = *code_ptr;
-
- code += "function " + NormalizedName(struct_def) + ".Create" + NormalizedName(struct_def);
- code += "(builder";
- }
-
- // Recursively generate arguments for a constructor, to deal with nested
- // structs.
- void StructBuilderArgs(const StructDef &struct_def,
- const char *nameprefix, std::string *code_ptr) {
- for (auto it = struct_def.fields.vec.begin();
- it != struct_def.fields.vec.end(); ++it) {
- auto &field = **it;
- if (IsStruct(field.value.type)) {
- // Generate arguments for a struct inside a struct. To ensure names
- // don't clash, and to make it obvious these arguments are constructing
- // a nested struct, prefix the name with the field name.
- StructBuilderArgs(*field.value.type.struct_def,
- (nameprefix + (NormalizedName(field) + "_")).c_str(), code_ptr);
- }
- else {
- std::string &code = *code_ptr;
- code += std::string(", ") + nameprefix;
- code += MakeCamel(NormalizedName(field), false);
- }
+ // Recursively generate arguments for a constructor, to deal with nested
+ // structs.
+ void StructBuilderArgs(const StructDef &struct_def, const char *nameprefix,
+ std::string *code_ptr) {
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (IsStruct(field.value.type)) {
+ // Generate arguments for a struct inside a struct. To ensure names
+ // don't clash, and to make it obvious these arguments are constructing
+ // a nested struct, prefix the name with the field name.
+ StructBuilderArgs(*field.value.type.struct_def,
+ (nameprefix + (NormalizedName(field) + "_")).c_str(),
+ code_ptr);
+ } else {
+ std::string &code = *code_ptr;
+ code += std::string(", ") + nameprefix;
+ code += MakeCamel(NormalizedName(field), false);
}
}
+ }
- // End the creator function signature.
- void EndBuilderArgs(std::string *code_ptr) {
- std::string &code = *code_ptr;
- code += ")\n";
- }
+ // End the creator function signature.
+ void EndBuilderArgs(std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += ")\n";
+ }
- // Recursively generate struct construction statements and instert manual
- // padding.
- void StructBuilderBody(const StructDef &struct_def,
- const char *nameprefix, std::string *code_ptr) {
- std::string &code = *code_ptr;
- code += std::string(Indent) + "builder:Prep(" + NumToString(struct_def.minalign) + ", ";
- code += NumToString(struct_def.bytesize) + ")\n";
- for (auto it = struct_def.fields.vec.rbegin();
- it != struct_def.fields.vec.rend(); ++it) {
- auto &field = **it;
- if (field.padding)
- code += std::string(Indent) + "builder:Pad(" + NumToString(field.padding) + ")\n";
- if (IsStruct(field.value.type)) {
- StructBuilderBody(*field.value.type.struct_def,
- (nameprefix + (NormalizedName(field) + "_")).c_str(), code_ptr);
- }
- else {
- code += std::string(Indent) + "builder:Prepend" + GenMethod(field) + "(";
- code += nameprefix + MakeCamel(NormalizedName(field), false) + ")\n";
- }
+ // Recursively generate struct construction statements and instert manual
+ // padding.
+ void StructBuilderBody(const StructDef &struct_def, const char *nameprefix,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += std::string(Indent) + "builder:Prep(" +
+ NumToString(struct_def.minalign) + ", ";
+ code += NumToString(struct_def.bytesize) + ")\n";
+ for (auto it = struct_def.fields.vec.rbegin();
+ it != struct_def.fields.vec.rend(); ++it) {
+ auto &field = **it;
+ if (field.padding)
+ code += std::string(Indent) + "builder:Pad(" +
+ NumToString(field.padding) + ")\n";
+ if (IsStruct(field.value.type)) {
+ StructBuilderBody(*field.value.type.struct_def,
+ (nameprefix + (NormalizedName(field) + "_")).c_str(),
+ code_ptr);
+ } else {
+ code +=
+ std::string(Indent) + "builder:Prepend" + GenMethod(field) + "(";
+ code += nameprefix + MakeCamel(NormalizedName(field), false) + ")\n";
}
}
+ }
- void EndBuilderBody(std::string *code_ptr) {
- std::string &code = *code_ptr;
- code += std::string(Indent) + "return builder:Offset()\n";
- code += EndFunc;
- }
+ void EndBuilderBody(std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += std::string(Indent) + "return builder:Offset()\n";
+ code += EndFunc;
+ }
- // Get the value of a table's starting offset.
- void GetStartOfTable(const StructDef &struct_def,
- std::string *code_ptr) {
- std::string &code = *code_ptr;
- code += "function " + NormalizedName(struct_def) + ".Start";
- code += "(builder) ";
- code += "builder:StartObject(";
- code += NumToString(struct_def.fields.vec.size());
- code += ") end\n";
- }
+ // Get the value of a table's starting offset.
+ void GetStartOfTable(const StructDef &struct_def, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "function " + NormalizedName(struct_def) + ".Start";
+ code += "(builder) ";
+ code += "builder:StartObject(";
+ code += NumToString(struct_def.fields.vec.size());
+ code += ") end\n";
+ }
- // Set the value of a table's field.
- void BuildFieldOfTable(const StructDef &struct_def,
- const FieldDef &field, const size_t offset,
- std::string *code_ptr) {
- std::string &code = *code_ptr;
- code += "function " + NormalizedName(struct_def) + ".Add" + MakeCamel(NormalizedName(field));
- code += "(builder, ";
- code += MakeCamel(NormalizedName(field), false);
- code += ") ";
- code += "builder:Prepend";
- code += GenMethod(field) + "Slot(";
- code += NumToString(offset) + ", ";
- // todo: i don't need to cast in Lua, but am I missing something?
+ // Set the value of a table's field.
+ void BuildFieldOfTable(const StructDef &struct_def, const FieldDef &field,
+ const size_t offset, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "function " + NormalizedName(struct_def) + ".Add" +
+ MakeCamel(NormalizedName(field));
+ code += "(builder, ";
+ code += MakeCamel(NormalizedName(field), false);
+ code += ") ";
+ code += "builder:Prepend";
+ code += GenMethod(field) + "Slot(";
+ code += NumToString(offset) + ", ";
+ // todo: i don't need to cast in Lua, but am I missing something?
// if (!IsScalar(field.value.type.base_type) && (!struct_def.fixed)) {
// code += "flatbuffers.N.UOffsetTFlags.py_type";
// code += "(";
// code += MakeCamel(NormalizedName(field), false) + ")";
// } else {
- code += MakeCamel(NormalizedName(field), false);
- // }
- code += ", " + field.value.constant;
- code += ") end\n";
- }
+ code += MakeCamel(NormalizedName(field), false);
+ // }
+ code += ", " + field.value.constant;
+ code += ") end\n";
+ }
- // Set the value of one of the members of a table's vector.
- void BuildVectorOfTable(const StructDef &struct_def,
- const FieldDef &field, std::string *code_ptr) {
- std::string &code = *code_ptr;
- code += "function " + NormalizedName(struct_def) + ".Start";
- code += MakeCamel(NormalizedName(field));
- code += "Vector(builder, numElems) return builder:StartVector(";
- auto vector_type = field.value.type.VectorType();
- auto alignment = InlineAlignment(vector_type);
- auto elem_size = InlineSize(vector_type);
- code += NumToString(elem_size);
- code += ", numElems, " + NumToString(alignment);
- code += ") end\n";
- }
+ // Set the value of one of the members of a table's vector.
+ void BuildVectorOfTable(const StructDef &struct_def, const FieldDef &field,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "function " + NormalizedName(struct_def) + ".Start";
+ code += MakeCamel(NormalizedName(field));
+ code += "Vector(builder, numElems) return builder:StartVector(";
+ auto vector_type = field.value.type.VectorType();
+ auto alignment = InlineAlignment(vector_type);
+ auto elem_size = InlineSize(vector_type);
+ code += NumToString(elem_size);
+ code += ", numElems, " + NumToString(alignment);
+ code += ") end\n";
+ }
- // Get the offset of the end of a table.
- void GetEndOffsetOnTable(const StructDef &struct_def,
- std::string *code_ptr) {
- std::string &code = *code_ptr;
- code += "function " + NormalizedName(struct_def) + ".End";
- code += "(builder) ";
- code += "return builder:EndObject() end\n";
- }
+ // Get the offset of the end of a table.
+ void GetEndOffsetOnTable(const StructDef &struct_def, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "function " + NormalizedName(struct_def) + ".End";
+ code += "(builder) ";
+ code += "return builder:EndObject() end\n";
+ }
- // Generate the receiver for function signatures.
- void GenReceiver(const StructDef &struct_def, std::string *code_ptr) {
- std::string &code = *code_ptr;
- code += "function " + NormalizedMetaName(struct_def) + ":";
- }
+ // Generate the receiver for function signatures.
+ void GenReceiver(const StructDef &struct_def, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "function " + NormalizedMetaName(struct_def) + ":";
+ }
- // Generate a struct field, conditioned on its child type(s).
- void GenStructAccessor(const StructDef &struct_def,
- const FieldDef &field, std::string *code_ptr) {
- GenComment(field.doc_comment, code_ptr, &def_comment);
- if (IsScalar(field.value.type.base_type)) {
- if (struct_def.fixed) {
- GetScalarFieldOfStruct(struct_def, field, code_ptr);
- }
- else {
- GetScalarFieldOfTable(struct_def, field, code_ptr);
- }
+ // Generate a struct field, conditioned on its child type(s).
+ void GenStructAccessor(const StructDef &struct_def, const FieldDef &field,
+ std::string *code_ptr) {
+ GenComment(field.doc_comment, code_ptr, &def_comment);
+ if (IsScalar(field.value.type.base_type)) {
+ if (struct_def.fixed) {
+ GetScalarFieldOfStruct(struct_def, field, code_ptr);
+ } else {
+ GetScalarFieldOfTable(struct_def, field, code_ptr);
}
- else {
- switch (field.value.type.base_type) {
+ } else {
+ switch (field.value.type.base_type) {
case BASE_TYPE_STRUCT:
if (struct_def.fixed) {
GetStructFieldOfStruct(struct_def, field, code_ptr);
- }
- else {
+ } else {
GetStructFieldOfTable(struct_def, field, code_ptr);
}
break;
- case BASE_TYPE_STRING: GetStringField(struct_def, field, code_ptr); break;
+ case BASE_TYPE_STRING:
+ GetStringField(struct_def, field, code_ptr);
+ break;
case BASE_TYPE_VECTOR: {
auto vectortype = field.value.type.VectorType();
if (vectortype.base_type == BASE_TYPE_STRUCT) {
GetMemberOfVectorOfStruct(struct_def, field, code_ptr);
- }
- else {
+ } else {
GetMemberOfVectorOfNonStruct(struct_def, field, code_ptr);
}
break;
}
case BASE_TYPE_UNION: GetUnionField(struct_def, field, code_ptr); break;
default: FLATBUFFERS_ASSERT(0);
- }
}
- if (field.value.type.base_type == BASE_TYPE_VECTOR) {
- GetVectorLen(struct_def, field, code_ptr);
+ }
+ if (IsVector(field.value.type)) {
+ GetVectorLen(struct_def, field, code_ptr);
+ }
+ }
+
+ // Generate table constructors, conditioned on its members' types.
+ void GenTableBuilders(const StructDef &struct_def, std::string *code_ptr) {
+ GetStartOfTable(struct_def, code_ptr);
+
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+
+ auto offset = it - struct_def.fields.vec.begin();
+ BuildFieldOfTable(struct_def, field, offset, code_ptr);
+ if (IsVector(field.value.type)) {
+ BuildVectorOfTable(struct_def, field, code_ptr);
}
}
- // Generate table constructors, conditioned on its members' types.
- void GenTableBuilders(const StructDef &struct_def,
- std::string *code_ptr) {
- GetStartOfTable(struct_def, code_ptr);
+ GetEndOffsetOnTable(struct_def, code_ptr);
+ }
- for (auto it = struct_def.fields.vec.begin();
- it != struct_def.fields.vec.end(); ++it) {
- auto &field = **it;
- if (field.deprecated) continue;
+ // Generate struct or table methods.
+ void GenStruct(const StructDef &struct_def, std::string *code_ptr) {
+ if (struct_def.generated) return;
- auto offset = it - struct_def.fields.vec.begin();
- BuildFieldOfTable(struct_def, field, offset, code_ptr);
- if (field.value.type.base_type == BASE_TYPE_VECTOR) {
- BuildVectorOfTable(struct_def, field, code_ptr);
- }
- }
+ GenComment(struct_def.doc_comment, code_ptr, &def_comment);
+ BeginClass(struct_def, code_ptr);
- GetEndOffsetOnTable(struct_def, code_ptr);
+ GenerateNewObjectPrototype(struct_def, code_ptr);
+
+ if (!struct_def.fixed) {
+ // Generate a special accessor for the table that has been declared as
+ // the root type.
+ NewRootTypeFromBuffer(struct_def, code_ptr);
}
- // Generate struct or table methods.
- void GenStruct(const StructDef &struct_def, std::string *code_ptr) {
- if (struct_def.generated) return;
+ // Generate the Init method that sets the field in a pre-existing
+ // accessor object. This is to allow object reuse.
+ InitializeExisting(struct_def, code_ptr);
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
- GenComment(struct_def.doc_comment, code_ptr, &def_comment);
- BeginClass(struct_def, code_ptr);
-
- GenerateNewObjectPrototype(struct_def, code_ptr);
-
- if (!struct_def.fixed) {
- // Generate a special accessor for the table that has been declared as
- // the root type.
- NewRootTypeFromBuffer(struct_def, code_ptr);
- }
-
- // Generate the Init method that sets the field in a pre-existing
- // accessor object. This is to allow object reuse.
- InitializeExisting(struct_def, code_ptr);
- for (auto it = struct_def.fields.vec.begin();
- it != struct_def.fields.vec.end(); ++it) {
- auto &field = **it;
- if (field.deprecated) continue;
-
- GenStructAccessor(struct_def, field, code_ptr);
- }
-
- if (struct_def.fixed) {
- // create a struct constructor function
- GenStructBuilder(struct_def, code_ptr);
- }
- else {
- // Create a set of functions that allow table construction.
- GenTableBuilders(struct_def, code_ptr);
- }
+ GenStructAccessor(struct_def, field, code_ptr);
}
- // Generate enum declarations.
- void GenEnum(const EnumDef &enum_def, std::string *code_ptr) {
- if (enum_def.generated) return;
-
- GenComment(enum_def.doc_comment, code_ptr, &def_comment);
- BeginEnum(NormalizedName(enum_def), code_ptr);
- for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
- ++it) {
- auto &ev = **it;
- GenComment(ev.doc_comment, code_ptr, &def_comment, Indent);
- EnumMember(enum_def, ev, code_ptr);
- }
- EndEnum(code_ptr);
+ if (struct_def.fixed) {
+ // create a struct constructor function
+ GenStructBuilder(struct_def, code_ptr);
+ } else {
+ // Create a set of functions that allow table construction.
+ GenTableBuilders(struct_def, code_ptr);
}
+ }
- // Returns the function name that is able to read a value of the given type.
- std::string GenGetter(const Type &type) {
- switch (type.base_type) {
+ // Generate enum declarations.
+ void GenEnum(const EnumDef &enum_def, std::string *code_ptr) {
+ if (enum_def.generated) return;
+
+ GenComment(enum_def.doc_comment, code_ptr, &def_comment);
+ BeginEnum(NormalizedName(enum_def), code_ptr);
+ for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
+ auto &ev = **it;
+ GenComment(ev.doc_comment, code_ptr, &def_comment, Indent);
+ EnumMember(enum_def, ev, code_ptr);
+ }
+ EndEnum(code_ptr);
+ }
+
+ // Returns the function name that is able to read a value of the given type.
+ std::string GenGetter(const Type &type) {
+ switch (type.base_type) {
case BASE_TYPE_STRING: return std::string(SelfData) + ":String(";
- case BASE_TYPE_UNION: return std::string(SelfData) + ":Union(";
+ case BASE_TYPE_UNION: return std::string(SelfData) + ":Union(";
case BASE_TYPE_VECTOR: return GenGetter(type.VectorType());
default:
return std::string(SelfData) + ":Get(flatbuffers.N." +
- MakeCamel(GenTypeGet(type)) + ", ";
- }
+ MakeCamel(GenTypeGet(type)) + ", ";
}
+ }
- // Returns the method name for use with add/put calls.
- std::string GenMethod(const FieldDef &field) {
- return IsScalar(field.value.type.base_type)
- ? MakeCamel(GenTypeBasic(field.value.type))
- : (IsStruct(field.value.type) ? "Struct" : "UOffsetTRelative");
- }
+ // Returns the method name for use with add/put calls.
+ std::string GenMethod(const FieldDef &field) {
+ return IsScalar(field.value.type.base_type)
+ ? MakeCamel(GenTypeBasic(field.value.type))
+ : (IsStruct(field.value.type) ? "Struct" : "UOffsetTRelative");
+ }
- std::string GenTypeBasic(const Type &type) {
- static const char *ctypename[] = {
- // clang-format off
- #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
- CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \
- #PTYPE,
- FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
- #undef FLATBUFFERS_TD
- // clang-format on
- };
- return ctypename[type.base_type];
- }
+ std::string GenTypeBasic(const Type &type) {
+ // clang-format off
+ static const char *ctypename[] = {
+ #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
+ CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, ...) \
+ #PTYPE,
+ FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
+ #undef FLATBUFFERS_TD
+ };
+ // clang-format on
+ return ctypename[type.base_type];
+ }
- std::string GenTypePointer(const Type &type) {
- switch (type.base_type) {
+ std::string GenTypePointer(const Type &type) {
+ switch (type.base_type) {
case BASE_TYPE_STRING: return "string";
case BASE_TYPE_VECTOR: return GenTypeGet(type.VectorType());
case BASE_TYPE_STRUCT: return type.struct_def->name;
case BASE_TYPE_UNION:
// fall through
default: return "*flatbuffers.Table";
- }
+ }
+ }
+
+ std::string GenTypeGet(const Type &type) {
+ return IsScalar(type.base_type) ? GenTypeBasic(type) : GenTypePointer(type);
+ }
+
+ std::string GetNamespace(const Type &type) {
+ return type.struct_def->defined_namespace->GetFullyQualifiedName(
+ type.struct_def->name);
+ }
+
+ std::string TypeName(const FieldDef &field) {
+ return GenTypeGet(field.value.type);
+ }
+
+ std::string TypeNameWithNamespace(const FieldDef &field) {
+ return GetNamespace(field.value.type);
+ }
+
+ // Create a struct with a builder and the struct's arguments.
+ void GenStructBuilder(const StructDef &struct_def, std::string *code_ptr) {
+ BeginBuilderArgs(struct_def, code_ptr);
+ StructBuilderArgs(struct_def, "", code_ptr);
+ EndBuilderArgs(code_ptr);
+
+ StructBuilderBody(struct_def, "", code_ptr);
+ EndBuilderBody(code_ptr);
+ }
+
+ bool generate() {
+ if (!generateEnums()) return false;
+ if (!generateStructs()) return false;
+ return true;
+ }
+
+ private:
+ bool generateEnums() {
+ for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
+ ++it) {
+ auto &enum_def = **it;
+ std::string enumcode;
+ GenEnum(enum_def, &enumcode);
+ if (!SaveType(enum_def, enumcode, false)) return false;
+ }
+ return true;
+ }
+
+ bool generateStructs() {
+ for (auto it = parser_.structs_.vec.begin();
+ it != parser_.structs_.vec.end(); ++it) {
+ auto &struct_def = **it;
+ std::string declcode;
+ GenStruct(struct_def, &declcode);
+ if (!SaveType(struct_def, declcode, true)) return false;
+ }
+ return true;
+ }
+
+ // Begin by declaring namespace and imports.
+ void BeginFile(const std::string &name_space_name, const bool needs_imports,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += std::string(Comment) + FlatBuffersGeneratedWarning() + "\n\n";
+ code += std::string(Comment) + "namespace: " + name_space_name + "\n\n";
+ if (needs_imports) {
+ code += "local flatbuffers = require('flatbuffers')\n\n";
+ }
+ }
+
+ // Save out the generated code for a Lua Table type.
+ bool SaveType(const Definition &def, const std::string &classcode,
+ bool needs_imports) {
+ if (!classcode.length()) return true;
+
+ std::string namespace_dir = path_;
+ auto &namespaces = def.defined_namespace->components;
+ for (auto it = namespaces.begin(); it != namespaces.end(); ++it) {
+ if (it != namespaces.begin()) namespace_dir += kPathSeparator;
+ namespace_dir += *it;
+ // std::string init_py_filename = namespace_dir + "/__init__.py";
+ // SaveFile(init_py_filename.c_str(), "", false);
}
- std::string GenTypeGet(const Type &type) {
- return IsScalar(type.base_type) ? GenTypeBasic(type) : GenTypePointer(type);
- }
-
- std::string GetNamespace(const Type &type) {
- return type.struct_def->defined_namespace->GetFullyQualifiedName(type.struct_def->name);
- }
-
- std::string TypeName(const FieldDef &field) {
- return GenTypeGet(field.value.type);
- }
-
- std::string TypeNameWithNamespace(const FieldDef &field) {
- return GetNamespace(field.value.type);
- }
-
- // Create a struct with a builder and the struct's arguments.
- void GenStructBuilder(const StructDef &struct_def,
- std::string *code_ptr) {
- BeginBuilderArgs(struct_def, code_ptr);
- StructBuilderArgs(struct_def, "", code_ptr);
- EndBuilderArgs(code_ptr);
-
- StructBuilderBody(struct_def, "", code_ptr);
- EndBuilderBody(code_ptr);
- }
-
- bool generate() {
- if (!generateEnums()) return false;
- if (!generateStructs()) return false;
- return true;
- }
-
- private:
- bool generateEnums() {
- for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
- ++it) {
- auto &enum_def = **it;
- std::string enumcode;
- GenEnum(enum_def, &enumcode);
- if (!SaveType(enum_def, enumcode, false)) return false;
- }
- return true;
- }
-
- bool generateStructs() {
- for (auto it = parser_.structs_.vec.begin();
- it != parser_.structs_.vec.end(); ++it) {
- auto &struct_def = **it;
- std::string declcode;
- GenStruct(struct_def, &declcode);
- if (!SaveType(struct_def, declcode, true)) return false;
- }
- return true;
- }
-
- // Begin by declaring namespace and imports.
- void BeginFile(const std::string &name_space_name, const bool needs_imports,
- std::string *code_ptr) {
- std::string &code = *code_ptr;
- code += std::string(Comment) + FlatBuffersGeneratedWarning() + "\n\n";
- code += std::string(Comment) + "namespace: " + name_space_name + "\n\n";
- if (needs_imports) {
- code += "local flatbuffers = require('flatbuffers')\n\n";
- }
- }
-
- // Save out the generated code for a Lua Table type.
- bool SaveType(const Definition &def, const std::string &classcode,
- bool needs_imports) {
- if (!classcode.length()) return true;
-
- std::string namespace_dir = path_;
- auto &namespaces = def.defined_namespace->components;
- for (auto it = namespaces.begin(); it != namespaces.end(); ++it) {
- if (it != namespaces.begin()) namespace_dir += kPathSeparator;
- namespace_dir += *it;
- //std::string init_py_filename = namespace_dir + "/__init__.py";
- //SaveFile(init_py_filename.c_str(), "", false);
- }
-
- std::string code = "";
- BeginFile(LastNamespacePart(*def.defined_namespace), needs_imports, &code);
- code += classcode;
- code += "\n";
- code += "return " + NormalizedName(def) + " " + Comment + "return the module";
- std::string filename =
+ std::string code = "";
+ BeginFile(LastNamespacePart(*def.defined_namespace), needs_imports, &code);
+ code += classcode;
+ code += "\n";
+ code +=
+ "return " + NormalizedName(def) + " " + Comment + "return the module";
+ std::string filename =
NamespaceDir(*def.defined_namespace) + NormalizedName(def) + ".lua";
- return SaveFile(filename.c_str(), code, false);
- }
- private:
- std::unordered_set<std::string> keywords_;
- };
+ return SaveFile(filename.c_str(), code, false);
+ }
+
+ private:
+ std::unordered_set<std::string> keywords_;
+};
} // namespace lua
bool GenerateLua(const Parser &parser, const std::string &path,
- const std::string &file_name) {
+ const std::string &file_name) {
lua::LuaGenerator generator(parser, path, file_name);
return generator.generate();
}
diff --git a/src/idl_gen_php.cpp b/src/idl_gen_php.cpp
index 9d81415..b986fe3 100644
--- a/src/idl_gen_php.cpp
+++ b/src/idl_gen_php.cpp
@@ -31,7 +31,7 @@
public:
PhpGenerator(const Parser &parser, const std::string &path,
const std::string &file_name)
- : BaseGenerator(parser, path, file_name, "\\", "\\") {}
+ : BaseGenerator(parser, path, file_name, "\\", "\\", "php") {}
bool generate() {
if (!GenerateEnums()) return false;
if (!GenerateStructs()) return false;
@@ -401,7 +401,7 @@
code += Indent + Indent + "$o = $this->__offset(" +
NumToString(field.value.offset) + ");\n";
- if (field.value.type.VectorType().base_type == BASE_TYPE_STRING) {
+ if (IsString(field.value.type.VectorType())) {
code += Indent + Indent;
code += "return $o != 0 ? $this->__string($this->__vector($o) + $j * ";
code += NumToString(InlineSize(vectortype)) + ") : ";
@@ -705,7 +705,7 @@
default: FLATBUFFERS_ASSERT(0);
}
}
- if (field.value.type.base_type == BASE_TYPE_VECTOR) {
+ if (IsVector(field.value.type)) {
GetVectorLen(field, code_ptr);
if (field.value.type.element == BASE_TYPE_UCHAR) {
GetUByte(field, code_ptr);
@@ -735,7 +735,7 @@
} else {
BuildFieldOfTable(field, offset, code_ptr);
}
- if (field.value.type.base_type == BASE_TYPE_VECTOR) {
+ if (IsVector(field.value.type)) {
BuildVectorOfTable(field, code_ptr);
}
}
@@ -826,7 +826,8 @@
code += Indent + "private static $names = array(\n";
for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
auto &ev = **it;
- code += Indent + Indent + enum_def.name + "::" + ev.name + "=>" + "\"" + ev.name + "\",\n";
+ code += Indent + Indent + enum_def.name + "::" + ev.name + "=>" + "\"" +
+ ev.name + "\",\n";
}
code += Indent + ");\n\n";
@@ -859,15 +860,15 @@
}
static std::string GenTypeBasic(const Type &type) {
- static const char *ctypename[] = {
// clang-format off
- #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
- CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \
- #NTYPE,
- FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
- #undef FLATBUFFERS_TD
- // clang-format on
+ static const char *ctypename[] = {
+ #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
+ CTYPE, JTYPE, GTYPE, NTYPE, ...) \
+ #NTYPE,
+ FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
+ #undef FLATBUFFERS_TD
};
+ // clang-format on
return ctypename[type.base_type];
}
diff --git a/src/idl_gen_python.cpp b/src/idl_gen_python.cpp
index c8db359..1260673 100644
--- a/src/idl_gen_python.cpp
+++ b/src/idl_gen_python.cpp
@@ -16,15 +16,17 @@
// independent from idl_parser, since this code is not needed for most clients
+#include <cctype>
+#include <set>
#include <string>
+#include <unordered_set>
+#include <vector>
#include "flatbuffers/code_generators.h"
#include "flatbuffers/flatbuffers.h"
#include "flatbuffers/idl.h"
#include "flatbuffers/util.h"
-#include <unordered_set>
-
namespace flatbuffers {
namespace python {
@@ -37,42 +39,14 @@
PythonGenerator(const Parser &parser, const std::string &path,
const std::string &file_name)
: BaseGenerator(parser, path, file_name, "" /* not used */,
- "" /* not used */),
+ "" /* not used */, "py"),
float_const_gen_("float('nan')", "float('inf')", "float('-inf')") {
- static const char * const keywords[] = {
- "False",
- "None",
- "True",
- "and",
- "as",
- "assert",
- "break",
- "class",
- "continue",
- "def",
- "del",
- "elif",
- "else",
- "except",
- "finally",
- "for",
- "from",
- "global",
- "if",
- "import",
- "in",
- "is",
- "lambda",
- "nonlocal",
- "not",
- "or",
- "pass",
- "raise",
- "return",
- "try",
- "while",
- "with",
- "yield"
+ static const char *const keywords[] = {
+ "False", "None", "True", "and", "as", "assert", "break",
+ "class", "continue", "def", "del", "elif", "else", "except",
+ "finally", "for", "from", "global", "if", "import", "in",
+ "is", "lambda", "nonlocal", "not", "or", "pass", "raise",
+ "return", "try", "while", "with", "yield"
};
keywords_.insert(std::begin(keywords), std::end(keywords));
}
@@ -81,14 +55,14 @@
// this is the prefix code for that.
std::string OffsetPrefix(const FieldDef &field) {
return "\n" + Indent + Indent +
- "o = flatbuffers.number_types.UOffsetTFlags.py_type" +
- "(self._tab.Offset(" + NumToString(field.value.offset) + "))\n" +
- Indent + Indent + "if o != 0:\n";
+ "o = flatbuffers.number_types.UOffsetTFlags.py_type" +
+ "(self._tab.Offset(" + NumToString(field.value.offset) + "))\n" +
+ Indent + Indent + "if o != 0:\n";
}
// Begin a class declaration.
void BeginClass(const StructDef &struct_def, std::string *code_ptr) {
- std::string &code = *code_ptr;
+ auto &code = *code_ptr;
code += "class " + NormalizedName(struct_def) + "(object):\n";
code += Indent + "__slots__ = ['_tab']";
code += "\n\n";
@@ -96,7 +70,7 @@
// Begin enum code with a class declaration.
void BeginEnum(const std::string &class_name, std::string *code_ptr) {
- std::string &code = *code_ptr;
+ auto &code = *code_ptr;
code += "class " + class_name + "(object):\n";
}
@@ -112,10 +86,27 @@
return EscapeKeyword(ev.name);
}
+ // Converts the name of a definition into upper Camel format.
+ std::string MakeUpperCamel(const Definition &definition) const {
+ return MakeCamel(NormalizedName(definition), true);
+ }
+
+ // Converts the name of a definition into lower Camel format.
+ std::string MakeLowerCamel(const Definition &definition) const {
+ auto name = MakeCamel(NormalizedName(definition), false);
+ name[0] = CharToLower(name[0]);
+ return name;
+ }
+
+ // Starts a new line and then indents.
+ std::string GenIndents(int num) {
+ return "\n" + std::string(num * Indent.length(), ' ');
+ }
+
// A single enum member.
void EnumMember(const EnumDef &enum_def, const EnumVal &ev,
std::string *code_ptr) {
- std::string &code = *code_ptr;
+ auto &code = *code_ptr;
code += Indent;
code += NormalizedName(ev);
code += " = ";
@@ -124,14 +115,14 @@
// End enum code.
void EndEnum(std::string *code_ptr) {
- std::string &code = *code_ptr;
+ auto &code = *code_ptr;
code += "\n";
}
// Initialize a new struct or table from existing data.
void NewRootTypeFromBuffer(const StructDef &struct_def,
std::string *code_ptr) {
- std::string &code = *code_ptr;
+ auto &code = *code_ptr;
code += Indent + "@classmethod\n";
code += Indent + "def GetRootAs";
@@ -148,9 +139,8 @@
}
// Initialize an existing object with other data, to avoid an allocation.
- void InitializeExisting(const StructDef &struct_def,
- std::string *code_ptr) {
- std::string &code = *code_ptr;
+ void InitializeExisting(const StructDef &struct_def, std::string *code_ptr) {
+ auto &code = *code_ptr;
GenReceiver(struct_def, code_ptr);
code += "Init(self, buf, pos):\n";
@@ -161,7 +151,7 @@
// Get the length of a vector.
void GetVectorLen(const StructDef &struct_def, const FieldDef &field,
std::string *code_ptr) {
- std::string &code = *code_ptr;
+ auto &code = *code_ptr;
GenReceiver(struct_def, code_ptr);
code += MakeCamel(NormalizedName(field)) + "Length(self";
@@ -170,11 +160,25 @@
code += Indent + Indent + "return 0\n\n";
}
+ // Determines whether a vector is none or not.
+ void GetVectorIsNone(const StructDef &struct_def, const FieldDef &field,
+ std::string *code_ptr) {
+ auto &code = *code_ptr;
+
+ GenReceiver(struct_def, code_ptr);
+ code += MakeCamel(NormalizedName(field)) + "IsNone(self";
+ code += "):";
+ code += GenIndents(2) +
+ "o = flatbuffers.number_types.UOffsetTFlags.py_type" +
+ "(self._tab.Offset(" + NumToString(field.value.offset) + "))";
+ code += GenIndents(2) + "return o == 0";
+ code += "\n\n";
+ }
+
// Get the value of a struct's scalar.
void GetScalarFieldOfStruct(const StructDef &struct_def,
- const FieldDef &field,
- std::string *code_ptr) {
- std::string &code = *code_ptr;
+ const FieldDef &field, std::string *code_ptr) {
+ auto &code = *code_ptr;
std::string getter = GenGetter(field.value.type);
GenReceiver(struct_def, code_ptr);
code += MakeCamel(NormalizedName(field));
@@ -184,10 +188,9 @@
}
// Get the value of a table's scalar.
- void GetScalarFieldOfTable(const StructDef &struct_def,
- const FieldDef &field,
+ void GetScalarFieldOfTable(const StructDef &struct_def, const FieldDef &field,
std::string *code_ptr) {
- std::string &code = *code_ptr;
+ auto &code = *code_ptr;
std::string getter = GenGetter(field.value.type);
GenReceiver(struct_def, code_ptr);
code += MakeCamel(NormalizedName(field));
@@ -195,9 +198,7 @@
code += OffsetPrefix(field);
getter += "o + self._tab.Pos)";
auto is_bool = IsBool(field.value.type.base_type);
- if (is_bool) {
- getter = "bool(" + getter + ")";
- }
+ if (is_bool) { getter = "bool(" + getter + ")"; }
code += Indent + Indent + Indent + "return " + getter + "\n";
std::string default_value;
if (is_bool) {
@@ -213,9 +214,8 @@
// Get a struct by initializing an existing struct.
// Specific to Struct.
void GetStructFieldOfStruct(const StructDef &struct_def,
- const FieldDef &field,
- std::string *code_ptr) {
- std::string &code = *code_ptr;
+ const FieldDef &field, std::string *code_ptr) {
+ auto &code = *code_ptr;
GenReceiver(struct_def, code_ptr);
code += MakeCamel(NormalizedName(field));
code += "(self, obj):\n";
@@ -227,7 +227,7 @@
// Get the value of a fixed size array.
void GetArrayOfStruct(const StructDef &struct_def, const FieldDef &field,
std::string *code_ptr) {
- std::string &code = *code_ptr;
+ auto &code = *code_ptr;
const auto vec_type = field.value.type.VectorType();
GenReceiver(struct_def, code_ptr);
code += MakeCamel(NormalizedName(field));
@@ -250,10 +250,9 @@
// Get a struct by initializing an existing struct.
// Specific to Table.
- void GetStructFieldOfTable(const StructDef &struct_def,
- const FieldDef &field,
+ void GetStructFieldOfTable(const StructDef &struct_def, const FieldDef &field,
std::string *code_ptr) {
- std::string &code = *code_ptr;
+ auto &code = *code_ptr;
GenReceiver(struct_def, code_ptr);
code += MakeCamel(NormalizedName(field));
code += "(self):";
@@ -264,8 +263,11 @@
code += Indent + Indent + Indent;
code += "x = self._tab.Indirect(o + self._tab.Pos)\n";
}
- code += Indent + Indent + Indent;
- code += "from ." + TypeName(field) + " import " + TypeName(field) + "\n";
+ if (parser_.opts.include_dependence_headers) {
+ code += Indent + Indent + Indent;
+ code += "from " + GenPackageReference(field.value.type) + " import " +
+ TypeName(field) + "\n";
+ }
code += Indent + Indent + Indent + "obj = " + TypeName(field) + "()\n";
code += Indent + Indent + Indent + "obj.Init(self._tab.Bytes, x)\n";
code += Indent + Indent + Indent + "return obj\n";
@@ -275,7 +277,7 @@
// Get the value of a string.
void GetStringField(const StructDef &struct_def, const FieldDef &field,
std::string *code_ptr) {
- std::string &code = *code_ptr;
+ auto &code = *code_ptr;
GenReceiver(struct_def, code_ptr);
code += MakeCamel(NormalizedName(field));
code += "(self):";
@@ -288,7 +290,7 @@
// Get the value of a union from an object.
void GetUnionField(const StructDef &struct_def, const FieldDef &field,
std::string *code_ptr) {
- std::string &code = *code_ptr;
+ auto &code = *code_ptr;
GenReceiver(struct_def, code_ptr);
code += MakeCamel(NormalizedName(field)) + "(self):";
code += OffsetPrefix(field);
@@ -296,10 +298,12 @@
// TODO(rw): this works and is not the good way to it:
bool is_native_table = TypeName(field) == "*flatbuffers.Table";
if (is_native_table) {
- code += Indent + Indent + Indent + "from flatbuffers.table import Table\n";
- } else {
+ code +=
+ Indent + Indent + Indent + "from flatbuffers.table import Table\n";
+ } else if (parser_.opts.include_dependence_headers) {
code += Indent + Indent + Indent;
- code += "from ." + TypeName(field) + " import " + TypeName(field) + "\n";
+ code += "from " + GenPackageReference(field.value.type) + " import " +
+ TypeName(field) + "\n";
}
code += Indent + Indent + Indent + "obj = Table(bytearray(), 0)\n";
code += Indent + Indent + Indent + GenGetter(field.value.type);
@@ -307,11 +311,25 @@
code += Indent + Indent + "return None\n\n";
}
+ // Generate the package reference when importing a struct or enum from its
+ // module.
+ std::string GenPackageReference(const Type &type) {
+ Namespace *namespaces;
+ if (type.struct_def) {
+ namespaces = type.struct_def->defined_namespace;
+ } else if (type.enum_def) {
+ namespaces = type.enum_def->defined_namespace;
+ } else {
+ return "." + GenTypeGet(type);
+ }
+
+ return namespaces->GetFullyQualifiedName(GenTypeGet(type));
+ }
+
// Get the value of a vector's struct member.
void GetMemberOfVectorOfStruct(const StructDef &struct_def,
- const FieldDef &field,
- std::string *code_ptr) {
- std::string &code = *code_ptr;
+ const FieldDef &field, std::string *code_ptr) {
+ auto &code = *code_ptr;
auto vectortype = field.value.type.VectorType();
GenReceiver(struct_def, code_ptr);
@@ -324,8 +342,11 @@
if (!(vectortype.struct_def->fixed)) {
code += Indent + Indent + Indent + "x = self._tab.Indirect(x)\n";
}
- code += Indent + Indent + Indent;
- code += "from ." + TypeName(field) + " import " + TypeName(field) + "\n";
+ if (parser_.opts.include_dependence_headers) {
+ code += Indent + Indent + Indent;
+ code += "from " + GenPackageReference(field.value.type) + " import " +
+ TypeName(field) + "\n";
+ }
code += Indent + Indent + Indent + "obj = " + TypeName(field) + "()\n";
code += Indent + Indent + Indent + "obj.Init(self._tab.Bytes, x)\n";
code += Indent + Indent + Indent + "return obj\n";
@@ -337,7 +358,7 @@
void GetMemberOfVectorOfNonStruct(const StructDef &struct_def,
const FieldDef &field,
std::string *code_ptr) {
- std::string &code = *code_ptr;
+ auto &code = *code_ptr;
auto vectortype = field.value.type.VectorType();
GenReceiver(struct_def, code_ptr);
@@ -349,7 +370,7 @@
code += "return " + GenGetter(field.value.type);
code += "a + flatbuffers.number_types.UOffsetTFlags.py_type(j * ";
code += NumToString(InlineSize(vectortype)) + "))\n";
- if (vectortype.base_type == BASE_TYPE_STRING) {
+ if (IsString(vectortype)) {
code += Indent + Indent + "return \"\"\n";
} else {
code += Indent + Indent + "return 0\n";
@@ -362,7 +383,7 @@
void GetVectorOfNonStructAsNumpy(const StructDef &struct_def,
const FieldDef &field,
std::string *code_ptr) {
- std::string &code = *code_ptr;
+ auto &code = *code_ptr;
auto vectortype = field.value.type.VectorType();
// Currently, we only support accessing as numpy array if
@@ -379,7 +400,7 @@
code += MakeCamel(GenTypeGet(field.value.type));
code += "Flags, o)\n";
- if (vectortype.base_type == BASE_TYPE_STRING) {
+ if (IsString(vectortype)) {
code += Indent + Indent + "return \"\"\n";
} else {
code += Indent + Indent + "return 0\n";
@@ -388,9 +409,8 @@
}
// Begin the creator function signature.
- void BeginBuilderArgs(const StructDef &struct_def,
- std::string *code_ptr) {
- std::string &code = *code_ptr;
+ void BeginBuilderArgs(const StructDef &struct_def, std::string *code_ptr) {
+ auto &code = *code_ptr;
code += "\n";
code += "def Create" + NormalizedName(struct_def);
@@ -400,9 +420,12 @@
// Recursively generate arguments for a constructor, to deal with nested
// structs.
void StructBuilderArgs(const StructDef &struct_def,
- const char *nameprefix, std::string *code_ptr) {
+ const std::string nameprefix,
+ const std::string namesuffix, bool has_field_name,
+ const std::string fieldname_suffix,
+ std::string *code_ptr) {
for (auto it = struct_def.fields.vec.begin();
- it != struct_def.fields.vec.end(); ++it) {
+ it != struct_def.fields.vec.end(); ++it) {
auto &field = **it;
const auto &field_type = field.value.type;
const auto &type =
@@ -411,20 +434,24 @@
// Generate arguments for a struct inside a struct. To ensure names
// don't clash, and to make it obvious these arguments are constructing
// a nested struct, prefix the name with the field name.
- StructBuilderArgs(*field_type.struct_def,
- (nameprefix + (NormalizedName(field) + "_")).c_str(),
- code_ptr);
+ auto subprefix = nameprefix;
+ if (has_field_name) {
+ subprefix += NormalizedName(field) + fieldname_suffix;
+ }
+ StructBuilderArgs(*field.value.type.struct_def, subprefix, namesuffix,
+ has_field_name, fieldname_suffix, code_ptr);
} else {
- std::string &code = *code_ptr;
+ auto &code = *code_ptr;
code += std::string(", ") + nameprefix;
- code += MakeCamel(NormalizedName(field), false);
+ if (has_field_name) { code += MakeCamel(NormalizedName(field), false); }
+ code += namesuffix;
}
}
}
// End the creator function signature.
void EndBuilderArgs(std::string *code_ptr) {
- std::string &code = *code_ptr;
+ auto &code = *code_ptr;
code += "):\n";
}
@@ -433,13 +460,13 @@
void StructBuilderBody(const StructDef &struct_def, const char *nameprefix,
std::string *code_ptr, size_t index = 0,
bool in_array = false) {
- std::string &code = *code_ptr;
+ auto &code = *code_ptr;
std::string indent(index * 4, ' ');
code +=
indent + " builder.Prep(" + NumToString(struct_def.minalign) + ", ";
code += NumToString(struct_def.bytesize) + ")\n";
for (auto it = struct_def.fields.vec.rbegin();
- it != struct_def.fields.vec.rend(); ++it) {
+ it != struct_def.fields.vec.rend(); ++it) {
auto &field = **it;
const auto &field_type = field.value.type;
const auto &type =
@@ -479,14 +506,13 @@
}
void EndBuilderBody(std::string *code_ptr) {
- std::string &code = *code_ptr;
+ auto &code = *code_ptr;
code += " return builder.Offset()\n";
}
// Get the value of a table's starting offset.
- void GetStartOfTable(const StructDef &struct_def,
- std::string *code_ptr) {
- std::string &code = *code_ptr;
+ void GetStartOfTable(const StructDef &struct_def, std::string *code_ptr) {
+ auto &code = *code_ptr;
code += "def " + NormalizedName(struct_def) + "Start";
code += "(builder): ";
code += "builder.StartObject(";
@@ -495,11 +521,11 @@
}
// Set the value of a table's field.
- void BuildFieldOfTable(const StructDef &struct_def,
- const FieldDef &field, const size_t offset,
- std::string *code_ptr) {
- std::string &code = *code_ptr;
- code += "def " + NormalizedName(struct_def) + "Add" + MakeCamel(NormalizedName(field));
+ void BuildFieldOfTable(const StructDef &struct_def, const FieldDef &field,
+ const size_t offset, std::string *code_ptr) {
+ auto &code = *code_ptr;
+ code += "def " + NormalizedName(struct_def) + "Add" +
+ MakeCamel(NormalizedName(field));
code += "(builder, ";
code += MakeCamel(NormalizedName(field), false);
code += "): ";
@@ -521,9 +547,9 @@
}
// Set the value of one of the members of a table's vector.
- void BuildVectorOfTable(const StructDef &struct_def,
- const FieldDef &field, std::string *code_ptr) {
- std::string &code = *code_ptr;
+ void BuildVectorOfTable(const StructDef &struct_def, const FieldDef &field,
+ std::string *code_ptr) {
+ auto &code = *code_ptr;
code += "def " + NormalizedName(struct_def) + "Start";
code += MakeCamel(NormalizedName(field));
code += "Vector(builder, numElems): return builder.StartVector(";
@@ -536,9 +562,8 @@
}
// Get the offset of the end of a table.
- void GetEndOffsetOnTable(const StructDef &struct_def,
- std::string *code_ptr) {
- std::string &code = *code_ptr;
+ void GetEndOffsetOnTable(const StructDef &struct_def, std::string *code_ptr) {
+ auto &code = *code_ptr;
code += "def " + NormalizedName(struct_def) + "End";
code += "(builder): ";
code += "return builder.EndObject()\n";
@@ -546,14 +571,14 @@
// Generate the receiver for function signatures.
void GenReceiver(const StructDef &struct_def, std::string *code_ptr) {
- std::string &code = *code_ptr;
+ auto &code = *code_ptr;
code += Indent + "# " + NormalizedName(struct_def) + "\n";
code += Indent + "def ";
}
// Generate a struct field, conditioned on its child type(s).
- void GenStructAccessor(const StructDef &struct_def,
- const FieldDef &field, std::string *code_ptr) {
+ void GenStructAccessor(const StructDef &struct_def, const FieldDef &field,
+ std::string *code_ptr) {
GenComment(field.doc_comment, code_ptr, &def_comment, Indent.c_str());
if (IsScalar(field.value.type.base_type)) {
if (struct_def.fixed) {
@@ -572,7 +597,9 @@
GetStructFieldOfTable(struct_def, field, code_ptr);
}
break;
- case BASE_TYPE_STRING: GetStringField(struct_def, field, code_ptr); break;
+ case BASE_TYPE_STRING:
+ GetStringField(struct_def, field, code_ptr);
+ break;
case BASE_TYPE_VECTOR: {
auto vectortype = field.value.type.VectorType();
if (vectortype.base_type == BASE_TYPE_STRUCT) {
@@ -587,24 +614,34 @@
default: FLATBUFFERS_ASSERT(0);
}
}
- if (field.value.type.base_type == BASE_TYPE_VECTOR) {
+ if (IsVector(field.value.type) || IsArray(field.value.type)) {
GetVectorLen(struct_def, field, code_ptr);
+ GetVectorIsNone(struct_def, field, code_ptr);
}
}
+ // Generate struct sizeof.
+ void GenStructSizeOf(const StructDef &struct_def, std::string *code_ptr) {
+ auto &code = *code_ptr;
+ code += Indent + "@classmethod\n";
+ code += Indent + "def SizeOf(cls):\n";
+ code +=
+ Indent + Indent + "return " + NumToString(struct_def.bytesize) + "\n";
+ code += "\n";
+ }
+
// Generate table constructors, conditioned on its members' types.
- void GenTableBuilders(const StructDef &struct_def,
- std::string *code_ptr) {
+ void GenTableBuilders(const StructDef &struct_def, std::string *code_ptr) {
GetStartOfTable(struct_def, code_ptr);
for (auto it = struct_def.fields.vec.begin();
- it != struct_def.fields.vec.end(); ++it) {
+ it != struct_def.fields.vec.end(); ++it) {
auto &field = **it;
if (field.deprecated) continue;
auto offset = it - struct_def.fields.vec.begin();
BuildFieldOfTable(struct_def, field, offset, code_ptr);
- if (field.value.type.base_type == BASE_TYPE_VECTOR) {
+ if (IsVector(field.value.type)) {
BuildVectorOfTable(struct_def, field, code_ptr);
}
}
@@ -615,7 +652,7 @@
// Generate function to check for proper file identifier
void GenHasFileIdentifier(const StructDef &struct_def,
std::string *code_ptr) {
- std::string &code = *code_ptr;
+ auto &code = *code_ptr;
std::string escapedID;
// In the event any of file_identifier characters are special(NULL, \, etc),
// problems occur. To prevent this, convert all chars to their hex-escaped
@@ -635,8 +672,8 @@
code += "\", size_prefixed=size_prefixed)\n";
code += "\n";
}
-
- // Generate struct or table methods.
+
+ // Generates struct or table methods.
void GenStruct(const StructDef &struct_def, std::string *code_ptr) {
if (struct_def.generated) return;
@@ -646,16 +683,19 @@
// Generate a special accessor for the table that has been declared as
// the root type.
NewRootTypeFromBuffer(struct_def, code_ptr);
- if (parser_.file_identifier_.length()){
+ if (parser_.file_identifier_.length()) {
// Generate a special function to test file_identifier
GenHasFileIdentifier(struct_def, code_ptr);
}
+ } else {
+ // Generates the SizeOf method for all structs.
+ GenStructSizeOf(struct_def, code_ptr);
}
- // Generate the Init method that sets the field in a pre-existing
+ // Generates the Init method that sets the field in a pre-existing
// accessor object. This is to allow object reuse.
InitializeExisting(struct_def, code_ptr);
for (auto it = struct_def.fields.vec.begin();
- it != struct_def.fields.vec.end(); ++it) {
+ it != struct_def.fields.vec.end(); ++it) {
auto &field = **it;
if (field.deprecated) continue;
@@ -663,14 +703,808 @@
}
if (struct_def.fixed) {
- // create a struct constructor function
+ // creates a struct constructor function
GenStructBuilder(struct_def, code_ptr);
} else {
- // Create a set of functions that allow table construction.
+ // Creates a set of functions that allow table construction.
GenTableBuilders(struct_def, code_ptr);
}
}
+ void GenReceiverForObjectAPI(const StructDef &struct_def,
+ std::string *code_ptr) {
+ auto &code = *code_ptr;
+ code += GenIndents(1) + "# " + NormalizedName(struct_def) + "T";
+ code += GenIndents(1) + "def ";
+ }
+
+ void BeginClassForObjectAPI(const StructDef &struct_def,
+ std::string *code_ptr) {
+ auto &code = *code_ptr;
+ code += "\n";
+ code += "class " + NormalizedName(struct_def) + "T(object):";
+ code += "\n";
+ }
+
+ // Gets the accoresponding python builtin type of a BaseType for scalars and
+ // string.
+ std::string GetBasePythonTypeForScalarAndString(const BaseType &base_type) {
+ if (IsBool(base_type)) {
+ return "bool";
+ } else if (IsFloat(base_type)) {
+ return "float";
+ } else if (IsInteger(base_type)) {
+ return "int";
+ } else if (base_type == BASE_TYPE_STRING) {
+ return "str";
+ } else {
+ FLATBUFFERS_ASSERT(false && "base_type is not a scalar or string type.");
+ return "";
+ }
+ }
+
+ std::string GetDefaultValue(const FieldDef &field) {
+ BaseType base_type = field.value.type.base_type;
+ if (IsBool(base_type)) {
+ return field.value.constant == "0" ? "False" : "True";
+ } else if (IsFloat(base_type)) {
+ return float_const_gen_.GenFloatConstant(field);
+ } else if (IsInteger(base_type)) {
+ return field.value.constant;
+ } else {
+ // For string, struct, and table.
+ return "None";
+ }
+ }
+
+ void GenUnionInit(const FieldDef &field, std::string *field_types_ptr,
+ std::set<std::string> *import_list,
+ std::set<std::string> *import_typing_list) {
+ // Gets all possible types in the union.
+ import_typing_list->insert("Union");
+ auto &field_types = *field_types_ptr;
+ field_types = "Union[";
+
+ std::string separator_string = ", ";
+ auto enum_def = field.value.type.enum_def;
+ for (auto it = enum_def->Vals().begin(); it != enum_def->Vals().end();
+ ++it) {
+ auto &ev = **it;
+ // Union only supports string and table.
+ std::string field_type;
+ switch (ev.union_type.base_type) {
+ case BASE_TYPE_STRUCT:
+ field_type = GenTypeGet(ev.union_type) + "T";
+ if (parser_.opts.include_dependence_headers) {
+ auto package_reference = GenPackageReference(ev.union_type);
+ field_type = package_reference + "." + field_type;
+ import_list->insert("import " + package_reference);
+ }
+ break;
+ case BASE_TYPE_STRING: field_type += "str"; break;
+ case BASE_TYPE_NONE: field_type += "None"; break;
+ default: break;
+ }
+ field_types += field_type + separator_string;
+ }
+
+ // Removes the last separator_string.
+ field_types.erase(field_types.length() - separator_string.size());
+ field_types += "]";
+
+ // Gets the import lists for the union.
+ if (parser_.opts.include_dependence_headers) {
+ // The package reference is generated based on enum_def, instead
+ // of struct_def in field.type. That's why GenPackageReference() is
+ // not used.
+ Namespace *namespaces = field.value.type.enum_def->defined_namespace;
+ auto package_reference = namespaces->GetFullyQualifiedName(
+ MakeUpperCamel(*(field.value.type.enum_def)));
+ auto union_name = MakeUpperCamel(*(field.value.type.enum_def));
+ import_list->insert("import " + package_reference);
+ }
+ }
+
+ void GenStructInit(const FieldDef &field, std::string *field_type_ptr,
+ std::set<std::string> *import_list,
+ std::set<std::string> *import_typing_list) {
+ import_typing_list->insert("Optional");
+ auto &field_type = *field_type_ptr;
+ if (parser_.opts.include_dependence_headers) {
+ auto package_reference = GenPackageReference(field.value.type);
+ field_type = package_reference + "." + TypeName(field) + "T]";
+ import_list->insert("import " + package_reference);
+ } else {
+ field_type = TypeName(field) + "T]";
+ }
+ field_type = "Optional[" + field_type;
+ }
+
+ void GenVectorInit(const FieldDef &field, std::string *field_type_ptr,
+ std::set<std::string> *import_list,
+ std::set<std::string> *import_typing_list) {
+ import_typing_list->insert("List");
+ auto &field_type = *field_type_ptr;
+ auto base_type = field.value.type.VectorType().base_type;
+ if (base_type == BASE_TYPE_STRUCT) {
+ field_type = GenTypeGet(field.value.type.VectorType()) + "T]";
+ if (parser_.opts.include_dependence_headers) {
+ auto package_reference =
+ GenPackageReference(field.value.type.VectorType());
+ field_type = package_reference + "." +
+ GenTypeGet(field.value.type.VectorType()) + "T]";
+ import_list->insert("import " + package_reference);
+ }
+ field_type = "List[" + field_type;
+ } else {
+ field_type =
+ "List[" + GetBasePythonTypeForScalarAndString(base_type) + "]";
+ }
+ }
+
+ void GenInitialize(const StructDef &struct_def, std::string *code_ptr,
+ std::set<std::string> *import_list) {
+ std::string code;
+ std::set<std::string> import_typing_list;
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+
+ // Determines field type, default value, and typing imports.
+ auto base_type = field.value.type.base_type;
+ std::string field_type;
+ switch (base_type) {
+ case BASE_TYPE_UNION: {
+ GenUnionInit(field, &field_type, import_list, &import_typing_list);
+ break;
+ }
+ case BASE_TYPE_STRUCT: {
+ GenStructInit(field, &field_type, import_list, &import_typing_list);
+ break;
+ }
+ case BASE_TYPE_VECTOR:
+ case BASE_TYPE_ARRAY: {
+ GenVectorInit(field, &field_type, import_list, &import_typing_list);
+ break;
+ }
+ default:
+ // Scalar or sting fields.
+ field_type = GetBasePythonTypeForScalarAndString(base_type);
+ break;
+ }
+
+ auto default_value = GetDefaultValue(field);
+ // Wrties the init statement.
+ auto field_instance_name = MakeLowerCamel(field);
+ code += GenIndents(2) + "self." + field_instance_name + " = " +
+ default_value + " # type: " + field_type;
+ }
+
+ // Writes __init__ method.
+ auto &code_base = *code_ptr;
+ GenReceiverForObjectAPI(struct_def, code_ptr);
+ code_base += "__init__(self):";
+ if (code.empty()) {
+ code_base += GenIndents(2) + "pass";
+ } else {
+ code_base += code;
+ }
+ code_base += "\n";
+
+ // Merges the typing imports into import_list.
+ if (!import_typing_list.empty()) {
+ // Adds the try statement.
+ std::string typing_imports = "try:";
+ typing_imports += GenIndents(1) + "from typing import ";
+ std::string separator_string = ", ";
+ for (auto it = import_typing_list.begin(); it != import_typing_list.end();
+ ++it) {
+ const std::string &im = *it;
+ typing_imports += im + separator_string;
+ }
+ // Removes the last separator_string.
+ typing_imports.erase(typing_imports.length() - separator_string.size());
+
+ // Adds the except statement.
+ typing_imports += "\n";
+ typing_imports += "except:";
+ typing_imports += GenIndents(1) + "pass";
+ import_list->insert(typing_imports);
+ }
+
+ // Removes the import of the struct itself, if applied.
+ auto package_reference =
+ struct_def.defined_namespace->GetFullyQualifiedName(
+ MakeUpperCamel(struct_def));
+ auto struct_import = "import " + package_reference;
+ import_list->erase(struct_import);
+ }
+
+ void InitializeFromBuf(const StructDef &struct_def, std::string *code_ptr) {
+ auto &code = *code_ptr;
+ auto instance_name = MakeLowerCamel(struct_def);
+ auto struct_name = NormalizedName(struct_def);
+
+ code += GenIndents(1) + "@classmethod";
+ code += GenIndents(1) + "def InitFromBuf(cls, buf, pos):";
+ code += GenIndents(2) + instance_name + " = " + struct_name + "()";
+ code += GenIndents(2) + instance_name + ".Init(buf, pos)";
+ code += GenIndents(2) + "return cls.InitFromObj(" + instance_name + ")";
+ code += "\n";
+ }
+
+ void InitializeFromObjForObject(const StructDef &struct_def,
+ std::string *code_ptr) {
+ auto &code = *code_ptr;
+ auto instance_name = MakeLowerCamel(struct_def);
+ auto struct_name = NormalizedName(struct_def);
+
+ code += GenIndents(1) + "@classmethod";
+ code += GenIndents(1) + "def InitFromObj(cls, " + instance_name + "):";
+ code += GenIndents(2) + "x = " + struct_name + "T()";
+ code += GenIndents(2) + "x._UnPack(" + instance_name + ")";
+ code += GenIndents(2) + "return x";
+ code += "\n";
+ }
+
+ void GenUnPackForStruct(const StructDef &struct_def, const FieldDef &field,
+ std::string *code_ptr) {
+ auto &code = *code_ptr;
+ auto struct_instance_name = MakeLowerCamel(struct_def);
+ auto field_instance_name = MakeLowerCamel(field);
+ auto field_accessor_name = MakeUpperCamel(field);
+ auto field_type = TypeName(field);
+
+ if (parser_.opts.include_dependence_headers) {
+ auto package_reference = GenPackageReference(field.value.type);
+ field_type = package_reference + "." + TypeName(field);
+ }
+
+ code += GenIndents(2) + "if " + struct_instance_name + "." +
+ field_accessor_name + "(";
+ // if field is a struct, we need to create an instance for it first.
+ if (struct_def.fixed && field.value.type.base_type == BASE_TYPE_STRUCT) {
+ code += field_type + "()";
+ }
+ code += ") is not None:";
+ code += GenIndents(3) + "self." + field_instance_name + " = " + field_type +
+ "T.InitFromObj(" + struct_instance_name + "." +
+ field_accessor_name + "(";
+ // A struct's accessor requires a struct buf instance.
+ if (struct_def.fixed && field.value.type.base_type == BASE_TYPE_STRUCT) {
+ code += field_type + "()";
+ }
+ code += "))";
+ }
+
+ void GenUnPackForUnion(const StructDef &struct_def, const FieldDef &field,
+ std::string *code_ptr) {
+ auto &code = *code_ptr;
+ auto field_instance_name = MakeLowerCamel(field);
+ auto field_accessor_name = MakeUpperCamel(field);
+ auto struct_instance_name = MakeLowerCamel(struct_def);
+ auto union_name = MakeUpperCamel(*(field.value.type.enum_def));
+
+ if (parser_.opts.include_dependence_headers) {
+ Namespace *namespaces = field.value.type.enum_def->defined_namespace;
+ auto package_reference = namespaces->GetFullyQualifiedName(
+ MakeUpperCamel(*(field.value.type.enum_def)));
+ union_name = package_reference + "." + union_name;
+ }
+ code += GenIndents(2) + "self." + field_instance_name + " = " + union_name +
+ "Creator(" + "self." + field_instance_name + "Type, " +
+ struct_instance_name + "." + field_accessor_name + "())";
+ }
+
+ void GenUnPackForStructVector(const StructDef &struct_def,
+ const FieldDef &field, std::string *code_ptr) {
+ auto &code = *code_ptr;
+ auto field_instance_name = MakeLowerCamel(field);
+ auto field_accessor_name = MakeUpperCamel(field);
+ auto struct_instance_name = MakeLowerCamel(struct_def);
+
+ code += GenIndents(2) + "if not " + struct_instance_name + "." +
+ field_accessor_name + "IsNone():";
+ code += GenIndents(3) + "self." + field_instance_name + " = []";
+ code += GenIndents(3) + "for i in range(" + struct_instance_name + "." +
+ field_accessor_name + "Length()):";
+
+ auto field_type_name = TypeName(field);
+ auto one_instance = field_type_name + "_";
+ one_instance[0] = CharToLower(one_instance[0]);
+
+ if (parser_.opts.include_dependence_headers) {
+ auto package_reference = GenPackageReference(field.value.type);
+ field_type_name = package_reference + "." + TypeName(field);
+ }
+
+ code += GenIndents(4) + "if " + struct_instance_name + "." +
+ field_accessor_name + "(i) is None:";
+ code += GenIndents(5) + "self." + field_instance_name + ".append(None)";
+ code += GenIndents(4) + "else:";
+ code += GenIndents(5) + one_instance + " = " + field_type_name +
+ "T.InitFromObj(" + struct_instance_name + "." +
+ field_accessor_name + "(i))";
+ code += GenIndents(5) + "self." + field_instance_name + ".append(" +
+ one_instance + ")";
+ }
+
+ void GenUnpackforScalarVectorHelper(const StructDef &struct_def,
+ const FieldDef &field,
+ std::string *code_ptr, int indents) {
+ auto &code = *code_ptr;
+ auto field_instance_name = MakeLowerCamel(field);
+ auto field_accessor_name = MakeUpperCamel(field);
+ auto struct_instance_name = MakeLowerCamel(struct_def);
+
+ code += GenIndents(indents) + "self." + field_instance_name + " = []";
+ code += GenIndents(indents) + "for i in range(" + struct_instance_name +
+ "." + field_accessor_name + "Length()):";
+ code += GenIndents(indents + 1) + "self." + field_instance_name +
+ ".append(" + struct_instance_name + "." + field_accessor_name +
+ "(i))";
+ }
+
+ void GenUnPackForScalarVector(const StructDef &struct_def,
+ const FieldDef &field, std::string *code_ptr) {
+ auto &code = *code_ptr;
+ auto field_instance_name = MakeLowerCamel(field);
+ auto field_accessor_name = MakeUpperCamel(field);
+ auto struct_instance_name = MakeLowerCamel(struct_def);
+
+ code += GenIndents(2) + "if not " + struct_instance_name + "." +
+ field_accessor_name + "IsNone():";
+
+ // String does not have the AsNumpy method.
+ if (!(IsScalar(field.value.type.VectorType().base_type))) {
+ GenUnpackforScalarVectorHelper(struct_def, field, code_ptr, 3);
+ return;
+ }
+
+ code += GenIndents(3) + "if np is None:";
+ GenUnpackforScalarVectorHelper(struct_def, field, code_ptr, 4);
+
+ // If numpy exists, use the AsNumpy method to optimize the unpack speed.
+ code += GenIndents(3) + "else:";
+ code += GenIndents(4) + "self." + field_instance_name + " = " +
+ struct_instance_name + "." + field_accessor_name + "AsNumpy()";
+ }
+
+ void GenUnPackForScalar(const StructDef &struct_def, const FieldDef &field,
+ std::string *code_ptr) {
+ auto &code = *code_ptr;
+ auto field_instance_name = MakeLowerCamel(field);
+ auto field_accessor_name = MakeUpperCamel(field);
+ auto struct_instance_name = MakeLowerCamel(struct_def);
+
+ code += GenIndents(2) + "self." + field_instance_name + " = " +
+ struct_instance_name + "." + field_accessor_name + "()";
+ }
+
+ // Generates the UnPack method for the object class.
+ void GenUnPack(const StructDef &struct_def, std::string *code_ptr) {
+ std::string code;
+ // Items that needs to be imported. No duplicate modules will be imported.
+ std::set<std::string> import_list;
+
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+
+ auto field_type = TypeName(field);
+ switch (field.value.type.base_type) {
+ case BASE_TYPE_STRUCT: {
+ GenUnPackForStruct(struct_def, field, &code);
+ break;
+ }
+ case BASE_TYPE_UNION: {
+ GenUnPackForUnion(struct_def, field, &code);
+ break;
+ }
+ case BASE_TYPE_VECTOR: {
+ auto vectortype = field.value.type.VectorType();
+ if (vectortype.base_type == BASE_TYPE_STRUCT) {
+ GenUnPackForStructVector(struct_def, field, &code);
+ } else {
+ GenUnPackForScalarVector(struct_def, field, &code);
+ }
+ break;
+ }
+ case BASE_TYPE_ARRAY: {
+ GenUnPackForScalarVector(struct_def, field, &code);
+ break;
+ }
+ default: GenUnPackForScalar(struct_def, field, &code);
+ }
+ }
+
+ // Writes import statements and code into the generated file.
+ auto &code_base = *code_ptr;
+ auto struct_instance_name = MakeLowerCamel(struct_def);
+ auto struct_name = MakeUpperCamel(struct_def);
+
+ GenReceiverForObjectAPI(struct_def, code_ptr);
+ code_base += "_UnPack(self, " + struct_instance_name + "):";
+ code_base += GenIndents(2) + "if " + struct_instance_name + " is None:";
+ code_base += GenIndents(3) + "return";
+
+ // Write the import statements.
+ for (std::set<std::string>::iterator it = import_list.begin();
+ it != import_list.end(); ++it) {
+ code_base += GenIndents(2) + *it;
+ }
+
+ // Write the code.
+ code_base += code;
+ code_base += "\n";
+ }
+
+ void GenPackForStruct(const StructDef &struct_def, std::string *code_ptr) {
+ auto &code = *code_ptr;
+ auto struct_name = MakeUpperCamel(struct_def);
+
+ GenReceiverForObjectAPI(struct_def, code_ptr);
+ code += "Pack(self, builder):";
+ code += GenIndents(2) + "return Create" + struct_name + "(builder";
+
+ StructBuilderArgs(struct_def,
+ /* nameprefix = */ "self.",
+ /* namesuffix = */ "",
+ /* has_field_name = */ true,
+ /* fieldname_suffix = */ ".", code_ptr);
+ code += ")\n";
+ }
+
+ void GenPackForStructVectorField(const StructDef &struct_def,
+ const FieldDef &field,
+ std::string *code_prefix_ptr,
+ std::string *code_ptr) {
+ auto &code_prefix = *code_prefix_ptr;
+ auto &code = *code_ptr;
+ auto field_instance_name = MakeLowerCamel(field);
+ auto struct_name = NormalizedName(struct_def);
+ auto field_accessor_name = MakeUpperCamel(field);
+
+ // Creates the field.
+ code_prefix +=
+ GenIndents(2) + "if self." + field_instance_name + " is not None:";
+ if (field.value.type.struct_def->fixed) {
+ code_prefix += GenIndents(3) + struct_name + "Start" +
+ field_accessor_name + "Vector(builder, len(self." +
+ field_instance_name + "))";
+ code_prefix += GenIndents(3) + "for i in reversed(range(len(self." +
+ field_instance_name + "))):";
+ code_prefix +=
+ GenIndents(4) + "self." + field_instance_name + "[i].Pack(builder)";
+ code_prefix += GenIndents(3) + field_instance_name +
+ " = builder.EndVector(len(self." + field_instance_name +
+ "))";
+ } else {
+ // If the vector is a struct vector, we need to first build accessor for
+ // each struct element.
+ code_prefix += GenIndents(3) + field_instance_name + "list = []";
+ code_prefix += GenIndents(3);
+ code_prefix += "for i in range(len(self." + field_instance_name + ")):";
+ code_prefix += GenIndents(4) + field_instance_name + "list.append(self." +
+ field_instance_name + "[i].Pack(builder))";
+
+ code_prefix += GenIndents(3) + struct_name + "Start" +
+ field_accessor_name + "Vector(builder, len(self." +
+ field_instance_name + "))";
+ code_prefix += GenIndents(3) + "for i in reversed(range(len(self." +
+ field_instance_name + "))):";
+ code_prefix += GenIndents(4) + "builder.PrependUOffsetTRelative" + "(" +
+ field_instance_name + "list[i])";
+ code_prefix += GenIndents(3) + field_instance_name +
+ " = builder.EndVector(len(self." + field_instance_name +
+ "))";
+ }
+
+ // Adds the field into the struct.
+ code += GenIndents(2) + "if self." + field_instance_name + " is not None:";
+ code += GenIndents(3) + struct_name + "Add" + field_accessor_name +
+ "(builder, " + field_instance_name + ")";
+ }
+
+ void GenPackForScalarVectorFieldHelper(const StructDef &struct_def,
+ const FieldDef &field,
+ std::string *code_ptr, int indents) {
+ auto &code = *code_ptr;
+ auto field_instance_name = MakeLowerCamel(field);
+ auto field_accessor_name = MakeUpperCamel(field);
+ auto struct_name = NormalizedName(struct_def);
+ auto vectortype = field.value.type.VectorType();
+
+ code += GenIndents(indents) + struct_name + "Start" + field_accessor_name +
+ "Vector(builder, len(self." + field_instance_name + "))";
+ code += GenIndents(indents) + "for i in reversed(range(len(self." +
+ field_instance_name + "))):";
+ code += GenIndents(indents + 1) + "builder.Prepend";
+
+ std::string type_name;
+ switch (vectortype.base_type) {
+ case BASE_TYPE_BOOL: type_name = "Bool"; break;
+ case BASE_TYPE_CHAR: type_name = "Byte"; break;
+ case BASE_TYPE_UCHAR: type_name = "Uint8"; break;
+ case BASE_TYPE_SHORT: type_name = "Int16"; break;
+ case BASE_TYPE_USHORT: type_name = "Uint16"; break;
+ case BASE_TYPE_INT: type_name = "Int32"; break;
+ case BASE_TYPE_UINT: type_name = "Uint32"; break;
+ case BASE_TYPE_LONG: type_name = "Int64"; break;
+ case BASE_TYPE_ULONG: type_name = "Uint64"; break;
+ case BASE_TYPE_FLOAT: type_name = "Float32"; break;
+ case BASE_TYPE_DOUBLE: type_name = "Float64"; break;
+ case BASE_TYPE_STRING: type_name = "UOffsetTRelative"; break;
+ default: type_name = "VOffsetT"; break;
+ }
+ code += type_name;
+ }
+
+ void GenPackForScalarVectorField(const StructDef &struct_def,
+ const FieldDef &field,
+ std::string *code_prefix_ptr,
+ std::string *code_ptr) {
+ auto &code = *code_ptr;
+ auto &code_prefix = *code_prefix_ptr;
+ auto field_instance_name = MakeLowerCamel(field);
+ auto field_accessor_name = MakeUpperCamel(field);
+ auto struct_name = NormalizedName(struct_def);
+
+ // Adds the field into the struct.
+ code += GenIndents(2) + "if self." + field_instance_name + " is not None:";
+ code += GenIndents(3) + struct_name + "Add" + field_accessor_name +
+ "(builder, " + field_instance_name + ")";
+
+ // Creates the field.
+ code_prefix +=
+ GenIndents(2) + "if self." + field_instance_name + " is not None:";
+ // If the vector is a string vector, we need to first build accessor for
+ // each string element. And this generated code, needs to be
+ // placed ahead of code_prefix.
+ auto vectortype = field.value.type.VectorType();
+ if (IsString(vectortype)) {
+ code_prefix += GenIndents(3) + MakeLowerCamel(field) + "list = []";
+ code_prefix += GenIndents(3) + "for i in range(len(self." +
+ field_instance_name + ")):";
+ code_prefix += GenIndents(4) + MakeLowerCamel(field) +
+ "list.append(builder.CreateString(self." +
+ field_instance_name + "[i]))";
+ GenPackForScalarVectorFieldHelper(struct_def, field, code_prefix_ptr, 3);
+ code_prefix += "(" + MakeLowerCamel(field) + "list[i])";
+ code_prefix += GenIndents(3) + field_instance_name +
+ " = builder.EndVector(len(self." + field_instance_name +
+ "))";
+ return;
+ }
+
+ code_prefix += GenIndents(3) + "if np is not None and type(self." +
+ field_instance_name + ") is np.ndarray:";
+ code_prefix += GenIndents(4) + field_instance_name +
+ " = builder.CreateNumpyVector(self." + field_instance_name +
+ ")";
+ code_prefix += GenIndents(3) + "else:";
+ GenPackForScalarVectorFieldHelper(struct_def, field, code_prefix_ptr, 4);
+ code_prefix += "(self." + field_instance_name + "[i])";
+ code_prefix += GenIndents(4) + field_instance_name +
+ " = builder.EndVector(len(self." + field_instance_name +
+ "))";
+ }
+
+ void GenPackForStructField(const StructDef &struct_def, const FieldDef &field,
+ std::string *code_prefix_ptr,
+ std::string *code_ptr) {
+ auto &code_prefix = *code_prefix_ptr;
+ auto &code = *code_ptr;
+ auto field_instance_name = MakeLowerCamel(field);
+
+ auto field_accessor_name = MakeUpperCamel(field);
+ auto struct_name = NormalizedName(struct_def);
+
+ if (field.value.type.struct_def->fixed) {
+ // Pure struct fields need to be created along with their parent
+ // structs.
+ code +=
+ GenIndents(2) + "if self." + field_instance_name + " is not None:";
+ code += GenIndents(3) + field_instance_name + " = self." +
+ field_instance_name + ".Pack(builder)";
+ } else {
+ // Tables need to be created before their parent structs are created.
+ code_prefix +=
+ GenIndents(2) + "if self." + field_instance_name + " is not None:";
+ code_prefix += GenIndents(3) + field_instance_name + " = self." +
+ field_instance_name + ".Pack(builder)";
+ code +=
+ GenIndents(2) + "if self." + field_instance_name + " is not None:";
+ }
+
+ code += GenIndents(3) + struct_name + "Add" + field_accessor_name +
+ "(builder, " + field_instance_name + ")";
+ }
+
+ void GenPackForUnionField(const StructDef &struct_def, const FieldDef &field,
+ std::string *code_prefix_ptr,
+ std::string *code_ptr) {
+ auto &code_prefix = *code_prefix_ptr;
+ auto &code = *code_ptr;
+ auto field_instance_name = MakeLowerCamel(field);
+
+ auto field_accessor_name = MakeUpperCamel(field);
+ auto struct_name = NormalizedName(struct_def);
+
+ // TODO(luwa): TypeT should be moved under the None check as well.
+ code_prefix +=
+ GenIndents(2) + "if self." + field_instance_name + " is not None:";
+ code_prefix += GenIndents(3) + field_instance_name + " = self." +
+ field_instance_name + ".Pack(builder)";
+ code += GenIndents(2) + "if self." + field_instance_name + " is not None:";
+ code += GenIndents(3) + struct_name + "Add" + field_accessor_name +
+ "(builder, " + field_instance_name + ")";
+ }
+
+ void GenPackForTable(const StructDef &struct_def, std::string *code_ptr) {
+ auto &code_base = *code_ptr;
+ std::string code, code_prefix;
+ auto struct_instance_name = MakeLowerCamel(struct_def);
+ auto struct_name = NormalizedName(struct_def);
+
+ GenReceiverForObjectAPI(struct_def, code_ptr);
+ code_base += "Pack(self, builder):";
+ code += GenIndents(2) + struct_name + "Start(builder)";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+
+ auto field_accessor_name = MakeUpperCamel(field);
+ auto field_instance_name = MakeLowerCamel(field);
+
+ switch (field.value.type.base_type) {
+ case BASE_TYPE_STRUCT: {
+ GenPackForStructField(struct_def, field, &code_prefix, &code);
+ break;
+ }
+ case BASE_TYPE_UNION: {
+ GenPackForUnionField(struct_def, field, &code_prefix, &code);
+ break;
+ }
+ case BASE_TYPE_VECTOR: {
+ auto vectortype = field.value.type.VectorType();
+ if (vectortype.base_type == BASE_TYPE_STRUCT) {
+ GenPackForStructVectorField(struct_def, field, &code_prefix, &code);
+ } else {
+ GenPackForScalarVectorField(struct_def, field, &code_prefix, &code);
+ }
+ break;
+ }
+ case BASE_TYPE_ARRAY: {
+ GenPackForScalarVectorField(struct_def, field, &code_prefix, &code);
+ break;
+ }
+ case BASE_TYPE_STRING: {
+ code_prefix += GenIndents(2) + "if self." + field_instance_name +
+ " is not None:";
+ code_prefix += GenIndents(3) + field_instance_name +
+ " = builder.CreateString(self." + field_instance_name +
+ ")";
+ code += GenIndents(2) + "if self." + field_instance_name +
+ " is not None:";
+ code += GenIndents(3) + struct_name + "Add" + field_accessor_name +
+ "(builder, " + field_instance_name + ")";
+ break;
+ }
+ default:
+ // Generates code for scalar values. If the value equals to the
+ // default value, builder will automatically ignore it. So we don't
+ // need to check the value ahead.
+ code += GenIndents(2) + struct_name + "Add" + field_accessor_name +
+ "(builder, self." + field_instance_name + ")";
+ break;
+ }
+ }
+
+ code += GenIndents(2) + struct_instance_name + " = " + struct_name +
+ "End(builder)";
+ code += GenIndents(2) + "return " + struct_instance_name;
+
+ code_base += code_prefix + code;
+ code_base += "\n";
+ }
+
+ void GenStructForObjectAPI(const StructDef &struct_def,
+ std::string *code_ptr) {
+ if (struct_def.generated) return;
+
+ std::set<std::string> import_list;
+ std::string code;
+
+ // Creates an object class for a struct or a table
+ BeginClassForObjectAPI(struct_def, &code);
+
+ GenInitialize(struct_def, &code, &import_list);
+
+ InitializeFromBuf(struct_def, &code);
+
+ InitializeFromObjForObject(struct_def, &code);
+
+ GenUnPack(struct_def, &code);
+
+ if (struct_def.fixed) {
+ GenPackForStruct(struct_def, &code);
+ } else {
+ GenPackForTable(struct_def, &code);
+ }
+
+ // Adds the imports at top.
+ auto &code_base = *code_ptr;
+ code_base += "\n";
+ for (auto it = import_list.begin(); it != import_list.end(); it++) {
+ auto im = *it;
+ code_base += im + "\n";
+ }
+ code_base += code;
+ }
+
+ void GenUnionCreatorForStruct(const EnumDef &enum_def, const EnumVal &ev,
+ std::string *code_ptr) {
+ auto &code = *code_ptr;
+ auto union_name = NormalizedName(enum_def);
+ auto field_name = NormalizedName(ev);
+ auto field_type = GenTypeGet(ev.union_type) + "T";
+
+ code += GenIndents(1) + "if unionType == " + union_name + "()." +
+ field_name + ":";
+ if (parser_.opts.include_dependence_headers) {
+ auto package_reference = GenPackageReference(ev.union_type);
+ code += GenIndents(2) + "import " + package_reference;
+ field_type = package_reference + "." + field_type;
+ }
+ code += GenIndents(2) + "return " + field_type +
+ ".InitFromBuf(table.Bytes, table.Pos)";
+ }
+
+ void GenUnionCreatorForString(const EnumDef &enum_def, const EnumVal &ev,
+ std::string *code_ptr) {
+ auto &code = *code_ptr;
+ auto union_name = NormalizedName(enum_def);
+ auto field_name = NormalizedName(ev);
+
+ code += GenIndents(1) + "if unionType == " + union_name + "()." +
+ field_name + ":";
+ code += GenIndents(2) + "tab = Table(table.Bytes, table.Pos)";
+ code += GenIndents(2) + "union = tab.String(table.Pos)";
+ code += GenIndents(2) + "return union";
+ }
+
+ // Creates an union object based on union type.
+ void GenUnionCreator(const EnumDef &enum_def, std::string *code_ptr) {
+ auto &code = *code_ptr;
+ auto union_name = MakeUpperCamel(enum_def);
+
+ code += "\n";
+ code += "def " + union_name + "Creator(unionType, table):";
+ code += GenIndents(1) + "from flatbuffers.table import Table";
+ code += GenIndents(1) + "if not isinstance(table, Table):";
+ code += GenIndents(2) + "return None";
+
+ for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
+ auto &ev = **it;
+ // Union only supports string and table.
+ switch (ev.union_type.base_type) {
+ case BASE_TYPE_STRUCT:
+ GenUnionCreatorForStruct(enum_def, ev, &code);
+ break;
+ case BASE_TYPE_STRING:
+ GenUnionCreatorForString(enum_def, ev, &code);
+ break;
+ default: break;
+ }
+ }
+ code += GenIndents(1) + "return None";
+ code += "\n";
+ }
+
// Generate enum declarations.
void GenEnum(const EnumDef &enum_def, std::string *code_ptr) {
if (enum_def.generated) return;
@@ -693,7 +1527,7 @@
case BASE_TYPE_VECTOR: return GenGetter(type.VectorType());
default:
return "self._tab.Get(flatbuffers.number_types." +
- MakeCamel(GenTypeGet(type)) + "Flags, ";
+ MakeCamel(GenTypeGet(type)) + "Flags, ";
}
}
@@ -705,15 +1539,15 @@
}
std::string GenTypeBasic(const Type &type) {
- static const char *ctypename[] = {
// clang-format off
+ static const char *ctypename[] = {
#define FLATBUFFERS_TD(ENUM, IDLTYPE, \
- CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \
+ CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, ...) \
#PTYPE,
FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
#undef FLATBUFFERS_TD
- // clang-format on
};
+ // clang-format on
return ctypename[IsArray(type) ? type.VectorType().base_type
: type.base_type];
}
@@ -738,10 +1572,13 @@
}
// Create a struct with a builder and the struct's arguments.
- void GenStructBuilder(const StructDef &struct_def,
- std::string *code_ptr) {
+ void GenStructBuilder(const StructDef &struct_def, std::string *code_ptr) {
BeginBuilderArgs(struct_def, code_ptr);
- StructBuilderArgs(struct_def, "", code_ptr);
+ StructBuilderArgs(struct_def,
+ /* nameprefix = */ "",
+ /* namesuffix = */ "",
+ /* has_field_name = */ true,
+ /* fieldname_suffix = */ "_", code_ptr);
EndBuilderArgs(code_ptr);
StructBuilderBody(struct_def, "", code_ptr);
@@ -761,6 +1598,9 @@
auto &enum_def = **it;
std::string enumcode;
GenEnum(enum_def, &enumcode);
+ if (parser_.opts.generate_object_based_api & enum_def.is_union) {
+ GenUnionCreator(enum_def, &enumcode);
+ }
if (!SaveType(enum_def, enumcode, false)) return false;
}
return true;
@@ -772,6 +1612,9 @@
auto &struct_def = **it;
std::string declcode;
GenStruct(struct_def, &declcode);
+ if (parser_.opts.generate_object_based_api) {
+ GenStructForObjectAPI(struct_def, &declcode);
+ }
if (!SaveType(struct_def, declcode, true)) return false;
}
return true;
@@ -780,10 +1623,14 @@
// Begin by declaring namespace and imports.
void BeginFile(const std::string &name_space_name, const bool needs_imports,
std::string *code_ptr) {
- std::string &code = *code_ptr;
+ auto &code = *code_ptr;
code = code + "# " + FlatBuffersGeneratedWarning() + "\n\n";
code += "# namespace: " + name_space_name + "\n\n";
- if (needs_imports) { code += "import flatbuffers\n\n"; }
+ if (needs_imports) {
+ code += "import flatbuffers\n";
+ code += "from flatbuffers.compat import import_numpy\n";
+ code += "np = import_numpy()\n\n";
+ }
}
// Save out the generated code for a Python Table type.
@@ -807,6 +1654,7 @@
NamespaceDir(*def.defined_namespace) + NormalizedName(def) + ".py";
return SaveFile(filename.c_str(), code, false);
}
+
private:
std::unordered_set<std::string> keywords_;
const SimpleFloatConstantGenerator float_const_gen_;
diff --git a/src/idl_gen_rust.cpp b/src/idl_gen_rust.cpp
index 936ac83..3995a7f 100644
--- a/src/idl_gen_rust.cpp
+++ b/src/idl_gen_rust.cpp
@@ -23,27 +23,20 @@
namespace flatbuffers {
-static std::string GeneratedFileName(const std::string &path,
- const std::string &file_name) {
- return path + file_name + "_generated.rs";
-}
-
// Convert a camelCaseIdentifier or CamelCaseIdentifier to a
// snake_case_indentifier.
std::string MakeSnakeCase(const std::string &in) {
std::string s;
for (size_t i = 0; i < in.length(); i++) {
if (i == 0) {
- s += static_cast<char>(tolower(in[0]));
+ s += CharToLower(in[0]);
} else if (in[i] == '_') {
s += '_';
} else if (!islower(in[i])) {
// Prevent duplicate underscores for Upper_Snake_Case strings
// and UPPERCASE strings.
- if (islower(in[i - 1])) {
- s += '_';
- }
- s += static_cast<char>(tolower(in[i]));
+ if (islower(in[i - 1])) { s += '_'; }
+ s += CharToLower(in[i]);
} else {
s += in[i];
}
@@ -54,9 +47,7 @@
// Convert a string to all uppercase.
std::string MakeUpper(const std::string &in) {
std::string s;
- for (size_t i = 0; i < in.length(); i++) {
- s += static_cast<char>(toupper(in[i]));
- }
+ for (size_t i = 0; i < in.length(); i++) { s += CharToUpper(in[i]); }
return s;
}
@@ -96,7 +87,7 @@
FullType GetFullType(const Type &type) {
// N.B. The order of these conditionals matters for some types.
- if (type.base_type == BASE_TYPE_STRING) {
+ if (IsString(type)) {
return ftString;
} else if (type.base_type == BASE_TYPE_STRUCT) {
if (type.struct_def->fixed) {
@@ -104,7 +95,7 @@
} else {
return ftTable;
}
- } else if (type.base_type == BASE_TYPE_VECTOR) {
+ } else if (IsVector(type)) {
switch (GetFullType(type.VectorType())) {
case ftInteger: {
return ftVectorOfInteger;
@@ -184,13 +175,21 @@
}
}
+bool IsBitFlagsEnum(const EnumDef &enum_def) {
+ return enum_def.attributes.Lookup("bit_flags") != nullptr;
+}
+bool IsBitFlagsEnum(const FieldDef &field) {
+ EnumDef* ed = field.value.type.enum_def;
+ return ed && IsBitFlagsEnum(*ed);
+}
+
namespace rust {
class RustGenerator : public BaseGenerator {
public:
RustGenerator(const Parser &parser, const std::string &path,
const std::string &file_name)
- : BaseGenerator(parser, path, file_name, "", "::"),
+ : BaseGenerator(parser, path, file_name, "", "::", "rs"),
cur_name_space_(nullptr) {
const char *keywords[] = {
// list taken from:
@@ -200,77 +199,19 @@
// changes to that webpage in the future.
// currently-used keywords
- "as",
- "break",
- "const",
- "continue",
- "crate",
- "else",
- "enum",
- "extern",
- "false",
- "fn",
- "for",
- "if",
- "impl",
- "in",
- "let",
- "loop",
- "match",
- "mod",
- "move",
- "mut",
- "pub",
- "ref",
- "return",
- "Self",
- "self",
- "static",
- "struct",
- "super",
- "trait",
- "true",
- "type",
- "unsafe",
- "use",
- "where",
- "while",
+ "as", "break", "const", "continue", "crate", "else", "enum", "extern",
+ "false", "fn", "for", "if", "impl", "in", "let", "loop", "match", "mod",
+ "move", "mut", "pub", "ref", "return", "Self", "self", "static", "struct",
+ "super", "trait", "true", "type", "unsafe", "use", "where", "while",
// future possible keywords
- "abstract",
- "alignof",
- "become",
- "box",
- "do",
- "final",
- "macro",
- "offsetof",
- "override",
- "priv",
- "proc",
- "pure",
- "sizeof",
- "typeof",
- "unsized",
- "virtual",
- "yield",
+ "abstract", "alignof", "become", "box", "do", "final", "macro",
+ "offsetof", "override", "priv", "proc", "pure", "sizeof", "typeof",
+ "unsized", "virtual", "yield",
// other rust terms we should not use
- "std",
- "usize",
- "isize",
- "u8",
- "i8",
- "u16",
- "i16",
- "u32",
- "i32",
- "u64",
- "i64",
- "u128",
- "i128",
- "f32",
- "f64",
+ "std", "usize", "isize", "u8", "i8", "u16", "i16", "u32", "i32", "u64",
+ "i64", "u128", "i128", "f32", "f64",
// These are terms the code generator can implement on types.
//
@@ -281,13 +222,12 @@
// implementation detail, and how we implement methods could change in
// the future. as a result, we proactively block these out as reserved
// words.
- "follow",
- "push",
- "size",
- "alignment",
- "to_little_endian",
- "from_little_endian",
- nullptr };
+ "follow", "push", "size", "alignment", "to_little_endian",
+ "from_little_endian", nullptr,
+
+ // used by Enum constants
+ "ENUM_MAX", "ENUM_MIN", "ENUM_VALUES",
+ };
for (auto kw = keywords; *kw; kw++) keywords_.insert(*kw);
}
@@ -310,8 +250,7 @@
// TODO(rw): Use a set data structure to reduce namespace evaluations from
// O(n**2) to O(n).
for (auto ns_it = parser_.namespaces_.begin();
- ns_it != parser_.namespaces_.end();
- ++ns_it) {
+ ns_it != parser_.namespaces_.end(); ++ns_it) {
const auto &ns = *ns_it;
// Generate code for all the enum declarations.
@@ -357,7 +296,7 @@
}
if (cur_name_space_) SetNameSpace(nullptr);
- const auto file_path = GeneratedFileName(path_, file_name_);
+ const auto file_path = GeneratedFileName(path_, file_name_, parser_.opts);
const auto final_code = code_.ToString();
return SaveFile(file_path.c_str(), final_code, false);
}
@@ -381,8 +320,12 @@
case ftBool:
case ftEnumKey:
case ftUnionKey:
- case ftUnionValue: { return false; }
- default: { return true; }
+ case ftUnionValue: {
+ return false;
+ }
+ default: {
+ return true;
+ }
}
}
@@ -393,35 +336,14 @@
for (auto it = struct_def.fields.vec.begin();
it != struct_def.fields.vec.end(); ++it) {
const auto &field = **it;
- if (field.deprecated) {
- continue;
- }
+ if (field.deprecated) { continue; }
- if (TableBuilderTypeNeedsLifetime(field.value.type)) {
- return true;
- }
+ if (TableBuilderTypeNeedsLifetime(field.value.type)) { return true; }
}
return false;
}
- // Determine if a Type needs to be copied (for endian safety) when used in a
- // Struct.
- bool StructMemberAccessNeedsCopy(const Type &type) const {
- switch (GetFullType(type)) {
- case ftInteger: // requires endian swap
- case ftFloat: // requires endian swap
- case ftBool: // no endian-swap, but do the copy for UX consistency
- case ftEnumKey: { return true; } // requires endian swap
- case ftStruct: { return false; } // no endian swap
- default: {
- // logic error: no other types can be struct members.
- FLATBUFFERS_ASSERT(false && "invalid struct member type");
- return false; // only to satisfy compiler's return analysis
- }
- }
- }
-
std::string EscapeKeyword(const std::string &name) const {
return keywords_.find(name) == keywords_.end() ? name : name + "_";
}
@@ -477,7 +399,7 @@
auto s = src->components.begin();
auto d = dst->components.begin();
- for(;;) {
+ for (;;) {
if (s == src->components.end()) { break; }
if (d == dst->components.end()) { break; }
if (*s != *d) { break; }
@@ -486,9 +408,7 @@
++i;
}
- for (; s != src->components.end(); ++s) {
- stream << "super::";
- }
+ for (; s != src->components.end(); ++s) { stream << "super::"; }
for (; d != dst->components.end(); ++d) {
stream << MakeSnakeCase(*d) + "::";
}
@@ -509,19 +429,23 @@
case ftFloat:
case ftBool:
case ftEnumKey:
- case ftUnionKey: { break; }
- default: { FLATBUFFERS_ASSERT(false && "incorrect type given");}
+ case ftUnionKey: {
+ break;
+ }
+ default: {
+ FLATBUFFERS_ASSERT(false && "incorrect type given");
+ }
}
// clang-format off
static const char * const ctypename[] = {
#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, \
- RTYPE, KTYPE) \
- #RTYPE,
- FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
+ RTYPE, ...) \
+ #RTYPE,
+ FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
#undef FLATBUFFERS_TD
- // clang-format on
};
+ // clang-format on
if (type.enum_def) { return WrapInNameSpace(*type.enum_def); }
return ctypename[type.base_type];
@@ -535,15 +459,15 @@
FLATBUFFERS_ASSERT(false && "precondition failed in GetEnumTypeForDecl");
}
- static const char *ctypename[] = {
// clang-format off
+ static const char *ctypename[] = {
#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, \
- RTYPE, KTYPE) \
- #RTYPE,
- FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
+ RTYPE, ...) \
+ #RTYPE,
+ FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
#undef FLATBUFFERS_TD
- // clang-format on
};
+ // clang-format on
// Enums can be bools, but their Rust representation must be a u8, as used
// in the repr attribute (#[repr(bool)] is an invalid attribute).
@@ -560,21 +484,42 @@
case ftBool:
case ftEnumKey:
case ftUnionKey: {
- return GetTypeBasic(type); }
+ return GetTypeBasic(type);
+ }
case ftTable: {
return WrapInNameSpace(type.struct_def->defined_namespace,
- type.struct_def->name) + "<'a>"; }
+ type.struct_def->name) +
+ "<'a>";
+ }
default: {
return WrapInNameSpace(type.struct_def->defined_namespace,
- type.struct_def->name); }
+ type.struct_def->name);
+ }
}
}
- std::string GetEnumValUse(const EnumDef &enum_def,
+ std::string GetEnumValue(const EnumDef &enum_def,
const EnumVal &enum_val) const {
return Name(enum_def) + "::" + Name(enum_val);
}
+ // 1 suffix since old C++ can't figure out the overload.
+ void ForAllEnumValues1(const EnumDef &enum_def,
+ std::function<void(const EnumVal&)> cb) {
+ for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
+ const auto &ev = **it;
+ code_.SetValue("VARIANT", Name(ev));
+ code_.SetValue("VALUE", enum_def.ToString(ev));
+ cb(ev);
+ }
+ }
+ void ForAllEnumValues(const EnumDef &enum_def, std::function<void()> cb) {
+ std::function<void(const EnumVal&)> wrapped = [&](const EnumVal& unused) {
+ (void) unused;
+ cb();
+ };
+ ForAllEnumValues1(enum_def, wrapped);
+ }
// Generate an enum declaration,
// an enum string lookup table,
// an enum match function,
@@ -582,61 +527,139 @@
void GenEnum(const EnumDef &enum_def) {
code_.SetValue("ENUM_NAME", Name(enum_def));
code_.SetValue("BASE_TYPE", GetEnumTypeForDecl(enum_def.underlying_type));
-
- GenComment(enum_def.doc_comment);
- code_ += "#[allow(non_camel_case_types)]";
- code_ += "#[repr({{BASE_TYPE}})]";
- code_ += "#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]";
- code_ += "pub enum " + Name(enum_def) + " {";
-
- for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
- const auto &ev = **it;
-
- GenComment(ev.doc_comment, " ");
- code_.SetValue("KEY", Name(ev));
- code_.SetValue("VALUE", enum_def.ToString(ev));
- code_ += " {{KEY}} = {{VALUE}},";
- }
+ code_.SetValue("ENUM_NAME_SNAKE", MakeSnakeCase(Name(enum_def)));
+ code_.SetValue("ENUM_NAME_CAPS", MakeUpper(MakeSnakeCase(Name(enum_def))));
const EnumVal *minv = enum_def.MinValue();
const EnumVal *maxv = enum_def.MaxValue();
FLATBUFFERS_ASSERT(minv && maxv);
-
- code_ += "";
- code_ += "}";
- code_ += "";
-
- code_.SetValue("ENUM_NAME", Name(enum_def));
- code_.SetValue("ENUM_NAME_SNAKE", MakeSnakeCase(Name(enum_def)));
- code_.SetValue("ENUM_NAME_CAPS", MakeUpper(MakeSnakeCase(Name(enum_def))));
code_.SetValue("ENUM_MIN_BASE_VALUE", enum_def.ToString(*minv));
code_.SetValue("ENUM_MAX_BASE_VALUE", enum_def.ToString(*maxv));
- // Generate enum constants, and impls for Follow, EndianScalar, and Push.
- code_ += "const ENUM_MIN_{{ENUM_NAME_CAPS}}: {{BASE_TYPE}} = \\";
- code_ += "{{ENUM_MIN_BASE_VALUE}};";
- code_ += "const ENUM_MAX_{{ENUM_NAME_CAPS}}: {{BASE_TYPE}} = \\";
- code_ += "{{ENUM_MAX_BASE_VALUE}};";
+ if (IsBitFlagsEnum(enum_def)) {
+ // Defer to the convenient and canonical bitflags crate. We declare it in a
+ // module to #allow camel case constants in a smaller scope. This matches
+ // Flatbuffers c-modeled enums where variants are associated constants but
+ // in camel case.
+ code_ += "#[allow(non_upper_case_globals)]";
+ code_ += "mod bitflags_{{ENUM_NAME_SNAKE}} {";
+ code_ += " flatbuffers::bitflags::bitflags! {";
+ GenComment(enum_def.doc_comment, " ");
+ code_ += " pub struct {{ENUM_NAME}}: {{BASE_TYPE}} {";
+ ForAllEnumValues1(enum_def, [&](const EnumVal &ev){
+ this->GenComment(ev.doc_comment, " ");
+ code_ += " const {{VARIANT}} = {{VALUE}};";
+ });
+ code_ += " }";
+ code_ += " }";
+ code_ += "}";
+ code_ += "pub use self::bitflags_{{ENUM_NAME_SNAKE}}::{{ENUM_NAME}};";
+ code_ += "";
+
+ // Generate Follow and Push so we can serialize and stuff.
+ code_ += "impl<'a> flatbuffers::Follow<'a> for {{ENUM_NAME}} {";
+ code_ += " type Inner = Self;";
+ code_ += " #[inline]";
+ code_ += " fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {";
+ code_ += " let bits = flatbuffers::read_scalar_at::<{{BASE_TYPE}}>(buf, loc);";
+ code_ += " unsafe { Self::from_bits_unchecked(bits) }";
+ code_ += " }";
+ code_ += "}";
+ code_ += "";
+ code_ += "impl flatbuffers::Push for {{ENUM_NAME}} {";
+ code_ += " type Output = {{ENUM_NAME}};";
+ code_ += " #[inline]";
+ code_ += " fn push(&self, dst: &mut [u8], _rest: &[u8]) {";
+ code_ += " flatbuffers::emplace_scalar::<{{BASE_TYPE}}>"
+ "(dst, self.bits());";
+ code_ += " }";
+ code_ += "}";
+ code_ += "";
+ code_ += "impl flatbuffers::EndianScalar for {{ENUM_NAME}} {";
+ code_ += " #[inline]";
+ code_ += " fn to_little_endian(self) -> Self {";
+ code_ += " let bits = {{BASE_TYPE}}::to_le(self.bits());";
+ code_ += " unsafe { Self::from_bits_unchecked(bits) }";
+ code_ += " }";
+ code_ += " #[inline]";
+ code_ += " fn from_little_endian(self) -> Self {";
+ code_ += " let bits = {{BASE_TYPE}}::from_le(self.bits());";
+ code_ += " unsafe { Self::from_bits_unchecked(bits) }";
+ code_ += " }";
+ code_ += "}";
+ code_ += "";
+ return;
+ }
+
+ // Deprecated associated constants;
+ code_ += "#[deprecated(since = \"1.13\", note = \"Use associated constants"
+ " instead. This will no longer be generated in 2021.\")]";
+ code_ += "pub const ENUM_MIN_{{ENUM_NAME_CAPS}}: {{BASE_TYPE}}"
+ " = {{ENUM_MIN_BASE_VALUE}};";
+ code_ += "#[deprecated(since = \"1.13\", note = \"Use associated constants"
+ " instead. This will no longer be generated in 2021.\")]";
+ code_ += "pub const ENUM_MAX_{{ENUM_NAME_CAPS}}: {{BASE_TYPE}}"
+ " = {{ENUM_MAX_BASE_VALUE}};";
+ auto num_fields = NumToString(enum_def.size());
+ code_ += "#[deprecated(since = \"1.13\", note = \"Use associated constants"
+ " instead. This will no longer be generated in 2021.\")]";
+ code_ += "#[allow(non_camel_case_types)]";
+ code_ += "pub const ENUM_VALUES_{{ENUM_NAME_CAPS}}: [{{ENUM_NAME}}; " +
+ num_fields + "] = [";
+ ForAllEnumValues1(enum_def, [&](const EnumVal &ev){
+ code_ += " " + GetEnumValue(enum_def, ev) + ",";
+ });
+ code_ += "];";
code_ += "";
+
+ GenComment(enum_def.doc_comment);
+ code_ +=
+ "#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]";
+ code_ += "#[repr(transparent)]";
+ code_ += "pub struct {{ENUM_NAME}}(pub {{BASE_TYPE}});";
+ code_ += "#[allow(non_upper_case_globals)]";
+ code_ += "impl {{ENUM_NAME}} {";
+ ForAllEnumValues1(enum_def, [&](const EnumVal &ev){
+ this->GenComment(ev.doc_comment, " ");
+ code_ += " pub const {{VARIANT}}: Self = Self({{VALUE}});";
+ });
+ code_ += "";
+ // Generate Associated constants
+ code_ += " pub const ENUM_MIN: {{BASE_TYPE}} = {{ENUM_MIN_BASE_VALUE}};";
+ code_ += " pub const ENUM_MAX: {{BASE_TYPE}} = {{ENUM_MAX_BASE_VALUE}};";
+ code_ += " pub const ENUM_VALUES: &'static [Self] = &[";
+ ForAllEnumValues(enum_def, [&](){
+ code_ += " Self::{{VARIANT}},";
+ });
+ code_ += " ];";
+ code_ += " /// Returns the variant's name or \"\" if unknown.";
+ code_ += " pub fn variant_name(self) -> Option<&'static str> {";
+ code_ += " match self {";
+ ForAllEnumValues(enum_def, [&](){
+ code_ += " Self::{{VARIANT}} => Some(\"{{VARIANT}}\"),";
+ });
+ code_ += " _ => None,";
+ code_ += " }";
+ code_ += " }";
+ code_ += "}";
+
+ // Generate Debug. Unknown variants are printed like "<UNKNOWN 42>".
+ code_ += "impl std::fmt::Debug for {{ENUM_NAME}} {";
+ code_ += " fn fmt(&self, f: &mut std::fmt::Formatter) ->"
+ " std::fmt::Result {";
+ code_ += " if let Some(name) = self.variant_name() {";
+ code_ += " f.write_str(name)";
+ code_ += " } else {";
+ code_ += " f.write_fmt(format_args!(\"<UNKNOWN {:?}>\", self.0))";
+ code_ += " }";
+ code_ += " }";
+ code_ += "}";
+
+ // Generate Follow and Push so we can serialize and stuff.
code_ += "impl<'a> flatbuffers::Follow<'a> for {{ENUM_NAME}} {";
code_ += " type Inner = Self;";
code_ += " #[inline]";
code_ += " fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {";
- code_ += " flatbuffers::read_scalar_at::<Self>(buf, loc)";
- code_ += " }";
- code_ += "}";
- code_ += "";
- code_ += "impl flatbuffers::EndianScalar for {{ENUM_NAME}} {";
- code_ += " #[inline]";
- code_ += " fn to_little_endian(self) -> Self {";
- code_ += " let n = {{BASE_TYPE}}::to_le(self as {{BASE_TYPE}});";
- code_ += " let p = &n as *const {{BASE_TYPE}} as *const {{ENUM_NAME}};";
- code_ += " unsafe { *p }";
- code_ += " }";
- code_ += " #[inline]";
- code_ += " fn from_little_endian(self) -> Self {";
- code_ += " let n = {{BASE_TYPE}}::from_le(self as {{BASE_TYPE}});";
- code_ += " let p = &n as *const {{BASE_TYPE}} as *const {{ENUM_NAME}};";
- code_ += " unsafe { *p }";
+ code_ += " Self(flatbuffers::read_scalar_at::<{{BASE_TYPE}}>(buf, loc))";
code_ += " }";
code_ += "}";
code_ += "";
@@ -644,69 +667,23 @@
code_ += " type Output = {{ENUM_NAME}};";
code_ += " #[inline]";
code_ += " fn push(&self, dst: &mut [u8], _rest: &[u8]) {";
- code_ += " flatbuffers::emplace_scalar::<{{ENUM_NAME}}>"
- "(dst, *self);";
+ code_ += " flatbuffers::emplace_scalar::<{{BASE_TYPE}}>"
+ "(dst, self.0);";
code_ += " }";
code_ += "}";
code_ += "";
-
- // Generate an array of all enumeration values.
- auto num_fields = NumToString(enum_def.size());
- code_ += "#[allow(non_camel_case_types)]";
- code_ += "const ENUM_VALUES_{{ENUM_NAME_CAPS}}:[{{ENUM_NAME}}; " +
- num_fields + "] = [";
- for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
- const auto &ev = **it;
- auto value = GetEnumValUse(enum_def, ev);
- auto suffix = *it != enum_def.Vals().back() ? "," : "";
- code_ += " " + value + suffix;
- }
- code_ += "];";
+ code_ += "impl flatbuffers::EndianScalar for {{ENUM_NAME}} {";
+ code_ += " #[inline]";
+ code_ += " fn to_little_endian(self) -> Self {";
+ code_ += " Self({{BASE_TYPE}}::to_le(self.0))";
+ code_ += " }";
+ code_ += " #[inline]";
+ code_ += " fn from_little_endian(self) -> Self {";
+ code_ += " Self({{BASE_TYPE}}::from_le(self.0))";
+ code_ += " }";
+ code_ += "}";
code_ += "";
- // Generate a string table for enum values.
- // Problem is, if values are very sparse that could generate really big
- // tables. Ideally in that case we generate a map lookup instead, but for
- // the moment we simply don't output a table at all.
- auto range = enum_def.Distance();
- // Average distance between values above which we consider a table
- // "too sparse". Change at will.
- static const uint64_t kMaxSparseness = 5;
- if (range / static_cast<uint64_t>(enum_def.size()) < kMaxSparseness) {
- code_ += "#[allow(non_camel_case_types)]";
- code_ += "const ENUM_NAMES_{{ENUM_NAME_CAPS}}:[&'static str; " +
- NumToString(range + 1) + "] = [";
-
- auto val = enum_def.Vals().front();
- for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
- ++it) {
- auto ev = *it;
- for (auto k = enum_def.Distance(val, ev); k > 1; --k) {
- code_ += " \"\",";
- }
- val = ev;
- auto suffix = *it != enum_def.Vals().back() ? "," : "";
- code_ += " \"" + Name(*ev) + "\"" + suffix;
- }
- code_ += "];";
- code_ += "";
-
- code_ +=
- "pub fn enum_name_{{ENUM_NAME_SNAKE}}(e: {{ENUM_NAME}}) -> "
- "&'static str {";
-
- code_ += " let index = e as {{BASE_TYPE}}\\";
- if (enum_def.MinValue()->IsNonZero()) {
- auto vals = GetEnumValUse(enum_def, *enum_def.MinValue());
- code_ += " - " + vals + " as {{BASE_TYPE}}\\";
- }
- code_ += ";";
-
- code_ += " ENUM_NAMES_{{ENUM_NAME_CAPS}}[index as usize]";
- code_ += "}";
- code_ += "";
- }
-
if (enum_def.is_union) {
// Generate tyoesafe offset(s) for unions
code_.SetValue("NAME", Name(enum_def));
@@ -719,30 +696,32 @@
return "VT_" + MakeUpper(Name(field));
}
- std::string GetDefaultConstant(const FieldDef &field) {
- return field.value.type.base_type == BASE_TYPE_FLOAT
- ? field.value.constant + ""
- : field.value.constant;
- }
-
std::string GetDefaultScalarValue(const FieldDef &field) {
switch (GetFullType(field.value.type)) {
- case ftInteger: { return GetDefaultConstant(field); }
- case ftFloat: { return GetDefaultConstant(field); }
+ case ftInteger:
+ case ftFloat: {
+ return field.optional ? "None" : field.value.constant;
+ }
case ftBool: {
- return field.value.constant == "0" ? "false" : "true";
+ return field.optional ? "None"
+ : field.value.constant == "0" ? "false" : "true";
}
case ftUnionKey:
case ftEnumKey: {
+ if (field.optional) {
+ return "None";
+ }
auto ev = field.value.type.enum_def->FindByValue(field.value.constant);
assert(ev);
return WrapInNameSpace(field.value.type.enum_def->defined_namespace,
- GetEnumValUse(*field.value.type.enum_def, *ev));
+ GetEnumValue(*field.value.type.enum_def, *ev));
}
// All pointer-ish types have a default value of None, because they are
// wrapped in Option.
- default: { return "None"; }
+ default: {
+ return "None";
+ }
}
}
@@ -759,14 +738,14 @@
// 3) return a hardcoded value because the vtable field value is set to zero.
std::string TableBuilderArgsDefnType(const FieldDef &field,
const std::string &lifetime) {
- const Type& type = field.value.type;
+ const Type &type = field.value.type;
switch (GetFullType(type)) {
case ftInteger:
case ftFloat:
case ftBool: {
const auto typname = GetTypeBasic(type);
- return typname;
+ return field.optional ? "Option<" + typname + ">" : typname;
}
case ftStruct: {
const auto typname = WrapInNameSpace(*type.struct_def);
@@ -774,7 +753,7 @@
}
case ftTable: {
const auto typname = WrapInNameSpace(*type.struct_def);
- return "Option<flatbuffers::WIPOffset<" + typname + "<" + lifetime + \
+ return "Option<flatbuffers::WIPOffset<" + typname + "<" + lifetime +
">>>";
}
case ftString: {
@@ -783,109 +762,87 @@
case ftEnumKey:
case ftUnionKey: {
const auto typname = WrapInNameSpace(*type.enum_def);
- return typname;
+ return field.optional ? "Option<" + typname + ">" : typname;
}
case ftUnionValue: {
return "Option<flatbuffers::WIPOffset<flatbuffers::UnionWIPOffset>>";
}
case ftVectorOfInteger:
+ case ftVectorOfBool:
case ftVectorOfFloat: {
const auto typname = GetTypeBasic(type.VectorType());
- return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + \
- lifetime + ", " + typname + ">>>";
- }
- case ftVectorOfBool: {
- return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + \
- lifetime + ", bool>>>";
+ return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime +
+ ", " + typname + ">>>";
}
case ftVectorOfEnumKey: {
const auto typname = WrapInNameSpace(*type.enum_def);
- return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + \
- lifetime + ", " + typname + ">>>";
+ return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime +
+ ", " + typname + ">>>";
}
case ftVectorOfStruct: {
const auto typname = WrapInNameSpace(*type.struct_def);
- return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + \
- lifetime + ", " + typname + ">>>";
+ return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime +
+ ", " + typname + ">>>";
}
case ftVectorOfTable: {
const auto typname = WrapInNameSpace(*type.struct_def);
- return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + \
- lifetime + ", flatbuffers::ForwardsUOffset<" + typname + \
- "<" + lifetime + ">>>>>";
+ return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime +
+ ", flatbuffers::ForwardsUOffset<" + typname + "<" + lifetime +
+ ">>>>>";
}
case ftVectorOfString: {
- return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + \
- lifetime + ", flatbuffers::ForwardsUOffset<&" + lifetime + \
- " str>>>>";
+ return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime +
+ ", flatbuffers::ForwardsUOffset<&" + lifetime + " str>>>>";
}
case ftVectorOfUnionValue: {
- const auto typname = WrapInNameSpace(*type.enum_def) + \
- "UnionTableOffset";
- return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + \
- lifetime + ", flatbuffers::ForwardsUOffset<"
- "flatbuffers::Table<" + lifetime + ">>>>";
+ const auto typname =
+ WrapInNameSpace(*type.enum_def) + "UnionTableOffset";
+ return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime +
+ ", flatbuffers::ForwardsUOffset<"
+ "flatbuffers::Table<" +
+ lifetime + ">>>>";
}
}
- return "INVALID_CODE_GENERATION"; // for return analysis
- }
-
- std::string TableBuilderArgsDefaultValue(const FieldDef &field) {
- return GetDefaultScalarValue(field);
- }
- std::string TableBuilderAddFuncDefaultValue(const FieldDef &field) {
- // All branches of switch do the same action!
- switch (GetFullType(field.value.type)) {
- case ftUnionKey:
- case ftEnumKey: {
- const std::string basetype = GetTypeBasic(field.value.type); //<- never used
- return GetDefaultScalarValue(field);
- }
-
- default: { return GetDefaultScalarValue(field); }
- }
+ return "INVALID_CODE_GENERATION"; // for return analysis
}
std::string TableBuilderArgsAddFuncType(const FieldDef &field,
const std::string &lifetime) {
- const Type& type = field.value.type;
+ const Type &type = field.value.type;
switch (GetFullType(field.value.type)) {
case ftVectorOfStruct: {
const auto typname = WrapInNameSpace(*type.struct_def);
- return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + \
- ", " + typname + ">>";
+ return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + ", " +
+ typname + ">>";
}
case ftVectorOfTable: {
const auto typname = WrapInNameSpace(*type.struct_def);
- return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + \
- ", flatbuffers::ForwardsUOffset<" + typname + \
- "<" + lifetime + ">>>>";
+ return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime +
+ ", flatbuffers::ForwardsUOffset<" + typname + "<" + lifetime +
+ ">>>>";
}
case ftVectorOfInteger:
+ case ftVectorOfBool:
case ftVectorOfFloat: {
const auto typname = GetTypeBasic(type.VectorType());
- return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + \
- ", " + typname + ">>";
- }
- case ftVectorOfBool: {
- return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + \
- ", bool>>";
+ return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + ", " +
+ typname + ">>";
}
case ftVectorOfString: {
- return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + \
+ return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime +
", flatbuffers::ForwardsUOffset<&" + lifetime + " str>>>";
}
case ftVectorOfEnumKey: {
const auto typname = WrapInNameSpace(*type.enum_def);
- return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + \
- ", " + typname + ">>";
+ return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + ", " +
+ typname + ">>";
}
case ftVectorOfUnionValue: {
- return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + \
- ", flatbuffers::ForwardsUOffset<flatbuffers::Table<" + \
- lifetime + ">>>";
+ return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime +
+ ", flatbuffers::ForwardsUOffset<flatbuffers::Table<" + lifetime +
+ ">>>";
}
case ftEnumKey: {
const auto typname = WrapInNameSpace(*type.enum_def);
@@ -893,19 +850,16 @@
}
case ftStruct: {
const auto typname = WrapInNameSpace(*type.struct_def);
- return "&" + lifetime + " " + typname + "";
+ return "&" + typname + "";
}
case ftTable: {
const auto typname = WrapInNameSpace(*type.struct_def);
return "flatbuffers::WIPOffset<" + typname + "<" + lifetime + ">>";
}
case ftInteger:
+ case ftBool:
case ftFloat: {
- const auto typname = GetTypeBasic(type);
- return typname;
- }
- case ftBool: {
- return "bool";
+ return GetTypeBasic(type);
}
case ftString: {
return "flatbuffers::WIPOffset<&" + lifetime + " str>";
@@ -919,26 +873,27 @@
}
}
- return "INVALID_CODE_GENERATION"; // for return analysis
+ return "INVALID_CODE_GENERATION"; // for return analysis
}
std::string TableBuilderArgsAddFuncBody(const FieldDef &field) {
- const Type& type = field.value.type;
+ const Type &type = field.value.type;
switch (GetFullType(field.value.type)) {
case ftInteger:
+ case ftBool:
case ftFloat: {
const auto typname = GetTypeBasic(field.value.type);
- return "self.fbb_.push_slot::<" + typname + ">";
+ return (field.optional ? "self.fbb_.push_slot_always::<"
+ : "self.fbb_.push_slot::<") +
+ typname + ">";
}
- case ftBool: {
- return "self.fbb_.push_slot::<bool>";
- }
-
case ftEnumKey:
case ftUnionKey: {
const auto underlying_typname = GetTypeBasic(type);
- return "self.fbb_.push_slot::<" + underlying_typname + ">";
+ return (field.optional ?
+ "self.fbb_.push_slot_always::<" :
+ "self.fbb_.push_slot::<") + underlying_typname + ">";
}
case ftStruct: {
@@ -947,8 +902,8 @@
}
case ftTable: {
const auto typname = WrapInNameSpace(*type.struct_def);
- return "self.fbb_.push_slot_always::<flatbuffers::WIPOffset<" + \
- typname + ">>";
+ return "self.fbb_.push_slot_always::<flatbuffers::WIPOffset<" +
+ typname + ">>";
}
case ftUnionValue:
@@ -964,183 +919,265 @@
return "self.fbb_.push_slot_always::<flatbuffers::WIPOffset<_>>";
}
}
- return "INVALID_CODE_GENERATION"; // for return analysis
+ return "INVALID_CODE_GENERATION"; // for return analysis
}
std::string GenTableAccessorFuncReturnType(const FieldDef &field,
const std::string &lifetime) {
- const Type& type = field.value.type;
-
- switch (GetFullType(field.value.type)) {
- case ftInteger:
- case ftFloat: {
- const auto typname = GetTypeBasic(type);
- return typname;
- }
- case ftBool: {
- return "bool";
- }
- case ftStruct: {
- const auto typname = WrapInNameSpace(*type.struct_def);
- return WrapInOptionIfNotRequired("&" + lifetime + " " + typname, field.required);
- }
- case ftTable: {
- const auto typname = WrapInNameSpace(*type.struct_def);
- return WrapInOptionIfNotRequired(typname + "<" + lifetime + ">", field.required);
- }
- case ftEnumKey:
- case ftUnionKey: {
- const auto typname = WrapInNameSpace(*type.enum_def);
- return typname;
- }
-
- case ftUnionValue: {
- return WrapInOptionIfNotRequired("flatbuffers::Table<" + lifetime + ">", field.required);
- }
- case ftString: {
- return WrapInOptionIfNotRequired("&" + lifetime + " str", field.required);
- }
- case ftVectorOfInteger:
- case ftVectorOfFloat: {
- const auto typname = GetTypeBasic(type.VectorType());
- if (IsOneByte(type.VectorType().base_type)) {
- return WrapInOptionIfNotRequired("&" + lifetime + " [" + typname + "]", field.required);
- }
- return WrapInOptionIfNotRequired("flatbuffers::Vector<" + lifetime + ", " + typname + ">", field.required);
- }
- case ftVectorOfBool: {
- return WrapInOptionIfNotRequired("&" + lifetime + " [bool]", field.required);
- }
- case ftVectorOfEnumKey: {
- const auto typname = WrapInNameSpace(*type.enum_def);
- return WrapInOptionIfNotRequired("flatbuffers::Vector<" + lifetime + ", " + typname + ">", field.required);
- }
- case ftVectorOfStruct: {
- const auto typname = WrapInNameSpace(*type.struct_def);
- return WrapInOptionIfNotRequired("&" + lifetime + " [" + typname + "]", field.required);
- }
- case ftVectorOfTable: {
- const auto typname = WrapInNameSpace(*type.struct_def);
- return WrapInOptionIfNotRequired("flatbuffers::Vector<" + lifetime + ", flatbuffers::ForwardsUOffset<" + \
- typname + "<" + lifetime + ">>>", field.required);
- }
- case ftVectorOfString: {
- return WrapInOptionIfNotRequired("flatbuffers::Vector<" + lifetime + ", flatbuffers::ForwardsUOffset<&" + \
- lifetime + " str>>", field.required);
- }
- case ftVectorOfUnionValue: {
- FLATBUFFERS_ASSERT(false && "vectors of unions are not yet supported");
- // TODO(rw): when we do support these, we should consider using the
- // Into trait to convert tables to typesafe union values.
- return "INVALID_CODE_GENERATION"; // for return analysis
- }
- }
- return "INVALID_CODE_GENERATION"; // for return analysis
- }
-
- std::string GenTableAccessorFuncBody(const FieldDef &field,
- const std::string &lifetime,
- const std::string &offset_prefix) {
- const std::string offset_name = offset_prefix + "::" + \
- GetFieldOffsetName(field);
- const Type& type = field.value.type;
+ const Type &type = field.value.type;
switch (GetFullType(field.value.type)) {
case ftInteger:
case ftFloat:
case ftBool: {
const auto typname = GetTypeBasic(type);
- const auto default_value = GetDefaultScalarValue(field);
- return "self._tab.get::<" + typname + ">(" + offset_name + ", Some(" + \
- default_value + ")).unwrap()";
+ return field.optional ? "Option<" + typname + ">" : typname;
}
case ftStruct: {
const auto typname = WrapInNameSpace(*type.struct_def);
- return AddUnwrapIfRequired("self._tab.get::<" + typname + ">(" + offset_name + ", None)", field.required);
+ return WrapInOptionIfNotRequired("&" + lifetime + " " + typname,
+ field.required);
}
case ftTable: {
const auto typname = WrapInNameSpace(*type.struct_def);
- return AddUnwrapIfRequired("self._tab.get::<flatbuffers::ForwardsUOffset<" + \
- typname + "<" + lifetime + ">>>(" + offset_name + ", None)", field.required);
+ return WrapInOptionIfNotRequired(typname + "<" + lifetime + ">",
+ field.required);
+ }
+ case ftEnumKey:
+ case ftUnionKey: {
+ const auto typname = WrapInNameSpace(*type.enum_def);
+ return field.optional ? "Option<" + typname + ">" : typname;
+ }
+
+ case ftUnionValue: {
+ return WrapInOptionIfNotRequired("flatbuffers::Table<" + lifetime + ">",
+ field.required);
+ }
+ case ftString: {
+ return WrapInOptionIfNotRequired("&" + lifetime + " str",
+ field.required);
+ }
+ case ftVectorOfInteger:
+ case ftVectorOfBool:
+ case ftVectorOfFloat: {
+ const auto typname = GetTypeBasic(type.VectorType());
+ if (IsOneByte(type.VectorType().base_type)) {
+ return WrapInOptionIfNotRequired(
+ "&" + lifetime + " [" + typname + "]", field.required);
+ }
+ return WrapInOptionIfNotRequired(
+ "flatbuffers::Vector<" + lifetime + ", " + typname + ">",
+ field.required);
+ }
+ case ftVectorOfEnumKey: {
+ const auto typname = WrapInNameSpace(*type.enum_def);
+ return WrapInOptionIfNotRequired(
+ "flatbuffers::Vector<" + lifetime + ", " + typname + ">",
+ field.required);
+ }
+ case ftVectorOfStruct: {
+ const auto typname = WrapInNameSpace(*type.struct_def);
+ return WrapInOptionIfNotRequired("&" + lifetime + " [" + typname + "]",
+ field.required);
+ }
+ case ftVectorOfTable: {
+ const auto typname = WrapInNameSpace(*type.struct_def);
+ return WrapInOptionIfNotRequired("flatbuffers::Vector<" + lifetime +
+ ", flatbuffers::ForwardsUOffset<" +
+ typname + "<" + lifetime + ">>>",
+ field.required);
+ }
+ case ftVectorOfString: {
+ return WrapInOptionIfNotRequired(
+ "flatbuffers::Vector<" + lifetime +
+ ", flatbuffers::ForwardsUOffset<&" + lifetime + " str>>",
+ field.required);
+ }
+ case ftVectorOfUnionValue: {
+ FLATBUFFERS_ASSERT(false && "vectors of unions are not yet supported");
+ // TODO(rw): when we do support these, we should consider using the
+ // Into trait to convert tables to typesafe union values.
+ return "INVALID_CODE_GENERATION"; // for return analysis
+ }
+ }
+ return "INVALID_CODE_GENERATION"; // for return analysis
+ }
+
+ std::string GenTableAccessorFuncBody(const FieldDef &field,
+ const std::string &lifetime,
+ const std::string &offset_prefix) {
+ const std::string offset_name =
+ offset_prefix + "::" + GetFieldOffsetName(field);
+ const Type &type = field.value.type;
+
+ switch (GetFullType(field.value.type)) {
+ case ftInteger:
+ case ftFloat:
+ case ftBool: {
+ const auto typname = GetTypeBasic(type);
+ if (field.optional) {
+ return "self._tab.get::<" + typname + ">(" + offset_name + ", None)";
+ } else {
+ const auto default_value = GetDefaultScalarValue(field);
+ return "self._tab.get::<" + typname + ">(" + offset_name + ", Some(" +
+ default_value + ")).unwrap()";
+ }
+ }
+ case ftStruct: {
+ const auto typname = WrapInNameSpace(*type.struct_def);
+ return AddUnwrapIfRequired(
+ "self._tab.get::<" + typname + ">(" + offset_name + ", None)",
+ field.required);
+ }
+ case ftTable: {
+ const auto typname = WrapInNameSpace(*type.struct_def);
+ return AddUnwrapIfRequired(
+ "self._tab.get::<flatbuffers::ForwardsUOffset<" + typname + "<" +
+ lifetime + ">>>(" + offset_name + ", None)",
+ field.required);
}
case ftUnionValue: {
- return AddUnwrapIfRequired("self._tab.get::<flatbuffers::ForwardsUOffset<"
- "flatbuffers::Table<" + lifetime + ">>>(" + offset_name + \
- ", None)", field.required);
+ return AddUnwrapIfRequired(
+ "self._tab.get::<flatbuffers::ForwardsUOffset<"
+ "flatbuffers::Table<" +
+ lifetime + ">>>(" + offset_name + ", None)",
+ field.required);
}
case ftUnionKey:
case ftEnumKey: {
- const auto underlying_typname = GetTypeBasic(type); //<- never used
- const auto typname = WrapInNameSpace(*type.enum_def);
- const auto default_value = GetDefaultScalarValue(field);
- return "self._tab.get::<" + typname + ">(" + offset_name + \
- ", Some(" + default_value + ")).unwrap()";
+ const std::string typname = WrapInNameSpace(*type.enum_def);
+ const std::string default_value = GetDefaultScalarValue(field);
+ if (field.optional) {
+ return "self._tab.get::<" + typname + ">(" + offset_name + ", None)";
+ } else {
+ return "self._tab.get::<" + typname + ">(" + offset_name + ", Some(" +
+ default_value + ")).unwrap()";
+ }
}
case ftString: {
- return AddUnwrapIfRequired("self._tab.get::<flatbuffers::ForwardsUOffset<&str>>(" + \
- offset_name + ", None)", field.required);
+ return AddUnwrapIfRequired(
+ "self._tab.get::<flatbuffers::ForwardsUOffset<&str>>(" +
+ offset_name + ", None)",
+ field.required);
}
case ftVectorOfInteger:
+ case ftVectorOfBool:
case ftVectorOfFloat: {
const auto typname = GetTypeBasic(type.VectorType());
- std::string s = "self._tab.get::<flatbuffers::ForwardsUOffset<"
- "flatbuffers::Vector<" + lifetime + ", " + typname + \
- ">>>(" + offset_name + ", None)";
+ std::string s =
+ "self._tab.get::<flatbuffers::ForwardsUOffset<"
+ "flatbuffers::Vector<" +
+ lifetime + ", " + typname + ">>>(" + offset_name + ", None)";
// single-byte values are safe to slice
if (IsOneByte(type.VectorType().base_type)) {
s += ".map(|v| v.safe_slice())";
}
return AddUnwrapIfRequired(s, field.required);
}
- case ftVectorOfBool: {
- return AddUnwrapIfRequired("self._tab.get::<flatbuffers::ForwardsUOffset<"
- "flatbuffers::Vector<" + lifetime + ", bool>>>(" + \
- offset_name + ", None).map(|v| v.safe_slice())", field.required);
- }
case ftVectorOfEnumKey: {
const auto typname = WrapInNameSpace(*type.enum_def);
- return AddUnwrapIfRequired("self._tab.get::<flatbuffers::ForwardsUOffset<"
- "flatbuffers::Vector<" + lifetime + ", " + typname + ">>>(" + \
- offset_name + ", None)", field.required);
+ return AddUnwrapIfRequired(
+ "self._tab.get::<flatbuffers::ForwardsUOffset<"
+ "flatbuffers::Vector<" +
+ lifetime + ", " + typname + ">>>(" + offset_name + ", None)",
+ field.required);
}
case ftVectorOfStruct: {
const auto typname = WrapInNameSpace(*type.struct_def);
- return AddUnwrapIfRequired("self._tab.get::<flatbuffers::ForwardsUOffset<"
- "flatbuffers::Vector<" + typname + ">>>(" + \
- offset_name + ", None).map(|v| v.safe_slice() )", field.required);
+ return AddUnwrapIfRequired(
+ "self._tab.get::<flatbuffers::ForwardsUOffset<"
+ "flatbuffers::Vector<" +
+ typname + ">>>(" + offset_name +
+ ", None).map(|v| v.safe_slice() )",
+ field.required);
}
case ftVectorOfTable: {
const auto typname = WrapInNameSpace(*type.struct_def);
- return AddUnwrapIfRequired("self._tab.get::<flatbuffers::ForwardsUOffset<"
- "flatbuffers::Vector<flatbuffers::ForwardsUOffset<" + typname + \
- "<" + lifetime + ">>>>>(" + offset_name + ", None)", field.required);
+ return AddUnwrapIfRequired(
+ "self._tab.get::<flatbuffers::ForwardsUOffset<"
+ "flatbuffers::Vector<flatbuffers::ForwardsUOffset<" +
+ typname + "<" + lifetime + ">>>>>(" + offset_name + ", None)",
+ field.required);
}
case ftVectorOfString: {
- return AddUnwrapIfRequired("self._tab.get::<flatbuffers::ForwardsUOffset<"
- "flatbuffers::Vector<flatbuffers::ForwardsUOffset<&" + \
- lifetime + " str>>>>(" + offset_name + ", None)", field.required);
+ return AddUnwrapIfRequired(
+ "self._tab.get::<flatbuffers::ForwardsUOffset<"
+ "flatbuffers::Vector<flatbuffers::ForwardsUOffset<&" +
+ lifetime + " str>>>>(" + offset_name + ", None)",
+ field.required);
}
case ftVectorOfUnionValue: {
FLATBUFFERS_ASSERT(false && "vectors of unions are not yet supported");
- return "INVALID_CODE_GENERATION"; // for return analysis
+ return "INVALID_CODE_GENERATION"; // for return analysis
}
}
- return "INVALID_CODE_GENERATION"; // for return analysis
+ return "INVALID_CODE_GENERATION"; // for return analysis
}
- bool TableFieldReturnsOption(const Type& type) {
- switch (GetFullType(type)) {
+ bool TableFieldReturnsOption(const FieldDef &field) {
+ if (field.optional) return true;
+ switch (GetFullType(field.value.type)) {
case ftInteger:
case ftFloat:
case ftBool:
case ftEnumKey:
- case ftUnionKey:
- return false;
+ case ftUnionKey: return false;
default: return true;
}
}
+ // Generates a fully-qualified name getter for use with --gen-name-strings
+ void GenFullyQualifiedNameGetter(const StructDef &struct_def,
+ const std::string &name) {
+ code_ += " pub const fn get_fully_qualified_name() -> &'static str {";
+ code_ += " \"" +
+ struct_def.defined_namespace->GetFullyQualifiedName(name) + "\"";
+ code_ += " }";
+ code_ += "";
+ }
+
+ void ForAllUnionVariantsBesidesNone(
+ const EnumDef &def,
+ std::function<void(const EnumVal &ev)> cb
+ ) {
+ FLATBUFFERS_ASSERT(def.is_union);
+
+ for (auto it = def.Vals().begin(); it != def.Vals().end(); ++it) {
+ const EnumVal & ev = **it;
+ // TODO(cneo): Can variants be deprecated, should we skip them?
+ if (ev.union_type.base_type == BASE_TYPE_NONE) { continue; }
+ code_.SetValue(
+ "U_ELEMENT_ENUM_TYPE",
+ WrapInNameSpace(def.defined_namespace, GetEnumValue(def, ev)));
+ code_.SetValue("U_ELEMENT_TABLE_TYPE",
+ WrapInNameSpace(ev.union_type.struct_def->defined_namespace,
+ ev.union_type.struct_def->name));
+ code_.SetValue("U_ELEMENT_NAME", MakeSnakeCase(Name(ev)));
+ cb(ev);
+ }
+ }
+
+ void ForAllTableFields(
+ const StructDef &struct_def,
+ std::function<void(const FieldDef&)> cb, bool reversed=false) {
+ // TODO(cneo): Remove `reversed` overload. It's only here to minimize the
+ // diff when refactoring to the `ForAllX` helper functions.
+ auto go = [&](const FieldDef& field) {
+ if (field.deprecated) return;
+ code_.SetValue("OFFSET_NAME", GetFieldOffsetName(field));
+ code_.SetValue("OFFSET_VALUE", NumToString(field.value.offset));
+ code_.SetValue("FIELD_NAME", Name(field));
+ code_.SetValue("DEFAULT_VALUE", GetDefaultScalarValue(field));
+ cb(field);
+ };
+ const auto &fields = struct_def.fields.vec;
+ if (reversed) {
+ for (auto it = fields.rbegin(); it != fields.rend(); ++it) go(**it);
+ } else {
+ for (auto it = fields.begin(); it != fields.end(); ++it) go(**it);
+ }
+ }
// Generate an accessor struct, builder struct, and create function for a
// table.
void GenTable(const StructDef &struct_def) {
@@ -1151,7 +1188,7 @@
// Generate an offset type, the base type, the Follow impl, and the
// init_from_table impl.
code_ += "pub enum {{OFFSET_TYPELABEL}} {}";
- code_ += "#[derive(Copy, Clone, Debug, PartialEq)]";
+ code_ += "#[derive(Copy, Clone, PartialEq)]";
code_ += "";
GenComment(struct_def.doc_comment);
@@ -1164,16 +1201,20 @@
code_ += " type Inner = {{STRUCT_NAME}}<'a>;";
code_ += " #[inline]";
code_ += " fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {";
- code_ += " Self {";
- code_ += " _tab: flatbuffers::Table { buf: buf, loc: loc },";
- code_ += " }";
+ code_ += " Self { _tab: flatbuffers::Table { buf, loc } }";
code_ += " }";
code_ += "}";
code_ += "";
code_ += "impl<'a> {{STRUCT_NAME}}<'a> {";
+
+ if (parser_.opts.generate_name_strings) {
+ GenFullyQualifiedNameGetter(struct_def, struct_def.name);
+ }
+
code_ += " #[inline]";
- code_ += " pub fn init_from_table(table: flatbuffers::Table<'a>) -> "
- "Self {";
+ code_ +=
+ " pub fn init_from_table(table: flatbuffers::Table<'a>) -> "
+ "Self {";
code_ += " {{STRUCT_NAME}} {";
code_ += " _tab: table,";
code_ += " }";
@@ -1181,57 +1222,44 @@
// Generate a convenient create* function that uses the above builder
// to create a table in one function call.
- code_.SetValue("MAYBE_US",
- struct_def.fields.vec.size() == 0 ? "_" : "");
+ code_.SetValue("MAYBE_US", struct_def.fields.vec.size() == 0 ? "_" : "");
code_.SetValue("MAYBE_LT",
- TableBuilderArgsNeedsLifetime(struct_def) ? "<'args>" : "");
+ TableBuilderArgsNeedsLifetime(struct_def) ? "<'args>" : "");
code_ += " #[allow(unused_mut)]";
code_ += " pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>(";
- code_ += " _fbb: "
- "&'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>,";
- code_ += " {{MAYBE_US}}args: &'args {{STRUCT_NAME}}Args{{MAYBE_LT}})"
- " -> flatbuffers::WIPOffset<{{STRUCT_NAME}}<'bldr>> {";
+ code_ +=
+ " _fbb: "
+ "&'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>,";
+ code_ +=
+ " {{MAYBE_US}}args: &'args {{STRUCT_NAME}}Args{{MAYBE_LT}})"
+ " -> flatbuffers::WIPOffset<{{STRUCT_NAME}}<'bldr>> {";
code_ += " let mut builder = {{STRUCT_NAME}}Builder::new(_fbb);";
for (size_t size = struct_def.sortbysize ? sizeof(largest_scalar_t) : 1;
size; size /= 2) {
- for (auto it = struct_def.fields.vec.rbegin();
- it != struct_def.fields.vec.rend(); ++it) {
- const auto &field = **it;
- // TODO(rw): fully understand this sortbysize usage
- if (!field.deprecated && (!struct_def.sortbysize ||
- size == SizeOf(field.value.type.base_type))) {
- code_.SetValue("FIELD_NAME", Name(field));
- if (TableFieldReturnsOption(field.value.type)) {
- code_ += " if let Some(x) = args.{{FIELD_NAME}} "
- "{ builder.add_{{FIELD_NAME}}(x); }";
- } else {
- code_ += " builder.add_{{FIELD_NAME}}(args.{{FIELD_NAME}});";
- }
+ ForAllTableFields(struct_def, [&](const FieldDef &field) {
+ if (struct_def.sortbysize && size != SizeOf(field.value.type.base_type))
+ return;
+ if (TableFieldReturnsOption(field)) {
+ code_ +=
+ " if let Some(x) = args.{{FIELD_NAME}} "
+ "{ builder.add_{{FIELD_NAME}}(x); }";
+ } else {
+ code_ += " builder.add_{{FIELD_NAME}}(args.{{FIELD_NAME}});";
}
- }
+ }, /*reverse=*/true);
}
code_ += " builder.finish()";
code_ += " }";
code_ += "";
// Generate field id constants.
- if (struct_def.fields.vec.size() > 0) {
- for (auto it = struct_def.fields.vec.begin();
- it != struct_def.fields.vec.end(); ++it) {
- const auto &field = **it;
- if (field.deprecated) {
- // Deprecated fields won't be accessible.
- continue;
- }
-
- code_.SetValue("OFFSET_NAME", GetFieldOffsetName(field));
- code_.SetValue("OFFSET_VALUE", NumToString(field.value.offset));
- code_ += " pub const {{OFFSET_NAME}}: flatbuffers::VOffsetT = "
- "{{OFFSET_VALUE}};";
- }
- code_ += "";
- }
+ ForAllTableFields(struct_def, [&](const FieldDef &unused){
+ (void) unused;
+ code_ += " pub const {{OFFSET_NAME}}: flatbuffers::VOffsetT = "
+ "{{OFFSET_VALUE}};";
+ });
+ if (struct_def.fields.vec.size() > 0) code_ += "";
// Generate the accessors. Each has one of two forms:
//
@@ -1245,30 +1273,20 @@
// self._tab.get::<internal_type>(offset, defaultval).unwrap()
// }
const auto offset_prefix = Name(struct_def);
- for (auto it = struct_def.fields.vec.begin();
- it != struct_def.fields.vec.end(); ++it) {
- const auto &field = **it;
- if (field.deprecated) {
- // Deprecated fields won't be accessible.
- continue;
- }
-
- code_.SetValue("FIELD_NAME", Name(field));
+ ForAllTableFields(struct_def, [&](const FieldDef &field) {
code_.SetValue("RETURN_TYPE",
GenTableAccessorFuncReturnType(field, "'a"));
code_.SetValue("FUNC_BODY",
GenTableAccessorFuncBody(field, "'a", offset_prefix));
- GenComment(field.doc_comment, " ");
+ this->GenComment(field.doc_comment, " ");
code_ += " #[inline]";
code_ += " pub fn {{FIELD_NAME}}(&self) -> {{RETURN_TYPE}} {";
code_ += " {{FUNC_BODY}}";
code_ += " }";
// Generate a comparison function for this field if it is a key.
- if (field.key) {
- GenKeyFieldMethods(field);
- }
+ if (field.key) { GenKeyFieldMethods(field); }
// Generate a nested flatbuffer field, if applicable.
auto nested = field.attributes.Lookup("nested_flatbuffer");
@@ -1281,80 +1299,84 @@
nested_root = parser_.LookupStruct(qualified_name);
}
FLATBUFFERS_ASSERT(nested_root); // Guaranteed to exist by parser.
- (void)nested_root;
- code_.SetValue("OFFSET_NAME",
- offset_prefix + "::" + GetFieldOffsetName(field));
- code_ += " pub fn {{FIELD_NAME}}_nested_flatbuffer(&'a self) -> "
- " Option<{{STRUCT_NAME}}<'a>> {";
- code_ += " match self.{{FIELD_NAME}}() {";
- code_ += " None => { None }";
- code_ += " Some(data) => {";
- code_ += " use self::flatbuffers::Follow;";
- code_ += " Some(<flatbuffers::ForwardsUOffset"
- "<{{STRUCT_NAME}}<'a>>>::follow(data, 0))";
- code_ += " },";
- code_ += " }";
+ code_.SetValue("NESTED", WrapInNameSpace(*nested_root));
+ code_ +=
+ " pub fn {{FIELD_NAME}}_nested_flatbuffer(&'a self) -> \\";
+ if (field.required) {
+ code_ += "{{NESTED}}<'a> {";
+ code_ += " let data = self.{{FIELD_NAME}}();";
+ code_ += " use flatbuffers::Follow;";
+ code_ += " <flatbuffers::ForwardsUOffset<{{NESTED}}<'a>>>"
+ "::follow(data, 0)";
+ } else {
+ code_ += "Option<{{NESTED}}<'a>> {";
+ code_ += " self.{{FIELD_NAME}}().map(|data| {";
+ code_ += " use flatbuffers::Follow;";
+ code_ += " <flatbuffers::ForwardsUOffset<{{NESTED}}<'a>>>"
+ "::follow(data, 0)";
+ code_ += " })";
+ }
code_ += " }";
}
- }
+ });
// Explicit specializations for union accessors
- for (auto it = struct_def.fields.vec.begin();
- it != struct_def.fields.vec.end(); ++it) {
- const auto &field = **it;
- if (field.deprecated || field.value.type.base_type != BASE_TYPE_UNION) {
- continue;
- }
-
- auto u = field.value.type.enum_def;
-
- code_.SetValue("FIELD_NAME", Name(field));
-
- for (auto u_it = u->Vals().begin(); u_it != u->Vals().end(); ++u_it) {
- auto &ev = **u_it;
- if (ev.union_type.base_type == BASE_TYPE_NONE) { continue; }
-
- auto table_init_type = WrapInNameSpace(
- ev.union_type.struct_def->defined_namespace,
- ev.union_type.struct_def->name);
-
- code_.SetValue("U_ELEMENT_ENUM_TYPE",
- WrapInNameSpace(u->defined_namespace, GetEnumValUse(*u, ev)));
- code_.SetValue("U_ELEMENT_TABLE_TYPE", table_init_type);
- code_.SetValue("U_ELEMENT_NAME", MakeSnakeCase(Name(ev)));
-
+ ForAllTableFields(struct_def, [&](const FieldDef &field) {
+ if (field.value.type.base_type != BASE_TYPE_UNION) return;
+ code_.SetValue("FIELD_TYPE_FIELD_NAME", field.name);
+ ForAllUnionVariantsBesidesNone(
+ *field.value.type.enum_def, [&](const EnumVal &unused){
+ (void) unused;
code_ += " #[inline]";
code_ += " #[allow(non_snake_case)]";
- code_ += " pub fn {{FIELD_NAME}}_as_{{U_ELEMENT_NAME}}(&self) -> "
- "Option<{{U_ELEMENT_TABLE_TYPE}}<'a>> {";
- code_ += " if self.{{FIELD_NAME}}_type() == {{U_ELEMENT_ENUM_TYPE}} {";
- code_ += " self.{{FIELD_NAME}}().map(|u| "
- "{{U_ELEMENT_TABLE_TYPE}}::init_from_table(u))";
+ code_ +=
+ " pub fn {{FIELD_NAME}}_as_{{U_ELEMENT_NAME}}(&self) -> "
+ "Option<{{U_ELEMENT_TABLE_TYPE}}<'a>> {";
+ // If the user defined schemas name a field that clashes with a
+ // language reserved word, flatc will try to escape the field name by
+ // appending an underscore. This works well for most cases, except
+ // one. When generating union accessors (and referring to them
+ // internally within the code generated here), an extra underscore
+ // will be appended to the name, causing build failures.
+ //
+ // This only happens when unions have members that overlap with
+ // language reserved words.
+ //
+ // To avoid this problem the type field name is used unescaped here:
+ code_ +=
+ " if self.{{FIELD_TYPE_FIELD_NAME}}_type() == "
+ "{{U_ELEMENT_ENUM_TYPE}} {";
+
+ // The following logic is not tested in the integration test,
+ // as of April 10, 2020
+ if (field.required) {
+ code_ += " let u = self.{{FIELD_NAME}}();";
+ code_ += " Some({{U_ELEMENT_TABLE_TYPE}}::init_from_table(u))";
+ } else {
+ code_ +=
+ " self.{{FIELD_NAME}}().map("
+ "{{U_ELEMENT_TABLE_TYPE}}::init_from_table)";
+ }
code_ += " } else {";
code_ += " None";
code_ += " }";
code_ += " }";
code_ += "";
- }
- }
+ });
+ });
code_ += "}"; // End of table impl.
code_ += "";
// Generate an args struct:
code_.SetValue("MAYBE_LT",
- TableBuilderArgsNeedsLifetime(struct_def) ? "<'a>" : "");
+ TableBuilderArgsNeedsLifetime(struct_def) ? "<'a>" : "");
code_ += "pub struct {{STRUCT_NAME}}Args{{MAYBE_LT}} {";
- for (auto it = struct_def.fields.vec.begin();
- it != struct_def.fields.vec.end(); ++it) {
- const auto &field = **it;
- if (!field.deprecated) {
- code_.SetValue("PARAM_NAME", Name(field));
- code_.SetValue("PARAM_TYPE", TableBuilderArgsDefnType(field, "'a "));
- code_ += " pub {{PARAM_NAME}}: {{PARAM_TYPE}},";
- }
- }
+ ForAllTableFields(struct_def, [&](const FieldDef &field) {
+ code_.SetValue("PARAM_TYPE", TableBuilderArgsDefnType(field, "'a"));
+ code_ += " pub {{FIELD_NAME}}: {{PARAM_TYPE}},";
+ });
code_ += "}";
// Generate an impl of Default for the *Args type:
@@ -1362,16 +1384,10 @@
code_ += " #[inline]";
code_ += " fn default() -> Self {";
code_ += " {{STRUCT_NAME}}Args {";
- for (auto it = struct_def.fields.vec.begin();
- it != struct_def.fields.vec.end(); ++it) {
- const auto &field = **it;
- if (!field.deprecated) {
- code_.SetValue("PARAM_VALUE", TableBuilderArgsDefaultValue(field));
- code_.SetValue("REQ", field.required ? " // required field" : "");
- code_.SetValue("PARAM_NAME", Name(field));
- code_ += " {{PARAM_NAME}}: {{PARAM_VALUE}},{{REQ}}";
- }
- }
+ ForAllTableFields(struct_def, [&](const FieldDef &field) {
+ code_ += " {{FIELD_NAME}}: {{DEFAULT_VALUE}},\\";
+ code_ += field.required ? " // required field" : "";
+ });
code_ += " }";
code_ += " }";
code_ += "}";
@@ -1379,49 +1395,42 @@
// Generate a builder struct:
code_ += "pub struct {{STRUCT_NAME}}Builder<'a: 'b, 'b> {";
code_ += " fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>,";
- code_ += " start_: flatbuffers::WIPOffset<"
- "flatbuffers::TableUnfinishedWIPOffset>,";
+ code_ +=
+ " start_: flatbuffers::WIPOffset<"
+ "flatbuffers::TableUnfinishedWIPOffset>,";
code_ += "}";
// Generate builder functions:
code_ += "impl<'a: 'b, 'b> {{STRUCT_NAME}}Builder<'a, 'b> {";
- for (auto it = struct_def.fields.vec.begin();
- it != struct_def.fields.vec.end(); ++it) {
- const auto &field = **it;
- if (!field.deprecated) {
- const bool is_scalar = IsScalar(field.value.type.base_type);
-
- std::string offset = GetFieldOffsetName(field);
-
- // Generate functions to add data, which take one of two forms.
- //
- // If a value has a default:
- // fn add_x(x_: type) {
- // fbb_.push_slot::<type>(offset, x_, Some(default));
- // }
- //
- // If a value does not have a default:
- // fn add_x(x_: type) {
- // fbb_.push_slot_always::<type>(offset, x_);
- // }
- code_.SetValue("FIELD_NAME", Name(field));
- code_.SetValue("FIELD_OFFSET", Name(struct_def) + "::" + offset);
- code_.SetValue("FIELD_TYPE", TableBuilderArgsAddFuncType(field, "'b "));
- code_.SetValue("FUNC_BODY", TableBuilderArgsAddFuncBody(field));
- code_ += " #[inline]";
- code_ += " pub fn add_{{FIELD_NAME}}(&mut self, {{FIELD_NAME}}: "
- "{{FIELD_TYPE}}) {";
- if (is_scalar) {
- code_.SetValue("FIELD_DEFAULT_VALUE",
- TableBuilderAddFuncDefaultValue(field));
- code_ += " {{FUNC_BODY}}({{FIELD_OFFSET}}, {{FIELD_NAME}}, "
- "{{FIELD_DEFAULT_VALUE}});";
- } else {
- code_ += " {{FUNC_BODY}}({{FIELD_OFFSET}}, {{FIELD_NAME}});";
- }
- code_ += " }";
+ ForAllTableFields(struct_def, [&](const FieldDef &field) {
+ const bool is_scalar = IsScalar(field.value.type.base_type);
+ std::string offset = GetFieldOffsetName(field);
+ // Generate functions to add data, which take one of two forms.
+ //
+ // If a value has a default:
+ // fn add_x(x_: type) {
+ // fbb_.push_slot::<type>(offset, x_, Some(default));
+ // }
+ //
+ // If a value does not have a default:
+ // fn add_x(x_: type) {
+ // fbb_.push_slot_always::<type>(offset, x_);
+ // }
+ code_.SetValue("FIELD_OFFSET", Name(struct_def) + "::" + offset);
+ code_.SetValue("FIELD_TYPE", TableBuilderArgsAddFuncType(field, "'b "));
+ code_.SetValue("FUNC_BODY", TableBuilderArgsAddFuncBody(field));
+ code_ += " #[inline]";
+ code_ += " pub fn add_{{FIELD_NAME}}(&mut self, {{FIELD_NAME}}: "
+ "{{FIELD_TYPE}}) {";
+ if (is_scalar && !field.optional) {
+ code_ +=
+ " {{FUNC_BODY}}({{FIELD_OFFSET}}, {{FIELD_NAME}}, "
+ "{{DEFAULT_VALUE}});";
+ } else {
+ code_ += " {{FUNC_BODY}}({{FIELD_OFFSET}}, {{FIELD_NAME}});";
}
- }
+ code_ += " }";
+ });
// Struct initializer (all fields required);
code_ += " #[inline]";
@@ -1438,24 +1447,60 @@
// finish() function.
code_ += " #[inline]";
- code_ += " pub fn finish(self) -> "
- "flatbuffers::WIPOffset<{{STRUCT_NAME}}<'a>> {";
+ code_ +=
+ " pub fn finish(self) -> "
+ "flatbuffers::WIPOffset<{{STRUCT_NAME}}<'a>> {";
code_ += " let o = self.fbb_.end_table(self.start_);";
- for (auto it = struct_def.fields.vec.begin();
- it != struct_def.fields.vec.end(); ++it) {
- const auto &field = **it;
- if (!field.deprecated && field.required) {
- code_.SetValue("FIELD_NAME", MakeSnakeCase(Name(field)));
- code_.SetValue("OFFSET_NAME", GetFieldOffsetName(field));
- code_ += " self.fbb_.required(o, {{STRUCT_NAME}}::{{OFFSET_NAME}},"
- "\"{{FIELD_NAME}}\");";
- }
- }
+ ForAllTableFields(struct_def, [&](const FieldDef &field) {
+ if (!field.required) return;
+ code_ +=
+ " self.fbb_.required(o, {{STRUCT_NAME}}::{{OFFSET_NAME}},"
+ "\"{{FIELD_NAME}}\");";
+ });
code_ += " flatbuffers::WIPOffset::new(o.value())";
code_ += " }";
code_ += "}";
code_ += "";
+
+ code_ += "impl std::fmt::Debug for {{STRUCT_NAME}}<'_> {";
+ code_ += " fn fmt(&self, f: &mut std::fmt::Formatter<'_>"
+ ") -> std::fmt::Result {";
+ code_ += " let mut ds = f.debug_struct(\"{{STRUCT_NAME}}\");";
+ ForAllTableFields(struct_def, [&](const FieldDef &field) {
+ if (GetFullType(field.value.type) == ftUnionValue) {
+ // Generate a match statement to handle unions properly.
+ code_.SetValue("KEY_TYPE", GenTableAccessorFuncReturnType(field, ""));
+ code_.SetValue("FIELD_TYPE_FIELD_NAME", field.name);
+ code_.SetValue("UNION_ERR", "&\"InvalidFlatbuffer: Union discriminant"
+ " does not match value.\"");
+
+ code_ += " match self.{{FIELD_NAME}}_type() {";
+ ForAllUnionVariantsBesidesNone(*field.value.type.enum_def,
+ [&](const EnumVal &unused){
+ (void) unused;
+ code_ += " {{U_ELEMENT_ENUM_TYPE}} => {";
+ code_ += " if let Some(x) = self.{{FIELD_TYPE_FIELD_NAME}}_as_"
+ "{{U_ELEMENT_NAME}}() {";
+ code_ += " ds.field(\"{{FIELD_NAME}}\", &x)";
+ code_ += " } else {";
+ code_ += " ds.field(\"{{FIELD_NAME}}\", {{UNION_ERR}})";
+ code_ += " }";
+ code_ += " },";
+ });
+ code_ += " _ => { ";
+ code_ += " let x: Option<()> = None;";
+ code_ += " ds.field(\"{{FIELD_NAME}}\", &x)";
+ code_ += " },";
+ code_ += " };";
+ } else {
+ // Most fields.
+ code_ += " ds.field(\"{{FIELD_NAME}}\", &self.{{FIELD_NAME}}());";
+ }
+ });
+ code_ += " ds.finish()";
+ code_ += " }";
+ code_ += "}";
}
// Generate functions to compare tables and structs by key. This function
@@ -1466,14 +1511,16 @@
code_.SetValue("KEY_TYPE", GenTableAccessorFuncReturnType(field, ""));
code_ += " #[inline]";
- code_ += " pub fn key_compare_less_than(&self, o: &{{STRUCT_NAME}}) -> "
- " bool {";
+ code_ +=
+ " pub fn key_compare_less_than(&self, o: &{{STRUCT_NAME}}) -> "
+ " bool {";
code_ += " self.{{FIELD_NAME}}() < o.{{FIELD_NAME}}()";
code_ += " }";
code_ += "";
code_ += " #[inline]";
- code_ += " pub fn key_compare_with_value(&self, val: {{KEY_TYPE}}) -> "
- " ::std::cmp::Ordering {";
+ code_ +=
+ " pub fn key_compare_with_value(&self, val: {{KEY_TYPE}}) -> "
+ " ::std::cmp::Ordering {";
code_ += " let key = self.{{FIELD_NAME}}();";
code_ += " key.cmp(&val)";
code_ += " }";
@@ -1499,16 +1546,19 @@
code_ += "";
code_ += "#[inline]";
- code_ += "pub fn get_size_prefixed_root_as_{{STRUCT_NAME_SNAKECASE}}"
- "<'a>(buf: &'a [u8]) -> {{STRUCT_NAME}}<'a> {";
- code_ += " flatbuffers::get_size_prefixed_root::<{{STRUCT_NAME}}<'a>>"
- "(buf)";
+ code_ +=
+ "pub fn get_size_prefixed_root_as_{{STRUCT_NAME_SNAKECASE}}"
+ "<'a>(buf: &'a [u8]) -> {{STRUCT_NAME}}<'a> {";
+ code_ +=
+ " flatbuffers::get_size_prefixed_root::<{{STRUCT_NAME}}<'a>>"
+ "(buf)";
code_ += "}";
code_ += "";
if (parser_.file_identifier_.length()) {
// Declare the identifier
- code_ += "pub const {{STRUCT_NAME_CAPS}}_IDENTIFIER: &'static str\\";
+ // (no lifetime needed as constants have static lifetimes by default)
+ code_ += "pub const {{STRUCT_NAME_CAPS}}_IDENTIFIER: &str\\";
code_ += " = \"" + parser_.file_identifier_ + "\";";
code_ += "";
@@ -1516,22 +1566,22 @@
code_ += "#[inline]";
code_ += "pub fn {{STRUCT_NAME_SNAKECASE}}_buffer_has_identifier\\";
code_ += "(buf: &[u8]) -> bool {";
- code_ += " return flatbuffers::buffer_has_identifier(buf, \\";
- code_ += "{{STRUCT_NAME_CAPS}}_IDENTIFIER, false);";
+ code_ += " flatbuffers::buffer_has_identifier(buf, \\";
+ code_ += "{{STRUCT_NAME_CAPS}}_IDENTIFIER, false)";
code_ += "}";
code_ += "";
code_ += "#[inline]";
code_ += "pub fn {{STRUCT_NAME_SNAKECASE}}_size_prefixed\\";
code_ += "_buffer_has_identifier(buf: &[u8]) -> bool {";
- code_ += " return flatbuffers::buffer_has_identifier(buf, \\";
- code_ += "{{STRUCT_NAME_CAPS}}_IDENTIFIER, true);";
+ code_ += " flatbuffers::buffer_has_identifier(buf, \\";
+ code_ += "{{STRUCT_NAME_CAPS}}_IDENTIFIER, true)";
code_ += "}";
code_ += "";
}
if (parser_.file_extension_.length()) {
// Return the extension
- code_ += "pub const {{STRUCT_NAME_CAPS}}_EXTENSION: &'static str = \\";
+ code_ += "pub const {{STRUCT_NAME_CAPS}}_EXTENSION: &str = \\";
code_ += "\"" + parser_.file_extension_ + "\";";
code_ += "";
}
@@ -1550,13 +1600,15 @@
code_ += "}";
code_ += "";
code_ += "#[inline]";
- code_ += "pub fn finish_size_prefixed_{{STRUCT_NAME_SNAKECASE}}_buffer"
- "<'a, 'b>("
- "fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>, "
- "root: flatbuffers::WIPOffset<{{STRUCT_NAME}}<'a>>) {";
+ code_ +=
+ "pub fn finish_size_prefixed_{{STRUCT_NAME_SNAKECASE}}_buffer"
+ "<'a, 'b>("
+ "fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>, "
+ "root: flatbuffers::WIPOffset<{{STRUCT_NAME}}<'a>>) {";
if (parser_.file_identifier_.length()) {
- code_ += " fbb.finish_size_prefixed(root, "
- "Some({{STRUCT_NAME_CAPS}}_IDENTIFIER));";
+ code_ +=
+ " fbb.finish_size_prefixed(root, "
+ "Some({{STRUCT_NAME_CAPS}}_IDENTIFIER));";
} else {
code_ += " fbb.finish_size_prefixed(root, None);";
}
@@ -1577,8 +1629,8 @@
}
static void PaddingDefinition(int bits, std::string *code_ptr, int *id) {
- *code_ptr += " padding" + NumToString((*id)++) + "__: u" + \
- NumToString(bits) + ",";
+ *code_ptr +=
+ " padding" + NumToString((*id)++) + "__: u" + NumToString(bits) + ",";
}
static void PaddingInitializer(int bits, std::string *code_ptr, int *id) {
@@ -1586,6 +1638,18 @@
*code_ptr += "padding" + NumToString((*id)++) + "__: 0,";
}
+ void ForAllStructFields(
+ const StructDef &struct_def,
+ std::function<void(const FieldDef &field)> cb
+ ) {
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ const auto &field = **it;
+ code_.SetValue("FIELD_TYPE", GetTypeGet(field.value.type));
+ code_.SetValue("FIELD_NAME", Name(field));
+ cb(field);
+ }
+ }
// Generate an accessor struct with constructor for a flatbuffers struct.
void GenStruct(const StructDef &struct_def) {
// Generates manual padding and alignment.
@@ -1601,26 +1665,35 @@
// PartialEq is useful to derive because we can correctly compare structs
// for equality by just comparing their underlying byte data. This doesn't
// hold for PartialOrd/Ord.
- code_ += "#[derive(Clone, Copy, Debug, PartialEq)]";
+ code_ += "#[derive(Clone, Copy, PartialEq)]";
code_ += "pub struct {{STRUCT_NAME}} {";
int padding_id = 0;
- for (auto it = struct_def.fields.vec.begin();
- it != struct_def.fields.vec.end(); ++it) {
- const auto &field = **it;
- code_.SetValue("FIELD_TYPE", GetTypeGet(field.value.type));
- code_.SetValue("FIELD_NAME", Name(field));
+ ForAllStructFields(struct_def, [&](const FieldDef &field) {
code_ += " {{FIELD_NAME}}_: {{FIELD_TYPE}},";
-
if (field.padding) {
std::string padding;
GenPadding(field, &padding, &padding_id, PaddingDefinition);
code_ += padding;
}
- }
-
+ });
code_ += "} // pub struct {{STRUCT_NAME}}";
+ // Debug for structs.
+ code_ += "impl std::fmt::Debug for {{STRUCT_NAME}} {";
+ code_ += " fn fmt(&self, f: &mut std::fmt::Formatter"
+ ") -> std::fmt::Result {";
+ code_ += " f.debug_struct(\"{{STRUCT_NAME}}\")";
+ ForAllStructFields(struct_def, [&](const FieldDef &unused) {
+ (void) unused;
+ code_ += " .field(\"{{FIELD_NAME}}\", &self.{{FIELD_NAME}}())";
+ });
+ code_ += " .finish()";
+ code_ += " }";
+ code_ += "}";
+ code_ += "";
+
+
// Generate impls for SafeSliceAccess (because all structs are endian-safe),
// Follow for the value type, Follow for the reference type, Push for the
// value type, and Push for the reference type.
@@ -1644,8 +1717,9 @@
code_ += " #[inline]";
code_ += " fn push(&self, dst: &mut [u8], _rest: &[u8]) {";
code_ += " let src = unsafe {";
- code_ += " ::std::slice::from_raw_parts("
- "self as *const {{STRUCT_NAME}} as *const u8, Self::size())";
+ code_ +=
+ " ::std::slice::from_raw_parts("
+ "self as *const {{STRUCT_NAME}} as *const u8, Self::size())";
code_ += " };";
code_ += " dst.copy_from_slice(src);";
code_ += " }";
@@ -1656,8 +1730,9 @@
code_ += " #[inline]";
code_ += " fn push(&self, dst: &mut [u8], _rest: &[u8]) {";
code_ += " let src = unsafe {";
- code_ += " ::std::slice::from_raw_parts("
- "*self as *const {{STRUCT_NAME}} as *const u8, Self::size())";
+ code_ +=
+ " ::std::slice::from_raw_parts("
+ "*self as *const {{STRUCT_NAME}} as *const u8, Self::size())";
code_ += " };";
code_ += " dst.copy_from_slice(src);";
code_ += " }";
@@ -1667,86 +1742,81 @@
// Generate a constructor that takes all fields as arguments.
code_ += "impl {{STRUCT_NAME}} {";
- std::string arg_list;
- std::string init_list;
- padding_id = 0;
- for (auto it = struct_def.fields.vec.begin();
- it != struct_def.fields.vec.end(); ++it) {
- const auto &field = **it;
- const auto member_name = Name(field) + "_";
- const auto reference = StructMemberAccessNeedsCopy(field.value.type)
- ? "" : "&'a ";
- const auto arg_name = "_" + Name(field);
- const auto arg_type = reference + GetTypeGet(field.value.type);
-
- if (it != struct_def.fields.vec.begin()) {
- arg_list += ", ";
- }
- arg_list += arg_name + ": ";
- arg_list += arg_type;
- init_list += " " + member_name;
- if (StructMemberAccessNeedsCopy(field.value.type)) {
- init_list += ": " + arg_name + ".to_little_endian(),\n";
- } else {
- init_list += ": *" + arg_name + ",\n";
- }
- }
-
- code_.SetValue("ARG_LIST", arg_list);
- code_.SetValue("INIT_LIST", init_list);
- code_ += " pub fn new<'a>({{ARG_LIST}}) -> Self {";
+ // TODO(cneo): Stop generating args on one line. Make it simpler.
+ bool first_arg = true;
+ code_ += " pub fn new(\\";
+ ForAllStructFields(struct_def, [&](const FieldDef &field) {
+ if (first_arg) first_arg = false; else code_ += ", \\";
+ code_.SetValue("REF", IsStruct(field.value.type) ? "&" : "");
+ code_ += "_{{FIELD_NAME}}: {{REF}}{{FIELD_TYPE}}\\";
+ });
+ code_ += ") -> Self {";
code_ += " {{STRUCT_NAME}} {";
- code_ += "{{INIT_LIST}}";
+
+ ForAllStructFields(struct_def, [&](const FieldDef &field) {
+ const bool is_struct = IsStruct(field.value.type);
+ code_.SetValue("DEREF", is_struct ? "*" : "");
+ code_.SetValue("TO_LE", is_struct ? "" : ".to_little_endian()");
+ code_ += " {{FIELD_NAME}}_: {{DEREF}}_{{FIELD_NAME}}{{TO_LE}},";
+ });
+ code_ += "";
+
+ // TODO(cneo): Does this padding even work? Why after all the fields?
padding_id = 0;
- for (auto it = struct_def.fields.vec.begin();
- it != struct_def.fields.vec.end(); ++it) {
- const auto &field = **it;
+ ForAllStructFields(struct_def, [&](const FieldDef &field) {
if (field.padding) {
std::string padding;
GenPadding(field, &padding, &padding_id, PaddingInitializer);
code_ += " " + padding;
}
- }
+ });
code_ += " }";
code_ += " }";
+ if (parser_.opts.generate_name_strings) {
+ GenFullyQualifiedNameGetter(struct_def, struct_def.name);
+ }
+
// Generate accessor methods for the struct.
- for (auto it = struct_def.fields.vec.begin();
- it != struct_def.fields.vec.end(); ++it) {
- const auto &field = **it;
+ ForAllStructFields(struct_def, [&](const FieldDef &field) {
+ const bool is_struct = IsStruct(field.value.type);
+ code_.SetValue("REF", is_struct ? "&" : "");
+ code_.SetValue("FROM_LE", is_struct ? "" : ".from_little_endian()");
- auto field_type = TableBuilderArgsAddFuncType(field, "'a");
- auto member = "self." + Name(field) + "_";
- auto value = StructMemberAccessNeedsCopy(field.value.type) ?
- member + ".from_little_endian()" : member;
-
- code_.SetValue("FIELD_NAME", Name(field));
- code_.SetValue("FIELD_TYPE", field_type);
- code_.SetValue("FIELD_VALUE", value);
- code_.SetValue("REF", IsStruct(field.value.type) ? "&" : "");
-
- GenComment(field.doc_comment, " ");
- code_ += " pub fn {{FIELD_NAME}}<'a>(&'a self) -> {{FIELD_TYPE}} {";
- code_ += " {{REF}}{{FIELD_VALUE}}";
+ this->GenComment(field.doc_comment, " ");
+ code_ += " pub fn {{FIELD_NAME}}(&self) -> {{REF}}{{FIELD_TYPE}} {";
+ code_ += " {{REF}}self.{{FIELD_NAME}}_{{FROM_LE}}";
code_ += " }";
// Generate a comparison function for this field if it is a key.
- if (field.key) {
- GenKeyFieldMethods(field);
- }
- }
+ if (field.key) { GenKeyFieldMethods(field); }
+ });
code_ += "}";
code_ += "";
}
void GenNamespaceImports(const int white_spaces) {
- std::string indent = std::string(white_spaces, ' ');
- code_ += "";
- code_ += indent + "use std::mem;";
- code_ += indent + "use std::cmp::Ordering;";
- code_ += "";
- code_ += indent + "extern crate flatbuffers;";
- code_ += indent + "use self::flatbuffers::EndianScalar;";
+ if (white_spaces == 0) {
+ code_ += "#![allow(unused_imports, dead_code)]";
+ }
+ std::string indent = std::string(white_spaces, ' ');
+ code_ += "";
+ if (!parser_.opts.generate_all) {
+ for (auto it = parser_.included_files_.begin();
+ it != parser_.included_files_.end(); ++it) {
+ if (it->second.empty()) continue;
+ auto noext = flatbuffers::StripExtension(it->second);
+ auto basename = flatbuffers::StripPath(noext);
+
+ code_ += indent + "use crate::" + basename + "_generated::*;";
+ }
+ }
+
+ code_ += indent + "use std::mem;";
+ code_ += indent + "use std::cmp::Ordering;";
+ code_ += "";
+ code_ += indent + "extern crate flatbuffers;";
+ code_ += indent + "use self::flatbuffers::EndianScalar;";
}
// Set up the correct namespace. This opens a namespace if the current
@@ -1805,7 +1875,9 @@
const std::string &file_name) {
std::string filebase =
flatbuffers::StripPath(flatbuffers::StripExtension(file_name));
- std::string make_rule = GeneratedFileName(path, filebase) + ": ";
+ rust::RustGenerator generator(parser, path, file_name);
+ std::string make_rule =
+ generator.GeneratedFileName(path, filebase, parser.opts) + ": ";
auto included_files = parser.GetIncludedFilesRecursive(file_name);
for (auto it = included_files.begin(); it != included_files.end(); ++it) {
@@ -1823,3 +1895,10 @@
// TODO(rw): Generated code should generate endian-safe Debug impls.
// TODO(rw): Generated code could use a Rust-only enum type to access unions,
// instead of making the user use _type() to manually switch.
+// TODO(maxburke): There should be test schemas added that use language
+// keywords as fields of structs, tables, unions, enums, to make sure
+// that internal code generated references escaped names correctly.
+// TODO(maxburke): We should see if there is a more flexible way of resolving
+// module paths for use declarations. Right now if schemas refer to
+// other flatbuffer files, the include paths in emitted Rust bindings
+// are crate-relative which may undesirable.
diff --git a/src/idl_gen_swift.cpp b/src/idl_gen_swift.cpp
new file mode 100644
index 0000000..c377e9f
--- /dev/null
+++ b/src/idl_gen_swift.cpp
@@ -0,0 +1,1484 @@
+/*
+ * Copyright 2020 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <cctype>
+#include <unordered_set>
+
+#include "flatbuffers/code_generators.h"
+#include "flatbuffers/flatbuffers.h"
+#include "flatbuffers/idl.h"
+#include "flatbuffers/util.h"
+
+namespace flatbuffers {
+
+namespace swift {
+
+inline std::string GenIndirect(const std::string &reading) {
+ return "{{ACCESS}}.indirect(" + reading + ")";
+}
+
+inline std::string GenArrayMainBody(const std::string &optional) {
+ return "{{ACCESS_TYPE}} func {{VALUENAME}}(at index: Int32) -> "
+ "{{VALUETYPE}}" +
+ optional + " { ";
+}
+
+class SwiftGenerator : public BaseGenerator {
+ private:
+ CodeWriter code_;
+ std::unordered_set<std::string> keywords_;
+ int namespace_depth;
+
+ public:
+ SwiftGenerator(const Parser &parser, const std::string &path,
+ const std::string &file_name)
+ : BaseGenerator(parser, path, file_name, "", "_", "swift") {
+ namespace_depth = 0;
+ code_.SetPadding(" ");
+ static const char *const keywords[] = {
+ "associatedtype",
+ "class",
+ "deinit",
+ "enum",
+ "extension",
+ "fileprivate",
+ "func",
+ "import",
+ "init",
+ "inout",
+ "internal",
+ "let",
+ "open",
+ "operator",
+ "private",
+ "protocol",
+ "public",
+ "rethrows",
+ "static",
+ "struct",
+ "subscript",
+ "typealias",
+ "var",
+ "break",
+ "case",
+ "continue",
+ "default",
+ "defer",
+ "do",
+ "else",
+ "fallthrough",
+ "for",
+ "guard",
+ "if",
+ "in",
+ "repeat",
+ "return",
+ "switch",
+ "where",
+ "while",
+ "Any",
+ "catch",
+ "false",
+ "is",
+ "nil",
+ "super",
+ "self",
+ "Self",
+ "throw",
+ "throws",
+ "true",
+ "try",
+ "associativity",
+ "convenience",
+ "dynamic",
+ "didSet",
+ "final",
+ "get",
+ "infix",
+ "indirect",
+ "lazy",
+ "left",
+ "mutating",
+ "none",
+ "nonmutating",
+ "optional",
+ "override",
+ "postfix",
+ "precedence",
+ "prefix",
+ "Protocol",
+ "required",
+ "right",
+ "set",
+ "Type",
+ "unowned",
+ "weak",
+ "willSet",
+ nullptr,
+ };
+ for (auto kw = keywords; *kw; kw++) keywords_.insert(*kw);
+ }
+
+ bool generate() {
+ code_.Clear();
+ code_.SetValue("ACCESS", "_accessor");
+ code_.SetValue("TABLEOFFSET", "VTOFFSET");
+ code_ += "// " + std::string(FlatBuffersGeneratedWarning());
+ code_ += "// swiftlint:disable all\n";
+ code_ += "import FlatBuffers\n";
+ // Generate code for all the enum declarations.
+
+ for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
+ ++it) {
+ const auto &enum_def = **it;
+ if (!enum_def.generated) { GenEnum(enum_def); }
+ }
+
+ for (auto it = parser_.structs_.vec.begin();
+ it != parser_.structs_.vec.end(); ++it) {
+ const auto &struct_def = **it;
+ if (struct_def.fixed && !struct_def.generated) {
+ GenStructReader(struct_def);
+ if (parser_.opts.generate_object_based_api) {
+ GenObjectAPI(struct_def);
+ }
+ }
+ }
+
+ for (auto it = parser_.structs_.vec.begin();
+ it != parser_.structs_.vec.end(); ++it) {
+ const auto &struct_def = **it;
+ if (struct_def.fixed && !struct_def.generated) {
+ GenStructWriter(struct_def);
+ }
+ }
+
+ for (auto it = parser_.structs_.vec.begin();
+ it != parser_.structs_.vec.end(); ++it) {
+ const auto &struct_def = **it;
+ if (!struct_def.fixed && !struct_def.generated) {
+ GenTable(struct_def);
+ if (parser_.opts.generate_object_based_api) {
+ GenObjectAPI(struct_def);
+ }
+ }
+ }
+
+ const auto filename = GeneratedFileName(path_, file_name_, parser_.opts);
+ const auto final_code = code_.ToString();
+ return SaveFile(filename.c_str(), final_code, false);
+ }
+
+ void mark(const std::string &str) {
+ code_.SetValue("MARKVALUE", str);
+ code_ += "\n// MARK: - {{MARKVALUE}}\n";
+ }
+
+ // Generates the create function for swift
+ void GenStructWriter(const StructDef &struct_def) {
+ auto is_private_access = struct_def.attributes.Lookup("private");
+ code_.SetValue("ACCESS_TYPE", is_private_access ? "internal" : "public");
+ code_.SetValue("STRUCTNAME", NameWrappedInNameSpace(struct_def));
+ code_.SetValue("SHORT_STRUCTNAME", Name(struct_def));
+ code_ += "extension {{STRUCTNAME}} {";
+ Indent();
+ code_ += "@discardableResult";
+ code_ +=
+ "{{ACCESS_TYPE}} static func create{{SHORT_STRUCTNAME}}(builder: inout "
+ "FlatBufferBuilder, \\";
+ std::string func_header = "";
+ GenerateStructArgs(struct_def, &func_header, "", "");
+ code_ += func_header.substr(0, func_header.size() - 2) + "\\";
+ code_ += ") -> Offset<UOffset> {";
+ Indent();
+ code_ +=
+ "builder.createStructOf(size: {{STRUCTNAME}}.size, alignment: "
+ "{{STRUCTNAME}}.alignment)";
+ GenerateStructBody(struct_def, "");
+ code_ += "return builder.endStruct()";
+ Outdent();
+ code_ += "}\n";
+ Outdent();
+ code_ += "}\n";
+ }
+
+ void GenerateStructBody(const StructDef &struct_def,
+ const std::string &nameprefix, int offset = 0) {
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+ auto name = nameprefix + Name(field);
+ const auto &field_type = field.value.type;
+ auto type = GenTypeBasic(field_type, false);
+ if (IsStruct(field.value.type)) {
+ GenerateStructBody(*field_type.struct_def, (nameprefix + field.name),
+ static_cast<int>(field.value.offset));
+ } else {
+ auto off = NumToString(offset + field.value.offset);
+ code_ += "builder.reverseAdd(v: " + name +
+ (field_type.enum_def ? ".rawValue" : "") +
+ ", postion: " + off + ")";
+ }
+ }
+ }
+
+ void GenerateStructArgs(const StructDef &struct_def, std::string *code_ptr,
+ const std::string &nameprefix,
+ const std::string &object_name,
+ const std::string &obj_api_named = "",
+ bool is_obj_api = false) {
+ auto &code = *code_ptr;
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+ const auto &field_type = field.value.type;
+ if (IsStruct(field.value.type)) {
+ GenerateStructArgs(
+ *field_type.struct_def, code_ptr, (nameprefix + field.name),
+ (object_name + "." + field.name), obj_api_named, is_obj_api);
+ } else {
+ auto name = Name(field);
+ auto type = GenType(field.value.type);
+ if (!is_obj_api) {
+ code += nameprefix + name + ": " + type;
+ if (!IsEnum(field.value.type)) {
+ code += " = ";
+ auto is_bool = IsBool(field.value.type.base_type);
+ auto constant =
+ is_bool ? ("0" == field.value.constant ? "false" : "true")
+ : field.value.constant;
+ code += constant;
+ }
+ code += ", ";
+ continue;
+ }
+ code +=
+ nameprefix + name + ": " + obj_api_named + object_name + "." + name;
+ code += ", ";
+ }
+ }
+ }
+
+ void GenObjectHeader(const StructDef &struct_def) {
+ GenComment(struct_def.doc_comment);
+ code_.SetValue("SHORT_STRUCTNAME", Name(struct_def));
+ code_.SetValue("STRUCTNAME", NameWrappedInNameSpace(struct_def));
+ code_.SetValue("PROTOCOL",
+ struct_def.fixed ? "Readable" : "FlatBufferObject");
+ code_.SetValue("OBJECTTYPE", struct_def.fixed ? "Struct" : "Table");
+ code_ += "{{ACCESS_TYPE}} struct {{STRUCTNAME}}: {{PROTOCOL}}\\";
+ if (!struct_def.fixed && parser_.opts.generate_object_based_api)
+ code_ += ", ObjectAPI\\";
+ code_ += " {\n";
+ Indent();
+ code_ += ValidateFunc();
+ code_ +=
+ "{{ACCESS_TYPE}} var __buffer: ByteBuffer! { return {{ACCESS}}.bb }";
+ code_ += "private var {{ACCESS}}: {{OBJECTTYPE}}\n";
+ if (struct_def.fixed) {
+ code_.SetValue("BYTESIZE", NumToString(struct_def.bytesize));
+ code_.SetValue("MINALIGN", NumToString(struct_def.minalign));
+ code_ += "{{ACCESS_TYPE}} static var size = {{BYTESIZE}}";
+ code_ += "{{ACCESS_TYPE}} static var alignment = {{MINALIGN}}";
+ } else {
+ if (parser_.file_identifier_.length()) {
+ code_.SetValue("FILENAME", parser_.file_identifier_);
+ code_ +=
+ "{{ACCESS_TYPE}} static func finish(_ fbb: inout "
+ "FlatBufferBuilder, end: "
+ "Offset<UOffset>, prefix: Bool = false) { fbb.finish(offset: end, "
+ "fileId: "
+ "\"{{FILENAME}}\", addPrefix: prefix) }";
+ }
+ code_ +=
+ "{{ACCESS_TYPE}} static func getRootAs{{SHORT_STRUCTNAME}}(bb: "
+ "ByteBuffer) -> "
+ "{{STRUCTNAME}} { return {{STRUCTNAME}}(Table(bb: bb, position: "
+ "Int32(bb.read(def: UOffset.self, position: bb.reader)) + "
+ "Int32(bb.reader))) }\n";
+ code_ += "private init(_ t: Table) { {{ACCESS}} = t }";
+ }
+ code_ +=
+ "{{ACCESS_TYPE}} init(_ bb: ByteBuffer, o: Int32) { {{ACCESS}} = "
+ "{{OBJECTTYPE}}(bb: "
+ "bb, position: o) }";
+ code_ += "";
+ }
+
+ // Generates the reader for swift
+ void GenTable(const StructDef &struct_def) {
+ auto is_private_access = struct_def.attributes.Lookup("private");
+ code_.SetValue("ACCESS_TYPE", is_private_access ? "internal" : "public");
+
+ GenObjectHeader(struct_def);
+ GenTableAccessors(struct_def);
+ GenTableReader(struct_def);
+ GenTableWriter(struct_def);
+ if (parser_.opts.generate_object_based_api)
+ GenerateObjectAPITableExtension(struct_def);
+ Outdent();
+ code_ += "}\n";
+ }
+
+ // Generates the reader for swift
+ void GenTableAccessors(const StructDef &struct_def) {
+ // Generate field id constants.
+ if (struct_def.fields.vec.size() > 0) {
+ code_ += "private enum {{TABLEOFFSET}}: VOffset {";
+ Indent();
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ const auto &field = **it;
+ if (field.deprecated) { continue; }
+ code_.SetValue("OFFSET_NAME", Name(field));
+ code_.SetValue("OFFSET_VALUE", NumToString(field.value.offset));
+ code_ += "case {{OFFSET_NAME}} = {{OFFSET_VALUE}}";
+ }
+ code_ += "var v: Int32 { Int32(self.rawValue) }";
+ code_ += "var p: VOffset { self.rawValue }";
+ Outdent();
+ code_ += "}";
+ code_ += "";
+ }
+ }
+
+ void GenerateObjectAPIExtensionHeader() {
+ code_ += "\n";
+ code_ += "{{ACCESS_TYPE}} mutating func unpack() -> " +
+ ObjectAPIName("{{STRUCTNAME}}") + " {";
+ Indent();
+ code_ += "return " + ObjectAPIName("{{STRUCTNAME}}") + "(&self)";
+ Outdent();
+ code_ += "}";
+ code_ +=
+ "{{ACCESS_TYPE}} static func pack(_ builder: inout FlatBufferBuilder, "
+ "obj: "
+ "inout " +
+ ObjectAPIName("{{STRUCTNAME}}") + "?) -> Offset<UOffset> {";
+ Indent();
+ code_ += "guard var obj = obj else { return Offset<UOffset>() }";
+ code_ += "return pack(&builder, obj: &obj)";
+ Outdent();
+ code_ += "}";
+ code_ += "";
+ code_ +=
+ "{{ACCESS_TYPE}} static func pack(_ builder: inout FlatBufferBuilder, "
+ "obj: "
+ "inout " +
+ ObjectAPIName("{{STRUCTNAME}}") + ") -> Offset<UOffset> {";
+ Indent();
+ }
+
+ void GenerateObjectAPIStructExtension(const StructDef &struct_def) {
+ GenerateObjectAPIExtensionHeader();
+ std::string code;
+ GenerateStructArgs(struct_def, &code, "", "", "obj", true);
+ code_ += "return create{{SHORT_STRUCTNAME}}(builder: &builder, \\";
+ code_ += code.substr(0, code.size() - 2) + "\\";
+ code_ += ")";
+ Outdent();
+ code_ += "}";
+ }
+
+ void GenTableReader(const StructDef &struct_def) {
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+ GenTableReaderFields(field);
+ }
+ }
+
+ void GenTableWriter(const StructDef &struct_def) {
+ flatbuffers::FieldDef *key_field = nullptr;
+ std::vector<std::string> require_fields;
+ std::vector<std::string> create_func_body;
+ std::vector<std::string> create_func_header;
+ auto should_generate_create = struct_def.fields.vec.size() != 0;
+
+ code_.SetValue("NUMBEROFFIELDS", NumToString(struct_def.fields.vec.size()));
+ code_ +=
+ "{{ACCESS_TYPE}} static func start{{SHORT_STRUCTNAME}}(_ fbb: inout "
+ "FlatBufferBuilder) -> "
+ "UOffset { fbb.startTable(with: {{NUMBEROFFIELDS}}) }";
+
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+ if (field.key) key_field = &field;
+ if (field.required)
+ require_fields.push_back(NumToString(field.value.offset));
+
+ GenTableWriterFields(field, &create_func_body, &create_func_header,
+ should_generate_create);
+ }
+ code_ +=
+ "{{ACCESS_TYPE}} static func end{{SHORT_STRUCTNAME}}(_ fbb: inout "
+ "FlatBufferBuilder, "
+ "start: "
+ "UOffset) -> Offset<UOffset> { let end = Offset<UOffset>(offset: "
+ "fbb.endTable(at: start))\\";
+ if (require_fields.capacity() != 0) {
+ std::string fields = "";
+ for (auto it = require_fields.begin(); it != require_fields.end(); ++it)
+ fields += *it + ", ";
+ code_.SetValue("FIELDS", fields.substr(0, fields.size() - 2));
+ code_ += "; fbb.require(table: end, fields: [{{FIELDS}}])\\";
+ }
+ code_ += "; return end }";
+
+ if (should_generate_create) {
+ code_ += "{{ACCESS_TYPE}} static func create{{SHORT_STRUCTNAME}}(";
+ Indent();
+ code_ += "_ fbb: inout FlatBufferBuilder,";
+ for (auto it = create_func_header.begin(); it < create_func_header.end();
+ ++it) {
+ code_ += *it + "\\";
+ if (it < create_func_header.end() - 1) code_ += ",";
+ }
+ code_ += "";
+ Outdent();
+ code_ += ") -> Offset<UOffset> {";
+ Indent();
+ code_ += "let __start = {{STRUCTNAME}}.start{{SHORT_STRUCTNAME}}(&fbb)";
+ for (auto it = create_func_body.begin(); it < create_func_body.end();
+ ++it) {
+ code_ += *it;
+ }
+ code_ +=
+ "return {{STRUCTNAME}}.end{{SHORT_STRUCTNAME}}(&fbb, start: __start)";
+ Outdent();
+ code_ += "}";
+ }
+
+ std::string spacing = "";
+
+ if (key_field != nullptr && !struct_def.fixed && struct_def.has_key) {
+ code_.SetValue("VALUENAME", NameWrappedInNameSpace(struct_def));
+ code_.SetValue("SHORT_VALUENAME", Name(struct_def));
+ code_.SetValue("VOFFSET", NumToString(key_field->value.offset));
+
+ code_ +=
+ "{{ACCESS_TYPE}} static func "
+ "sortVectorOf{{SHORT_VALUENAME}}(offsets:[Offset<UOffset>], "
+ "_ fbb: inout FlatBufferBuilder) -> Offset<UOffset> {";
+ Indent();
+ code_ += spacing + "var off = offsets";
+ code_ +=
+ spacing +
+ "off.sort { Table.compare(Table.offset(Int32($1.o), vOffset: "
+ "{{VOFFSET}}, fbb: fbb.buffer), Table.offset(Int32($0.o), vOffset: "
+ "{{VOFFSET}}, fbb: fbb.buffer), fbb: fbb.buffer) < 0 } ";
+ code_ += spacing + "return fbb.createVector(ofOffsets: off)";
+ Outdent();
+ code_ += "}";
+ GenLookup(*key_field);
+ }
+ }
+
+ void GenTableWriterFields(const FieldDef &field,
+ std::vector<std::string> *create_body,
+ std::vector<std::string> *create_header,
+ bool &contains_structs) {
+ std::string builder_string = ", _ fbb: inout FlatBufferBuilder) { ";
+ auto &create_func_body = *create_body;
+ auto &create_func_header = *create_header;
+ auto name = Name(field);
+ auto type = GenType(field.value.type);
+ bool opt_scalar = field.optional && IsScalar(field.value.type.base_type);
+ auto nullable_type = opt_scalar ? type + "?" : type;
+ code_.SetValue("VALUENAME", name);
+ code_.SetValue("VALUETYPE", nullable_type);
+ code_.SetValue("OFFSET", name);
+ code_.SetValue("CONSTANT", field.value.constant);
+ std::string check_if_vector =
+ (IsVector(field.value.type) ||
+ IsArray(field.value.type))
+ ? "VectorOf("
+ : "(";
+ auto body = "add" + check_if_vector + name + ": ";
+ code_ += "{{ACCESS_TYPE}} static func " + body + "\\";
+
+ create_func_body.push_back("{{STRUCTNAME}}." + body + name + ", &fbb)");
+
+ if (IsScalar(field.value.type.base_type) &&
+ !IsBool(field.value.type.base_type)) {
+ std::string is_enum = IsEnum(field.value.type) ? ".rawValue" : "";
+ std::string optional_enum =
+ IsEnum(field.value.type) ? ("?" + is_enum) : "";
+ code_ +=
+ "{{VALUETYPE}}" + builder_string + "fbb.add(element: {{VALUENAME}}\\";
+
+ code_ += field.optional ? (optional_enum + "\\")
+ : (is_enum + ", def: {{CONSTANT}}\\");
+
+ code_ += ", at: {{TABLEOFFSET}}.{{OFFSET}}.p) }";
+
+ auto default_value =
+ IsEnum(field.value.type)
+ ? (field.optional ? "nil" : GenEnumDefaultValue(field))
+ : field.value.constant;
+ create_func_header.push_back("" + name + ": " + nullable_type + " = " +
+ (field.optional ? "nil" : default_value));
+ return;
+ }
+
+ if (IsBool(field.value.type.base_type)) {
+ std::string default_value =
+ "0" == field.value.constant ? "false" : "true";
+
+ code_.SetValue("CONSTANT", default_value);
+ code_.SetValue("VALUETYPE", field.optional ? "Bool?" : "Bool");
+ code_ += "{{VALUETYPE}}" + builder_string +
+ "fbb.add(element: {{VALUENAME}},\\";
+ code_ += field.optional ? "\\" : " def: {{CONSTANT}},";
+ code_ += " at: {{TABLEOFFSET}}.{{OFFSET}}.p) }";
+ create_func_header.push_back(name + ": " + nullable_type + " = " +
+ (field.optional ? "nil" : default_value));
+ return;
+ }
+
+ if (IsStruct(field.value.type)) {
+ contains_structs = false;
+ auto struct_type = "Offset<UOffset>?";
+ auto camel_case_name = "structOf" + MakeCamel(name, true);
+ auto reader_type =
+ "fbb.add(structOffset: {{TABLEOFFSET}}.{{OFFSET}}.p) }";
+ auto create_struct = "guard {{VALUENAME}} != nil else { return }; ";
+ code_ += struct_type + builder_string + create_struct + reader_type;
+ return;
+ }
+
+ auto offset_type = IsString(field.value.type)
+ ? "Offset<String>"
+ : "Offset<UOffset>";
+ auto camel_case_name =
+ (IsVector(field.value.type) ||
+ IsArray(field.value.type)
+ ? "vectorOf"
+ : "offsetOf") +
+ MakeCamel(name, true);
+ create_func_header.push_back(camel_case_name + " " + name + ": " +
+ offset_type + " = Offset()");
+ auto reader_type =
+ IsStruct(field.value.type) && field.value.type.struct_def->fixed
+ ? "structOffset: {{TABLEOFFSET}}.{{OFFSET}}.p) }"
+ : "offset: {{VALUENAME}}, at: {{TABLEOFFSET}}.{{OFFSET}}.p) }";
+ code_ += offset_type + builder_string + "fbb.add(" + reader_type;
+
+ auto vectortype = field.value.type.VectorType();
+
+ if ((vectortype.base_type == BASE_TYPE_STRUCT &&
+ field.value.type.struct_def->fixed) &&
+ (IsVector(field.value.type) ||
+ IsArray(field.value.type))) {
+ auto field_name = NameWrappedInNameSpace(*vectortype.struct_def);
+ code_ += "public static func startVectorOf" + MakeCamel(name, true) +
+ "(_ size: Int, in builder: inout "
+ "FlatBufferBuilder) {";
+ Indent();
+ code_ += "builder.startVectorOfStructs(count: size, size: " + field_name +
+ ".size, "
+ "alignment: " +
+ field_name + ".alignment)";
+ Outdent();
+ code_ += "}";
+ }
+ }
+
+ void GenTableReaderFields(const FieldDef &field) {
+ auto offset = NumToString(field.value.offset);
+ auto name = Name(field);
+ auto type = GenType(field.value.type);
+ code_.SetValue("VALUENAME", name);
+ code_.SetValue("VALUETYPE", type);
+ code_.SetValue("OFFSET", name);
+ code_.SetValue("CONSTANT", field.value.constant);
+ bool opt_scalar = field.optional && IsScalar(field.value.type.base_type);
+ std::string def_Val = opt_scalar ? "nil" : "{{CONSTANT}}";
+ std::string optional = opt_scalar ? "?" : "";
+ auto const_string = "return o == 0 ? " + def_Val + " : ";
+ GenComment(field.doc_comment);
+ if (IsScalar(field.value.type.base_type) && !IsEnum(field.value.type) &&
+ !IsBool(field.value.type.base_type)) {
+ code_ += GenReaderMainBody(optional) + GenOffset() + const_string +
+ GenReader("VALUETYPE", "o") + " }";
+ if (parser_.opts.mutable_buffer) code_ += GenMutate("o", GenOffset());
+ return;
+ }
+
+ if (IsBool(field.value.type.base_type)) {
+ std::string default_value =
+ "0" == field.value.constant ? "false" : "true";
+ code_.SetValue("CONSTANT", default_value);
+ code_.SetValue("VALUETYPE", "Bool");
+ code_ += GenReaderMainBody(optional) + "\\";
+ code_.SetValue("VALUETYPE", "Byte");
+ code_ += GenOffset() + "return o == 0 ? {{CONSTANT}} : 0 != " +
+ GenReader("VALUETYPE", "o") + " }";
+ if (parser_.opts.mutable_buffer) code_ += GenMutate("o", GenOffset());
+ return;
+ }
+
+ if (IsEnum(field.value.type)) {
+ auto default_value = field.optional ? "nil" : GenEnumDefaultValue(field);
+ code_.SetValue("BASEVALUE", GenTypeBasic(field.value.type, false));
+ code_ += GenReaderMainBody(optional) + "\\";
+ code_ += GenOffset() + "return o == 0 ? " + default_value + " : " +
+ GenEnumConstructor("o") + "?? " + default_value + " }";
+ if (parser_.opts.mutable_buffer && !IsUnion(field.value.type))
+ code_ += GenMutate("o", GenOffset(), true);
+ return;
+ }
+
+ std::string is_required = field.required ? "!" : "?";
+ auto required_reader = field.required ? "return " : const_string;
+
+ if (IsStruct(field.value.type) && field.value.type.struct_def->fixed) {
+ code_.SetValue("VALUETYPE", GenType(field.value.type));
+ code_.SetValue("CONSTANT", "nil");
+ code_ += GenReaderMainBody(is_required) + GenOffset() + required_reader +
+ GenConstructor("o + {{ACCESS}}.postion");
+ return;
+ }
+ switch (field.value.type.base_type) {
+ case BASE_TYPE_STRUCT:
+ code_.SetValue("VALUETYPE", GenType(field.value.type));
+ code_.SetValue("CONSTANT", "nil");
+ code_ += GenReaderMainBody(is_required) + GenOffset() +
+ required_reader +
+ GenConstructor(GenIndirect("o + {{ACCESS}}.postion"));
+ break;
+
+ case BASE_TYPE_STRING:
+ code_.SetValue("VALUETYPE", GenType(field.value.type));
+ code_.SetValue("CONSTANT", "nil");
+ code_ += GenReaderMainBody(is_required) + GenOffset() +
+ required_reader + "{{ACCESS}}.string(at: o) }";
+ code_ += "{{ACCESS_TYPE}} var {{VALUENAME}}SegmentArray: [UInt8]" +
+ is_required +
+ " { return "
+ "{{ACCESS}}.getVector(at: {{TABLEOFFSET}}.{{OFFSET}}.v) }";
+ break;
+
+ case BASE_TYPE_ARRAY: FLATBUFFERS_FALLTHROUGH(); // fall thru
+ case BASE_TYPE_VECTOR:
+ GenTableReaderVectorFields(field, const_string);
+ break;
+ case BASE_TYPE_UNION:
+ code_.SetValue("CONSTANT", "nil");
+ code_ +=
+ "{{ACCESS_TYPE}} func {{VALUENAME}}<T: FlatBufferObject>(type: "
+ "T.Type) -> T" +
+ is_required + " { " + GenOffset() + required_reader +
+ "{{ACCESS}}.union(o) }";
+ break;
+ default: FLATBUFFERS_ASSERT(0);
+ }
+ }
+
+ void GenTableReaderVectorFields(const FieldDef &field,
+ const std::string &const_string) {
+ auto vectortype = field.value.type.VectorType();
+ code_.SetValue("SIZE", NumToString(InlineSize(vectortype)));
+ code_ += "{{ACCESS_TYPE}} var {{VALUENAME}}Count: Int32 { " + GenOffset() +
+ const_string + "{{ACCESS}}.vector(count: o) }";
+ code_.SetValue("CONSTANT", IsScalar(vectortype.base_type) == true
+ ? field.value.constant
+ : "nil");
+ auto nullable = IsScalar(vectortype.base_type) == true ? "" : "?";
+ nullable = IsEnum(vectortype) == true ? "?" : nullable;
+ if (vectortype.base_type != BASE_TYPE_UNION) {
+ code_ += GenArrayMainBody(nullable) + GenOffset() + "\\";
+ } else {
+ code_ +=
+ "{{ACCESS_TYPE}} func {{VALUENAME}}<T: FlatBufferObject>(at index: "
+ "Int32, type: T.Type) -> T? { " +
+ GenOffset() + "\\";
+ }
+
+ if (IsBool(vectortype.base_type)) {
+ code_.SetValue("CONSTANT", field.value.offset == 0 ? "false" : "true");
+ code_.SetValue("VALUETYPE", "Byte");
+ }
+ if (!IsEnum(vectortype))
+ code_ +=
+ const_string + (IsBool(vectortype.base_type) ? "0 != " : "") + "\\";
+
+ if (IsScalar(vectortype.base_type) && !IsEnum(vectortype) &&
+ !IsBool(field.value.type.base_type)) {
+ code_ +=
+ "{{ACCESS}}.directRead(of: {{VALUETYPE}}.self, offset: "
+ "{{ACCESS}}.vector(at: o) + index * {{SIZE}}) }";
+ code_ +=
+ "{{ACCESS_TYPE}} var {{VALUENAME}}: [{{VALUETYPE}}] { return "
+ "{{ACCESS}}.getVector(at: {{TABLEOFFSET}}.{{OFFSET}}.v) ?? [] }";
+ if (parser_.opts.mutable_buffer) code_ += GenMutateArray();
+ return;
+ }
+ if (vectortype.base_type == BASE_TYPE_STRUCT &&
+ field.value.type.struct_def->fixed) {
+ code_ += GenConstructor("{{ACCESS}}.vector(at: o) + index * {{SIZE}}");
+ return;
+ }
+
+ if (IsString(vectortype)) {
+ code_ +=
+ "{{ACCESS}}.directString(at: {{ACCESS}}.vector(at: o) + "
+ "index * {{SIZE}}) }";
+ return;
+ }
+
+ if (IsEnum(vectortype)) {
+ code_.SetValue("BASEVALUE", GenTypeBasic(vectortype, false));
+ code_ += "return o == 0 ? {{VALUETYPE}}" + GenEnumDefaultValue(field) +
+ " : {{VALUETYPE}}(rawValue: {{ACCESS}}.directRead(of: "
+ "{{BASEVALUE}}.self, offset: {{ACCESS}}.vector(at: o) + "
+ "index * {{SIZE}})) }";
+ return;
+ }
+ if (vectortype.base_type == BASE_TYPE_UNION) {
+ code_ +=
+ "{{ACCESS}}.directUnion({{ACCESS}}.vector(at: o) + "
+ "index * {{SIZE}}) }";
+ return;
+ }
+
+ if (vectortype.base_type == BASE_TYPE_STRUCT &&
+ !field.value.type.struct_def->fixed) {
+ code_ += GenConstructor(
+ "{{ACCESS}}.indirect({{ACCESS}}.vector(at: o) + index * "
+ "{{SIZE}})");
+ auto &sd = *field.value.type.struct_def;
+ auto &fields = sd.fields.vec;
+ for (auto kit = fields.begin(); kit != fields.end(); ++kit) {
+ auto &key_field = **kit;
+ if (key_field.key) {
+ GenByKeyFunctions(key_field);
+ break;
+ }
+ }
+ }
+ }
+
+ void GenByKeyFunctions(const FieldDef &key_field) {
+ code_.SetValue("TYPE", GenType(key_field.value.type));
+ code_ +=
+ "{{ACCESS_TYPE}} func {{VALUENAME}}By(key: {{TYPE}}) -> {{VALUETYPE}}? "
+ "{ \\";
+ code_ += GenOffset() +
+ "return o == 0 ? nil : {{VALUETYPE}}.lookupByKey(vector: "
+ "{{ACCESS}}.vector(at: o), key: key, fbb: {{ACCESS}}.bb) }";
+ }
+
+ // Generates the reader for swift
+ void GenStructReader(const StructDef &struct_def) {
+ auto is_private_access = struct_def.attributes.Lookup("private");
+ code_.SetValue("ACCESS_TYPE", is_private_access ? "internal" : "public");
+
+ GenObjectHeader(struct_def);
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+ auto offset = NumToString(field.value.offset);
+ auto name = Name(field);
+ auto type = GenType(field.value.type);
+ code_.SetValue("VALUENAME", name);
+ code_.SetValue("VALUETYPE", type);
+ code_.SetValue("OFFSET", offset);
+ GenComment(field.doc_comment);
+ if (IsScalar(field.value.type.base_type) && !IsEnum(field.value.type)) {
+ code_ +=
+ GenReaderMainBody() + "return " + GenReader("VALUETYPE") + " }";
+ if (parser_.opts.mutable_buffer) code_ += GenMutate("{{OFFSET}}", "");
+ } else if (IsEnum(field.value.type)) {
+ code_.SetValue("BASEVALUE", GenTypeBasic(field.value.type, false));
+ code_ += GenReaderMainBody() + "return " +
+ GenEnumConstructor("{{OFFSET}}") + "?? " +
+ GenEnumDefaultValue(field) + " }";
+ } else if (IsStruct(field.value.type)) {
+ code_.SetValue("VALUETYPE", GenType(field.value.type));
+ code_ += GenReaderMainBody() + "return " +
+ GenConstructor("{{ACCESS}}.postion + {{OFFSET}}");
+ }
+ }
+ if (parser_.opts.generate_object_based_api)
+ GenerateObjectAPIStructExtension(struct_def);
+ Outdent();
+ code_ += "}\n";
+ }
+
+ void GenEnum(const EnumDef &enum_def) {
+ if (enum_def.generated) return;
+ auto is_private_access = enum_def.attributes.Lookup("private");
+ code_.SetValue("ACCESS_TYPE", is_private_access ? "internal" : "public");
+ code_.SetValue("ENUM_NAME", NameWrappedInNameSpace(enum_def));
+ code_.SetValue("BASE_TYPE", GenTypeBasic(enum_def.underlying_type, false));
+ GenComment(enum_def.doc_comment);
+ code_ += "{{ACCESS_TYPE}} enum {{ENUM_NAME}}: {{BASE_TYPE}}, Enum { ";
+ Indent();
+ code_ += "{{ACCESS_TYPE}} typealias T = {{BASE_TYPE}}";
+ code_ +=
+ "{{ACCESS_TYPE}} static var byteSize: Int { return "
+ "MemoryLayout<{{BASE_TYPE}}>.size "
+ "}";
+ code_ +=
+ "{{ACCESS_TYPE}} var value: {{BASE_TYPE}} { return self.rawValue }";
+ for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
+ const auto &ev = **it;
+ auto name = Name(ev);
+ code_.SetValue("KEY", name);
+ code_.SetValue("VALUE", enum_def.ToString(ev));
+ GenComment(ev.doc_comment);
+ code_ += "case {{KEY}} = {{VALUE}}";
+ }
+ code_ += "\n";
+ AddMinOrMaxEnumValue(Name(*enum_def.MaxValue()), "max");
+ AddMinOrMaxEnumValue(Name(*enum_def.MinValue()), "min");
+ Outdent();
+ code_ += "}\n";
+ if (parser_.opts.generate_object_based_api && enum_def.is_union) {
+ code_ += "{{ACCESS_TYPE}} struct {{ENUM_NAME}}Union {";
+ Indent();
+ code_ += "{{ACCESS_TYPE}} var type: {{ENUM_NAME}}";
+ code_ += "{{ACCESS_TYPE}} var value: NativeTable?";
+ code_ += "{{ACCESS_TYPE}} init(_ v: NativeTable?, type: {{ENUM_NAME}}) {";
+ Indent();
+ code_ += "self.type = type";
+ code_ += "self.value = v";
+ Outdent();
+ code_ += "}";
+ code_ +=
+ "{{ACCESS_TYPE}} func pack(builder: inout FlatBufferBuilder) -> "
+ "Offset<UOffset> {";
+ Indent();
+ BuildUnionEnumSwitchCaseWritter(enum_def);
+ Outdent();
+ code_ += "}";
+ Outdent();
+ code_ += "}";
+ }
+ }
+
+ void GenObjectAPI(const StructDef &struct_def) {
+ code_ += "{{ACCESS_TYPE}} class " + ObjectAPIName("{{STRUCTNAME}}") +
+ ": NativeTable {\n";
+ std::vector<std::string> buffer_constructor;
+ std::vector<std::string> base_constructor;
+ Indent();
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+ BuildObjectAPIConstructorBody(field, struct_def.fixed, buffer_constructor,
+ base_constructor);
+ }
+ code_ += "";
+ BuildObjectAPIConstructor(
+ buffer_constructor,
+ "_ _t: inout " + NameWrappedInNameSpace(struct_def));
+ BuildObjectAPIConstructor(base_constructor);
+ if (!struct_def.fixed)
+ code_ +=
+ "{{ACCESS_TYPE}} func serialize() -> ByteBuffer { return "
+ "serialize(type: "
+ "{{STRUCTNAME}}.self) }\n";
+ Outdent();
+ code_ += "}";
+ }
+
+ void GenerateObjectAPITableExtension(const StructDef &struct_def) {
+ GenerateObjectAPIExtensionHeader();
+ std::vector<std::string> unpack_body;
+ std::string builder = ", &builder)";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+ auto name = Name(field);
+ auto type = GenType(field.value.type);
+ std::string check_if_vector =
+ (IsVector(field.value.type) ||
+ IsArray(field.value.type))
+ ? "VectorOf("
+ : "(";
+ std::string body = "add" + check_if_vector + name + ": ";
+ switch (field.value.type.base_type) {
+ case BASE_TYPE_ARRAY: FLATBUFFERS_FALLTHROUGH();
+ case BASE_TYPE_VECTOR: {
+ GenerateVectorObjectAPITableExtension(field, name, type);
+ unpack_body.push_back("{{STRUCTNAME}}." + body + "__" + name +
+ builder);
+ break;
+ }
+ case BASE_TYPE_UNION: {
+ code_ += "let __" + name + " = obj." + name +
+ "?.pack(builder: &builder) ?? Offset()";
+ unpack_body.push_back("if let o = obj." + name + "?.type {");
+ unpack_body.push_back(" {{STRUCTNAME}}.add(" + name + "Type: o" +
+ builder);
+ unpack_body.push_back(" {{STRUCTNAME}}." + body + "__" + name +
+ builder);
+ unpack_body.push_back("}\n");
+ break;
+ }
+ case BASE_TYPE_STRUCT: {
+ if (field.value.type.struct_def &&
+ field.value.type.struct_def->fixed) {
+ // This is a Struct (IsStruct), not a table. We create
+ // UnsafeMutableRawPointer in this case.
+ std::string code;
+ GenerateStructArgs(*field.value.type.struct_def, &code, "", "",
+ "$0", true);
+ code = code.substr(0, code.size() - 2);
+ unpack_body.push_back(
+ "{{STRUCTNAME}}." + body + "obj." + name + ".map { " +
+ NameWrappedInNameSpace(*field.value.type.struct_def) +
+ ".create" + Name(*field.value.type.struct_def) +
+ "(builder: &builder, " + code + ") }" + builder);
+ } else {
+ code_ += "let __" + name + " = " + type +
+ ".pack(&builder, obj: &obj." + name + ")";
+ unpack_body.push_back("{{STRUCTNAME}}." + body + "__" + name +
+ builder);
+ }
+ break;
+ }
+ case BASE_TYPE_STRING: {
+ unpack_body.push_back("{{STRUCTNAME}}." + body + "__" + name +
+ builder);
+ if (field.required) {
+ code_ +=
+ "let __" + name + " = builder.create(string: obj." + name + ")";
+ } else {
+ BuildingOptionalObjects(name, "String",
+ "builder.create(string: s)");
+ }
+ break;
+ }
+ case BASE_TYPE_UTYPE: break;
+ default:
+ unpack_body.push_back("{{STRUCTNAME}}." + body + "obj." + name +
+ builder);
+ }
+ }
+ code_ += "let __root = {{STRUCTNAME}}.start{{SHORT_STRUCTNAME}}(&builder)";
+ for (auto it = unpack_body.begin(); it < unpack_body.end(); it++)
+ code_ += *it;
+ code_ +=
+ "return {{STRUCTNAME}}.end{{SHORT_STRUCTNAME}}(&builder, start: "
+ "__root)";
+ Outdent();
+ code_ += "}";
+ }
+
+ void GenerateVectorObjectAPITableExtension(const FieldDef &field,
+ const std::string &name,
+ const std::string &type) {
+ auto vectortype = field.value.type.VectorType();
+ switch (vectortype.base_type) {
+ case BASE_TYPE_UNION: {
+ code_ += "var __" + name + "__: [Offset<UOffset>] = []";
+ code_ += "for i in obj." + name + " {";
+ Indent();
+ code_ += "guard let off = i?.pack(builder: &builder) else { continue }";
+ code_ += "__" + name + "__.append(off)";
+ Outdent();
+ code_ += "}";
+ code_ += "let __" + name + " = builder.createVector(ofOffsets: __" +
+ name + "__)";
+ code_ += "let __" + name + "Type = builder.createVector(obj." + name +
+ ".compactMap { $0?.type })";
+ break;
+ }
+ case BASE_TYPE_UTYPE: break;
+ case BASE_TYPE_STRUCT: {
+ if (field.value.type.struct_def &&
+ !field.value.type.struct_def->fixed) {
+ code_ += "var __" + name + "__: [Offset<UOffset>] = []";
+ code_ += "for var i in obj." + name + " {";
+ Indent();
+ code_ +=
+ "__" + name + "__.append(" + type + ".pack(&builder, obj: &i))";
+ Outdent();
+ code_ += "}";
+ code_ += "let __" + name + " = builder.createVector(ofOffsets: __" +
+ name + "__)";
+ } else {
+ code_ += "{{STRUCTNAME}}.startVectorOf" + MakeCamel(name, true) +
+ "(obj." + name + ".count, in: &builder)";
+ std::string code;
+ GenerateStructArgs(*field.value.type.struct_def, &code, "", "", "_o",
+ true);
+ code = code.substr(0, code.size() - 2);
+ code_ += "for i in obj." + name + " {";
+ Indent();
+ code_ += "guard let _o = i else { continue }";
+ code_ += NameWrappedInNameSpace(*field.value.type.struct_def) +
+ ".create" + Name(*field.value.type.struct_def) +
+ "(builder: &builder, " + code + ")";
+ Outdent();
+ code_ += "}";
+ code_ += "let __" + name +
+ " = builder.endVectorOfStructs(count: obj." + name +
+ ".count)";
+ }
+ break;
+ }
+ case BASE_TYPE_STRING: {
+ code_ += "let __" + name + " = builder.createVector(ofStrings: obj." +
+ name + ".compactMap({ $0 }) )";
+ break;
+ }
+ default: {
+ code_ += "let __" + name + " = builder.createVector(obj." + name + ")";
+ break;
+ }
+ }
+ }
+
+ void BuildingOptionalObjects(const std::string &name,
+ const std::string &object_type,
+ const std::string &body_front) {
+ code_ += "let __" + name + ": Offset<" + object_type + ">";
+ code_ += "if let s = obj." + name + " {";
+ Indent();
+ code_ += "__" + name + " = " + body_front;
+ Outdent();
+ code_ += "} else {";
+ Indent();
+ code_ += "__" + name + " = Offset<" + object_type + ">()";
+ Outdent();
+ code_ += "}";
+ code_ += "";
+ }
+
+ void BuildObjectAPIConstructor(const std::vector<std::string> &body,
+ const std::string &header = "") {
+ code_.SetValue("HEADER", header);
+ code_ += "{{ACCESS_TYPE}} init({{HEADER}}) {";
+ Indent();
+ for (auto it = body.begin(); it < body.end(); ++it) code_ += *it;
+ Outdent();
+ code_ += "}\n";
+ }
+
+ void BuildObjectAPIConstructorBody(
+ const FieldDef &field, bool is_fixed,
+ std::vector<std::string> &buffer_constructor,
+ std::vector<std::string> &base_constructor) {
+ auto name = Name(field);
+ auto type = GenType(field.value.type);
+ code_.SetValue("VALUENAME", name);
+ code_.SetValue("VALUETYPE", type);
+ std::string is_required = field.required ? "" : "?";
+
+ switch (field.value.type.base_type) {
+ case BASE_TYPE_STRUCT: {
+ type = GenType(field.value.type, true);
+ code_.SetValue("VALUETYPE", type);
+ buffer_constructor.push_back("var __" + name + " = _t." + name);
+ auto optional =
+ (field.value.type.struct_def && field.value.type.struct_def->fixed);
+ std::string question_mark =
+ (field.required || (optional && is_fixed) ? "" : "?");
+
+ code_ +=
+ "{{ACCESS_TYPE}} var {{VALUENAME}}: {{VALUETYPE}}" + question_mark;
+ buffer_constructor.push_back("" + name + " = __" + name +
+ (field.required ? "!" : question_mark) +
+ ".unpack()");
+ base_constructor.push_back("" + name + " = " + type + "()");
+ break;
+ }
+ case BASE_TYPE_ARRAY: FLATBUFFERS_FALLTHROUGH();
+ case BASE_TYPE_VECTOR: {
+ BuildObjectAPIConstructorBodyVectors(field, name, buffer_constructor,
+ base_constructor, " ");
+ break;
+ }
+ case BASE_TYPE_STRING: {
+ code_ += "{{ACCESS_TYPE}} var {{VALUENAME}}: String" + is_required;
+ buffer_constructor.push_back(name + " = _t." + name);
+ if (field.required) base_constructor.push_back(name + " = \"\"");
+ break;
+ }
+ case BASE_TYPE_UTYPE: break;
+ case BASE_TYPE_UNION: {
+ BuildUnionEnumSwitchCase(*field.value.type.enum_def, name,
+ buffer_constructor);
+ break;
+ }
+ default: {
+ buffer_constructor.push_back(name + " = _t." + name);
+ std::string nullable = field.optional ? "?" : "";
+ if (IsScalar(field.value.type.base_type) &&
+ !IsBool(field.value.type.base_type) && !IsEnum(field.value.type)) {
+ code_ +=
+ "{{ACCESS_TYPE}} var {{VALUENAME}}: {{VALUETYPE}}" + nullable;
+ if (!field.optional)
+ base_constructor.push_back(name + " = " + field.value.constant);
+ break;
+ }
+
+ if (IsEnum(field.value.type)) {
+ auto default_value = IsEnum(field.value.type)
+ ? GenEnumDefaultValue(field)
+ : field.value.constant;
+ code_ += "{{ACCESS_TYPE}} var {{VALUENAME}}: {{VALUETYPE}}";
+ base_constructor.push_back(name + " = " + default_value);
+ break;
+ }
+
+ if (IsBool(field.value.type.base_type)) {
+ code_ += "{{ACCESS_TYPE}} var {{VALUENAME}}: Bool" + nullable;
+ std::string default_value =
+ "0" == field.value.constant ? "false" : "true";
+ if (!field.optional)
+ base_constructor.push_back(name + " = " + default_value);
+ }
+ }
+ }
+ }
+
+ void BuildObjectAPIConstructorBodyVectors(
+ const FieldDef &field, const std::string &name,
+ std::vector<std::string> &buffer_constructor,
+ std::vector<std::string> &base_constructor,
+ const std::string &indentation) {
+ auto vectortype = field.value.type.VectorType();
+
+ if (vectortype.base_type != BASE_TYPE_UTYPE) {
+ buffer_constructor.push_back(name + " = []");
+ buffer_constructor.push_back("for index in 0..<_t." + name + "Count {");
+ base_constructor.push_back(name + " = []");
+ }
+
+ switch (vectortype.base_type) {
+ case BASE_TYPE_STRUCT: {
+ code_.SetValue("VALUETYPE", GenType(vectortype, true));
+ code_ += "{{ACCESS_TYPE}} var {{VALUENAME}}: [{{VALUETYPE}}?]";
+ buffer_constructor.push_back(indentation + "var __v_ = _t." + name +
+ "(at: index)");
+ buffer_constructor.push_back(indentation + name +
+ ".append(__v_?.unpack())");
+ break;
+ }
+ case BASE_TYPE_ARRAY: FLATBUFFERS_FALLTHROUGH();
+ case BASE_TYPE_VECTOR: {
+ break;
+ }
+ case BASE_TYPE_UNION: {
+ BuildUnionEnumSwitchCase(*field.value.type.enum_def, name,
+ buffer_constructor, indentation, true);
+ break;
+ }
+ case BASE_TYPE_UTYPE: break;
+ default: {
+ code_.SetValue("VALUETYPE", (IsString(vectortype)
+ ? "String?"
+ : GenType(vectortype)));
+ code_ += "{{ACCESS_TYPE}} var {{VALUENAME}}: [{{VALUETYPE}}]";
+
+ if (IsEnum(vectortype) && vectortype.base_type != BASE_TYPE_UNION) {
+ auto default_value = IsEnum(field.value.type)
+ ? GenEnumDefaultValue(field)
+ : field.value.constant;
+ buffer_constructor.push_back(indentation + name + ".append(_t." +
+ name + "(at: index)!)");
+ break;
+ }
+ buffer_constructor.push_back(indentation + name + ".append(_t." + name +
+ "(at: index))");
+ break;
+ }
+ }
+ if (vectortype.base_type != BASE_TYPE_UTYPE)
+ buffer_constructor.push_back("}");
+ }
+
+ void BuildUnionEnumSwitchCaseWritter(const EnumDef &ev) {
+ auto field_name = Name(ev);
+ code_.SetValue("VALUETYPE", field_name);
+ code_ += "switch type {";
+ for (auto it = ev.Vals().begin(); it < ev.Vals().end(); ++it) {
+ auto field = **it;
+ auto ev_name = Name(field);
+ auto type = GenType(field.union_type);
+
+ if (field.union_type.base_type == BASE_TYPE_NONE ||
+ IsString(field.union_type)) {
+ continue;
+ }
+ code_ += "case ." + ev_name + ":";
+ Indent();
+ code_ += "var __obj = value as? " + GenType(field.union_type, true);
+ code_ += "return " + type + ".pack(&builder, obj: &__obj)";
+ Outdent();
+ }
+ code_ += "default: return Offset()";
+ code_ += "}";
+ }
+
+ void BuildUnionEnumSwitchCase(const EnumDef &ev, const std::string &name,
+ std::vector<std::string> &buffer_constructor,
+ const std::string &indentation = "",
+ const bool is_vector = false) {
+ auto field_name = NameWrappedInNameSpace(ev);
+ code_.SetValue("VALUETYPE", field_name);
+ code_ += "{{ACCESS_TYPE}} var {{VALUENAME}}: \\";
+ code_ += is_vector ? "[{{VALUETYPE}}Union?]" : "{{VALUETYPE}}Union?";
+
+ auto vector_reader = is_vector ? "(at: index" : "";
+ buffer_constructor.push_back(indentation + "switch _t." + name + "Type" +
+ vector_reader + (is_vector ? ")" : "") + " {");
+
+ for (auto it = ev.Vals().begin(); it < ev.Vals().end(); ++it) {
+ auto field = **it;
+ auto ev_name = Name(field);
+ if (field.union_type.base_type == BASE_TYPE_NONE ||
+ IsString(field.union_type)) {
+ continue;
+ }
+ buffer_constructor.push_back(indentation + "case ." + ev_name + ":");
+ buffer_constructor.push_back(
+ indentation + " var _v = _t." + name + (is_vector ? "" : "(") +
+ vector_reader + (is_vector ? ", " : "") +
+ "type: " + GenType(field.union_type) + ".self)");
+ auto constructor =
+ field_name + "Union(_v?.unpack(), type: ." + ev_name + ")";
+ buffer_constructor.push_back(
+ indentation + " " + name +
+ (is_vector ? ".append(" + constructor + ")" : " = " + constructor));
+ }
+ buffer_constructor.push_back(indentation + "default: break");
+ buffer_constructor.push_back(indentation + "}");
+ }
+
+ void AddMinOrMaxEnumValue(const std::string &str, const std::string &type) {
+ auto current_value = str;
+ code_.SetValue(type, current_value);
+ code_ += "{{ACCESS_TYPE}} static var " + type +
+ ": {{ENUM_NAME}} { return .{{" + type + "}} }";
+ }
+
+ void GenLookup(const FieldDef &key_field) {
+ code_.SetValue("OFFSET", NumToString(key_field.value.offset));
+ std::string offset_reader =
+ "Table.offset(Int32(fbb.capacity) - tableOffset, vOffset: {{OFFSET}}, "
+ "fbb: fbb)";
+
+ code_.SetValue("TYPE", GenType(key_field.value.type));
+ code_ +=
+ "fileprivate static func lookupByKey(vector: Int32, key: {{TYPE}}, "
+ "fbb: "
+ "ByteBuffer) -> {{VALUENAME}}? {";
+ Indent();
+ if (IsString(key_field.value.type))
+ code_ += "let key = key.utf8.map { $0 }";
+ code_ += "var span = fbb.read(def: Int32.self, position: Int(vector - 4))";
+ code_ += "var start: Int32 = 0";
+ code_ += "while span != 0 {";
+ Indent();
+ code_ += "var middle = span / 2";
+ code_ +=
+ "let tableOffset = Table.indirect(vector + 4 * (start + middle), fbb)";
+ if (IsString(key_field.value.type)) {
+ code_ += "let comp = Table.compare(" + offset_reader + ", key, fbb: fbb)";
+ } else {
+ code_ += "let comp = fbb.read(def: {{TYPE}}.self, position: Int(" +
+ offset_reader + "))";
+ }
+
+ code_ += "if comp > 0 {";
+ Indent();
+ code_ += "span = middle";
+ Outdent();
+ code_ += "} else if comp < 0 {";
+ Indent();
+ code_ += "middle += 1";
+ code_ += "start += middle";
+ code_ += "span -= middle";
+ Outdent();
+ code_ += "} else {";
+ Indent();
+ code_ += "return {{VALUENAME}}(fbb, o: tableOffset)";
+ Outdent();
+ code_ += "}";
+ Outdent();
+ code_ += "}";
+ code_ += "return nil";
+ Outdent();
+ code_ += "}";
+ }
+
+ void GenComment(const std::vector<std::string> &dc) {
+ if (dc.begin() == dc.end()) {
+ // Don't output empty comment blocks with 0 lines of comment content.
+ return;
+ }
+ for (auto it = dc.begin(); it != dc.end(); ++it) { code_ += "/// " + *it; }
+ }
+
+ std::string GenOffset() {
+ return "let o = {{ACCESS}}.offset({{TABLEOFFSET}}.{{OFFSET}}.v); ";
+ }
+
+ std::string GenReaderMainBody(const std::string &optional = "") {
+ return "{{ACCESS_TYPE}} var {{VALUENAME}}: {{VALUETYPE}}" + optional +
+ " { ";
+ }
+
+ std::string GenReader(const std::string &type,
+ const std::string &at = "{{OFFSET}}") {
+ return "{{ACCESS}}.readBuffer(of: {{" + type + "}}.self, at: " + at + ")";
+ }
+
+ std::string GenConstructor(const std::string &offset) {
+ return "{{VALUETYPE}}({{ACCESS}}.bb, o: " + offset + ") }";
+ }
+
+ std::string GenMutate(const std::string &offset,
+ const std::string &get_offset, bool isRaw = false) {
+ return "@discardableResult {{ACCESS_TYPE}} func mutate({{VALUENAME}}: "
+ "{{VALUETYPE}}) -> Bool {" +
+ get_offset + " return {{ACCESS}}.mutate({{VALUENAME}}" +
+ (isRaw ? ".rawValue" : "") + ", index: " + offset + ") }";
+ }
+
+ std::string GenMutateArray() {
+ return "{{ACCESS_TYPE}} func mutate({{VALUENAME}}: {{VALUETYPE}}, at "
+ "index: "
+ "Int32) -> Bool { " +
+ GenOffset() +
+ "return {{ACCESS}}.directMutate({{VALUENAME}}, index: "
+ "{{ACCESS}}.vector(at: o) + index * {{SIZE}}) }";
+ }
+
+ std::string GenEnumDefaultValue(const FieldDef &field) {
+ auto &value = field.value;
+ FLATBUFFERS_ASSERT(value.type.enum_def);
+ auto &enum_def = *value.type.enum_def;
+ auto enum_val = enum_def.FindByValue(value.constant);
+ std::string name;
+ if (enum_val) {
+ name = Name(*enum_val);
+ } else {
+ const auto &ev = **enum_def.Vals().begin();
+ name = Name(ev);
+ }
+ std::transform(name.begin(), name.end(), name.begin(), CharToLower);
+ return "." + name;
+ }
+
+ std::string GenEnumConstructor(const std::string &at) {
+ return "{{VALUETYPE}}(rawValue: " + GenReader("BASEVALUE", at) + ") ";
+ }
+
+ std::string ValidateFunc() {
+ return "static func validateVersion() { FlatBuffersVersion_1_12_0() }";
+ }
+
+ std::string GenType(const Type &type,
+ const bool should_consider_suffix = false) const {
+ return IsScalar(type.base_type)
+ ? GenTypeBasic(type)
+ : (IsArray(type) ? GenType(type.VectorType())
+ : GenTypePointer(type, should_consider_suffix));
+ }
+
+ std::string GenTypePointer(const Type &type,
+ const bool should_consider_suffix) const {
+ switch (type.base_type) {
+ case BASE_TYPE_STRING: return "String";
+ case BASE_TYPE_VECTOR: return GenType(type.VectorType());
+ case BASE_TYPE_STRUCT: {
+ auto &struct_ = *type.struct_def;
+ if (should_consider_suffix) {
+ return WrapInNameSpace(struct_.defined_namespace,
+ ObjectAPIName(Name(struct_)));
+ }
+ return WrapInNameSpace(struct_.defined_namespace, Name(struct_));
+ }
+ case BASE_TYPE_UNION:
+ default: return "FlatBufferObject";
+ }
+ }
+
+ std::string GenTypeBasic(const Type &type) const {
+ return GenTypeBasic(type, true);
+ }
+
+ std::string ObjectAPIName(const std::string &name) const {
+ return parser_.opts.object_prefix + name + parser_.opts.object_suffix;
+ }
+
+ void Indent() { code_.IncrementIdentLevel(); }
+
+ void Outdent() { code_.DecrementIdentLevel(); }
+
+ std::string NameWrappedInNameSpace(const EnumDef &enum_def) const {
+ return WrapInNameSpace(enum_def.defined_namespace, Name(enum_def));
+ }
+
+ std::string NameWrappedInNameSpace(const StructDef &struct_def) const {
+ return WrapInNameSpace(struct_def.defined_namespace, Name(struct_def));
+ }
+
+ std::string GenTypeBasic(const Type &type, bool can_override) const {
+ // clang-format off
+ static const char * const swift_type[] = {
+ #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
+ CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE, STYPE) \
+ #STYPE,
+ FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
+ #undef FLATBUFFERS_TD
+ };
+ // clang-format on
+ if (can_override) {
+ if (type.enum_def) return NameWrappedInNameSpace(*type.enum_def);
+ if (type.base_type == BASE_TYPE_BOOL) return "Bool";
+ }
+ return swift_type[static_cast<int>(type.base_type)];
+ }
+
+ std::string EscapeKeyword(const std::string &name) const {
+ return keywords_.find(name) == keywords_.end() ? name : name + "_";
+ }
+
+ std::string Name(const EnumVal &ev) const {
+ auto name = ev.name;
+ if (isupper(name.front())) {
+ std::transform(name.begin(), name.end(), name.begin(), CharToLower);
+ }
+ return EscapeKeyword(MakeCamel(name, false));
+ }
+
+ std::string Name(const Definition &def) const {
+ return EscapeKeyword(MakeCamel(def.name, false));
+ }
+};
+} // namespace swift
+bool GenerateSwift(const Parser &parser, const std::string &path,
+ const std::string &file_name) {
+ swift::SwiftGenerator generator(parser, path, file_name);
+ return generator.generate();
+}
+} // namespace flatbuffers
diff --git a/src/idl_gen_text.cpp b/src/idl_gen_text.cpp
index 9825dce..e4d2182 100644
--- a/src/idl_gen_text.cpp
+++ b/src/idl_gen_text.cpp
@@ -23,293 +23,337 @@
namespace flatbuffers {
-static bool GenStruct(const StructDef &struct_def, const Table *table,
- int indent, const IDLOptions &opts, std::string *_text);
+struct PrintScalarTag {};
+struct PrintPointerTag {};
+template<typename T> struct PrintTag { typedef PrintScalarTag type; };
+template<> struct PrintTag<const void *> { typedef PrintPointerTag type; };
-// If indentation is less than 0, that indicates we don't want any newlines
-// either.
-const char *NewLine(const IDLOptions &opts) {
- return opts.indent_step >= 0 ? "\n" : "";
-}
-
-int Indent(const IDLOptions &opts) { return std::max(opts.indent_step, 0); }
-
-// Output an identifier with or without quotes depending on strictness.
-void OutputIdentifier(const std::string &name, const IDLOptions &opts,
- std::string *_text) {
- std::string &text = *_text;
- if (opts.strict_json) text += "\"";
- text += name;
- if (opts.strict_json) text += "\"";
-}
-
-// Print (and its template specialization below for pointers) generate text
-// for a single FlatBuffer value into JSON format.
-// The general case for scalars:
-template<typename T>
-bool Print(T val, Type type, int /*indent*/, Type * /*union_type*/,
- const IDLOptions &opts, std::string *_text) {
- std::string &text = *_text;
- if (type.enum_def && opts.output_enum_identifiers) {
- std::vector<EnumVal const *> enum_values;
- if (auto ev = type.enum_def->ReverseLookup(static_cast<int64_t>(val))) {
- enum_values.push_back(ev);
- } else if (val && type.enum_def->attributes.Lookup("bit_flags")) {
- for (auto it = type.enum_def->Vals().begin(),
- e = type.enum_def->Vals().end();
- it != e; ++it) {
- if ((*it)->GetAsUInt64() & static_cast<uint64_t>(val))
- enum_values.push_back(*it);
- }
- }
- if (!enum_values.empty()) {
- text += '\"';
- for (auto it = enum_values.begin(), e = enum_values.end(); it != e; ++it)
- text += (*it)->name + ' ';
- text[text.length() - 1] = '\"';
- return true;
- }
+struct JsonPrinter {
+ // If indentation is less than 0, that indicates we don't want any newlines
+ // either.
+ void AddNewLine() {
+ if (opts.indent_step >= 0) text += '\n';
}
- if (type.base_type == BASE_TYPE_BOOL) {
- text += val != 0 ? "true" : "false";
- } else {
+ void AddIndent(int ident) { text.append(ident, ' '); }
+
+ int Indent() const { return std::max(opts.indent_step, 0); }
+
+ // Output an identifier with or without quotes depending on strictness.
+ void OutputIdentifier(const std::string &name) {
+ if (opts.strict_json) text += '\"';
+ text += name;
+ if (opts.strict_json) text += '\"';
+ }
+
+ // Print (and its template specialization below for pointers) generate text
+ // for a single FlatBuffer value into JSON format.
+ // The general case for scalars:
+ template<typename T>
+ bool PrintScalar(T val, const Type &type, int /*indent*/) {
+ if (IsBool(type.base_type)) {
+ text += val != 0 ? "true" : "false";
+ return true; // done
+ }
+
+ if (opts.output_enum_identifiers && type.enum_def) {
+ const auto &enum_def = *type.enum_def;
+ if (auto ev = enum_def.ReverseLookup(static_cast<int64_t>(val))) {
+ text += '\"';
+ text += ev->name;
+ text += '\"';
+ return true; // done
+ } else if (val && enum_def.attributes.Lookup("bit_flags")) {
+ const auto entry_len = text.length();
+ const auto u64 = static_cast<uint64_t>(val);
+ uint64_t mask = 0;
+ text += '\"';
+ for (auto it = enum_def.Vals().begin(), e = enum_def.Vals().end();
+ it != e; ++it) {
+ auto f = (*it)->GetAsUInt64();
+ if (f & u64) {
+ mask |= f;
+ text += (*it)->name;
+ text += ' ';
+ }
+ }
+ // Don't slice if (u64 != mask)
+ if (mask && (u64 == mask)) {
+ text[text.length() - 1] = '\"';
+ return true; // done
+ }
+ text.resize(entry_len); // restore
+ }
+ // print as numeric value
+ }
+
text += NumToString(val);
+ return true;
}
- return true;
-}
-
-// Print a vector or an array of JSON values, comma seperated, wrapped in "[]".
-template<typename T, typename Container>
-bool PrintContainer(const Container &c, size_t size, Type type, int indent,
- const IDLOptions &opts, std::string *_text) {
- std::string &text = *_text;
- text += "[";
- text += NewLine(opts);
- for (uoffset_t i = 0; i < size; i++) {
- if (i) {
- if (!opts.protobuf_ascii_alike) text += ",";
- text += NewLine(opts);
- }
- text.append(indent + Indent(opts), ' ');
- if (IsStruct(type)) {
- if (!Print(reinterpret_cast<const void *>(c.Data() +
- i * type.struct_def->bytesize),
- type, indent + Indent(opts), nullptr, opts, _text)) {
- return false;
- }
- } else {
- if (!Print(c[i], type, indent + Indent(opts), nullptr, opts, _text)) {
- return false;
- }
- }
+ void AddComma() {
+ if (!opts.protobuf_ascii_alike) text += ',';
}
- text += NewLine(opts);
- text.append(indent, ' ');
- text += "]";
- return true;
-}
-template<typename T>
-bool PrintVector(const Vector<T> &v, Type type, int indent,
- const IDLOptions &opts, std::string *_text) {
- return PrintContainer<T, Vector<T>>(v, v.size(), type, indent, opts, _text);
-}
-
-// Print an array a sequence of JSON values, comma separated, wrapped in "[]".
-template<typename T>
-bool PrintArray(const Array<T, 0xFFFF> &a, size_t size, Type type, int indent,
- const IDLOptions &opts, std::string *_text) {
- return PrintContainer<T, Array<T, 0xFFFF>>(a, size, type, indent, opts,
- _text);
-}
-
-// Specialization of Print above for pointer types.
-template<>
-bool Print<const void *>(const void *val, Type type, int indent,
- Type *union_type, const IDLOptions &opts,
- std::string *_text) {
- switch (type.base_type) {
- case BASE_TYPE_UNION:
- // If this assert hits, you have an corrupt buffer, a union type field
- // was not present or was out of range.
- FLATBUFFERS_ASSERT(union_type);
- return Print<const void *>(val, *union_type, indent, nullptr, opts,
- _text);
- case BASE_TYPE_STRUCT:
- if (!GenStruct(*type.struct_def, reinterpret_cast<const Table *>(val),
- indent, opts, _text)) {
- return false;
+ // Print a vector or an array of JSON values, comma seperated, wrapped in
+ // "[]".
+ template<typename Container>
+ bool PrintContainer(PrintScalarTag, const Container &c, size_t size,
+ const Type &type, int indent, const uint8_t *) {
+ const auto elem_indent = indent + Indent();
+ text += '[';
+ AddNewLine();
+ for (uoffset_t i = 0; i < size; i++) {
+ if (i) {
+ AddComma();
+ AddNewLine();
}
- break;
- case BASE_TYPE_STRING: {
- auto s = reinterpret_cast<const String *>(val);
- if (!EscapeString(s->c_str(), s->size(), _text, opts.allow_non_utf8,
- opts.natural_utf8)) {
- return false;
- }
- break;
+ AddIndent(elem_indent);
+ if (!PrintScalar(c[i], type, elem_indent)) { return false; }
}
- case BASE_TYPE_VECTOR: {
- const auto vec_type = type.VectorType();
- // Call PrintVector above specifically for each element type:
- // clang-format off
- switch (vec_type.base_type) {
- #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
- CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \
+ AddNewLine();
+ AddIndent(indent);
+ text += ']';
+ return true;
+ }
+
+ // Print a vector or an array of JSON values, comma seperated, wrapped in
+ // "[]".
+ template<typename Container>
+ bool PrintContainer(PrintPointerTag, const Container &c, size_t size,
+ const Type &type, int indent, const uint8_t *prev_val) {
+ const auto is_struct = IsStruct(type);
+ const auto elem_indent = indent + Indent();
+ text += '[';
+ AddNewLine();
+ for (uoffset_t i = 0; i < size; i++) {
+ if (i) {
+ AddComma();
+ AddNewLine();
+ }
+ AddIndent(elem_indent);
+ auto ptr = is_struct ? reinterpret_cast<const void *>(
+ c.Data() + type.struct_def->bytesize * i)
+ : c[i];
+ if (!PrintOffset(ptr, type, elem_indent, prev_val,
+ static_cast<soffset_t>(i))) {
+ return false;
+ }
+ }
+ AddNewLine();
+ AddIndent(indent);
+ text += ']';
+ return true;
+ }
+
+ template<typename T>
+ bool PrintVector(const void *val, const Type &type, int indent,
+ const uint8_t *prev_val) {
+ typedef Vector<T> Container;
+ typedef typename PrintTag<typename Container::return_type>::type tag;
+ auto &vec = *reinterpret_cast<const Container *>(val);
+ return PrintContainer<Container>(tag(), vec, vec.size(), type, indent,
+ prev_val);
+ }
+
+ // Print an array a sequence of JSON values, comma separated, wrapped in "[]".
+ template<typename T>
+ bool PrintArray(const void *val, size_t size, const Type &type, int indent) {
+ typedef Array<T, 0xFFFF> Container;
+ typedef typename PrintTag<typename Container::return_type>::type tag;
+ auto &arr = *reinterpret_cast<const Container *>(val);
+ return PrintContainer<Container>(tag(), arr, size, type, indent, nullptr);
+ }
+
+ bool PrintOffset(const void *val, const Type &type, int indent,
+ const uint8_t *prev_val, soffset_t vector_index) {
+ switch (type.base_type) {
+ case BASE_TYPE_UNION: {
+ // If this assert hits, you have an corrupt buffer, a union type field
+ // was not present or was out of range.
+ FLATBUFFERS_ASSERT(prev_val);
+ auto union_type_byte = *prev_val; // Always a uint8_t.
+ if (vector_index >= 0) {
+ auto type_vec = reinterpret_cast<const Vector<uint8_t> *>(
+ prev_val + ReadScalar<uoffset_t>(prev_val));
+ union_type_byte = type_vec->Get(static_cast<uoffset_t>(vector_index));
+ }
+ auto enum_val = type.enum_def->ReverseLookup(union_type_byte, true);
+ if (enum_val) {
+ return PrintOffset(val, enum_val->union_type, indent, nullptr, -1);
+ } else {
+ return false;
+ }
+ }
+ case BASE_TYPE_STRUCT:
+ return GenStruct(*type.struct_def, reinterpret_cast<const Table *>(val),
+ indent);
+ case BASE_TYPE_STRING: {
+ auto s = reinterpret_cast<const String *>(val);
+ return EscapeString(s->c_str(), s->size(), &text, opts.allow_non_utf8,
+ opts.natural_utf8);
+ }
+ case BASE_TYPE_VECTOR: {
+ const auto vec_type = type.VectorType();
+ // Call PrintVector above specifically for each element type:
+ // clang-format off
+ switch (vec_type.base_type) {
+ #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \
case BASE_TYPE_ ## ENUM: \
if (!PrintVector<CTYPE>( \
- *reinterpret_cast<const Vector<CTYPE> *>(val), \
- vec_type, indent, opts, _text)) { \
+ val, vec_type, indent, prev_val)) { \
return false; \
} \
break;
FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
#undef FLATBUFFERS_TD
+ }
+ // clang-format on
+ return true;
}
- // clang-format on
- break;
- }
- case BASE_TYPE_ARRAY: {
- const auto vec_type = type.VectorType();
- // Call PrintArray above specifically for each element type:
- // clang-format off
- switch (vec_type.base_type) {
- #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
- CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \
- case BASE_TYPE_ ## ENUM: \
- if (!PrintArray<CTYPE>( \
- *reinterpret_cast<const Array<CTYPE, 0xFFFF> *>(val), \
- type.fixed_length, \
- vec_type, indent, opts, _text)) { \
- return false; \
- } \
- break;
- FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD)
- FLATBUFFERS_GEN_TYPES_POINTER(FLATBUFFERS_TD)
+ case BASE_TYPE_ARRAY: {
+ const auto vec_type = type.VectorType();
+ // Call PrintArray above specifically for each element type:
+ // clang-format off
+ switch (vec_type.base_type) {
+ #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \
+ case BASE_TYPE_ ## ENUM: \
+ if (!PrintArray<CTYPE>( \
+ val, type.fixed_length, vec_type, indent)) { \
+ return false; \
+ } \
+ break;
+ FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD)
+ // Arrays of scalars or structs are only possible.
+ FLATBUFFERS_GEN_TYPES_POINTER(FLATBUFFERS_TD)
#undef FLATBUFFERS_TD
- case BASE_TYPE_ARRAY: FLATBUFFERS_ASSERT(0);
+ case BASE_TYPE_ARRAY: FLATBUFFERS_ASSERT(0);
+ }
+ // clang-format on
+ return true;
}
- // clang-format on
- break;
+ default: FLATBUFFERS_ASSERT(0); return false;
}
- default: FLATBUFFERS_ASSERT(0);
}
- return true;
-}
-template<typename T> static T GetFieldDefault(const FieldDef &fd) {
- T val;
- auto check = StringToNumber(fd.value.constant.c_str(), &val);
- (void)check;
- FLATBUFFERS_ASSERT(check);
- return val;
-}
-
-// Generate text for a scalar field.
-template<typename T>
-static bool GenField(const FieldDef &fd, const Table *table, bool fixed,
- const IDLOptions &opts, int indent, std::string *_text) {
- return Print(
- fixed ? reinterpret_cast<const Struct *>(table)->GetField<T>(
- fd.value.offset)
- : table->GetField<T>(fd.value.offset, GetFieldDefault<T>(fd)),
- fd.value.type, indent, nullptr, opts, _text);
-}
-
-static bool GenStruct(const StructDef &struct_def, const Table *table,
- int indent, const IDLOptions &opts, std::string *_text);
-
-// Generate text for non-scalar field.
-static bool GenFieldOffset(const FieldDef &fd, const Table *table, bool fixed,
- int indent, Type *union_type, const IDLOptions &opts,
- std::string *_text) {
- const void *val = nullptr;
- if (fixed) {
- // The only non-scalar fields in structs are structs or arrays.
- FLATBUFFERS_ASSERT(IsStruct(fd.value.type) || IsArray(fd.value.type));
- val = reinterpret_cast<const Struct *>(table)->GetStruct<const void *>(
- fd.value.offset);
- } else if (fd.flexbuffer) {
- auto vec = table->GetPointer<const Vector<uint8_t> *>(fd.value.offset);
- auto root = flexbuffers::GetRoot(vec->data(), vec->size());
- root.ToString(true, opts.strict_json, *_text);
- return true;
- } else if (fd.nested_flatbuffer) {
- auto vec = table->GetPointer<const Vector<uint8_t> *>(fd.value.offset);
- auto root = GetRoot<Table>(vec->data());
- return GenStruct(*fd.nested_flatbuffer, root, indent, opts, _text);
- } else {
- val = IsStruct(fd.value.type)
- ? table->GetStruct<const void *>(fd.value.offset)
- : table->GetPointer<const void *>(fd.value.offset);
+ template<typename T> static T GetFieldDefault(const FieldDef &fd) {
+ T val;
+ auto check = StringToNumber(fd.value.constant.c_str(), &val);
+ (void)check;
+ FLATBUFFERS_ASSERT(check);
+ return val;
}
- return Print(val, fd.value.type, indent, union_type, opts, _text);
-}
-// Generate text for a struct or table, values separated by commas, indented,
-// and bracketed by "{}"
-static bool GenStruct(const StructDef &struct_def, const Table *table,
- int indent, const IDLOptions &opts, std::string *_text) {
- std::string &text = *_text;
- text += "{";
- int fieldout = 0;
- Type *union_type = nullptr;
- for (auto it = struct_def.fields.vec.begin();
- it != struct_def.fields.vec.end(); ++it) {
- FieldDef &fd = **it;
- auto is_present = struct_def.fixed || table->CheckField(fd.value.offset);
- auto output_anyway = opts.output_default_scalars_in_json &&
- IsScalar(fd.value.type.base_type) && !fd.deprecated;
- if (is_present || output_anyway) {
- if (fieldout++) {
- if (!opts.protobuf_ascii_alike) text += ",";
- }
- text += NewLine(opts);
- text.append(indent + Indent(opts), ' ');
- OutputIdentifier(fd.name, opts, _text);
- if (!opts.protobuf_ascii_alike ||
- (fd.value.type.base_type != BASE_TYPE_STRUCT &&
- fd.value.type.base_type != BASE_TYPE_VECTOR))
- text += ":";
- text += " ";
- switch (fd.value.type.base_type) {
- // clang-format off
- #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
- CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \
- case BASE_TYPE_ ## ENUM: \
- if (!GenField<CTYPE>(fd, table, struct_def.fixed, \
- opts, indent + Indent(opts), _text)) { \
- return false; \
- } \
- break;
- FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD)
+ // Generate text for a scalar field.
+ template<typename T>
+ bool GenField(const FieldDef &fd, const Table *table, bool fixed,
+ int indent) {
+ return PrintScalar(
+ fixed ? reinterpret_cast<const Struct *>(table)->GetField<T>(
+ fd.value.offset)
+ : table->GetField<T>(fd.value.offset, GetFieldDefault<T>(fd)),
+ fd.value.type, indent);
+ }
+
+ // Generate text for non-scalar field.
+ bool GenFieldOffset(const FieldDef &fd, const Table *table, bool fixed,
+ int indent, const uint8_t *prev_val) {
+ const void *val = nullptr;
+ if (fixed) {
+ // The only non-scalar fields in structs are structs or arrays.
+ FLATBUFFERS_ASSERT(IsStruct(fd.value.type) || IsArray(fd.value.type));
+ val = reinterpret_cast<const Struct *>(table)->GetStruct<const void *>(
+ fd.value.offset);
+ } else if (fd.flexbuffer) {
+ auto vec = table->GetPointer<const Vector<uint8_t> *>(fd.value.offset);
+ auto root = flexbuffers::GetRoot(vec->data(), vec->size());
+ root.ToString(true, opts.strict_json, text);
+ return true;
+ } else if (fd.nested_flatbuffer) {
+ auto vec = table->GetPointer<const Vector<uint8_t> *>(fd.value.offset);
+ auto root = GetRoot<Table>(vec->data());
+ return GenStruct(*fd.nested_flatbuffer, root, indent);
+ } else {
+ val = IsStruct(fd.value.type)
+ ? table->GetStruct<const void *>(fd.value.offset)
+ : table->GetPointer<const void *>(fd.value.offset);
+ }
+ return PrintOffset(val, fd.value.type, indent, prev_val, -1);
+ }
+
+ // Generate text for a struct or table, values separated by commas, indented,
+ // and bracketed by "{}"
+ bool GenStruct(const StructDef &struct_def, const Table *table, int indent) {
+ text += '{';
+ int fieldout = 0;
+ const uint8_t *prev_val = nullptr;
+ const auto elem_indent = indent + Indent();
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ FieldDef &fd = **it;
+ auto is_present = struct_def.fixed || table->CheckField(fd.value.offset);
+ auto output_anyway = opts.output_default_scalars_in_json &&
+ IsScalar(fd.value.type.base_type) && !fd.deprecated;
+ if (is_present || output_anyway) {
+ if (fieldout++) { AddComma(); }
+ AddNewLine();
+ AddIndent(elem_indent);
+ OutputIdentifier(fd.name);
+ if (!opts.protobuf_ascii_alike ||
+ (fd.value.type.base_type != BASE_TYPE_STRUCT &&
+ fd.value.type.base_type != BASE_TYPE_VECTOR))
+ text += ':';
+ text += ' ';
+ // clang-format off
+ switch (fd.value.type.base_type) {
+ #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \
+ case BASE_TYPE_ ## ENUM: \
+ if (!GenField<CTYPE>(fd, table, struct_def.fixed, elem_indent)) { \
+ return false; \
+ } \
+ break;
+ FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD)
#undef FLATBUFFERS_TD
// Generate drop-thru case statements for all pointer types:
- #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
- CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \
+ #define FLATBUFFERS_TD(ENUM, ...) \
case BASE_TYPE_ ## ENUM:
- FLATBUFFERS_GEN_TYPES_POINTER(FLATBUFFERS_TD)
- FLATBUFFERS_GEN_TYPE_ARRAY(FLATBUFFERS_TD)
+ FLATBUFFERS_GEN_TYPES_POINTER(FLATBUFFERS_TD)
+ FLATBUFFERS_GEN_TYPE_ARRAY(FLATBUFFERS_TD)
#undef FLATBUFFERS_TD
- if (!GenFieldOffset(fd, table, struct_def.fixed, indent + Indent(opts),
- union_type, opts, _text)) {
- return false;
- }
+ if (!GenFieldOffset(fd, table, struct_def.fixed, elem_indent, prev_val)) {
+ return false;
+ }
break;
- // clang-format on
- }
- if (fd.value.type.base_type == BASE_TYPE_UTYPE) {
- auto enum_val = fd.value.type.enum_def->ReverseLookup(
- table->GetField<uint8_t>(fd.value.offset, 0), true);
- union_type = enum_val ? &enum_val->union_type : nullptr;
+ }
+ // clang-format on
+ // Track prev val for use with union types.
+ if (struct_def.fixed) {
+ prev_val = reinterpret_cast<const uint8_t *>(table) + fd.value.offset;
+ } else {
+ prev_val = table->GetAddressOf(fd.value.offset);
+ }
}
}
+ AddNewLine();
+ AddIndent(indent);
+ text += '}';
+ return true;
}
- text += NewLine(opts);
- text.append(indent, ' ');
- text += "}";
+
+ JsonPrinter(const Parser &parser, std::string &dest)
+ : opts(parser.opts), text(dest) {
+ text.reserve(1024); // Reduce amount of inevitable reallocs.
+ }
+
+ const IDLOptions &opts;
+ std::string &text;
+};
+
+static bool GenerateTextImpl(const Parser &parser, const Table *table,
+ const StructDef &struct_def, std::string *_text) {
+ JsonPrinter printer(parser, *_text);
+ if (!printer.GenStruct(struct_def, table, 0)) { return false; }
+ printer.AddNewLine();
return true;
}
@@ -317,41 +361,33 @@
bool GenerateTextFromTable(const Parser &parser, const void *table,
const std::string &table_name, std::string *_text) {
auto struct_def = parser.LookupStruct(table_name);
- if (struct_def == nullptr) {
- return false;
- }
- auto &text = *_text;
- text.reserve(1024); // Reduce amount of inevitable reallocs.
+ if (struct_def == nullptr) { return false; }
auto root = static_cast<const Table *>(table);
- if (!GenStruct(*struct_def, root, 0, parser.opts, &text)) {
- return false;
- }
- text += NewLine(parser.opts);
- return true;
+ return GenerateTextImpl(parser, root, *struct_def, _text);
}
// Generate a text representation of a flatbuffer in JSON format.
bool GenerateText(const Parser &parser, const void *flatbuffer,
std::string *_text) {
- std::string &text = *_text;
FLATBUFFERS_ASSERT(parser.root_struct_def_); // call SetRootType()
- text.reserve(1024); // Reduce amount of inevitable reallocs.
- auto root = parser.opts.size_prefixed ?
- GetSizePrefixedRoot<Table>(flatbuffer) : GetRoot<Table>(flatbuffer);
- if (!GenStruct(*parser.root_struct_def_, root, 0, parser.opts, _text)) {
- return false;
- }
- text += NewLine(parser.opts);
- return true;
+ auto root = parser.opts.size_prefixed ? GetSizePrefixedRoot<Table>(flatbuffer)
+ : GetRoot<Table>(flatbuffer);
+ return GenerateTextImpl(parser, root, *parser.root_struct_def_, _text);
}
-std::string TextFileName(const std::string &path,
- const std::string &file_name) {
+static std::string TextFileName(const std::string &path,
+ const std::string &file_name) {
return path + file_name + ".json";
}
bool GenerateTextFile(const Parser &parser, const std::string &path,
const std::string &file_name) {
+ if (parser.opts.use_flexbuffers) {
+ std::string json;
+ parser.flex_root_.ToString(true, parser.opts.strict_json, json);
+ return flatbuffers::SaveFile(TextFileName(path, file_name).c_str(),
+ json.c_str(), json.size(), true);
+ }
if (!parser.builder_.GetSize() || !parser.root_struct_def_) return true;
std::string text;
if (!GenerateText(parser, parser.builder_.GetBufferPointer(), &text)) {
diff --git a/src/idl_parser.cpp b/src/idl_parser.cpp
index 31b315c..a87fbce 100644
--- a/src/idl_parser.cpp
+++ b/src/idl_parser.cpp
@@ -15,12 +15,11 @@
*/
#include <algorithm>
+#include <cmath>
#include <list>
#include <string>
#include <utility>
-#include <cmath>
-
#include "flatbuffers/idl.h"
#include "flatbuffers/util.h"
@@ -38,26 +37,22 @@
const double kPi = 3.14159265358979323846;
-const char *const kTypeNames[] = {
// clang-format off
- #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
- CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \
+const char *const kTypeNames[] = {
+ #define FLATBUFFERS_TD(ENUM, IDLTYPE, ...) \
IDLTYPE,
FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
#undef FLATBUFFERS_TD
- // clang-format on
nullptr
};
const char kTypeSizes[] = {
-// clang-format off
- #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
- CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \
- sizeof(CTYPE),
+ #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \
+ sizeof(CTYPE),
FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
#undef FLATBUFFERS_TD
- // clang-format on
};
+// clang-format on
// The enums in the reflection schema should match the ones we use internally.
// Compare the last element to check if these go out of sync.
@@ -87,23 +82,45 @@
return true;
}
+static bool IsLowerSnakeCase(const std::string &str) {
+ for (size_t i = 0; i < str.length(); i++) {
+ char c = str[i];
+ if (!check_ascii_range(c, 'a', 'z') && !is_digit(c) && c != '_') {
+ return false;
+ }
+ }
+ return true;
+}
+
// Convert an underscore_based_indentifier in to camelCase.
// Also uppercases the first character if first is true.
std::string MakeCamel(const std::string &in, bool first) {
std::string s;
for (size_t i = 0; i < in.length(); i++) {
if (!i && first)
- s += static_cast<char>(toupper(in[0]));
+ s += CharToUpper(in[0]);
else if (in[i] == '_' && i + 1 < in.length())
- s += static_cast<char>(toupper(in[++i]));
+ s += CharToUpper(in[++i]);
else
s += in[i];
}
return s;
}
-void DeserializeDoc( std::vector<std::string> &doc,
- const Vector<Offset<String>> *documentation) {
+// Convert an underscore_based_identifier in to screaming snake case.
+std::string MakeScreamingCamel(const std::string &in) {
+ std::string s;
+ for (size_t i = 0; i < in.length(); i++) {
+ if (in[i] != '_')
+ s += CharToUpper(in[i]);
+ else
+ s += in[i];
+ }
+ return s;
+}
+
+void DeserializeDoc(std::vector<std::string> &doc,
+ const Vector<Offset<String>> *documentation) {
if (documentation == nullptr) return;
for (uoffset_t index = 0; index < documentation->size(); index++)
doc.push_back(documentation->Get(index)->str());
@@ -211,8 +228,7 @@
#define FLATBUFFERS_TOKEN(NAME, VALUE, STRING) STRING,
FLATBUFFERS_GEN_TOKENS(FLATBUFFERS_TOKEN)
#undef FLATBUFFERS_TOKEN
- #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
- CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \
+ #define FLATBUFFERS_TD(ENUM, IDLTYPE, ...) \
IDLTYPE,
FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
#undef FLATBUFFERS_TD
@@ -387,7 +403,8 @@
"illegal Unicode sequence (unpaired high surrogate)");
}
// reset if non-printable
- attr_is_trivial_ascii_string_ &= check_ascii_range(*cursor_, ' ', '~');
+ attr_is_trivial_ascii_string_ &=
+ check_ascii_range(*cursor_, ' ', '~');
attribute_ += *cursor_++;
}
@@ -425,11 +442,11 @@
cursor_ += 2;
break;
}
- FLATBUFFERS_FALLTHROUGH(); // else fall thru
+ FLATBUFFERS_FALLTHROUGH(); // else fall thru
default:
const auto has_sign = (c == '+') || (c == '-');
// '-'/'+' and following identifier - can be a predefined constant like:
- // NAN, INF, PI, etc.
+ // NAN, INF, PI, etc or it can be a function name like cos/sin/deg.
if (IsIdentifierStart(c) || (has_sign && IsIdentifierStart(*cursor_))) {
// Collect all chars of an identifier:
const char *start = cursor_ - 1;
@@ -439,14 +456,15 @@
return NoError();
}
- auto dot_lvl = (c == '.') ? 0 : 1; // dot_lvl==0 <=> exactly one '.' seen
- if (!dot_lvl && !is_digit(*cursor_)) return NoError(); // enum?
+ auto dot_lvl =
+ (c == '.') ? 0 : 1; // dot_lvl==0 <=> exactly one '.' seen
+ if (!dot_lvl && !is_digit(*cursor_)) return NoError(); // enum?
// Parser accepts hexadecimal-floating-literal (see C++ 5.13.4).
if (is_digit(c) || has_sign || !dot_lvl) {
const auto start = cursor_ - 1;
auto start_digits = !is_digit(c) ? cursor_ : cursor_ - 1;
- if (!is_digit(c) && is_digit(*cursor_)){
- start_digits = cursor_; // see digit in cursor_ position
+ if (!is_digit(c) && is_digit(*cursor_)) {
+ start_digits = cursor_; // see digit in cursor_ position
c = *cursor_++;
}
// hex-float can't begind with '.'
@@ -489,7 +507,8 @@
}
std::string ch;
ch = c;
- if (false == check_ascii_range(c, ' ', '~')) ch = "code: " + NumToString(c);
+ if (false == check_ascii_range(c, ' ', '~'))
+ ch = "code: " + NumToString(c);
return Error("illegal character: " + ch);
}
}
@@ -618,12 +637,6 @@
"length of fixed-length array must be positive and fit to "
"uint16_t type");
}
- // Check if enum arrays are used in C++ without specifying --scoped-enums
- if ((opts.lang_to_generate & IDLOptions::kCpp) && !opts.scoped_enums &&
- IsEnum(subtype)) {
- return Error(
- "--scoped-enums must be enabled to use enum arrays in C++\n");
- }
type = Type(BASE_TYPE_ARRAY, subtype.struct_def, subtype.enum_def,
fixed_length);
NEXT();
@@ -665,18 +678,28 @@
CheckedError Parser::ParseField(StructDef &struct_def) {
std::string name = attribute_;
- if (LookupStruct(name))
+ if (LookupCreateStruct(name, false, false))
return Error("field name can not be the same as table/struct name");
+ if (!IsLowerSnakeCase(name)) {
+ Warning("field names should be lowercase snake_case, got: " + name);
+ }
+
std::vector<std::string> dc = doc_comment_;
EXPECT(kTokenIdentifier);
EXPECT(':');
Type type;
ECHECK(ParseType(type));
- if (struct_def.fixed && !IsScalar(type.base_type) && !IsStruct(type) &&
- !IsArray(type))
- return Error("structs_ may contain only scalar or struct fields");
+ if (struct_def.fixed) {
+ auto valid = IsScalar(type.base_type) || IsStruct(type);
+ if (!valid && IsArray(type)) {
+ const auto &elem_type = type.VectorType();
+ valid |= IsScalar(elem_type.base_type) || IsStruct(elem_type);
+ }
+ if (!valid)
+ return Error("structs may contain only scalar or struct fields");
+ }
if (!struct_def.fixed && IsArray(type))
return Error("fixed-length array in table must be wrapped in struct");
@@ -693,12 +716,11 @@
// with a special suffix.
ECHECK(AddField(struct_def, name + UnionTypeFieldSuffix(),
type.enum_def->underlying_type, &typefield));
- } else if (type.base_type == BASE_TYPE_VECTOR &&
- type.element == BASE_TYPE_UNION) {
+ } else if (IsVector(type) && type.element == BASE_TYPE_UNION) {
// Only cpp, js and ts supports the union vector feature so far.
if (!SupportsAdvancedUnionFeatures()) {
return Error(
- "Vectors of unions are not yet supported in all "
+ "Vectors of unions are not yet supported in at least one of "
"the specified programming languages.");
}
// For vector of union fields, add a second auto-generated vector field to
@@ -718,15 +740,44 @@
if (!IsScalar(type.base_type) ||
(struct_def.fixed && field->value.constant != "0"))
return Error(
- "default values currently only supported for scalars in tables");
+ "default values currently only supported for scalars in tables");
}
+
+ // Mark the optional scalars. Note that a side effect of ParseSingleValue is
+ // fixing field->value.constant to null.
+ if (IsScalar(type.base_type)) {
+ field->optional = (field->value.constant == "null");
+ if (field->optional) {
+ if (type.enum_def && type.enum_def->Lookup("null")) {
+ FLATBUFFERS_ASSERT(IsInteger(type.base_type));
+ return Error(
+ "the default 'null' is reserved for declaring optional scalar "
+ "fields, it conflicts with declaration of enum '" +
+ type.enum_def->name + "'.");
+ }
+ if (field->attributes.Lookup("key")) {
+ return Error(
+ "only a non-optional scalar field can be used as a 'key' field");
+ }
+ if (!SupportsOptionalScalars()) {
+ return Error(
+ "Optional scalars are not yet supported in at least one the of "
+ "the specified programming languages.");
+ }
+ }
+ } else {
+ // For nonscalars, only required fields are non-optional.
+ // At least until https://github.com/google/flatbuffers/issues/6053
+ field->optional = !field->required;
+ }
+
// Append .0 if the value has not it (skip hex and scientific floats).
// This suffix needed for generated C++ code.
if (IsFloat(type.base_type)) {
auto &text = field->value.constant;
FLATBUFFERS_ASSERT(false == text.empty());
auto s = text.c_str();
- while(*s == ' ') s++;
+ while (*s == ' ') s++;
if (*s == '-' || *s == '+') s++;
// 1) A float constants (nan, inf, pi, etc) is a kind of identifier.
// 2) A float number needn't ".0" at the end if it has exponent.
@@ -740,15 +791,15 @@
// Table, struct or string can't have enum_def.
// Default value of union and vector in NONE, NULL translated to "0".
FLATBUFFERS_ASSERT(IsInteger(type.base_type) ||
- (type.base_type == BASE_TYPE_UNION) ||
- (type.base_type == BASE_TYPE_VECTOR) ||
- (type.base_type == BASE_TYPE_ARRAY));
- if (type.base_type == BASE_TYPE_VECTOR) {
+ (type.base_type == BASE_TYPE_UNION) || IsVector(type) ||
+ IsArray(type));
+ if (IsVector(type)) {
// Vector can't use initialization list.
FLATBUFFERS_ASSERT(field->value.constant == "0");
} else {
// All unions should have the NONE ("0") enum value.
auto in_enum = type.enum_def->attributes.Lookup("bit_flags") ||
+ field->IsScalarOptional() ||
type.enum_def->FindByValue(field->value.constant);
if (false == in_enum)
return Error("default value of " + field->value.constant +
@@ -762,7 +813,7 @@
field->deprecated = field->attributes.Lookup("deprecated") != nullptr;
auto hash_name = field->attributes.Lookup("hash");
if (hash_name) {
- switch ((type.base_type == BASE_TYPE_VECTOR) ? type.element : type.base_type) {
+ switch ((IsVector(type)) ? type.element : type.base_type) {
case BASE_TYPE_SHORT:
case BASE_TYPE_USHORT: {
if (FindHashFunction16(hash_name->constant.c_str()) == nullptr)
@@ -786,7 +837,8 @@
}
default:
return Error(
- "only short, ushort, int, uint, long and ulong data types support hashing.");
+ "only short, ushort, int, uint, long and ulong data types support "
+ "hashing.");
}
}
auto cpp_type = field->attributes.Lookup("cpp_type");
@@ -805,9 +857,15 @@
if (field->deprecated && struct_def.fixed)
return Error("can't deprecate fields in a struct");
field->required = field->attributes.Lookup("required") != nullptr;
- if (field->required &&
- (struct_def.fixed || IsScalar(type.base_type)))
+ if (field->required && (struct_def.fixed || IsScalar(type.base_type)))
return Error("only non-scalar fields in tables may be 'required'");
+
+ if (!IsScalar(type.base_type)) {
+ // For nonscalars, only required fields are non-optional.
+ // At least until https://github.com/google/flatbuffers/issues/6053
+ field->optional = !field->required;
+ }
+
field->key = field->attributes.Lookup("key") != nullptr;
if (field->key) {
if (struct_def.has_key) return Error("only one field may be set as 'key'");
@@ -849,8 +907,7 @@
if (field->attributes.Lookup("flexbuffer")) {
field->flexbuffer = true;
uses_flexbuffers_ = true;
- if (type.base_type != BASE_TYPE_VECTOR ||
- type.element != BASE_TYPE_UCHAR)
+ if (type.base_type != BASE_TYPE_VECTOR || type.element != BASE_TYPE_UCHAR)
return Error("flexbuffer attribute may only apply to a vector of ubyte");
}
@@ -869,16 +926,23 @@
val->constant = NumToString(id - 1);
typefield->attributes.Add("id", val);
}
+ // if this field is a union that is deprecated,
+ // the automatically added type field should be deprecated as well
+ if (field->deprecated) { typefield->deprecated = true; }
}
EXPECT(';');
return NoError();
}
-CheckedError Parser::ParseString(Value &val) {
+CheckedError Parser::ParseString(Value &val, bool use_string_pooling) {
auto s = attribute_;
EXPECT(kTokenStringConstant);
- val.constant = NumToString(builder_.CreateString(s).o);
+ if (use_string_pooling) {
+ val.constant = NumToString(builder_.CreateSharedString(s).o);
+ } else {
+ val.constant = NumToString(builder_.CreateString(s).o);
+ }
return NoError();
}
@@ -890,8 +954,7 @@
CheckedError Parser::ParseAnyValue(Value &val, FieldDef *field,
size_t parent_fieldn,
const StructDef *parent_struct_def,
- uoffset_t count,
- bool inside_vector) {
+ uoffset_t count, bool inside_vector) {
switch (val.type.base_type) {
case BASE_TYPE_UNION: {
FLATBUFFERS_ASSERT(field);
@@ -903,14 +966,13 @@
auto &type = elem->second->value.type;
if (type.enum_def == val.type.enum_def) {
if (inside_vector) {
- if (type.base_type == BASE_TYPE_VECTOR &&
- type.element == BASE_TYPE_UTYPE) {
+ if (IsVector(type) && type.element == BASE_TYPE_UTYPE) {
// Vector of union type field.
uoffset_t offset;
ECHECK(atot(elem->first.constant.c_str(), *this, &offset));
vector_of_union_types = reinterpret_cast<Vector<uint8_t> *>(
- builder_.GetCurrentBufferPointer() +
- builder_.GetSize() - offset);
+ builder_.GetCurrentBufferPointer() + builder_.GetSize() -
+ offset);
break;
}
} else {
@@ -952,8 +1014,7 @@
}
}
if (constant.empty() && !vector_of_union_types) {
- return Error("missing type field for this union value: " +
- field->name);
+ return Error("missing type field for this union value: " + field->name);
}
uint8_t enum_idx;
if (vector_of_union_types) {
@@ -972,8 +1033,8 @@
builder_.ClearOffsets();
val.constant = NumToString(builder_.GetSize());
}
- } else if (enum_val->union_type.base_type == BASE_TYPE_STRING) {
- ECHECK(ParseString(val));
+ } else if (IsString(enum_val->union_type)) {
+ ECHECK(ParseString(val, field->shared));
} else {
FLATBUFFERS_ASSERT(false);
}
@@ -983,7 +1044,7 @@
ECHECK(ParseTable(*val.type.struct_def, &val.constant, nullptr));
break;
case BASE_TYPE_STRING: {
- ECHECK(ParseString(val));
+ ECHECK(ParseString(val, field->shared));
break;
}
case BASE_TYPE_VECTOR: {
@@ -1028,10 +1089,9 @@
builder.AddStructOffset(val.offset, builder.GetSize());
}
-template <typename F>
+template<typename F>
CheckedError Parser::ParseTableDelimiters(size_t &fieldn,
- const StructDef *struct_def,
- F body) {
+ const StructDef *struct_def, F body) {
// We allow tables both as JSON object{ .. } with field names
// or vector[..] with all fields in order
char terminator = '}';
@@ -1167,9 +1227,8 @@
if (!struct_def.sortbysize ||
size == SizeOf(field_value.type.base_type)) {
switch (field_value.type.base_type) {
- // clang-format off
- #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
- CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \
+// clang-format off
+ #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \
case BASE_TYPE_ ## ENUM: \
builder_.Pad(field->padding); \
if (struct_def.fixed) { \
@@ -1183,10 +1242,9 @@
builder_.AddElement(field_value.offset, val, valdef); \
} \
break;
- FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD);
+ FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD)
#undef FLATBUFFERS_TD
- #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
- CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \
+ #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \
case BASE_TYPE_ ## ENUM: \
builder_.Pad(field->padding); \
if (IsStruct(field->value.type)) { \
@@ -1197,7 +1255,7 @@
builder_.AddOffset(field_value.offset, val); \
} \
break;
- FLATBUFFERS_GEN_TYPES_POINTER(FLATBUFFERS_TD);
+ FLATBUFFERS_GEN_TYPES_POINTER(FLATBUFFERS_TD)
#undef FLATBUFFERS_TD
case BASE_TYPE_ARRAY:
builder_.Pad(field->padding);
@@ -1205,7 +1263,7 @@
reinterpret_cast<const uint8_t*>(field_value.constant.c_str()),
InlineSize(field_value.type));
break;
- // clang-format on
+ // clang-format on
}
}
}
@@ -1231,7 +1289,7 @@
return NoError();
}
-template <typename F>
+template<typename F>
CheckedError Parser::ParseVectorDelimiters(uoffset_t &count, F body) {
EXPECT('[');
for (;;) {
@@ -1245,6 +1303,42 @@
return NoError();
}
+static bool CompareType(const uint8_t *a, const uint8_t *b, BaseType ftype) {
+ switch (ftype) {
+#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \
+ case BASE_TYPE_##ENUM: return ReadScalar<CTYPE>(a) < ReadScalar<CTYPE>(b);
+ FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD)
+#undef FLATBUFFERS_TD
+ case BASE_TYPE_STRING:
+ // Indirect offset pointer to string pointer.
+ a += ReadScalar<uoffset_t>(a);
+ b += ReadScalar<uoffset_t>(b);
+ return *reinterpret_cast<const String *>(a) <
+ *reinterpret_cast<const String *>(b);
+ default: return false;
+ }
+}
+
+// See below for why we need our own sort :(
+template<typename T, typename F, typename S>
+void SimpleQsort(T *begin, T *end, size_t width, F comparator, S swapper) {
+ if (end - begin <= static_cast<ptrdiff_t>(width)) return;
+ auto l = begin + width;
+ auto r = end;
+ while (l < r) {
+ if (comparator(begin, l)) {
+ r -= width;
+ swapper(l, r);
+ } else {
+ l += width;
+ }
+ }
+ l -= width;
+ swapper(begin, l);
+ SimpleQsort(begin, l, width, comparator, swapper);
+ SimpleQsort(r, end, width, comparator, swapper);
+}
+
CheckedError Parser::ParseVector(const Type &type, uoffset_t *ovalue,
FieldDef *field, size_t fieldn) {
uoffset_t count = 0;
@@ -1259,15 +1353,21 @@
});
ECHECK(err);
- builder_.StartVector(count * InlineSize(type) / InlineAlignment(type),
- InlineAlignment(type));
+ const auto *force_align = field->attributes.Lookup("force_align");
+ const size_t align =
+ force_align ? static_cast<size_t>(atoi(force_align->constant.c_str()))
+ : 1;
+ const size_t len = count * InlineSize(type) / InlineAlignment(type);
+ const size_t elemsize = InlineAlignment(type);
+ if (align > 1) { builder_.ForceVectorAlignment(len, elemsize, align); }
+
+ builder_.StartVector(len, elemsize);
for (uoffset_t i = 0; i < count; i++) {
// start at the back, since we're building the data backwards.
auto &val = field_stack_.back().first;
switch (val.type.base_type) {
- // clang-format off
- #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
- CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \
+// clang-format off
+ #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE,...) \
case BASE_TYPE_ ## ENUM: \
if (IsStruct(val.type)) SerializeStruct(*val.type.struct_def, val); \
else { \
@@ -1285,6 +1385,75 @@
builder_.ClearOffsets();
*ovalue = builder_.EndVector(count);
+
+ if (type.base_type == BASE_TYPE_STRUCT && type.struct_def->has_key) {
+ // We should sort this vector. Find the key first.
+ const FieldDef *key = nullptr;
+ for (auto it = type.struct_def->fields.vec.begin();
+ it != type.struct_def->fields.vec.end(); ++it) {
+ if ((*it)->key) {
+ key = (*it);
+ break;
+ }
+ }
+ FLATBUFFERS_ASSERT(key);
+ // Now sort it.
+ // We can't use std::sort because for structs the size is not known at
+ // compile time, and for tables our iterators dereference offsets, so can't
+ // be used to swap elements.
+ // And we can't use C qsort either, since that would force use to use
+ // globals, making parsing thread-unsafe.
+ // So for now, we use SimpleQsort above.
+ // TODO: replace with something better, preferably not recursive.
+ voffset_t offset = key->value.offset;
+ BaseType ftype = key->value.type.base_type;
+
+ if (type.struct_def->fixed) {
+ auto v =
+ reinterpret_cast<VectorOfAny *>(builder_.GetCurrentBufferPointer());
+ SimpleQsort<uint8_t>(
+ v->Data(), v->Data() + v->size() * type.struct_def->bytesize,
+ type.struct_def->bytesize,
+ [&](const uint8_t *a, const uint8_t *b) -> bool {
+ return CompareType(a + offset, b + offset, ftype);
+ },
+ [&](uint8_t *a, uint8_t *b) {
+ // FIXME: faster?
+ for (size_t i = 0; i < type.struct_def->bytesize; i++) {
+ std::swap(a[i], b[i]);
+ }
+ });
+ } else {
+ auto v = reinterpret_cast<Vector<Offset<Table>> *>(
+ builder_.GetCurrentBufferPointer());
+ // Here also can't use std::sort. We do have an iterator type for it,
+ // but it is non-standard as it will dereference the offsets, and thus
+ // can't be used to swap elements.
+ SimpleQsort<Offset<Table>>(
+ v->data(), v->data() + v->size(), 1,
+ [&](const Offset<Table> *_a, const Offset<Table> *_b) -> bool {
+ // Indirect offset pointer to table pointer.
+ auto a = reinterpret_cast<const uint8_t *>(_a) +
+ ReadScalar<uoffset_t>(_a);
+ auto b = reinterpret_cast<const uint8_t *>(_b) +
+ ReadScalar<uoffset_t>(_b);
+ // Fetch field address from table.
+ a = reinterpret_cast<const Table *>(a)->GetAddressOf(offset);
+ b = reinterpret_cast<const Table *>(b)->GetAddressOf(offset);
+ return CompareType(a, b, ftype);
+ },
+ [&](Offset<Table> *a, Offset<Table> *b) {
+ // These are serialized offsets, so are relative where they are
+ // stored in memory, so compute the distance between these pointers:
+ ptrdiff_t diff = (b - a) * sizeof(Offset<Table>);
+ FLATBUFFERS_ASSERT(diff >= 0); // Guaranteed by SimpleQsort.
+ auto udiff = static_cast<uoffset_t>(diff);
+ a->o = EndianScalar(ReadScalar<uoffset_t>(a) - udiff);
+ b->o = EndianScalar(ReadScalar<uoffset_t>(b) + udiff);
+ std::swap(*a, *b);
+ });
+ }
+ }
return NoError();
}
@@ -1312,8 +1481,7 @@
auto &val = *it;
// clang-format off
switch (val.type.base_type) {
- #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
- CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \
+ #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \
case BASE_TYPE_ ## ENUM: \
if (IsStruct(val.type)) { \
SerializeStruct(builder, *val.type.struct_def, val); \
@@ -1362,12 +1530,11 @@
nested_parser.enums_.dict.clear();
nested_parser.enums_.vec.clear();
- if (!ok) {
- ECHECK(Error(nested_parser.error_));
- }
+ if (!ok) { ECHECK(Error(nested_parser.error_)); }
// Force alignment for nested flatbuffer
- builder_.ForceVectorAlignment(nested_parser.builder_.GetSize(), sizeof(uint8_t),
- nested_parser.builder_.GetBufferMinAlignment());
+ builder_.ForceVectorAlignment(
+ nested_parser.builder_.GetSize(), sizeof(uint8_t),
+ nested_parser.builder_.GetBufferMinAlignment());
auto off = builder_.CreateVector(nested_parser.builder_.GetBufferPointer(),
nested_parser.builder_.GetSize());
@@ -1383,13 +1550,13 @@
auto name = attribute_;
if (false == (Is(kTokenIdentifier) || Is(kTokenStringConstant)))
return Error("attribute name must be either identifier or string: " +
- name);
+ name);
if (known_attributes_.find(name) == known_attributes_.end())
return Error("user define attributes must be declared before use: " +
name);
NEXT();
auto e = new Value();
- attributes->Add(name, e);
+ if (attributes->Add(name, e)) Warning("attribute already found: " + name);
if (Is(':')) {
NEXT();
ECHECK(ParseSingleValue(&name, *e, true));
@@ -1404,45 +1571,6 @@
return NoError();
}
-CheckedError Parser::TryTypedValue(const std::string *name, int dtoken,
- bool check, Value &e, BaseType req,
- bool *destmatch) {
- bool match = dtoken == token_;
- if (match) {
- FLATBUFFERS_ASSERT(*destmatch == false);
- *destmatch = true;
- e.constant = attribute_;
- // Check token match
- if (!check) {
- if (e.type.base_type == BASE_TYPE_NONE) {
- e.type.base_type = req;
- } else {
- return Error(
- std::string("type mismatch: expecting: ") +
- kTypeNames[e.type.base_type] + ", found: " + kTypeNames[req] +
- ", name: " + (name ? *name : "") + ", value: " + e.constant);
- }
- }
- // The exponent suffix of hexadecimal float-point number is mandatory.
- // A hex-integer constant is forbidden as an initializer of float number.
- if ((kTokenFloatConstant != dtoken) && IsFloat(e.type.base_type)) {
- const auto &s = e.constant;
- const auto k = s.find_first_of("0123456789.");
- if ((std::string::npos != k) && (s.length() > (k + 1)) &&
- (s[k] == '0' && is_alpha_char(s[k + 1], 'X')) &&
- (std::string::npos == s.find_first_of("pP", k + 2))) {
- return Error(
- "invalid number, the exponent suffix of hexadecimal "
- "floating-point literals is mandatory: \"" +
- s + "\"");
- }
- }
-
- NEXT();
- }
- return NoError();
-}
-
CheckedError Parser::ParseEnumFromString(const Type &type,
std::string *result) {
const auto base_type =
@@ -1531,61 +1659,106 @@
if (IsInteger(e.type.base_type)) { e.constant = NumToString(val); }
}
#if defined(FLATBUFFERS_HAS_NEW_STRTOD) && (FLATBUFFERS_HAS_NEW_STRTOD > 0)
-// Normilaze defaults NaN to unsigned quiet-NaN(0).
-static inline void SingleValueRepack(Value& e, float val) {
+// Normalize defaults NaN to unsigned quiet-NaN(0) if value was parsed from
+// hex-float literal.
+static inline void SingleValueRepack(Value &e, float val) {
if (val != val) e.constant = "nan";
}
-static inline void SingleValueRepack(Value& e, double val) {
+static inline void SingleValueRepack(Value &e, double val) {
if (val != val) e.constant = "nan";
}
#endif
-CheckedError Parser::ParseSingleValue(const std::string *name, Value &e,
- bool check_now) {
- // First see if this could be a conversion function:
- if (token_ == kTokenIdentifier && *cursor_ == '(') {
- // todo: Extract processing of conversion functions to ParseFunction.
- const auto functionname = attribute_;
- if (!IsFloat(e.type.base_type)) {
- return Error(functionname + ": type of argument mismatch, expecting: " +
- kTypeNames[BASE_TYPE_DOUBLE] +
- ", found: " + kTypeNames[e.type.base_type] +
- ", name: " + (name ? *name : "") + ", value: " + e.constant);
+CheckedError Parser::ParseFunction(const std::string *name, Value &e) {
+ // Copy name, attribute will be changed on NEXT().
+ const auto functionname = attribute_;
+ if (!IsFloat(e.type.base_type)) {
+ return Error(functionname + ": type of argument mismatch, expecting: " +
+ kTypeNames[BASE_TYPE_DOUBLE] +
+ ", found: " + kTypeNames[e.type.base_type] +
+ ", name: " + (name ? *name : "") + ", value: " + e.constant);
+ }
+ NEXT();
+ EXPECT('(');
+ ECHECK(Recurse([&]() { return ParseSingleValue(name, e, false); }));
+ EXPECT(')');
+ // calculate with double precision
+ double x, y = 0.0;
+ ECHECK(atot(e.constant.c_str(), *this, &x));
+ // clang-format off
+ auto func_match = false;
+ #define FLATBUFFERS_FN_DOUBLE(name, op) \
+ if (!func_match && functionname == name) { y = op; func_match = true; }
+ FLATBUFFERS_FN_DOUBLE("deg", x / kPi * 180);
+ FLATBUFFERS_FN_DOUBLE("rad", x * kPi / 180);
+ FLATBUFFERS_FN_DOUBLE("sin", sin(x));
+ FLATBUFFERS_FN_DOUBLE("cos", cos(x));
+ FLATBUFFERS_FN_DOUBLE("tan", tan(x));
+ FLATBUFFERS_FN_DOUBLE("asin", asin(x));
+ FLATBUFFERS_FN_DOUBLE("acos", acos(x));
+ FLATBUFFERS_FN_DOUBLE("atan", atan(x));
+ // TODO(wvo): add more useful conversion functions here.
+ #undef FLATBUFFERS_FN_DOUBLE
+ // clang-format on
+ if (true != func_match) {
+ return Error(std::string("Unknown conversion function: ") + functionname +
+ ", field name: " + (name ? *name : "") +
+ ", value: " + e.constant);
+ }
+ e.constant = NumToString(y);
+ return NoError();
+}
+
+CheckedError Parser::TryTypedValue(const std::string *name, int dtoken,
+ bool check, Value &e, BaseType req,
+ bool *destmatch) {
+ bool match = dtoken == token_;
+ if (match) {
+ FLATBUFFERS_ASSERT(*destmatch == false);
+ *destmatch = true;
+ e.constant = attribute_;
+ // Check token match
+ if (!check) {
+ if (e.type.base_type == BASE_TYPE_NONE) {
+ e.type.base_type = req;
+ } else {
+ return Error(
+ std::string("type mismatch: expecting: ") +
+ kTypeNames[e.type.base_type] + ", found: " + kTypeNames[req] +
+ ", name: " + (name ? *name : "") + ", value: " + e.constant);
+ }
+ }
+ // The exponent suffix of hexadecimal float-point number is mandatory.
+ // A hex-integer constant is forbidden as an initializer of float number.
+ if ((kTokenFloatConstant != dtoken) && IsFloat(e.type.base_type)) {
+ const auto &s = e.constant;
+ const auto k = s.find_first_of("0123456789.");
+ if ((std::string::npos != k) && (s.length() > (k + 1)) &&
+ (s[k] == '0' && is_alpha_char(s[k + 1], 'X')) &&
+ (std::string::npos == s.find_first_of("pP", k + 2))) {
+ return Error(
+ "invalid number, the exponent suffix of hexadecimal "
+ "floating-point literals is mandatory: \"" +
+ s + "\"");
+ }
}
NEXT();
- EXPECT('(');
- ECHECK(Recurse([&]() { return ParseSingleValue(name, e, false); }));
- EXPECT(')');
- // calculate with double precision
- double x, y = 0.0;
- ECHECK(atot(e.constant.c_str(), *this, &x));
- auto func_match = false;
- // clang-format off
- #define FLATBUFFERS_FN_DOUBLE(name, op) \
- if (!func_match && functionname == name) { y = op; func_match = true; }
- FLATBUFFERS_FN_DOUBLE("deg", x / kPi * 180);
- FLATBUFFERS_FN_DOUBLE("rad", x * kPi / 180);
- FLATBUFFERS_FN_DOUBLE("sin", sin(x));
- FLATBUFFERS_FN_DOUBLE("cos", cos(x));
- FLATBUFFERS_FN_DOUBLE("tan", tan(x));
- FLATBUFFERS_FN_DOUBLE("asin", asin(x));
- FLATBUFFERS_FN_DOUBLE("acos", acos(x));
- FLATBUFFERS_FN_DOUBLE("atan", atan(x));
- // TODO(wvo): add more useful conversion functions here.
- #undef FLATBUFFERS_FN_DOUBLE
- // clang-format on
- if (true != func_match) {
- return Error(std::string("Unknown conversion function: ") + functionname +
- ", field name: " + (name ? *name : "") +
- ", value: " + e.constant);
- }
- e.constant = NumToString(y);
- return NoError();
}
+ return NoError();
+}
- auto match = false;
+CheckedError Parser::ParseSingleValue(const std::string *name, Value &e,
+ bool check_now) {
const auto in_type = e.type.base_type;
+ const auto is_tok_ident = (token_ == kTokenIdentifier);
+ const auto is_tok_string = (token_ == kTokenStringConstant);
+
+ // First see if this could be a conversion function:
+ if (is_tok_ident && *cursor_ == '(') { return ParseFunction(name, e); }
+
// clang-format off
+ auto match = false;
+
#define IF_ECHECK_(force, dtoken, check, req) \
if (!match && ((check) || IsConstTrue(force))) \
ECHECK(TryTypedValue(name, dtoken, check, e, req, &match))
@@ -1593,14 +1766,14 @@
#define FORCE_ECHECK(dtoken, check, req) IF_ECHECK_(true, dtoken, check, req)
// clang-format on
- if (token_ == kTokenStringConstant || token_ == kTokenIdentifier) {
+ if (is_tok_ident || is_tok_string) {
const auto kTokenStringOrIdent = token_;
// The string type is a most probable type, check it first.
TRY_ECHECK(kTokenStringConstant, in_type == BASE_TYPE_STRING,
BASE_TYPE_STRING);
// avoid escaped and non-ascii in the string
- if (!match && (token_ == kTokenStringConstant) && IsScalar(in_type) &&
+ if (!match && is_tok_string && IsScalar(in_type) &&
!attr_is_trivial_ascii_string_) {
return Error(
std::string("type mismatch or invalid value, an initializer of "
@@ -1618,6 +1791,12 @@
TRY_ECHECK(kTokenStringOrIdent, IsBool(in_type), BASE_TYPE_BOOL);
}
}
+ // Check for optional scalars.
+ if (!match && IsScalar(in_type) && attribute_ == "null") {
+ e.constant = "null";
+ NEXT();
+ match = true;
+ }
// Check if this could be a string/identifier enum value.
// Enum can have only true integer base type.
if (!match && IsInteger(in_type) && !IsBool(in_type) &&
@@ -1628,11 +1807,19 @@
}
// Parse a float/integer number from the string.
if (!match) check_now = true; // Re-pack if parsed from string literal.
- if (!match && (token_ == kTokenStringConstant) && IsScalar(in_type)) {
- // remove trailing whitespaces from attribute_
- auto last = attribute_.find_last_not_of(' ');
- if (std::string::npos != last) // has non-whitespace
- attribute_.resize(last + 1);
+ // A "scalar-in-string" value needs extra checks.
+ if (!match && is_tok_string && IsScalar(in_type)) {
+ // Strip trailing whitespaces from attribute_.
+ auto last_non_ws = attribute_.find_last_not_of(' ');
+ if (std::string::npos != last_non_ws) attribute_.resize(last_non_ws + 1);
+ if (IsFloat(e.type.base_type)) {
+ // The functions strtod() and strtof() accept both 'nan' and
+ // 'nan(number)' literals. While 'nan(number)' is rejected by the parser
+ // as an unsupported function if is_tok_ident is true.
+ if (attribute_.find_last_of(')') != std::string::npos) {
+ return Error("invalid number: " + attribute_);
+ }
+ }
}
// Float numbers or nan, inf, pi, etc.
TRY_ECHECK(kTokenStringOrIdent, IsFloat(in_type), BASE_TYPE_FLOAT);
@@ -1658,22 +1845,22 @@
"' to value of <" + std::string(kTypeNames[in_type]) + "> type.";
return Error(msg);
}
- const auto match_type = e.type.base_type; // may differ from in_type
+ const auto match_type = e.type.base_type; // may differ from in_type
// The check_now flag must be true when parse a fbs-schema.
// This flag forces to check default scalar values or metadata of field.
// For JSON parser the flag should be false.
// If it is set for JSON each value will be checked twice (see ParseTable).
- if (check_now && IsScalar(match_type)) {
+ // Special case 'null' since atot can't handle that.
+ if (check_now && IsScalar(match_type) && e.constant != "null") {
// clang-format off
switch (match_type) {
- #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
- CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \
- case BASE_TYPE_ ## ENUM: {\
- CTYPE val; \
- ECHECK(atot(e.constant.c_str(), *this, &val)); \
- SingleValueRepack(e, val); \
- break; }
- FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD);
+ #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \
+ case BASE_TYPE_ ## ENUM: {\
+ CTYPE val; \
+ ECHECK(atot(e.constant.c_str(), *this, &val)); \
+ SingleValueRepack(e, val); \
+ break; }
+ FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD)
#undef FLATBUFFERS_TD
default: break;
}
@@ -1865,21 +2052,16 @@
FLATBUFFERS_CHECKED_ERROR AssignEnumeratorValue(const std::string &value) {
user_value = true;
auto fit = false;
- auto ascending = false;
if (enum_def.IsUInt64()) {
uint64_t u64;
fit = StringToNumber(value.c_str(), &u64);
- ascending = u64 > temp->GetAsUInt64();
temp->value = static_cast<int64_t>(u64); // well-defined since C++20.
} else {
int64_t i64;
fit = StringToNumber(value.c_str(), &i64);
- ascending = i64 > temp->GetAsInt64();
temp->value = i64;
}
if (!fit) return parser.Error("enum value does not fit, \"" + value + "\"");
- if (!ascending && strict_ascending && !enum_def.vals.vec.empty())
- return parser.Error("enum values must be specified in ascending order");
return NoError();
}
@@ -1902,13 +2084,12 @@
FLATBUFFERS_CHECKED_ERROR ValidateValue(int64_t *ev, bool next) {
// clang-format off
switch (enum_def.underlying_type.base_type) {
- #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, \
- PTYPE, RTYPE, KTYPE) \
+ #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \
case BASE_TYPE_##ENUM: { \
if (!IsInteger(BASE_TYPE_##ENUM)) break; \
return ValidateImpl<BASE_TYPE_##ENUM, CTYPE>(ev, next ? 1 : 0); \
}
- FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD);
+ FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD)
#undef FLATBUFFERS_TD
default: break;
}
@@ -1916,11 +2097,10 @@
return parser.Error("fatal: invalid enum underlying type");
}
- EnumValBuilder(Parser &_parser, EnumDef &_enum_def, bool strict_order = true)
+ EnumValBuilder(Parser &_parser, EnumDef &_enum_def)
: parser(_parser),
enum_def(_enum_def),
temp(nullptr),
- strict_ascending(strict_order),
user_value(false) {}
~EnumValBuilder() { delete temp; }
@@ -1928,7 +2108,6 @@
Parser &parser;
EnumDef &enum_def;
EnumVal *temp;
- const bool strict_ascending;
bool user_value;
};
@@ -1965,9 +2144,7 @@
// todo: Convert to the Error in the future?
Warning("underlying type of bit_flags enum must be unsigned");
}
- // Protobuf allows them to be specified in any order, so sort afterwards.
- const auto strict_ascending = (false == opts.proto_mode);
- EnumValBuilder evb(*this, *enum_def, strict_ascending);
+ EnumValBuilder evb(*this, *enum_def);
EXPECT('{');
// A lot of code generatos expect that an enum is not-empty.
if ((is_union || Is('}')) && !opts.proto_mode) {
@@ -2011,9 +2188,6 @@
NEXT();
ECHECK(evb.AssignEnumeratorValue(attribute_));
EXPECT(kTokenIntegerConstant);
- } else if (false == strict_ascending) {
- // The opts.proto_mode flag is active.
- return Error("Protobuf mode doesn't allow implicit enum values.");
}
ECHECK(evb.AcceptEnumerator());
@@ -2049,8 +2223,18 @@
}
}
- if (false == strict_ascending)
- enum_def->SortByValue(); // Must be sorted to use MinValue/MaxValue.
+ enum_def->SortByValue(); // Must be sorted to use MinValue/MaxValue.
+
+ // Ensure enum value uniqueness.
+ auto prev_it = enum_def->Vals().begin();
+ for (auto it = prev_it + 1; it != enum_def->Vals().end(); ++it) {
+ auto prev_ev = *prev_it;
+ auto ev = *it;
+ if (prev_ev->GetAsUInt64() == ev->GetAsUInt64())
+ return Error("all enum values must be unique: " + prev_ev->name +
+ " and " + ev->name + " are both " +
+ NumToString(ev->GetAsInt64()));
+ }
if (dest) *dest = enum_def;
types_.Add(current_namespace_->GetFullyQualifiedName(enum_def->name),
@@ -2092,13 +2276,28 @@
return NoError();
}
+bool Parser::SupportsOptionalScalars(const flatbuffers::IDLOptions &opts) {
+ static FLATBUFFERS_CONSTEXPR unsigned long supported_langs =
+ IDLOptions::kRust | IDLOptions::kSwift | IDLOptions::kLobster |
+ IDLOptions::kKotlin | IDLOptions::kCpp | IDLOptions::kJava |
+ IDLOptions::kCSharp | IDLOptions::kTs | IDLOptions::kJs |
+ IDLOptions::kBinary;
+ unsigned long langs = opts.lang_to_generate;
+ return (langs > 0 && langs < IDLOptions::kMAX) && !(langs & ~supported_langs);
+}
+
+bool Parser::SupportsOptionalScalars() const {
+ // Check in general if a language isn't specified.
+ return opts.lang_to_generate == 0 || SupportsOptionalScalars(opts);
+}
+
bool Parser::SupportsAdvancedUnionFeatures() const {
return opts.lang_to_generate != 0 &&
- (opts.lang_to_generate & ~(IDLOptions::kCpp | IDLOptions::kJs |
- IDLOptions::kTs | IDLOptions::kPhp |
- IDLOptions::kJava | IDLOptions::kCSharp |
- IDLOptions::kKotlin |
- IDLOptions::kBinary)) == 0;
+ (opts.lang_to_generate &
+ ~(IDLOptions::kCpp | IDLOptions::kJs | IDLOptions::kTs |
+ IDLOptions::kPhp | IDLOptions::kJava | IDLOptions::kCSharp |
+ IDLOptions::kKotlin | IDLOptions::kBinary | IDLOptions::kSwift)) ==
+ 0;
}
bool Parser::SupportsAdvancedArrayFeatures() const {
@@ -2370,8 +2569,8 @@
if (enums_.Add(current_namespace_->GetFullyQualifiedName(enum_name),
&enum_def))
return Error("enum already exists: " + enum_name);
- enum_def.underlying_type.base_type = is_union ? BASE_TYPE_UTYPE
- : BASE_TYPE_INT;
+ enum_def.underlying_type.base_type =
+ is_union ? BASE_TYPE_UTYPE : BASE_TYPE_INT;
enum_def.underlying_type.enum_def = &enum_def;
if (dest) *dest = &enum_def;
return NoError();
@@ -2479,10 +2678,13 @@
auto val = attribute_;
ECHECK(ParseProtoCurliesOrIdent());
if (key == "default") {
- // Temp: skip non-numeric defaults (enums).
+ // Temp: skip non-numeric and non-boolean defaults (enums).
auto numeric = strpbrk(val.c_str(), "0123456789-+.");
- if (IsScalar(type.base_type) && numeric == val.c_str())
+ if (IsScalar(type.base_type) && numeric == val.c_str()) {
field->value.constant = val;
+ } else if (val == "true") {
+ field->value.constant = val;
+ } // "false" is default, no need to handle explicitly.
} else if (key == "deprecated") {
field->deprecated = val == "true";
}
@@ -2507,8 +2709,8 @@
if (oneof_type.base_type != BASE_TYPE_STRUCT ||
!oneof_type.struct_def || oneof_type.struct_def->fixed)
return Error("oneof '" + name +
- "' cannot be mapped to a union because member '" +
- oneof_field.name + "' is not a table type.");
+ "' cannot be mapped to a union because member '" +
+ oneof_field.name + "' is not a table type.");
EnumValBuilder evb(*this, *oneof_union);
auto ev = evb.CreateEnumerator(oneof_type.struct_def->name);
ev->union_type = oneof_type;
@@ -2667,10 +2869,13 @@
builder->Int(StringToInt(attribute_.c_str()));
EXPECT(kTokenIntegerConstant);
break;
- case kTokenFloatConstant:
- builder->Double(strtod(attribute_.c_str(), nullptr));
+ case kTokenFloatConstant: {
+ double d;
+ StringToNumber(attribute_.c_str(), &d);
+ builder->Double(d);
EXPECT(kTokenFloatConstant);
break;
+ }
default:
if (IsIdent("true")) {
builder->Bool(true);
@@ -2698,7 +2903,13 @@
bool Parser::Parse(const char *source, const char **include_paths,
const char *source_filename) {
FLATBUFFERS_ASSERT(0 == recurse_protection_counter);
- auto r = !ParseRoot(source, include_paths, source_filename).Check();
+ bool r;
+
+ if (opts.use_flexbuffers) {
+ r = ParseFlexBuffer(source, source_filename, &flex_builder_);
+ } else {
+ r = !ParseRoot(source, include_paths, source_filename).Check();
+ }
FLATBUFFERS_ASSERT(0 == recurse_protection_counter);
return r;
}
@@ -2747,7 +2958,7 @@
if (field.value.type.struct_def == &struct_def) {
field.value.type.struct_def = nullptr;
field.value.type.enum_def = enum_def;
- auto &bt = field.value.type.base_type == BASE_TYPE_VECTOR
+ auto &bt = IsVector(field.value.type)
? field.value.type.element
: field.value.type.base_type;
FLATBUFFERS_ASSERT(bt == BASE_TYPE_STRUCT);
@@ -2785,8 +2996,8 @@
for (auto val_it = enum_def.Vals().begin();
val_it != enum_def.Vals().end(); ++val_it) {
auto &val = **val_it;
- if (!SupportsAdvancedUnionFeatures() && val.union_type.struct_def &&
- val.union_type.struct_def->fixed)
+ if (!SupportsAdvancedUnionFeatures() &&
+ (IsStruct(val.union_type) || IsString(val.union_type)))
return Error(
"only tables can be union elements in the generated language: " +
val.name);
@@ -2867,9 +3078,7 @@
// entered into included_files_.
// This is recursive, but only go as deep as the number of include
// statements.
- if (source_filename) {
- included_files_.erase(source_filename);
- }
+ if (source_filename) { included_files_.erase(source_filename); }
return DoParse(source, include_paths, source_filename,
include_filename);
}
@@ -2893,9 +3102,9 @@
uoffset_t toff;
ECHECK(ParseTable(*root_struct_def_, nullptr, &toff));
if (opts.size_prefixed) {
- builder_.FinishSizePrefixed(Offset<Table>(toff), file_identifier_.length()
- ? file_identifier_.c_str()
- : nullptr);
+ builder_.FinishSizePrefixed(
+ Offset<Table>(toff),
+ file_identifier_.length() ? file_identifier_.c_str() : nullptr);
} else {
builder_.Finish(Offset<Table>(toff), file_identifier_.length()
? file_identifier_.c_str()
@@ -2916,8 +3125,7 @@
if (opts.root_type.empty()) {
if (!SetRootType(root_type.c_str()))
return Error("unknown root type: " + root_type);
- if (root_struct_def_->fixed)
- return Error("root type must be a table");
+ if (root_struct_def_->fixed) return Error("root type must be a table");
}
EXPECT(';');
} else if (IsIdent("file_identifier")) {
@@ -3022,10 +3230,9 @@
auto fiid__ = builder_.CreateString(file_identifier_);
auto fext__ = builder_.CreateString(file_extension_);
auto serv__ = builder_.CreateVectorOfSortedTables(&service_offsets);
- auto schema_offset =
- reflection::CreateSchema(builder_, objs__, enum__, fiid__, fext__,
- (root_struct_def_ ? root_struct_def_->serialized_location : 0),
- serv__);
+ auto schema_offset = reflection::CreateSchema(
+ builder_, objs__, enum__, fiid__, fext__,
+ (root_struct_def_ ? root_struct_def_->serialized_location : 0), serv__);
if (opts.size_prefixed) {
builder_.FinishSizePrefixed(schema_offset, reflection::SchemaIdentifier());
} else {
@@ -3071,22 +3278,20 @@
auto flds__ = builder->CreateVectorOfSortedTables(&field_offsets);
auto attr__ = SerializeAttributes(builder, parser);
auto docs__ = parser.opts.binary_schema_comments
- ? builder->CreateVectorOfStrings(doc_comment)
- : 0;
+ ? builder->CreateVectorOfStrings(doc_comment)
+ : 0;
return reflection::CreateObject(*builder, name__, flds__, fixed,
static_cast<int>(minalign),
- static_cast<int>(bytesize),
- attr__, docs__);
+ static_cast<int>(bytesize), attr__, docs__);
}
bool StructDef::Deserialize(Parser &parser, const reflection::Object *object) {
- if (!DeserializeAttributes(parser, object->attributes()))
- return false;
+ if (!DeserializeAttributes(parser, object->attributes())) return false;
DeserializeDoc(doc_comment, object->documentation());
name = parser.UnqualifiedName(object->name()->str());
predecl = false;
sortbysize = attributes.Lookup("original_order") == nullptr && !fixed;
- const auto& of = *(object->fields());
+ const auto &of = *(object->fields());
auto indexes = std::vector<uoffset_t>(of.size());
for (uoffset_t i = 0; i < of.size(); i++) indexes[of.Get(i)->id()] = i;
size_t tmp_struct_size = 0;
@@ -3102,9 +3307,7 @@
// Recompute padding since that's currently not serialized.
auto size = InlineSize(field_def->value.type);
auto next_field =
- i + 1 < indexes.size()
- ? of.Get(indexes[i+1])
- : nullptr;
+ i + 1 < indexes.size() ? of.Get(indexes[i + 1]) : nullptr;
tmp_struct_size += size;
field_def->padding =
next_field ? (next_field->offset() - field_def->value.offset) - size
@@ -3123,15 +3326,17 @@
auto type__ = value.type.Serialize(builder);
auto attr__ = SerializeAttributes(builder, parser);
auto docs__ = parser.opts.binary_schema_comments
- ? builder->CreateVectorOfStrings(doc_comment)
- : 0;
- return reflection::CreateField(*builder, name__, type__, id, value.offset,
+ ? builder->CreateVectorOfStrings(doc_comment)
+ : 0;
+ double d;
+ StringToNumber(value.constant.c_str(), &d);
+ return reflection::CreateField(
+ *builder, name__, type__, id, value.offset,
// Is uint64>max(int64) tested?
IsInteger(value.type.base_type) ? StringToInt(value.constant.c_str()) : 0,
// result may be platform-dependent if underlying is float (not double)
- IsFloat(value.type.base_type) ? strtod(value.constant.c_str(), nullptr)
- : 0.0,
- deprecated, required, key, attr__, docs__);
+ IsFloat(value.type.base_type) ? d : 0.0, deprecated, required, key,
+ attr__, docs__, optional);
// TODO: value.constant is almost always "0", we could save quite a bit of
// space by sharing it. Same for common values of value.type.
}
@@ -3139,23 +3344,17 @@
bool FieldDef::Deserialize(Parser &parser, const reflection::Field *field) {
name = field->name()->str();
defined_namespace = parser.current_namespace_;
- if (!value.type.Deserialize(parser, field->type()))
- return false;
+ if (!value.type.Deserialize(parser, field->type())) return false;
value.offset = field->offset();
if (IsInteger(value.type.base_type)) {
value.constant = NumToString(field->default_integer());
} else if (IsFloat(value.type.base_type)) {
value.constant = FloatToString(field->default_real(), 16);
- size_t last_zero = value.constant.find_last_not_of('0');
- if (last_zero != std::string::npos && last_zero != 0) {
- value.constant.erase(last_zero, std::string::npos);
- }
}
deprecated = field->deprecated();
required = field->required();
key = field->key();
- if (!DeserializeAttributes(parser, field->attributes()))
- return false;
+ if (!DeserializeAttributes(parser, field->attributes())) return false;
// TODO: this should probably be handled by a separate attribute
if (attributes.Lookup("flexbuffer")) {
flexbuffer = true;
@@ -3170,6 +3369,7 @@
nested_flatbuffer = parser.LookupStruct(nested_qualified_name);
if (!nested_flatbuffer) return false;
}
+ shared = attributes.Lookup("shared") != nullptr;
DeserializeDoc(doc_comment, field->documentation());
return true;
}
@@ -3179,18 +3379,16 @@
auto name__ = builder->CreateString(name);
auto attr__ = SerializeAttributes(builder, parser);
auto docs__ = parser.opts.binary_schema_comments
- ? builder->CreateVectorOfStrings(doc_comment)
- : 0;
- return reflection::CreateRPCCall(*builder, name__,
- request->serialized_location,
- response->serialized_location,
- attr__, docs__);
+ ? builder->CreateVectorOfStrings(doc_comment)
+ : 0;
+ return reflection::CreateRPCCall(
+ *builder, name__, request->serialized_location,
+ response->serialized_location, attr__, docs__);
}
bool RPCCall::Deserialize(Parser &parser, const reflection::RPCCall *call) {
name = call->name()->str();
- if (!DeserializeAttributes(parser, call->attributes()))
- return false;
+ if (!DeserializeAttributes(parser, call->attributes())) return false;
DeserializeDoc(doc_comment, call->documentation());
request = parser.structs_.Lookup(call->request()->name()->str());
response = parser.structs_.Lookup(call->response()->name()->str());
@@ -3209,8 +3407,8 @@
auto call__ = builder->CreateVector(servicecall_offsets);
auto attr__ = SerializeAttributes(builder, parser);
auto docs__ = parser.opts.binary_schema_comments
- ? builder->CreateVectorOfStrings(doc_comment)
- : 0;
+ ? builder->CreateVectorOfStrings(doc_comment)
+ : 0;
return reflection::CreateService(*builder, name__, call__, attr__, docs__);
}
@@ -3227,8 +3425,7 @@
}
}
}
- if (!DeserializeAttributes(parser, service->attributes()))
- return false;
+ if (!DeserializeAttributes(parser, service->attributes())) return false;
DeserializeDoc(doc_comment, service->documentation());
return true;
}
@@ -3245,8 +3442,8 @@
auto type__ = underlying_type.Serialize(builder);
auto attr__ = SerializeAttributes(builder, parser);
auto docs__ = parser.opts.binary_schema_comments
- ? builder->CreateVectorOfStrings(doc_comment)
- : 0;
+ ? builder->CreateVectorOfStrings(doc_comment)
+ : 0;
return reflection::CreateEnum(*builder, name__, vals__, is_union, type__,
attr__, docs__);
}
@@ -3265,8 +3462,7 @@
if (!underlying_type.Deserialize(parser, _enum->underlying_type())) {
return false;
}
- if (!DeserializeAttributes(parser, _enum->attributes()))
- return false;
+ if (!DeserializeAttributes(parser, _enum->attributes())) return false;
DeserializeDoc(doc_comment, _enum->documentation());
return true;
}
@@ -3276,9 +3472,10 @@
auto name__ = builder->CreateString(name);
auto type__ = union_type.Serialize(builder);
auto docs__ = parser.opts.binary_schema_comments
- ? builder->CreateVectorOfStrings(doc_comment)
- : 0;
- return reflection::CreateEnumVal(*builder, name__, value,
+ ? builder->CreateVectorOfStrings(doc_comment)
+ : 0;
+ return reflection::CreateEnumVal(
+ *builder, name__, value,
union_type.struct_def ? union_type.struct_def->serialized_location : 0,
type__, docs__);
}
@@ -3287,8 +3484,7 @@
const reflection::EnumVal *val) {
name = val->name()->str();
value = val->value();
- if (!union_type.Deserialize(parser, val->union_type()))
- return false;
+ if (!union_type.Deserialize(parser, val->union_type())) return false;
DeserializeDoc(doc_comment, val->documentation());
return true;
}
@@ -3310,8 +3506,7 @@
bool is_series = type->base_type() == reflection::Vector ||
type->base_type() == reflection::Array;
if (type->base_type() == reflection::Obj ||
- (is_series &&
- type->element() == reflection::Obj)) {
+ (is_series && type->element() == reflection::Obj)) {
if (static_cast<size_t>(type->index()) < parser.structs_.vec.size()) {
struct_def = parser.structs_.vec[type->index()];
struct_def->refcount++;
@@ -3352,8 +3547,7 @@
bool Definition::DeserializeAttributes(
Parser &parser, const Vector<Offset<reflection::KeyValue>> *attrs) {
- if (attrs == nullptr)
- return true;
+ if (attrs == nullptr) return true;
for (uoffset_t i = 0; i < attrs->size(); ++i) {
auto kv = attrs->Get(i);
auto value = new Value();
@@ -3373,7 +3567,7 @@
bool Parser::Deserialize(const uint8_t *buf, const size_t size) {
flatbuffers::Verifier verifier(reinterpret_cast<const uint8_t *>(buf), size);
bool size_prefixed = false;
- if(!reflection::SchemaBufferHasIdentifier(buf)) {
+ if (!reflection::SchemaBufferHasIdentifier(buf)) {
if (!flatbuffers::BufferHasIdentifier(buf, reflection::SchemaIdentifier(),
true))
return false;
@@ -3382,9 +3576,7 @@
}
auto verify_fn = size_prefixed ? &reflection::VerifySizePrefixedSchemaBuffer
: &reflection::VerifySchemaBuffer;
- if (!verify_fn(verifier)) {
- return false;
- }
+ if (!verify_fn(verifier)) { return false; }
auto schema = size_prefixed ? reflection::GetSizePrefixedSchema(buf)
: reflection::GetSchema(buf);
return Deserialize(schema);
@@ -3433,7 +3625,7 @@
auto struct_def = structs_.Lookup(qualified_name);
struct_def->defined_namespace =
GetNamespace(qualified_name, namespaces_, namespaces_index);
- if (!struct_def->Deserialize(*this, * it)) { return false; }
+ if (!struct_def->Deserialize(*this, *it)) { return false; }
if (schema->root_table() == *it) { root_struct_def_ = struct_def; }
}
for (auto it = schema->enums()->begin(); it != schema->enums()->end(); ++it) {
diff --git a/src/reflection.cpp b/src/reflection.cpp
index 89ce783..2dedcb4 100644
--- a/src/reflection.cpp
+++ b/src/reflection.cpp
@@ -15,6 +15,7 @@
*/
#include "flatbuffers/reflection.h"
+
#include "flatbuffers/util.h"
// Helper functionality for reflection.
@@ -22,7 +23,7 @@
namespace flatbuffers {
int64_t GetAnyValueI(reflection::BaseType type, const uint8_t *data) {
- // clang-format off
+// clang-format off
#define FLATBUFFERS_GET(T) static_cast<int64_t>(ReadScalar<T>(data))
switch (type) {
case reflection::UType:
@@ -55,7 +56,13 @@
case reflection::String: {
auto s =
reinterpret_cast<const String *>(ReadScalar<uoffset_t>(data) + data);
- return s ? strtod(s->c_str(), nullptr) : 0.0;
+ if (s) {
+ double d;
+ StringToNumber(s->c_str(), &d);
+ return d;
+ } else {
+ return 0.0;
+ }
}
default: return static_cast<double>(GetAnyValueI(type, data));
}
@@ -114,7 +121,7 @@
}
void SetAnyValueI(reflection::BaseType type, uint8_t *data, int64_t val) {
- // clang-format off
+// clang-format off
#define FLATBUFFERS_SET(T) WriteScalar(data, static_cast<T>(val))
switch (type) {
case reflection::UType:
@@ -148,9 +155,12 @@
void SetAnyValueS(reflection::BaseType type, uint8_t *data, const char *val) {
switch (type) {
case reflection::Float:
- case reflection::Double:
- SetAnyValueF(type, data, strtod(val, nullptr));
+ case reflection::Double: {
+ double d;
+ StringToNumber(val, &d);
+ SetAnyValueF(type, data, d);
break;
+ }
// TODO: support strings.
default: SetAnyValueI(type, data, StringToInt(val)); break;
}
@@ -185,7 +195,7 @@
if (delta_ > 0)
buf_.insert(buf_.begin() + start, delta_, 0);
else
- buf_.erase(buf_.begin() + start, buf_.begin() + start - delta_);
+ buf_.erase(buf_.begin() + start + delta_, buf_.begin() + start);
}
// Check if the range between first (lower address) and second straddles
@@ -286,8 +296,6 @@
}
}
- void operator=(const ResizeContext &rc);
-
private:
const reflection::Schema &schema_;
uint8_t *startptr_;
@@ -388,16 +396,17 @@
case reflection::Obj: {
auto &subobjectdef = *schema.objects()->Get(fielddef.type()->index());
if (!subobjectdef.is_struct()) {
- offset =
- CopyTable(fbb, schema, subobjectdef, *GetFieldT(table, fielddef))
- .o;
+ offset = CopyTable(fbb, schema, subobjectdef,
+ *GetFieldT(table, fielddef), use_string_pooling)
+ .o;
}
break;
}
case reflection::Union: {
auto &subobjectdef = GetUnionType(schema, objectdef, fielddef, table);
- offset =
- CopyTable(fbb, schema, subobjectdef, *GetFieldT(table, fielddef)).o;
+ offset = CopyTable(fbb, schema, subobjectdef,
+ *GetFieldT(table, fielddef), use_string_pooling)
+ .o;
break;
}
case reflection::Vector: {
@@ -424,15 +433,15 @@
if (!elemobjectdef->is_struct()) {
std::vector<Offset<const Table *>> elements(vec->size());
for (uoffset_t i = 0; i < vec->size(); i++) {
- elements[i] =
- CopyTable(fbb, schema, *elemobjectdef, *vec->Get(i));
+ elements[i] = CopyTable(fbb, schema, *elemobjectdef,
+ *vec->Get(i), use_string_pooling);
}
offset = fbb.CreateVector(elements).o;
break;
}
}
- FLATBUFFERS_FALLTHROUGH(); // fall thru
- default: { // Scalars and structs.
+ FLATBUFFERS_FALLTHROUGH(); // fall thru
+ default: { // Scalars and structs.
auto element_size = GetTypeSize(element_base_type);
if (elemobjectdef && elemobjectdef->is_struct())
element_size = elemobjectdef->bytesize();
@@ -466,7 +475,7 @@
break;
}
}
- FLATBUFFERS_FALLTHROUGH(); // fall thru
+ FLATBUFFERS_FALLTHROUGH(); // fall thru
case reflection::Union:
case reflection::String:
case reflection::Vector:
@@ -495,9 +504,8 @@
auto offset = parent_table.GetOptionalFieldOffset(field_offset);
if (required && !offset) { return false; }
- return !offset ||
- v.Verify(reinterpret_cast<const uint8_t *>(&parent_table), offset,
- obj.bytesize());
+ return !offset || v.Verify(reinterpret_cast<const uint8_t *>(&parent_table),
+ offset, obj.bytesize());
}
bool VerifyVectorOfStructs(flatbuffers::Verifier &v,
@@ -515,6 +523,31 @@
const reflection::Object &obj,
const flatbuffers::Table *table, bool required);
+bool VerifyUnion(flatbuffers::Verifier &v, const reflection::Schema &schema,
+ uint8_t utype, const uint8_t *elem,
+ const reflection::Field &union_field) {
+ if (!utype) return true; // Not present.
+ auto fb_enum = schema.enums()->Get(union_field.type()->index());
+ if (utype >= fb_enum->values()->size()) return false;
+ auto elem_type = fb_enum->values()->Get(utype)->union_type();
+ switch (elem_type->base_type()) {
+ case reflection::Obj: {
+ auto elem_obj = schema.objects()->Get(elem_type->index());
+ if (elem_obj->is_struct()) {
+ return v.VerifyFromPointer(elem, elem_obj->bytesize());
+ } else {
+ return VerifyObject(v, schema, *elem_obj,
+ reinterpret_cast<const flatbuffers::Table *>(elem),
+ true);
+ }
+ }
+ case reflection::String:
+ return v.VerifyString(
+ reinterpret_cast<const flatbuffers::String *>(elem));
+ default: return false;
+ }
+}
+
bool VerifyVector(flatbuffers::Verifier &v, const reflection::Schema &schema,
const flatbuffers::Table &table,
const reflection::Field &vec_field) {
@@ -522,7 +555,6 @@
if (!table.VerifyField<uoffset_t>(v, vec_field.offset())) return false;
switch (vec_field.type()->element()) {
- case reflection::None: FLATBUFFERS_ASSERT(false); break;
case reflection::UType:
return v.VerifyVector(flatbuffers::GetFieldV<uint8_t>(table, vec_field));
case reflection::Bool:
@@ -552,48 +584,52 @@
return false;
}
}
- case reflection::Vector: FLATBUFFERS_ASSERT(false); break;
case reflection::Obj: {
auto obj = schema.objects()->Get(vec_field.type()->index());
if (obj->is_struct()) {
- if (!VerifyVectorOfStructs(v, table, vec_field.offset(), *obj,
- vec_field.required())) {
- return false;
- }
+ return VerifyVectorOfStructs(v, table, vec_field.offset(), *obj,
+ vec_field.required());
} else {
auto vec =
flatbuffers::GetFieldV<flatbuffers::Offset<flatbuffers::Table>>(
table, vec_field);
if (!v.VerifyVector(vec)) return false;
- if (vec) {
- for (uoffset_t j = 0; j < vec->size(); j++) {
- if (!VerifyObject(v, schema, *obj, vec->Get(j), true)) {
- return false;
- }
+ if (!vec) return true;
+ for (uoffset_t j = 0; j < vec->size(); j++) {
+ if (!VerifyObject(v, schema, *obj, vec->Get(j), true)) {
+ return false;
}
}
+ return true;
+ }
+ }
+ case reflection::Union: {
+ auto vec = flatbuffers::GetFieldV<flatbuffers::Offset<uint8_t>>(
+ table, vec_field);
+ if (!v.VerifyVector(vec)) return false;
+ if (!vec) return true;
+ auto type_vec = table.GetPointer<Vector<uint8_t> *>(vec_field.offset() -
+ sizeof(voffset_t));
+ if (!v.VerifyVector(type_vec)) return false;
+ for (uoffset_t j = 0; j < vec->size(); j++) {
+ // get union type from the prev field
+ auto utype = type_vec->Get(j);
+ auto elem = vec->Get(j);
+ if (!VerifyUnion(v, schema, utype, elem, vec_field)) return false;
}
return true;
}
- case reflection::Union: FLATBUFFERS_ASSERT(false); break;
- default: FLATBUFFERS_ASSERT(false); break;
+ case reflection::Vector:
+ case reflection::None:
+ default: FLATBUFFERS_ASSERT(false); return false;
}
-
- return false;
}
bool VerifyObject(flatbuffers::Verifier &v, const reflection::Schema &schema,
const reflection::Object &obj,
const flatbuffers::Table *table, bool required) {
- if (!table) {
- if (!required)
- return true;
- else
- return false;
- }
-
+ if (!table) return !required;
if (!table->VerifyTableStart(v)) return false;
-
for (uoffset_t i = 0; i < obj.fields()->size(); i++) {
auto field_def = obj.fields()->Get(i);
switch (field_def->type()->base_type()) {
@@ -653,16 +689,9 @@
// get union type from the prev field
voffset_t utype_offset = field_def->offset() - sizeof(voffset_t);
auto utype = table->GetField<uint8_t>(utype_offset, 0);
- if (utype != 0) {
- // Means we have this union field present
- auto fb_enum = schema.enums()->Get(field_def->type()->index());
- auto child_obj = fb_enum->values()->Get(utype)->object();
- if (!VerifyObject(v, schema, *child_obj,
- flatbuffers::GetFieldT(*table, *field_def),
- field_def->required())) {
- return false;
- }
- }
+ auto uval = reinterpret_cast<const uint8_t *>(
+ flatbuffers::GetFieldT(*table, *field_def));
+ if (!VerifyUnion(v, schema, utype, uval, *field_def)) { return false; }
break;
}
default: FLATBUFFERS_ASSERT(false); break;
@@ -675,8 +704,9 @@
}
bool Verify(const reflection::Schema &schema, const reflection::Object &root,
- const uint8_t *buf, size_t length) {
- Verifier v(buf, length);
+ const uint8_t *buf, size_t length, uoffset_t max_depth /*= 64*/,
+ uoffset_t max_tables /*= 1000000*/) {
+ Verifier v(buf, length, max_depth, max_tables);
return VerifyObject(v, schema, root, flatbuffers::GetAnyRoot(buf), true);
}
diff --git a/src/util.cpp b/src/util.cpp
index 5483cee..3670a01 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -16,6 +16,13 @@
// clang-format off
// Dont't remove `format off`, it prevent reordering of win-includes.
+
+#if defined(__MINGW32__) || defined(__MINGW64__) || defined(__CYGWIN__) || \
+ defined(__QNXNTO__)
+# define _POSIX_C_SOURCE 200809L
+# define _XOPEN_SOURCE 700L
+#endif
+
#ifdef _WIN32
# ifndef WIN32_LEAN_AND_MEAN
# define WIN32_LEAN_AND_MEAN
@@ -30,8 +37,6 @@
# include <direct.h>
# include <winbase.h>
# undef interface // This is also important because of reasons
-#else
-# include <limits.h>
#endif
// clang-format on
@@ -40,6 +45,7 @@
#include <sys/stat.h>
#include <clocale>
+#include <cstdlib>
#include <fstream>
namespace flatbuffers {
@@ -194,8 +200,14 @@
char abs_path[MAX_PATH];
return GetFullPathNameA(filepath.c_str(), MAX_PATH, abs_path, nullptr)
#else
- char abs_path[PATH_MAX];
- return realpath(filepath.c_str(), abs_path)
+ char *abs_path_temp = realpath(filepath.c_str(), nullptr);
+ bool success = abs_path_temp != nullptr;
+ std::string abs_path;
+ if(success) {
+ abs_path = abs_path_temp;
+ free(abs_path_temp);
+ }
+ return success
#endif
? abs_path
: filepath;
@@ -240,9 +252,9 @@
}
bool ReadEnvironmentVariable(const char *var_name, std::string *_value) {
- #ifdef _MSC_VER
- __pragma(warning(disable : 4996)); // _CRT_SECURE_NO_WARNINGS
- #endif
+#ifdef _MSC_VER
+ __pragma(warning(disable : 4996)); // _CRT_SECURE_NO_WARNINGS
+#endif
auto env_str = std::getenv(var_name);
if (!env_str) return false;
if (_value) *_value = std::string(env_str);