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 &params,
-                            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 &params,
-                                   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 &params,
-                                   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 &params,
-                                   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 &not_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()> &not_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 &params,
+                          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 &params,
+                                 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 &params,
+                                  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 &params,
+                                         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 &not_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()> &not_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);