Squashed 'third_party/flatbuffers/' changes from 338393f85..e5f331db9

e5f331db9 [TS] Add single-file ts codegen & bazel rule for typescript (#7161)
2f84c6038 Apply Namer to Go code gen (#7150)
d64839651 [Lobster] file_identifier support
777e78d8d [Lobster] support unsigned integer reads
4016c549d Apply Namer to Python code gen (#7146)
40827b21b Fix missing 'break' (#7151)
65a10b6e3 Implement a config based name manager and use it in Rust codegen (#7144)
8db2fef3f [TS] Escape keywords in typescript object names (#7137)
9ed132304 Fix 64-bit numeric enum values in typescript (#7135)
1a4c40566 updated npm to 2.0.6
318594e4b prevent name clash (#7133)
3d903302c [Rust] Add length checks to arrays and vectors. (#7130)
c9571d989 Replaced ToDasherCase with ConvertCase (#7131)
3694b830a Use ConvertCase instead of Make{Upper,Lower,Snake} implementations (#7127)
0471fa807 remove stall reference to version
914344ea9 some minor help edits
b40266c56 Use target_compile_features to target C++11 (#7122)
8a9303d46 update proto tests with alaised enum (#7121)
30c4bf47f Trigger fuzzing CI only on relevant changes (#7120)
46ce45601 remove auto generate code from cmakelists (#7119)
433312c55 add the missing checkNullConditionnal code in the "GenObjApi" function when the field is scalar optional (#7114)
9c52ec374 Add deps attribute to flatbuffer_cc_library (#7107)
70e2f49bf fixed string-json -> strict-json typo
5ac0367ed [TS] Fix generation of reserved words in object api (#7106) (#7115)
5d101afb5 Fix minor typo in WhitePaper.md (#7108)
06f4af11b Go optional scalars (#7104)
57e338f81 explicitly use windows-2019 to unblock ci (#7105)
615616cb5 Change Rust generated file defaults (#7101)
3413c3300 Fixed FlexBuffers verifier fuzzer timing out
69f5660a4 Fixed Parser not checking size of union types vector
d5add9fca Fixed FlexBuffers ToString unquoted non-ident keys
15df50eb7 Remove @ExperimentalUnsignedTypes annotation from kotlin code generator. (#7092)
a94132a45 Swift FlatBufferBuilder.sizedByteArray to ByteBuffer.toArray() (#7093)
48befb6be [TS] Refactor away circular ref (#7099)
b30069133 Add reflection support for python (#7026)
faadbc10e Add CreateVector overload to accept array like (#7095)
ed6ae8d32 explicitly defined std::allocator (#7094)
e910bddbc [JS] Add ".js" suffix to all import statements to generate a browser compatible mjs version. (#7086)
c85fb690f Add Parsing Completed function for Rust (#7084)
c1daa6ba0 rust: Bump thiserror version and remove git dependency (#7080)
4c71c7b02 replace framework include of flatbuffers (#7079)
f5664d33f fix go_test implement error (#7012)
39c8a19ce fixed comparator for native_inline (#7076)
826193ff6 skip generating reflection.fbs in generate_scripts (#7077)
fd0d1ed92 update C++ generator to emit scoped enums in vector of unions (#7075)
424988f30 replaced removed xml tag
b2550dbaa removed BSD-3-Clause license and Zlib licenses (#7073)
a2b238960 Fixed default value of bool in struct for Swift (#7072)
619b78437 one last dart omit local (#7070)
68a766154 more omit type annotations for dart local variables (#7069)
7dac9961f omit type annotations for dart local variables (#7067)
c65c389c6 add xmlns to .Net (#7066)
6446dcf3d Updates swift gen licence for grpc code (#7063)
e090d8da1 Fixed long cast to int in flexbufferbuilder.java (#7059)
bc901436d clang format on codebase (#7058)
240be9b5a attempt to remove appveyor (#7056)
bc366a7f9 Provide a short help text and default in error case (#6992)
14b19d446 Use FindPython3 (#7055)
9e6f17b94 remove BIICODE
c3801ad37 Update readme.md
4f3b24db0 Fixes a bug where bools arent being nil when marked optional (#7051)
1d294a31b Implement Serialize on generated rust types (#7022)
dd8fccfb1 Cmake 3.16 de-facto minimum version (#7049)
7089c9ecd Convert flatbuffers_version_string to inline function (#7046)
43203984f [C++] Support C++ object copies and moves (#5988)
5993338ee [ts] Builder incorrectly serializing empty strings (#7047)
19920db39 Include a SizePrefixed..HasIdentifier for c++. (#6871)
dbbaeac85 Use `${PYTHON_EXECUTABLE}` instead of `py` in cmake (#7042)
028f0fde6 'flattest': Add --test_path option (#7041)
87343631b Added support for clang-cl on windows (CMake) (#7038)
1fbfaf5c5 Fix/cmake build grpc (#7028)
4421375bb Add FlatBuffers::FlatBuffers interface, needed for FetchContent_Declare (#7023)
162ad7a37 Fix comment with line orders - Rust should be last. (#7037)
a0a6c3f8c Use actions/checkout@v2, which fixes security vulnerability. (#7036)
a2d38fbb9 Add --warnings-as-errors to flatc compiler. (#7034)
9ef1524d3 Emit include for bfbs-gen-embed (#7031)
0c9de0352 Upgraded GRPC version to 1.42.0 (#7033)
a783bc926 chore: dart 2.0.5 release changes (#6983)
aff818ceb rust: Allow for usage in no_std environment (#6989)
d7b75417f Make flatbuffer builder deterministic (#6993)
a42e89897 Added verifier alignment checking to table fields (#7018)
96cc2f3ee BuildFlatBuffers.cmake: fix arguments not passed properly to flatc (#7013)
3250a1f8d Add initial C# vector of unions support to the documentation. (#6880)
ace4a37f2 [TS/JS] BigInt implementation (#6998)
f28c2b293 Avoid implicit conversion from float to double. (#7003)
96f3cf690 Rearrange #include directives to pass to compilation with a particular DSP toolchain (#7000)
b3edfdbfb Reverting grpc generated file suffix (#6995)
b8aaccee8 Disable parsing of nested_flatbuffers as bytes by default
2dc8ae774 Enable OSS-Fuzz on CI
5b0d49112 Updated FlexBuffers fuzzer
d8b7041d7 Added alignment checking to FlexBuffers verifier
5a0c3366c FlexBuffers verifier additionally checks for nesting
f8148b8da Made FlexBuffers reuse tracker track types
a22b1b626 Prevent shadow with _{{FIELD_NAME}} (#6991)
4264daadd FlexBuffers fuzzer fixes
3cbc120a0 Refractor Flatc Options (#6987)
8dcd2682c [CMake] Add option for disable universal on OSX (#6990)
b78002ff3 Validate C# json/object-api options (#6985)
c555ee8fa Add .NET test to github workflows (#6982)
b92bb0584 [CMake]: Fix version in pkgconfig file (#6986)
956d11569 re-enabled FlexBuffer JSON in fuzzer
e367ca32a Verifier for FlexBuffers (#6977)
705f27f6e [CMake]: Fix python command for mingw environment (#6984)
5fc87f4c4 Enable --gen-onefile in Python (#6953)
11749095a Make idl_parser deterministic (#6976)
d0cede9c9 Bumping to Version 2.0.5 (#6967)
fcc2bee0b Fix typo in variable name (#6973)
e08da4dea remove Appveyor's Vs2010 and 13 builds (#6969)
18538c401 [TS] Fix reserved words as arguments (#6955) (#6956)
e57f4ab2d Update stale bot version and provide away to exempt issues with the not-stale label (#6968)
deed68db5 missing generated files (#6966)
061d61f3f Lua Generator using IR. (#6940)
cffe0c454 FixedTypedVector: add const to ElementType() and size() (#6965)
fadd40e40 Have grpc include file with correct filename-suffix given to flatc (#6954)
e47dc0e46 Removed test/generate_code.{sh|bat} (#6873)
5c5475479 switched to windows-lastest, removed deadcode (#6948)
4f7f6dc30 Restore FlatBufferBuilder::kFileIdentifierLength. (#6960)
0fadaf391 Enable verifier on nested_flatbuffers
4d0e9a870 Turn off nested FlatBuffers/FlexBuffers for the fuzzer
c05f6783a invalid conditional running genrate_code.py (#6952)
a14f4052c rust: remove needless borrow (#6922)
9e4ca857b Vector Downward GetSize optimization (#6925)
a2b99084b Fix flexbuffers clang-analyzer warning (#6947)
85b4effac test: fix undefined order of functio parameters. (#6946)
790f41154 [cmake] Fix getting version info from tags during the build (#6936)
e89de4411 clang-all (#6941)
256ab3798 WIP: Dart release 2.0 (#6927)
a59288a01 Add benchmarks to Linux CI (#6928)
587bbd49a [C++] Fix compile failure on Object API union construction for struct member (#6923)
a9c341545 Fix integer overflow warnings
8aa18b629 fixed cmp0048 error (#6932)
d727579b6 fuzzers: fix typo in file path (#6931)
97a30171c Added Raw C++ benchmarks (#6924)
0989fc5e5 Added Google benchmarks (and gtests) (#6920)
927175ea2 [Java] lookup by byteArray is giving back wrong entry (#6915)
6748c373b Removal of support for FLATBUFFERS_CPP98_STL (#6918)
3fab0c6ee move [[ ]] to calling sites (#6914)
6c8c29155 [C++] Split flatbuffers.h into separate files (#6868)
fd4ff23da Keep methods with struct name and switch them to default (#6879)
f8b69e330 [Python] Verify EnumDef is not generated in GenUnionCreator (#6903)
c0394bb09 Support `--conform` for vector of unions (#6883)
8433eb108 Typo fixes in comments of flatbuffers.h and flexbuffers.h (#6901)
f2f9380c8 [Java] Prevent generation of enum names when underlying type is long (#6781) (#6895)
e672dabfe [C++] Fix memory leak when using grpc (#6896) (#6897)
9a4ca2764 Output errors / warnings on stderr instead of stdout (#6881)
4c7a9c10d Adds JSON encoding to swift (#6874)
38295a187 [Kotlin] Fix missing escape for struct construction statements (#6877)
31bb0b972 add working directory (#6878)
45e5642e9 Default Arguments for Mutators C++ [Updated] (#6872)
a592f4c89 [Cmake] Add a post build command after flatc to run the new generate_code.py script. (#6866)
b9d43a557 dart - add Packable interface (#6846)
2ece9e25b Bumped package.json to 2.0.4
2dd212637 Fix linker errors on (Free|Open)BSD. (#6860)
f63c130c2 Improves documentation, and adding DocC (#6784)
e2b26ee19 Make and generate_code.sh generate same outputs (#6855)
9d686bf43 Include subdirectories in published npm package (#6850)
1d26daff3 Use ArrayBuffer type for JS flexbuffer's toObject (#6851)
e72e18d9f feat(build): compile "universal" libraries and executables for Mac (#6852)
354d97f6d fixed errant itemgroup element in C# test project (#6854)
6f7a57eaa [C#] Using 'global::' as qualifying_start_ within BaseGenerator (#6767)
90baa1444 Dart: binary lists (typed_data) (#6839)
0a3b017f0 Delete IDLOptions::lang (#6841)
47d35f105 BugFix: Optional enum when it is null (#6835)
8fb8c2ce1 [C#] Use @ for keyword escaping (#6834)
1d063d87c [C++] Let builder accept custom-alloc std::vector (#6814)
338331b55 Changes to support binary schema file loading and parsing (flatc) (#6823)
156a30c75 Move Apple-specific build flags to Clang section (#6802)
550d2f904 Issue error if jsonschema has no root type defined #6821 (#6831)
c3a38242e Fix typos in docs (#6829)
74c3d7eba [C++] Add mutable version of LookupByKey and test (#6826)
db6eae5c4 Add html and latex to gitignore (#6819)
0e9d79c35 [Java] Avoid casting ByteBuffer to Buffer (#6785)
b20c4d3aa [C++] Add GetMutableSizePrefixedRoot and generate GetMutableSizePrefixedXxx functions (#6815)
ae145293c flattests_cpp17 doesn't compile with Visual Studio 2017: warning C4100: 'indent': unreferenced formal parameter (#6811)
e3c76a5cd Dart lints (#6808)
4b9123baf fix parser string=null (#6810)
f89e0b1a6 Refactor idl_gen_rust and Rust generated code to use consistent whitespace (#6809)
273f6084e Fix Rust keyword inconsistency (#6794)
4a0879458 [C#] Remove superfluous semicolon in C# structs (#6791)
d6f51ea16 fix ptr in flatbuffers cpp tutorial (#6787)
067dce6e7 [C#] Handle keywords (#6775)
2ca5f0e72 [C#] Respect command line parameter for file name extension and suffix (#6779)
f20d2253a update Java version to 2.0.3
390d438e2 [Kotlin] Fix CI by changing compiler to Java 11 (#6783)
6fb2c90d9 avoiding even more NoSuchMethod exceptions (#6729)
a7b527d94 java: Use maven profile to target Java 8 bytecode (#6764)
5d77820b3 [C++] Using calculated fields_number for field_names size (#6769)
909ce970a [C++] Use UnPackTo instead of UnPack if pointer exists (#6725)
35e2cac6e Store vtables sorted in Rust builder (#6765)
c39fc9dd9 [C++] Use nullptr instead of 0 in generated headers (#6762)
775c6567d [C++] Fix compiler warning -Wredundant-parens in clang (#6761)
97d9527f6 Dart 2.0 release prep (#6759)
e01205466 [C++] Use proper gRPC C++ API when using MemoryBuffer Slice (#6756)
5235133f3 Dart - make ascii optimization optional in StringReader, same as in writeString() (#6758)
c871df770 Dart - change table building to assert() instead of exceptions (#6754)
a6eeeb3b9 Dart - inline small functions to increase performance (#6755)
3dd02144d [C#] Fix field name struct name collision (#6744) (#6757)
e77926f0e [C#] Add Union Constructor Utility for ObjectAPI. (#6105)
ac2348202 Dart - fixup writeString() return type after previous merges (#6753)
8be8a0a71 [C++] Fix union type handling on object api in C++17 (#6745)
12e341e4f Rework how Rust generated files are laid out (#6731)
c36672d80 Dart - optimize writeString for ASCII (#6736)
2bfc8e9f0 Dart - make writeString() argument non-nullable (#6737)
674a9f2aa fix lints in rust tests (#6743)
016e6aa13 Add a split on ':' to build_defs.bzl (#6742)
65700441d Dart - make vTable fixed size (expect the number of fields when creating) (#6735)
dd5bb55ca Dart - make vTable deduplication optional (#6734)
e8423da1b Dart - regenerate example after recent flatc changes (#6733)
0980e39c9 flexbuffers: Add variant of Blob() that takes a key (#6730)
e73fab27d Dart - store empty vectors instead of NULL (#6728)
92ae532e4 Dart - finish/lowFinish/buffer changes (#6712)
7482b25f8 Remove ubuntu1604 from presubmit.yml (#6715)
3f77dc9a0 Dart - unpack() must use eager list reader (#6723)
838c93b84 Dart - fix flex-builder compilation error (#6722)
089f48a4a Dart - make sure added padding is zeroed, same as in C++ (#6716)
bf3470c16 Fix UB in CreateVectorOfStructs in case of an empty vector: avoid calling memcpy in this case (#6726)
8f8196e13 Fix 6348 (#6717)
8ab35b2a5 Dart - add custom allocator support (#6711)
c0ba2870c Fix typo in docu (#6714)
22498cf3a [C++] add make_span for Array<T,N> (#6663)
bd37e67ac [C++] Fix a -Wdeprecated-copy warning. (#6708)
a6ee33557 Dart null safety (#6696)
71d43f3be Make --bfbs-filenames default to location of first schema file. (#6705)
c8db1ca5d Jsonschema add prop comments (#6617)
962751a6e Improve generated comparisons for tables (#6486)
06fd6d640 Replace filenames in reflection with filenames+includes. (#6703)
acce4ac3f Fix incorrect assertion usage. (#6702)
8fd7861b7 Fix warning about deprecated module: imp (#6362)
c58ae9422 Add the file a symbol is declared in to Reflection (#6613)
2cf7bb796 Intermediate Representation docs (#6685)
4e3a66c14 Dart object API (#6682)
d959e2320 dart - change Builder.reset() to reuse an existing buffer (#6661)
a9fb54088 use improved versioning (#6691)
337eb8b8f update docs - structs can't be roots (#6690)
6415ef05d [Python] [Codegen] Fixes nested structs with underscore names (#6686)
f069396d1 [C++] flatc --cpp-field-case-style option to permit camel-case field names in C++ (#6669)
021177af0 Fix snap version formatting (#6683)
e1e9f9373 [C++/grpc] added hiding of unused variables in the generated code (#6677)
15110094e Fix GitHub Actions CI gcc/clang versions
093badb0a Use unoptimized path for ReadUInt64 for win32 build as the optimized path crashes. (#6681)
752c7b576 avoiding more NoSuchMethod exceptions (#6671)
7c3e267e1 [Java] ObjectAPI implementation (#6521) (#6582)
baaffbaed npm update to 2.0.3 and script fix
4cb3f222b [TS] Fix module reference in package.json (#6676)
eabdbda75 [TS] Generate entry point module (#6674)
bec23700f Prepare for Java 2.0.1 release
12f2eedad Update CI to GCC/Clang 11
221eeb231 Fix typo in C++ doc (#6664)
813d3632e avoiding NoSuchMethod exception (#6658)
d84bccb0c Removed most heap allocations in builder (#6662)
b4e67f9bf Dart test fix (#6660)
54c11932f [Java] Flexbuffers - Negative signed object length (#6651)
fbcb3c423 [TS/JS] Updates the grpc (#6654)
8937dcfd7 Updates go lang support to allow other languages to communicate with it (#6653)
512d5a689 Update readme.md to point to security policy
a92cb5dd7 Create Security.md
d151dcbb9 Revert "[C++] Removed most heap allocations in builder (#6620)" (#6659)
f1884c66f Fix gRPC test to use EndVector without specifying the length. (#6646)
72730ecd8 [C++] Removed most heap allocations in builder (#6620)
fe2bc2b0a Added README for Rust Flatbuffers (before publishing v=2.0) (#6652)
4867c9456 Fixed generation of c++ code with flags (#6637)
ef0eb3701 Ran clang-format-all.sh. Removed default --style=file parameter (#6639)
f83ee1af5 [idl_parser] Check structs and enums do not clash in a namespace (#6562)
a5175c513 Implements verifier and code gen for swift (#6373)
04b10f5a3 Deprecate EnumVal.object (#6612)
c121c0345 Fixed Java gRPC version number dependency
8fd10606c Implement Serialize for flexbuffer::Reader (#6635)
a1730fcea [Swift] Updated cocoapods to 2.0.0 (#6634)
a9a295fec More missing version changes
5c01ad387 Dart generated code update
42ca1b914 Swift/Kotlin generated code version updates
6ed780dbd C++/Rust version changes
3412fab8e C#/Java generated code version updates
8a7d013f8 Updated main version numbers to 2.0
170af5978 [Go] Add missing namespace when using Object API (#6633)
c8c16de16 Fix reverse iterators for Vector and Array (#6626)
4525cd9c5 [Lua] manipulate byte array as string (#6624)
47361baf6 [C++] Fix union copy constructor to work with nested structs (#6552) (#6607)
8a582883a Updates swift generated monster sample file (#6616)
a4bb8f0c2 [Lua] Avoid infinite loop when creating empty string (#6614)
82aed82b8 Added support for Lua 5.1, 5.2 and 5.4 (#6606)
60ff76630 [TS] Remove wrong and obsolete NS prefix use (#6604)
a27c7d809 Fixed LuaJIT when not compiled with COMPAT mode (#6605)
363220823 removed unneeded type prefixing (#6601)
6b44c605b Bump Rust to 0.9.0 (#6610)
d3cd78a87 [Lua] Add LuaJIT support (#6584)
8fa3dfdb5 Introduce new_from_vec in Rust (also fix formatting) (#6599)
29379e8e4 fix typo in CppUsage.md (#6595)
14725d6c3 [Lua] GetRootAs can accept strings. Made Luatest Benchmarks optional (#6593)
16836ff95 Add advance feature indicators to reflection (#6546)
c87179e73 Rust Remove SafeSliceAccess for Arrays, and fix miri. (#6592)
c24031c36 Mark endian_scalar as unsafe. (#6588)
4ccc52c7a [swift] Implements union strings (#6589)
b82fe0738 [Rust] Fix small mistyping (#6585)
1e7f6c8c7 [TS] Commit the generated tests code (#6579)
84714b109 chore: ensure bash is used to generate code (#6577)
1045d7dd4 [Lua] Fix EnforceNumberAndPack for bool type (#6576)
0c7777596 [TS] Remove duplicated build-ts ci (#6575)
c43ba1752 [Rust] Specify Minimum Supported Rust Version (#6573)
da3bb64ef [Rust] Add support for fixed size arrays (#6548)
151900ba9 [Kotlin][FlexBuffers] Add support for Kotlin-iOS (#6564)
c012f29f9 silenced clippy warning (#6565)
df2df21ec [Kotlin] Bump kotlinx.benchmark dependency to 0.3.0 (#6560)
408e4db4a [TS] Add Build TS to CI jobs (#6524)
4d2364f34 [Kotlin][FlexBuffers] Add support for Kotlin-JS (#6554)
261cf3b20 Default-empty vectors of enums (#6505)
cd67261bb [CI] fixes buildkite (#6544)
1aa0c2f6a Limit formatter to pull requests only (#6540)
4133a39df Rust structz (#6539)
1c26d2a1a [Kotlin][FlexBuffers] JSON support for Flexbuffers (#6417)
276b1bc34 [grpc] Support latest version of grpc PoC (#6338)
124654ffc fixed packing structs (#6530)
3b7d1e86b [GO] Tries to add go format to the CI (#6518)
78f0c0d1d [C++] #6501 - Problem when mapping a native type multiple times (#6514)
c992eafb5 [fuzzer] Add `monster_debug` target (#6513)
ef8dd7792 [Swift] Removes allman rule (#6519)
69b329fc8 [flexbuffers, json] Parse `nan` and `inf` (#6512)
6543ba529 fixed packing structs in nested buffers (#6509)
0e453ac35 [idl_parser] Add kTokenNumericConstant token (#6432)
e9b4ae69d Remove `flatbuffers.pc` from the repository (#6508)
fc4fffea4 Bump grpc to 1.0.0 (#6507)
b240ab704 Move Traits struct and Create method out of --cpp-static-reflection. (#6503)
9a4f1f434 Disable x64-specific optimizations for ARM64EC ReadInt64 (#6506)
fac64918d Add --cpp-static-reflection to generate_code.bat. (#6502)
a69815f72 [C++17] Add compile-time reflection for fields. (#6324)
4033ff589 fixed invalid TS call and added test files (#6495)
a08357251 disable clippy (#6494)
5319dedb1 [idl_parser, JSON] Disable parsing of JSON for incomplete schemes (#6493)
bd4e0b30a [idl_parser] Track included files by hash (#6434)
bf9061200 fix for noUncheckedIndexedAccess in ts (#6474)
8142fedd1 Working on a python example plus fixing python grpc code (#6456)
c0be1cb7a [rust] Remove debug code (#6475)
8cccdfba5 Revert "[C#] Fix truncated ArraySegment<byte> if elementSize != 1 (#6462)" (#6488)
cbbbaa61b [C#] Fix truncated ArraySegment<byte> if elementSize != 1 (#6462)
ffc2ef77c [CI] Adds Code Generation tests on Github Actions (#6482)
1da6f4f18 [CMake] generate pkg-config flatbuffers.pc file (#6455)
b5da526e6 [Swift] Moves grpc example to grpc/examples (#6479)
3b5365762 [TS] Moves grpc code to examples folder (#6476)
e2f5438ac Fixes grammer (#6477)
5e3613f73 Fix sample_binary.py to use latest EndVector without a size. (#6478)
e6b911d40 updated JS docs to reflect current status (#6436)
0c7ae5816 [Go] Working on a go example plus fixing go grpc code (#6448)
ae603b977 [Swift] adds support for default vectors and strings (#6461)
7f47718b6 Update Building.md (#6473)
54dc09e8a GetUOffsetT must get value by GetUint32 not GetInt32 (#6072)
334c6be49 Fix a typo in Swift codegen (#6470)
4174c10e7 [rust] Genericize flexbuffer reader (#6450)
a20f606c2 [Swift] Renaming protocols (#6469)
a72a20827 Update swift docs (#6460)
86401e078 Default strings and vectors: Parser + Rust support (#6421)
6af37e672 [CMake] Renames BUILD files (#6457)
1b88655b0 [Build, cmake] Add -Werror override option (#6429)
0b15916e5 [C++]Fix extra char generation for byte type during json schema generation (#6276)
60eed0ca6 Updating working code (#6441)
0f83367f5 JSON schema - tailing double quotes for maximum (#6452)
fee095410 [idl_parser] Validate `force_align` on all possible paths (#6430)
6f3e45eca Implement Rust object API defaults (#6444)
815d3e820 Upgrade swift grpc to alpha 24 (#6439)
76e7a0ff5 [fuzzer] Limit parser_fuzzer execution time (#6431)
6d91096a2 This commit contains the initial implementation of Flexbuffers in Kotlin. The code was ported based (#6387)
13d9e3585 Better python generated code naming (#6336)
6effe431b Rust: remove inner attributes (#6410)
efcbdc769 [Rust] Ensure unions are referenced with the correct path (#6422)
e581013e3 Refactor FieldDef to model presense as an enum rather than 2 bools. (#6420)
0984d4328 [c++] Apply NativeName before WrapInNameSpace in idl_gen_cpp.cpp (#6419)
786f69b24 Formats cpp code (#6349)
1da0a2dfa Rust Object API (#6070)
796ed68fa Clarify that (Flat|Flex)Buffers do not deduplicate vector elements (#6415)
7b1ee31d8 Clarify that FlatBuffers unions do not support scalars (#6416)
4aff1198d Explain how FlatBuffers encodes unions (#6414)
ad3a729f9 dart Builder - expose finished buffer size (#6403)
52e217706 Remove invalid claim that Protocol Buffers does not support unions (#6413)
760c65755 [TS/JS] New gen TS code gen (#6302)
75c859e98 [idl_parser] Improve symbols lookup thru parent namespaces (#6407)
91b0958c4 Search for includes in the directory containg the current file (#6371)
8008dde11 Upgrade Rust dependencies (#6406)
c81cf8249 [TS/JS] New gen TS code gen prequel to preserve history (#6404)
8573108bb Unset FieldDef.optional if its key (#6402)
7abe612b5 [fuzzer] Fix the binary schema loading in the monster_fuzzer (#6396)
408cf5802 Fix Rust UB problems (#6393)
39e115fdb Define Vector::value_type for STL compatibility (#6394)
85719669c [fuzzer] Debug the monster_tets.bfbs on clusterfuzz server (#6392)
809fe49c7 Fix up scripts, fix generated enum value for strong mode, regenerate files (#6389)
41253e574 [go] tests/GoTest.sh: Fix flags.Parse location to work on new go SDKs. (#6388)
08d2ce844 fix Dart Builder._writeString() - always write trailing zero byte (#6390)
a15a8d930 fix Dart Builder.reset() - clear vTables (#6386)
83ce29cc2 [C++, JSON] Fix nullptr access when reading a key with a default value. (#6375)
4363c1d2c Fix generated EndVector. (#6385)
1bf1ec027 Implements type promotion for Java enum  (#6382)
080097653 Delete label_notify.yml
795408115 Disabled PHP CI (#6381)
46545e627 fixed warnings (#6355)
0168178a1 Fix multiple fbs code generation failure (#6365)
82836a62b [idl_parser] Improve stack overflow protection (#6364)
e7430bbeb [idl_parser] Check the range of explicitly set field's id value (#6363)
24dd85fd2 Generate code to encode and decode nested flatbuffers in Python. (#6354)
57f68e289 [Rust] Shared String (#6367)
44cf2bde1 Updates license  date to 2021 (#6378)
be37d4da1 include_prefix support for rust (#6330)
4e79d129c [Swift] Rebuild the way swift handles structs from scratch (#6326)
05192553f Fix typos in usage/comments; Make rust generator respect to --filenam… (#6342)
f2511d7d4 Renaming infinity variables in test.cpp (#6340)
f8b203c9c Add vectorNumElements attribute to Builder for simpler vector creation. (#6328)
8ab7c7e2c [CI] Adds formatter to CI (#6272)
7e0039028 Fix Max CI build path (#6333)
65c415911 Generate nullable properties in C# object-based API for optional scalars. (without -gen-mutable) (#6273)
a9e91116d [Python] Commit some orphan python genfile diffs. (#6325)
80a745d9b Fixed missing ending quotes in labeller (#6327)
9fca5e4f4 Add flatc option to inhibit all warnings #6005 (#6301)
92a806b4e [fuzzer] Rename fuzzing dictionaries for `oss-fuzz` (#6318)
9c9baf6d5 bumprust (#6322)
aafc5dc95 Set default initialSize for Builder to 0 (#6310)
442949bc1 Rust Flatbuffers Verifier (#6269)
9064072e8 Version message should be a "STATUS" to avoid going to stderr. (#6316)
fd4c1b5ff Replace std::string and const char* CreateSharedString with string_view (#6315)
bc7eb8ade [fuzzer] Fix mistakes in the `parser` and `scalar` fuzzers. (#6314)
fc960f367 Add default to offset param of Python generated GetRootAs (#6312)
f437f0f7e [fuzzer] Fix loading of schema in monster_fuzzer (#6308)
7f33cf682 [C++] Switch `flatc` to `--cpp-std c++11` C++ code generator (#6306)
8d9eae9ac [idl_parser] Unify parsing of NaN values read from .fbs and .json files (#6296)
2046bffa4 Moved various language tests from AppVeyor to GitHub Actions (#6300)

git-subtree-dir: third_party/flatbuffers
git-subtree-split: e5f331db998a808f78cf5a4880e6f5d0a321c4d0
Signed-off-by: James Kuszmaul <jabukuszmaul+collab@gmail.com>
Change-Id: I37f8aaf007fc86226cfa250169a87807afa64a78
diff --git a/dart/CHANGELOG.md b/dart/CHANGELOG.md
index 5e2d2de..a582e2e 100644
--- a/dart/CHANGELOG.md
+++ b/dart/CHANGELOG.md
@@ -1,4 +1,22 @@
-# CHANGELOG
+## 2.0.5
+
+- switch to null safety (#6696)
+- add Object APIs (pack/unpack) (#6682, #6723, #6846)
+- add custom builder buffer allocator support (#6711)
+- add `Builder.size()` - finished buffer size (#6403)
+- make `writeString()` argument non-nullable (#6737)
+- make tables fixed size (expect the number of fields when creating) (#6735)
+- make table deduplication optional (param `deduplicateTables`) (#6734)
+- change `Builder.reset()` to reuse an existing buffer (#6661)
+- change table building to assert() instead of exceptions (#6754)
+- optimize `writeString()` for ASCII (param `asciiOptimization`) (#6736)
+- change `StringReader` to make ASCII optimization optional (param `asciiOptimization`) (#6758)
+- change `[byte]` and `[ubyte]` representation to `dart:typed_data` `Int8List` and `Uint8List` (#6839)
+- rename `lowFinish()` to `buffer` getter (#6712)
+- fix `Builder._writeString()` - always write trailing zero byte (#6390)
+- fix `Builder.reset()` - clear vTables (#6386)
+- make sure added padding is zeroed, same as in C++ (#6716)
+- many performance improvements (#6755)
 
 ## 1.9.2
 
@@ -11,4 +29,4 @@
 
 ## 1.9.0
 
-- Initial release, supports Dart 1.x and many dev versions of Dart 2.x
\ No newline at end of file
+- Initial release, supports Dart 1.x and many dev versions of Dart 2.x
diff --git a/dart/LICENSE b/dart/LICENSE
index b2ae013..c02ca2f 100644
--- a/dart/LICENSE
+++ b/dart/LICENSE
@@ -1,35 +1,3 @@
-The code in lib/flat_buffers.dart is based on code that was releases under the 
-following license:
-
-Copyright 2012, the Dart project authors. All rights reserved.
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-    * Redistributions of source code must retain the above copyright
-      notice, this list of conditions and the following disclaimer.
-    * Redistributions in binary form must reproduce the above
-      copyright notice, this list of conditions and the following
-      disclaimer in the documentation and/or other materials provided
-      with the distribution.
-    * Neither the name of Google Inc. nor the names of its
-      contributors may be used to endorse or promote products derived
-      from this software without specific prior written permission.
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-To the extent permissible, the changes to that code and the other assets in 
-this package are licensed under the Apache2 license:
-
-
                                  Apache License
                            Version 2.0, January 2004
                         http://www.apache.org/licenses/
diff --git a/dart/README.md b/dart/README.md
index 11bc0c4..123cdc3 100644
--- a/dart/README.md
+++ b/dart/README.md
@@ -1,13 +1,23 @@
 # FlatBuffers for Dart
 
-This package is used to read and write FlatBuffer files in Dart.
+This package is used to read and write [FlatBuffers](https://google.github.io/flatbuffers/).
 
-Most consumers will want to use the [`flatc`](https://github.com/google/flatbuffers)
-compiler to generate Dart code from a FlatBuffers IDL schema.  For example, the
-`monster_my_game.sample_generated.dart` was generated with `flatc` from
-`monster.fbs` in the example folder. The generated classes can be used to read
-or write binary files that are interoperable with other languages and platforms
-supported by FlatBuffers, as illustrated in the `example.dart` in the
+Most consumers will want to use the [`flatc` - FlatBuffer compiler](https://github.com/google/flatbuffers) binary for your platform.
+You can find it in the `generator/{Platform}` directory of the [released package archive](https://pub.dev/packages/flat_buffers/versions/2.0.5.tar.gz).
+
+The FlatBuffer compiler `flatc` reads a FlatBuffers IDL schema and generates Dart code.
+The generated classes can be used to read or write binary data/files that are interoperable with
+other languages and platforms supported by FlatBuffers, as illustrated in the `example.dart` in the
 examples folder.
 
-Additional documentation and examples are available [at the FlatBuffers site](https://google.github.io/flatbuffers/index.html)
\ No newline at end of file
+For more details and documentation, head over to the official site and read the
+[Tutorial](https://google.github.io/flatbuffers/flatbuffers_guide_tutorial.html) and how to
+[use FlatBuffers in Dart](https://google.github.io/flatbuffers/flatbuffers_guide_use_dart.html).
+
+## Dart 2.0 notes
+Version 2.0.5 ships with it's own custom build of `flatc` because this is an extraordinary release to catch-up
+with FlatBuffers for other platforms. This generator can only generate dart code (to avoid generating code for other platforms which isn't released yet).
+On the other hand, the generated code still produces standard binary FlatBuffers compatible with other languages.
+In other words: only `flatc --dart ...` works with this generator, but your app will be able to produce and read standard binary (`Uint8List`) FlatBuffers that are fully compotible with other languages supporting FlatBuffers (e.g. Java, C++, ...).
+
+In the future a common `flatc` binary for all platforms would be shipped through GitHub release page instead.
diff --git a/dart/analysis_options.yaml b/dart/analysis_options.yaml
new file mode 100644
index 0000000..572dd23
--- /dev/null
+++ b/dart/analysis_options.yaml
@@ -0,0 +1 @@
+include: package:lints/recommended.yaml
diff --git a/dart/example/example.dart b/dart/example/example.dart
index d95bb31..d397bbb 100644
--- a/dart/example/example.dart
+++ b/dart/example/example.dart
@@ -15,7 +15,7 @@
  */
 
 import 'package:flat_buffers/flat_buffers.dart' as fb;
-import './monster_my_game.sample_generated.dart' as myGame;
+import './monster_my_game.sample_generated.dart' as my_game;
 
 // Example how to use FlatBuffers to create and read binary buffers.
 
@@ -25,27 +25,27 @@
 }
 
 void builderTest() {
-  final builder = new fb.Builder(initialSize: 1024);
-  final int weaponOneName = builder.writeString("Sword");
+  final builder = fb.Builder(initialSize: 1024);
+  final int? weaponOneName = builder.writeString("Sword");
   final int weaponOneDamage = 3;
 
-  final int weaponTwoName = builder.writeString("Axe");
+  final int? weaponTwoName = builder.writeString("Axe");
   final int weaponTwoDamage = 5;
 
-  final swordBuilder = new myGame.WeaponBuilder(builder)
+  final swordBuilder = my_game.WeaponBuilder(builder)
     ..begin()
     ..addNameOffset(weaponOneName)
     ..addDamage(weaponOneDamage);
   final int sword = swordBuilder.finish();
 
-  final axeBuilder = new myGame.WeaponBuilder(builder)
+  final axeBuilder = my_game.WeaponBuilder(builder)
     ..begin()
     ..addNameOffset(weaponTwoName)
     ..addDamage(weaponTwoDamage);
   final int axe = axeBuilder.finish();
 
   // Serialize a name for our monster, called "Orc".
-  final int name = builder.writeString('Orc');
+  final int? name = builder.writeString('Orc');
 
   // Create a list representing the inventory of the Orc. Each number
   // could correspond to an item that can be claimed after he is slain.
@@ -54,7 +54,7 @@
   final weapons = builder.writeList([sword, axe]);
 
   // Struct builders are very easy to reuse.
-  final vec3Builder = new myGame.Vec3Builder(builder);
+  final vec3Builder = my_game.Vec3Builder(builder);
 
   vec3Builder.finish(4.0, 5.0, 6.0);
   vec3Builder.finish(1.0, 2.0, 3.0);
@@ -62,21 +62,21 @@
   final int hp = 300;
   final int mana = 150;
 
-  final monster = new myGame.MonsterBuilder(builder)
+  final monster = my_game.MonsterBuilder(builder)
     ..begin()
     ..addNameOffset(name)
     ..addInventoryOffset(inventory)
     ..addWeaponsOffset(weapons)
-    ..addEquippedType(myGame.EquipmentTypeId.Weapon)
+    ..addEquippedType(my_game.EquipmentTypeId.Weapon)
     ..addEquippedOffset(axe)
     ..addHp(hp)
     ..addMana(mana)
     ..addPos(vec3Builder.finish(1.0, 2.0, 3.0))
-    ..addColor(myGame.Color.Red);
+    ..addColor(my_game.Color.Red);
 
   final int monsteroff = monster.finish();
-  final buffer = builder.finish(monsteroff);
-  if (verify(buffer)) {
+  builder.finish(monsteroff);
+  if (verify(builder.buffer)) {
     print(
         "The FlatBuffer was successfully created with a builder and verified!");
   }
@@ -85,17 +85,17 @@
 void objectBuilderTest() {
   // Create the builder here so we can use it for both weapons and equipped
   // the actual data will only be written to the buffer once.
-  var axe = new myGame.WeaponObjectBuilder(name: 'Axe', damage: 5);
+  var axe = my_game.WeaponObjectBuilder(name: 'Axe', damage: 5);
 
-  var monsterBuilder = new myGame.MonsterObjectBuilder(
-    pos: new myGame.Vec3ObjectBuilder(x: 1.0, y: 2.0, z: 3.0),
+  var monsterBuilder = my_game.MonsterObjectBuilder(
+    pos: my_game.Vec3ObjectBuilder(x: 1.0, y: 2.0, z: 3.0),
     mana: 150,
     hp: 300,
     name: 'Orc',
     inventory: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
-    color: myGame.Color.Red,
-    weapons: [new myGame.WeaponObjectBuilder(name: 'Sword', damage: 3), axe],
-    equippedType: myGame.EquipmentTypeId.Weapon,
+    color: my_game.Color.Red,
+    weapons: [my_game.WeaponObjectBuilder(name: 'Sword', damage: 3), axe],
+    equippedType: my_game.EquipmentTypeId.Weapon,
     equipped: axe,
   );
 
@@ -114,7 +114,7 @@
 
 bool verify(List<int> buffer) {
   // Get access to the root:
-  var monster = new myGame.Monster(buffer);
+  var monster = my_game.Monster(buffer);
 
   // Get and test some scalar types from the FlatBuffer.
   assert(monster.hp == 80);
@@ -122,31 +122,29 @@
   assert(monster.name == "MyMonster");
 
   // Get and test a field of the FlatBuffer's `struct`.
-  var pos = monster.pos;
-  assert(pos != null);
+  var pos = monster.pos!;
   assert(pos.z == 3.0);
 
   // Get a test an element from the `inventory` FlatBuffer's `vector`.
-  var inv = monster.inventory;
-  assert(inv != null);
+  var inv = monster.inventory!;
   assert(inv.length == 10);
   assert(inv[9] == 9);
 
   // Get and test the `weapons` FlatBuffers's `vector`.
-  var expected_weapon_names = ["Sword", "Axe"];
-  var expected_weapon_damages = [3, 5];
-  var weps = monster.weapons;
+  var expectedWeaponNames = ["Sword", "Axe"];
+  var expectedWeaponDamages = [3, 5];
+  var weps = monster.weapons!;
   for (int i = 0; i < weps.length; i++) {
-    assert(weps[i].name == expected_weapon_names[i]);
-    assert(weps[i].damage == expected_weapon_damages[i]);
+    assert(weps[i].name == expectedWeaponNames[i]);
+    assert(weps[i].damage == expectedWeaponDamages[i]);
   }
 
   // Get and test the `Equipment` union (`equipped` field).
-  assert(monster.equippedType.value == myGame.EquipmentTypeId.Weapon.value);
-  assert(monster.equippedType == myGame.EquipmentTypeId.Weapon);
+  assert(monster.equippedType!.value == my_game.EquipmentTypeId.Weapon.value);
+  assert(monster.equippedType == my_game.EquipmentTypeId.Weapon);
 
-  assert(monster.equipped is myGame.Weapon);
-  var equipped = monster.equipped as myGame.Weapon;
+  assert(monster.equipped is my_game.Weapon);
+  var equipped = monster.equipped as my_game.Weapon;
   assert(equipped.name == "Axe");
   assert(equipped.damage == 5);
 
diff --git a/dart/example/monster_my_game.sample_generated.dart b/dart/example/monster_my_game.sample_generated.dart
index 2c7c10d..ba0a81f 100644
--- a/dart/example/monster_my_game.sample_generated.dart
+++ b/dart/example/monster_my_game.sample_generated.dart
@@ -1,5 +1,5 @@
 // automatically generated by the FlatBuffers compiler, do not modify
-// ignore_for_file: unused_import, non_constant_identifier_names
+// ignore_for_file: unused_import, unused_field, unused_element, unused_local_variable
 
 library my_game.sample;
 
@@ -12,23 +12,29 @@
   const Color._(this.value);
 
   factory Color.fromValue(int value) {
-    if (value == null) return null;
-    if (!values.containsKey(value)) {
-      throw new StateError('Invalid value $value for bit flag enum Color');
+    final result = values[value];
+    if (result == null) {
+      throw StateError('Invalid value $value for bit flag enum Color');
     }
-    return values[value];
+    return result;
   }
 
+  static Color? _createOrNull(int? value) => 
+      value == null ? null : Color.fromValue(value);
+
   static const int minValue = 0;
   static const int maxValue = 2;
   static bool containsValue(int value) => values.containsKey(value);
 
-  static const Color Red = const Color._(0);
-  static const Color Green = const Color._(1);
-  static const Color Blue = const Color._(2);
-  static get values => {0: Red,1: Green,2: Blue,};
+  static const Color Red = Color._(0);
+  static const Color Green = Color._(1);
+  static const Color Blue = Color._(2);
+  static const Map<int, Color> values = {
+    0: Red,
+    1: Green,
+    2: Blue};
 
-  static const fb.Reader<Color> reader = const _ColorReader();
+  static const fb.Reader<Color> reader = _ColorReader();
 
   @override
   String toString() {
@@ -44,7 +50,7 @@
 
   @override
   Color read(fb.BufferContext bc, int offset) =>
-      new Color.fromValue(const fb.Int8Reader().read(bc, offset));
+      Color.fromValue(const fb.Int8Reader().read(bc, offset));
 }
 
 class EquipmentTypeId {
@@ -52,22 +58,27 @@
   const EquipmentTypeId._(this.value);
 
   factory EquipmentTypeId.fromValue(int value) {
-    if (value == null) return null;
-    if (!values.containsKey(value)) {
-      throw new StateError('Invalid value $value for bit flag enum EquipmentTypeId');
+    final result = values[value];
+    if (result == null) {
+      throw StateError('Invalid value $value for bit flag enum EquipmentTypeId');
     }
-    return values[value];
+    return result;
   }
 
+  static EquipmentTypeId? _createOrNull(int? value) => 
+      value == null ? null : EquipmentTypeId.fromValue(value);
+
   static const int minValue = 0;
   static const int maxValue = 1;
   static bool containsValue(int value) => values.containsKey(value);
 
-  static const EquipmentTypeId NONE = const EquipmentTypeId._(0);
-  static const EquipmentTypeId Weapon = const EquipmentTypeId._(1);
-  static get values => {0: NONE,1: Weapon,};
+  static const EquipmentTypeId NONE = EquipmentTypeId._(0);
+  static const EquipmentTypeId Weapon = EquipmentTypeId._(1);
+  static const Map<int, EquipmentTypeId> values = {
+    0: NONE,
+    1: Weapon};
 
-  static const fb.Reader<EquipmentTypeId> reader = const _EquipmentTypeIdReader();
+  static const fb.Reader<EquipmentTypeId> reader = _EquipmentTypeIdReader();
 
   @override
   String toString() {
@@ -83,13 +94,13 @@
 
   @override
   EquipmentTypeId read(fb.BufferContext bc, int offset) =>
-      new EquipmentTypeId.fromValue(const fb.Uint8Reader().read(bc, offset));
+      EquipmentTypeId.fromValue(const fb.Uint8Reader().read(bc, offset));
 }
 
 class Vec3 {
   Vec3._(this._bc, this._bcOffset);
 
-  static const fb.Reader<Vec3> reader = const _Vec3Reader();
+  static const fb.Reader<Vec3> reader = _Vec3Reader();
 
   final fb.BufferContext _bc;
   final int _bcOffset;
@@ -112,13 +123,11 @@
 
   @override
   Vec3 createObject(fb.BufferContext bc, int offset) => 
-    new Vec3._(bc, offset);
+    Vec3._(bc, offset);
 }
 
 class Vec3Builder {
-  Vec3Builder(this.fbBuilder) {
-    assert(fbBuilder != null);
-  }
+  Vec3Builder(this.fbBuilder);
 
   final fb.Builder fbBuilder;
 
@@ -137,9 +146,9 @@
   final double _z;
 
   Vec3ObjectBuilder({
-    double x,
-    double y,
-    double z,
+    required double x,
+    required double y,
+    required double z,
   })
       : _x = x,
         _y = y,
@@ -147,10 +156,7 @@
 
   /// Finish building, and store into the [fbBuilder].
   @override
-  int finish(
-    fb.Builder fbBuilder) {
-    assert(fbBuilder != null);
-
+  int finish(fb.Builder fbBuilder) {
     fbBuilder.putFloat32(_z);
     fbBuilder.putFloat32(_y);
     fbBuilder.putFloat32(_x);
@@ -159,39 +165,39 @@
 
   /// Convenience method to serialize to byte list.
   @override
-  Uint8List toBytes([String fileIdentifier]) {
-    fb.Builder fbBuilder = new fb.Builder();
-    int offset = finish(fbBuilder);
-    return fbBuilder.finish(offset, fileIdentifier);
+  Uint8List toBytes([String? fileIdentifier]) {
+    final fbBuilder = fb.Builder(deduplicateTables: false);
+    fbBuilder.finish(finish(fbBuilder), fileIdentifier);
+    return fbBuilder.buffer;
   }
 }
 class Monster {
   Monster._(this._bc, this._bcOffset);
   factory Monster(List<int> bytes) {
-    fb.BufferContext rootRef = new fb.BufferContext.fromBytes(bytes);
+    final rootRef = fb.BufferContext.fromBytes(bytes);
     return reader.read(rootRef, 0);
   }
 
-  static const fb.Reader<Monster> reader = const _MonsterReader();
+  static const fb.Reader<Monster> reader = _MonsterReader();
 
   final fb.BufferContext _bc;
   final int _bcOffset;
 
-  Vec3 get pos => Vec3.reader.vTableGet(_bc, _bcOffset, 4, null);
+  Vec3? get pos => Vec3.reader.vTableGetNullable(_bc, _bcOffset, 4);
   int get mana => const fb.Int16Reader().vTableGet(_bc, _bcOffset, 6, 150);
   int get hp => const fb.Int16Reader().vTableGet(_bc, _bcOffset, 8, 100);
-  String get name => const fb.StringReader().vTableGet(_bc, _bcOffset, 10, null);
-  List<int> get inventory => const fb.ListReader<int>(const fb.Uint8Reader()).vTableGet(_bc, _bcOffset, 14, null);
-  Color get color => new Color.fromValue(const fb.Int8Reader().vTableGet(_bc, _bcOffset, 16, 2));
-  List<Weapon> get weapons => const fb.ListReader<Weapon>(Weapon.reader).vTableGet(_bc, _bcOffset, 18, null);
-  EquipmentTypeId get equippedType => new EquipmentTypeId.fromValue(const fb.Uint8Reader().vTableGet(_bc, _bcOffset, 20, null));
+  String? get name => const fb.StringReader().vTableGetNullable(_bc, _bcOffset, 10);
+  List<int>? get inventory => const fb.Uint8ListReader().vTableGetNullable(_bc, _bcOffset, 14);
+  Color get color => Color.fromValue(const fb.Int8Reader().vTableGet(_bc, _bcOffset, 16, 2));
+  List<Weapon>? get weapons => const fb.ListReader<Weapon>(Weapon.reader).vTableGetNullable(_bc, _bcOffset, 18);
+  EquipmentTypeId? get equippedType => EquipmentTypeId._createOrNull(const fb.Uint8Reader().vTableGetNullable(_bc, _bcOffset, 20));
   dynamic get equipped {
     switch (equippedType?.value) {
-      case 1: return Weapon.reader.vTableGet(_bc, _bcOffset, 22, null);
+      case 1: return Weapon.reader.vTableGetNullable(_bc, _bcOffset, 22);
       default: return null;
     }
   }
-  List<Vec3> get path => const fb.ListReader<Vec3>(Vec3.reader).vTableGet(_bc, _bcOffset, 24, null);
+  List<Vec3>? get path => const fb.ListReader<Vec3>(Vec3.reader).vTableGetNullable(_bc, _bcOffset, 24);
 
   @override
   String toString() {
@@ -204,57 +210,55 @@
 
   @override
   Monster createObject(fb.BufferContext bc, int offset) => 
-    new Monster._(bc, offset);
+    Monster._(bc, offset);
 }
 
 class MonsterBuilder {
-  MonsterBuilder(this.fbBuilder) {
-    assert(fbBuilder != null);
-  }
+  MonsterBuilder(this.fbBuilder);
 
   final fb.Builder fbBuilder;
 
   void begin() {
-    fbBuilder.startTable();
+    fbBuilder.startTable(10);
   }
 
   int addPos(int offset) {
     fbBuilder.addStruct(0, offset);
     return fbBuilder.offset;
   }
-  int addMana(int mana) {
+  int addMana(int? mana) {
     fbBuilder.addInt16(1, mana);
     return fbBuilder.offset;
   }
-  int addHp(int hp) {
+  int addHp(int? hp) {
     fbBuilder.addInt16(2, hp);
     return fbBuilder.offset;
   }
-  int addNameOffset(int offset) {
+  int addNameOffset(int? offset) {
     fbBuilder.addOffset(3, offset);
     return fbBuilder.offset;
   }
-  int addInventoryOffset(int offset) {
+  int addInventoryOffset(int? offset) {
     fbBuilder.addOffset(5, offset);
     return fbBuilder.offset;
   }
-  int addColor(Color color) {
+  int addColor(Color? color) {
     fbBuilder.addInt8(6, color?.value);
     return fbBuilder.offset;
   }
-  int addWeaponsOffset(int offset) {
+  int addWeaponsOffset(int? offset) {
     fbBuilder.addOffset(7, offset);
     return fbBuilder.offset;
   }
-  int addEquippedType(EquipmentTypeId equippedType) {
+  int addEquippedType(EquipmentTypeId? equippedType) {
     fbBuilder.addUint8(8, equippedType?.value);
     return fbBuilder.offset;
   }
-  int addEquippedOffset(int offset) {
+  int addEquippedOffset(int? offset) {
     fbBuilder.addOffset(9, offset);
     return fbBuilder.offset;
   }
-  int addPathOffset(int offset) {
+  int addPathOffset(int? offset) {
     fbBuilder.addOffset(10, offset);
     return fbBuilder.offset;
   }
@@ -265,28 +269,28 @@
 }
 
 class MonsterObjectBuilder extends fb.ObjectBuilder {
-  final Vec3ObjectBuilder _pos;
-  final int _mana;
-  final int _hp;
-  final String _name;
-  final List<int> _inventory;
-  final Color _color;
-  final List<WeaponObjectBuilder> _weapons;
-  final EquipmentTypeId _equippedType;
+  final Vec3ObjectBuilder? _pos;
+  final int? _mana;
+  final int? _hp;
+  final String? _name;
+  final List<int>? _inventory;
+  final Color? _color;
+  final List<WeaponObjectBuilder>? _weapons;
+  final EquipmentTypeId? _equippedType;
   final dynamic _equipped;
-  final List<Vec3ObjectBuilder> _path;
+  final List<Vec3ObjectBuilder>? _path;
 
   MonsterObjectBuilder({
-    Vec3ObjectBuilder pos,
-    int mana,
-    int hp,
-    String name,
-    List<int> inventory,
-    Color color,
-    List<WeaponObjectBuilder> weapons,
-    EquipmentTypeId equippedType,
+    Vec3ObjectBuilder? pos,
+    int? mana,
+    int? hp,
+    String? name,
+    List<int>? inventory,
+    Color? color,
+    List<WeaponObjectBuilder>? weapons,
+    EquipmentTypeId? equippedType,
     dynamic equipped,
-    List<Vec3ObjectBuilder> path,
+    List<Vec3ObjectBuilder>? path,
   })
       : _pos = pos,
         _mana = mana,
@@ -301,69 +305,54 @@
 
   /// Finish building, and store into the [fbBuilder].
   @override
-  int finish(
-    fb.Builder fbBuilder) {
-    assert(fbBuilder != null);
-    final int nameOffset = fbBuilder.writeString(_name);
-    final int inventoryOffset = _inventory?.isNotEmpty == true
-        ? fbBuilder.writeListUint8(_inventory)
-        : null;
-    final int weaponsOffset = _weapons?.isNotEmpty == true
-        ? fbBuilder.writeList(_weapons.map((b) => b.getOrCreateOffset(fbBuilder)).toList())
-        : null;
-    final int equippedOffset = _equipped?.getOrCreateOffset(fbBuilder);
-    final int pathOffset = _path?.isNotEmpty == true
-        ? fbBuilder.writeListOfStructs(_path)
-        : null;
-
-    fbBuilder.startTable();
+  int finish(fb.Builder fbBuilder) {
+    final int? nameOffset = _name == null ? null
+        : fbBuilder.writeString(_name!);
+    final int? inventoryOffset = _inventory == null ? null
+        : fbBuilder.writeListUint8(_inventory!);
+    final int? weaponsOffset = _weapons == null ? null
+        : fbBuilder.writeList(_weapons!.map((b) => b.getOrCreateOffset(fbBuilder)).toList());
+    final int? equippedOffset = _equipped?.getOrCreateOffset(fbBuilder);
+    final int? pathOffset = _path == null ? null
+        : fbBuilder.writeListOfStructs(_path!);
+    fbBuilder.startTable(10);
     if (_pos != null) {
-      fbBuilder.addStruct(0, _pos.finish(fbBuilder));
+      fbBuilder.addStruct(0, _pos!.finish(fbBuilder));
     }
     fbBuilder.addInt16(1, _mana);
     fbBuilder.addInt16(2, _hp);
-    if (nameOffset != null) {
-      fbBuilder.addOffset(3, nameOffset);
-    }
-    if (inventoryOffset != null) {
-      fbBuilder.addOffset(5, inventoryOffset);
-    }
+    fbBuilder.addOffset(3, nameOffset);
+    fbBuilder.addOffset(5, inventoryOffset);
     fbBuilder.addInt8(6, _color?.value);
-    if (weaponsOffset != null) {
-      fbBuilder.addOffset(7, weaponsOffset);
-    }
+    fbBuilder.addOffset(7, weaponsOffset);
     fbBuilder.addUint8(8, _equippedType?.value);
-    if (equippedOffset != null) {
-      fbBuilder.addOffset(9, equippedOffset);
-    }
-    if (pathOffset != null) {
-      fbBuilder.addOffset(10, pathOffset);
-    }
+    fbBuilder.addOffset(9, equippedOffset);
+    fbBuilder.addOffset(10, pathOffset);
     return fbBuilder.endTable();
   }
 
   /// Convenience method to serialize to byte list.
   @override
-  Uint8List toBytes([String fileIdentifier]) {
-    fb.Builder fbBuilder = new fb.Builder();
-    int offset = finish(fbBuilder);
-    return fbBuilder.finish(offset, fileIdentifier);
+  Uint8List toBytes([String? fileIdentifier]) {
+    final fbBuilder = fb.Builder(deduplicateTables: false);
+    fbBuilder.finish(finish(fbBuilder), fileIdentifier);
+    return fbBuilder.buffer;
   }
 }
 class Weapon {
   Weapon._(this._bc, this._bcOffset);
   factory Weapon(List<int> bytes) {
-    fb.BufferContext rootRef = new fb.BufferContext.fromBytes(bytes);
+    final rootRef = fb.BufferContext.fromBytes(bytes);
     return reader.read(rootRef, 0);
   }
 
-  static const fb.Reader<Weapon> reader = const _WeaponReader();
+  static const fb.Reader<Weapon> reader = _WeaponReader();
 
   final fb.BufferContext _bc;
   final int _bcOffset;
 
-  String get name => const fb.StringReader().vTableGet(_bc, _bcOffset, 4, null);
-  int get damage => const fb.Int16Reader().vTableGet(_bc, _bcOffset, 6, null);
+  String? get name => const fb.StringReader().vTableGetNullable(_bc, _bcOffset, 4);
+  int get damage => const fb.Int16Reader().vTableGet(_bc, _bcOffset, 6, 0);
 
   @override
   String toString() {
@@ -376,25 +365,23 @@
 
   @override
   Weapon createObject(fb.BufferContext bc, int offset) => 
-    new Weapon._(bc, offset);
+    Weapon._(bc, offset);
 }
 
 class WeaponBuilder {
-  WeaponBuilder(this.fbBuilder) {
-    assert(fbBuilder != null);
-  }
+  WeaponBuilder(this.fbBuilder);
 
   final fb.Builder fbBuilder;
 
   void begin() {
-    fbBuilder.startTable();
+    fbBuilder.startTable(2);
   }
 
-  int addNameOffset(int offset) {
+  int addNameOffset(int? offset) {
     fbBuilder.addOffset(0, offset);
     return fbBuilder.offset;
   }
-  int addDamage(int damage) {
+  int addDamage(int? damage) {
     fbBuilder.addInt16(1, damage);
     return fbBuilder.offset;
   }
@@ -405,36 +392,32 @@
 }
 
 class WeaponObjectBuilder extends fb.ObjectBuilder {
-  final String _name;
-  final int _damage;
+  final String? _name;
+  final int? _damage;
 
   WeaponObjectBuilder({
-    String name,
-    int damage,
+    String? name,
+    int? damage,
   })
       : _name = name,
         _damage = damage;
 
   /// Finish building, and store into the [fbBuilder].
   @override
-  int finish(
-    fb.Builder fbBuilder) {
-    assert(fbBuilder != null);
-    final int nameOffset = fbBuilder.writeString(_name);
-
-    fbBuilder.startTable();
-    if (nameOffset != null) {
-      fbBuilder.addOffset(0, nameOffset);
-    }
+  int finish(fb.Builder fbBuilder) {
+    final int? nameOffset = _name == null ? null
+        : fbBuilder.writeString(_name!);
+    fbBuilder.startTable(2);
+    fbBuilder.addOffset(0, nameOffset);
     fbBuilder.addInt16(1, _damage);
     return fbBuilder.endTable();
   }
 
   /// Convenience method to serialize to byte list.
   @override
-  Uint8List toBytes([String fileIdentifier]) {
-    fb.Builder fbBuilder = new fb.Builder();
-    int offset = finish(fbBuilder);
-    return fbBuilder.finish(offset, fileIdentifier);
+  Uint8List toBytes([String? fileIdentifier]) {
+    final fbBuilder = fb.Builder(deduplicateTables: false);
+    fbBuilder.finish(finish(fbBuilder), fileIdentifier);
+    return fbBuilder.buffer;
   }
 }
diff --git a/dart/lib/flat_buffers.dart b/dart/lib/flat_buffers.dart
index 3d4cf81..d27d4bf 100644
--- a/dart/lib/flat_buffers.dart
+++ b/dart/lib/flat_buffers.dart
@@ -22,69 +22,70 @@
 ///
 /// This callback is used by other struct's `finish` methods to write the nested
 /// struct's fields inline.
-typedef void StructBuilder();
+typedef StructBuilder = void Function();
 
 /// Buffer with data and some context about it.
 class BufferContext {
   final ByteData _buffer;
 
-  factory BufferContext.fromBytes(List<int> byteList) {
-    Uint8List uint8List = _asUint8List(byteList);
-    ByteData buf = new ByteData.view(uint8List.buffer, uint8List.offsetInBytes);
-    return new BufferContext._(buf);
-  }
+  ByteData get buffer => _buffer;
 
-  BufferContext._(this._buffer);
+  /// Create from a FlatBuffer represented by a list of bytes (uint8).
+  factory BufferContext.fromBytes(List<int> byteList) =>
+      BufferContext(byteList is Uint8List
+          ? byteList.buffer.asByteData(byteList.offsetInBytes)
+          : ByteData.view(Uint8List.fromList(byteList).buffer));
 
-  int derefObject(int offset) {
-    return offset + _getUint32(offset);
-  }
+  /// Create from a FlatBuffer represented by ByteData.
+  BufferContext(this._buffer);
 
-  Uint8List _asUint8LIst(int offset, int length) =>
+  @pragma('vm:prefer-inline')
+  int derefObject(int offset) => offset + _getUint32(offset);
+
+  @pragma('vm:prefer-inline')
+  Uint8List _asUint8List(int offset, int length) =>
       _buffer.buffer.asUint8List(_buffer.offsetInBytes + offset, length);
 
-  double _getFloat64(int offset) =>
-      _buffer.getFloat64(offset, Endian.little);
+  @pragma('vm:prefer-inline')
+  double _getFloat64(int offset) => _buffer.getFloat64(offset, Endian.little);
 
-  double _getFloat32(int offset) =>
-      _buffer.getFloat32(offset, Endian.little);
+  @pragma('vm:prefer-inline')
+  double _getFloat32(int offset) => _buffer.getFloat32(offset, Endian.little);
 
-  int _getInt64(int offset) =>
-      _buffer.getInt64(offset, Endian.little);
+  @pragma('vm:prefer-inline')
+  int _getInt64(int offset) => _buffer.getInt64(offset, Endian.little);
 
-  int _getInt32(int offset) =>
-      _buffer.getInt32(offset, Endian.little);
+  @pragma('vm:prefer-inline')
+  int _getInt32(int offset) => _buffer.getInt32(offset, Endian.little);
 
-  int _getInt16(int offset) =>
-      _buffer.getInt16(offset, Endian.little);
+  @pragma('vm:prefer-inline')
+  int _getInt16(int offset) => _buffer.getInt16(offset, Endian.little);
 
+  @pragma('vm:prefer-inline')
   int _getInt8(int offset) => _buffer.getInt8(offset);
 
-  int _getUint64(int offset) =>
-      _buffer.getUint64(offset, Endian.little);
+  @pragma('vm:prefer-inline')
+  int _getUint64(int offset) => _buffer.getUint64(offset, Endian.little);
 
-  int _getUint32(int offset) =>
-      _buffer.getUint32(offset, Endian.little);
+  @pragma('vm:prefer-inline')
+  int _getUint32(int offset) => _buffer.getUint32(offset, Endian.little);
 
-  int _getUint16(int offset) =>
-      _buffer.getUint16(offset, Endian.little);
+  @pragma('vm:prefer-inline')
+  int _getUint16(int offset) => _buffer.getUint16(offset, Endian.little);
 
+  @pragma('vm:prefer-inline')
   int _getUint8(int offset) => _buffer.getUint8(offset);
+}
 
-  /// If the [byteList] is already a [Uint8List] return it.
-  /// Otherwise return a [Uint8List] copy of the [byteList].
-  static Uint8List _asUint8List(List<int> byteList) {
-    if (byteList is Uint8List) {
-      return byteList;
-    } else {
-      return new Uint8List.fromList(byteList);
-    }
-  }
+/// Interface implemented by the "object-api" classes (ending with "T").
+abstract class Packable {
+  /// Serialize the object using the given builder, returning the offset.
+  int pack(Builder fbBuilder);
 }
 
 /// Class implemented by typed builders generated by flatc.
 abstract class ObjectBuilder {
-  int _firstOffset;
+  int? _firstOffset;
 
   /// Can be used to write the data represented by this builder to the [Builder]
   /// and reuse the offset created in multiple tables.
@@ -94,7 +95,7 @@
   /// first call to this method.
   int getOrCreateOffset(Builder fbBuilder) {
     _firstOffset ??= finish(fbBuilder);
-    return _firstOffset;
+    return _firstOffset!;
   }
 
   /// Writes the data in this helper to the [Builder].
@@ -107,34 +108,39 @@
 
 /// Class that helps building flat buffers.
 class Builder {
+  bool _finished = false;
+
   final int initialSize;
 
   /// The list of existing VTable(s).
-  //final List<_VTable> _vTables = <_VTable>[];
-  final List<int> _vTables = <int>[];
+  final List<int> _vTables;
+
+  final bool deduplicateTables;
 
   ByteData _buf;
 
+  final Allocator _allocator;
+
   /// The maximum alignment that has been seen so far.  If [_buf] has to be
   /// reallocated in the future (to insert room at its start for more bytes) the
   /// reallocation will need to be a multiple of this many bytes.
-  int _maxAlign;
+  int _maxAlign = 1;
 
   /// The number of bytes that have been written to the buffer so far.  The
   /// most recently written byte is this many bytes from the end of [_buf].
-  int _tail;
+  int _tail = 0;
 
   /// The location of the end of the current table, measured in bytes from the
-  /// end of [_buf], or `null` if a table is not currently being built.
-  int _currentTableEndTail;
+  /// end of [_buf].
+  int _currentTableEndTail = 0;
 
-  _VTable _currentVTable;
+  _VTable? _currentVTable;
 
   /// Map containing all strings that have been written so far.  This allows us
   /// to avoid duplicating strings.
   ///
   /// Allocated only if `internStrings` is set to true on the constructor.
-  Map<String, int> _strings;
+  Map<String, int>? _strings;
 
   /// Creates a new FlatBuffers Builder.
   ///
@@ -142,18 +148,28 @@
   /// automatically grow the array if/as needed.  `internStrings`, if set to
   /// true, will cause [writeString] to pool strings in the buffer so that
   /// identical strings will always use the same offset in tables.
-  Builder({this.initialSize: 1024, bool internStrings = false}) {
-    if (internStrings == true) {
-      _strings = new Map<String, int>();
+  Builder({
+    this.initialSize = 1024,
+    bool internStrings = false,
+    Allocator allocator = const DefaultAllocator(),
+    this.deduplicateTables = true,
+  })  : _allocator = allocator,
+        _buf = allocator.allocate(initialSize),
+        _vTables = deduplicateTables ? [] : const [] {
+    if (internStrings) {
+      _strings = <String, int>{};
     }
-    reset();
   }
 
+  /// Calculate the finished buffer size (aligned).
+  @pragma('vm:prefer-inline')
+  int size() => _tail + ((-_tail) & (_maxAlign - 1));
+
   /// Add the [field] with the given boolean [value].  The field is not added if
   /// the [value] is equal to [def].  Booleans are stored as 8-bit fields with
   /// `0` for `false` and `1` for `true`.
-  void addBool(int field, bool value, [bool def]) {
-    _ensureCurrentVTable();
+  void addBool(int field, bool? value, [bool? def]) {
+    assert(_inVTable);
     if (value != null && value != def) {
       _prepare(_sizeofUint8, 1);
       _trackField(field);
@@ -163,180 +179,183 @@
 
   /// Add the [field] with the given 32-bit signed integer [value].  The field is
   /// not added if the [value] is equal to [def].
-  void addInt32(int field, int value, [int def]) {
-    _ensureCurrentVTable();
+  void addInt32(int field, int? value, [int? def]) {
+    assert(_inVTable);
     if (value != null && value != def) {
       _prepare(_sizeofInt32, 1);
       _trackField(field);
-      _setInt32AtTail(_buf, _tail, value);
+      _setInt32AtTail(_tail, value);
     }
   }
 
   /// Add the [field] with the given 32-bit signed integer [value].  The field is
   /// not added if the [value] is equal to [def].
-  void addInt16(int field, int value, [int def]) {
-    _ensureCurrentVTable();
+  void addInt16(int field, int? value, [int? def]) {
+    assert(_inVTable);
     if (value != null && value != def) {
       _prepare(_sizeofInt16, 1);
       _trackField(field);
-      _setInt16AtTail(_buf, _tail, value);
+      _setInt16AtTail(_tail, value);
     }
   }
 
   /// Add the [field] with the given 8-bit signed integer [value].  The field is
   /// not added if the [value] is equal to [def].
-  void addInt8(int field, int value, [int def]) {
-    _ensureCurrentVTable();
+  void addInt8(int field, int? value, [int? def]) {
+    assert(_inVTable);
     if (value != null && value != def) {
       _prepare(_sizeofInt8, 1);
       _trackField(field);
-      _setInt8AtTail(_buf, _tail, value);
+      _setInt8AtTail(_tail, value);
     }
   }
 
   void addStruct(int field, int offset) {
-    _ensureCurrentVTable();
+    assert(_inVTable);
     _trackField(field);
-    _currentVTable.addField(field, offset);
+    _currentVTable!.addField(field, offset);
   }
 
   /// Add the [field] referencing an object with the given [offset].
-  void addOffset(int field, int offset) {
-    _ensureCurrentVTable();
+  void addOffset(int field, int? offset) {
+    assert(_inVTable);
     if (offset != null) {
       _prepare(_sizeofUint32, 1);
       _trackField(field);
-      _setUint32AtTail(_buf, _tail, _tail - offset);
+      _setUint32AtTail(_tail, _tail - offset);
     }
   }
 
   /// Add the [field] with the given 32-bit unsigned integer [value].  The field
   /// is not added if the [value] is equal to [def].
-  void addUint32(int field, int value, [int def]) {
-    _ensureCurrentVTable();
+  void addUint32(int field, int? value, [int? def]) {
+    assert(_inVTable);
     if (value != null && value != def) {
       _prepare(_sizeofUint32, 1);
       _trackField(field);
-      _setUint32AtTail(_buf, _tail, value);
+      _setUint32AtTail(_tail, value);
     }
   }
 
   /// Add the [field] with the given 32-bit unsigned integer [value].  The field
   /// is not added if the [value] is equal to [def].
-  void addUint16(int field, int value, [int def]) {
-    _ensureCurrentVTable();
+  void addUint16(int field, int? value, [int? def]) {
+    assert(_inVTable);
     if (value != null && value != def) {
       _prepare(_sizeofUint16, 1);
       _trackField(field);
-      _setUint16AtTail(_buf, _tail, value);
+      _setUint16AtTail(_tail, value);
     }
   }
 
   /// Add the [field] with the given 8-bit unsigned integer [value].  The field
   /// is not added if the [value] is equal to [def].
-  void addUint8(int field, int value, [int def]) {
-    _ensureCurrentVTable();
+  void addUint8(int field, int? value, [int? def]) {
+    assert(_inVTable);
     if (value != null && value != def) {
       _prepare(_sizeofUint8, 1);
       _trackField(field);
-      _setUint8AtTail(_buf, _tail, value);
+      _setUint8AtTail(_tail, value);
     }
   }
 
   /// Add the [field] with the given 32-bit float [value].  The field
   /// is not added if the [value] is equal to [def].
-  void addFloat32(int field, double value, [double def]) {
-    _ensureCurrentVTable();
+  void addFloat32(int field, double? value, [double? def]) {
+    assert(_inVTable);
     if (value != null && value != def) {
       _prepare(_sizeofFloat32, 1);
       _trackField(field);
-      _setFloat32AtTail(_buf, _tail, value);
+      _setFloat32AtTail(_tail, value);
     }
   }
 
   /// Add the [field] with the given 64-bit double [value].  The field
   /// is not added if the [value] is equal to [def].
-  void addFloat64(int field, double value, [double def]) {
-    _ensureCurrentVTable();
+  void addFloat64(int field, double? value, [double? def]) {
+    assert(_inVTable);
     if (value != null && value != def) {
       _prepare(_sizeofFloat64, 1);
       _trackField(field);
-      _setFloat64AtTail(_buf, _tail, value);
+      _setFloat64AtTail(_tail, value);
     }
   }
 
   /// Add the [field] with the given 64-bit unsigned integer [value].  The field
   /// is not added if the [value] is equal to [def].
-  void addUint64(int field, int value, [double def]) {
-    _ensureCurrentVTable();
+  void addUint64(int field, int? value, [double? def]) {
+    assert(_inVTable);
     if (value != null && value != def) {
       _prepare(_sizeofUint64, 1);
       _trackField(field);
-      _setUint64AtTail(_buf, _tail, value);
+      _setUint64AtTail(_tail, value);
     }
   }
 
   /// Add the [field] with the given 64-bit unsigned integer [value].  The field
   /// is not added if the [value] is equal to [def].
-  void addInt64(int field, int value, [double def]) {
-    _ensureCurrentVTable();
+  void addInt64(int field, int? value, [double? def]) {
+    assert(_inVTable);
     if (value != null && value != def) {
       _prepare(_sizeofInt64, 1);
       _trackField(field);
-      _setInt64AtTail(_buf, _tail, value);
+      _setInt64AtTail(_tail, value);
     }
   }
 
   /// End the current table and return its offset.
   int endTable() {
-    if (_currentVTable == null) {
-      throw new StateError('Start a table before ending it.');
-    }
+    assert(_inVTable);
     // Prepare for writing the VTable.
     _prepare(_sizeofInt32, 1);
-    int tableTail = _tail;
+    var tableTail = _tail;
     // Prepare the size of the current table.
-    _currentVTable.tableSize = tableTail - _currentTableEndTail;
+    final currentVTable = _currentVTable!;
+    currentVTable.tableSize = tableTail - _currentTableEndTail;
     // Prepare the VTable to use for the current table.
-    int vTableTail;
+    int? vTableTail;
     {
-      _currentVTable.computeFieldOffsets(tableTail);
-      // Try to find an existing compatible VTable.
-      // Search backward - more likely to have recently used one
-      for (int i = _vTables.length - 1; i >= 0; i--) {
-        final int vt2Offset = _vTables[i];
-        final int vt2Start = _buf.lengthInBytes - vt2Offset;
-        final int vt2Size = _buf.getUint16(vt2Start, Endian.little);
+      currentVTable.computeFieldOffsets(tableTail);
 
-        if (_currentVTable._vTableSize == vt2Size &&
-            _currentVTable._offsetsMatch(vt2Start, _buf)) {
-          vTableTail = vt2Offset;
-          break;
+      // Try to find an existing compatible VTable.
+      if (deduplicateTables) {
+        // Search backward - more likely to have recently used one
+        for (var i = _vTables.length - 1; i >= 0; i--) {
+          final vt2Offset = _vTables[i];
+          final vt2Start = _buf.lengthInBytes - vt2Offset;
+          final vt2Size = _buf.getUint16(vt2Start, Endian.little);
+
+          if (currentVTable._vTableSize == vt2Size &&
+              currentVTable._offsetsMatch(vt2Start, _buf)) {
+            vTableTail = vt2Offset;
+            break;
+          }
         }
       }
+
       // Write a new VTable.
       if (vTableTail == null) {
-        _prepare(_sizeofUint16, _currentVTable.numOfUint16);
+        _prepare(_sizeofUint16, _currentVTable!.numOfUint16);
         vTableTail = _tail;
-        _currentVTable.tail = vTableTail;
-        _currentVTable.output(_buf, _buf.lengthInBytes - _tail);
-        _vTables.add(_currentVTable.tail);
+        currentVTable.tail = vTableTail;
+        currentVTable.output(_buf, _buf.lengthInBytes - _tail);
+        if (deduplicateTables) _vTables.add(currentVTable.tail);
       }
     }
     // Set the VTable offset.
-    _setInt32AtTail(_buf, tableTail, vTableTail - tableTail);
+    _setInt32AtTail(tableTail, vTableTail - tableTail);
     // Done with this table.
     _currentVTable = null;
     return tableTail;
   }
 
-  /// This method low level method can be used to return a raw piece of the buffer
-  /// after using the the put* methods.
-  ///
-  /// Most clients should prefer calling [finish].
-  Uint8List lowFinish() {
-    int alignedTail = _tail + ((-_tail) % _maxAlign);
-    return _buf.buffer.asUint8List(_buf.lengthInBytes - alignedTail);
+  /// Returns the finished buffer. You must call [finish] before accessing this.
+  @pragma('vm:prefer-inline')
+  Uint8List get buffer {
+    assert(_finished);
+    final finishedSize = size();
+    return _buf.buffer
+        .asUint8List(_buf.lengthInBytes - finishedSize, finishedSize);
   }
 
   /// Finish off the creation of the buffer.  The given [offset] is used as the
@@ -344,17 +363,26 @@
   /// written object.  If [fileIdentifier] is specified (and not `null`), it is
   /// interpreted as a 4-byte Latin-1 encoded string that should be placed at
   /// bytes 4-7 of the file.
-  Uint8List finish(int offset, [String fileIdentifier]) {
-    _prepare(max(_sizeofUint32, _maxAlign), fileIdentifier == null ? 1 : 2);
-    int alignedTail = _tail + ((-_tail) % _maxAlign);
-    _setUint32AtTail(_buf, alignedTail, alignedTail - offset);
+  void finish(int offset, [String? fileIdentifier]) {
+    final sizeBeforePadding = size();
+    final requiredBytes = _sizeofUint32 * (fileIdentifier == null ? 1 : 2);
+    _prepare(max(requiredBytes, _maxAlign), 1);
+    final finishedSize = size();
+    _setUint32AtTail(finishedSize, finishedSize - offset);
     if (fileIdentifier != null) {
-      for (int i = 0; i < 4; i++) {
-        _setUint8AtTail(_buf, alignedTail - _sizeofUint32 - i,
-            fileIdentifier.codeUnitAt(i));
+      for (var i = 0; i < 4; i++) {
+        _setUint8AtTail(
+            finishedSize - _sizeofUint32 - i, fileIdentifier.codeUnitAt(i));
       }
     }
-    return _buf.buffer.asUint8List(_buf.lengthInBytes - alignedTail);
+
+    // zero out the added padding
+    for (var i = sizeBeforePadding + 1;
+        i <= finishedSize - requiredBytes;
+        i++) {
+      _setUint8AtTail(i, 0);
+    }
+    _finished = true;
   }
 
   /// Writes a Float64 to the tail of the buffer after preparing space for it.
@@ -362,7 +390,7 @@
   /// Updates the [offset] pointer.  This method is intended for use when writing structs to the buffer.
   void putFloat64(double value) {
     _prepare(_sizeofFloat64, 1);
-    _setFloat32AtTail(_buf, _tail, value);
+    _setFloat32AtTail(_tail, value);
   }
 
   /// Writes a Float32 to the tail of the buffer after preparing space for it.
@@ -370,7 +398,7 @@
   /// Updates the [offset] pointer.  This method is intended for use when writing structs to the buffer.
   void putFloat32(double value) {
     _prepare(_sizeofFloat32, 1);
-    _setFloat32AtTail(_buf, _tail, value);
+    _setFloat32AtTail(_tail, value);
   }
 
   /// Writes a Int64 to the tail of the buffer after preparing space for it.
@@ -378,7 +406,7 @@
   /// Updates the [offset] pointer.  This method is intended for use when writing structs to the buffer.
   void putInt64(int value) {
     _prepare(_sizeofInt64, 1);
-    _setInt64AtTail(_buf, _tail, value);
+    _setInt64AtTail(_tail, value);
   }
 
   /// Writes a Uint32 to the tail of the buffer after preparing space for it.
@@ -386,7 +414,7 @@
   /// Updates the [offset] pointer.  This method is intended for use when writing structs to the buffer.
   void putInt32(int value) {
     _prepare(_sizeofInt32, 1);
-    _setInt32AtTail(_buf, _tail, value);
+    _setInt32AtTail(_tail, value);
   }
 
   /// Writes a Uint16 to the tail of the buffer after preparing space for it.
@@ -394,7 +422,7 @@
   /// Updates the [offset] pointer.  This method is intended for use when writing structs to the buffer.
   void putInt16(int value) {
     _prepare(_sizeofInt16, 1);
-    _setInt16AtTail(_buf, _tail, value);
+    _setInt16AtTail(_tail, value);
   }
 
   /// Writes a Uint8 to the tail of the buffer after preparing space for it.
@@ -410,7 +438,7 @@
   /// Updates the [offset] pointer.  This method is intended for use when writing structs to the buffer.
   void putUint64(int value) {
     _prepare(_sizeofUint64, 1);
-    _setUint64AtTail(_buf, _tail, value);
+    _setUint64AtTail(_tail, value);
   }
 
   /// Writes a Uint32 to the tail of the buffer after preparing space for it.
@@ -418,7 +446,7 @@
   /// Updates the [offset] pointer.  This method is intended for use when writing structs to the buffer.
   void putUint32(int value) {
     _prepare(_sizeofUint32, 1);
-    _setUint32AtTail(_buf, _tail, value);
+    _setUint32AtTail(_tail, value);
   }
 
   /// Writes a Uint16 to the tail of the buffer after preparing space for it.
@@ -426,7 +454,7 @@
   /// Updates the [offset] pointer.  This method is intended for use when writing structs to the buffer.
   void putUint16(int value) {
     _prepare(_sizeofUint16, 1);
-    _setUint16AtTail(_buf, _tail, value);
+    _setUint16AtTail(_tail, value);
   }
 
   /// Writes a Uint8 to the tail of the buffer after preparing space for it.
@@ -439,21 +467,20 @@
 
   /// Reset the builder and make it ready for filling a new buffer.
   void reset() {
-    _buf = new ByteData(initialSize);
+    _finished = false;
     _maxAlign = 1;
     _tail = 0;
     _currentVTable = null;
+    if (deduplicateTables) _vTables.clear();
     if (_strings != null) {
-      _strings = new Map<String, int>();
+      _strings = <String, int>{};
     }
   }
 
-  /// Start a new table.  Must be finished with [endTable] invocation.
-  void startTable() {
-    if (_currentVTable != null) {
-      throw new StateError('Inline tables are not supported.');
-    }
-    _currentVTable = new _VTable();
+  /// Start a new table. Must be finished with [endTable] invocation.
+  void startTable(int numFields) {
+    assert(!_inVTable); // Inline tables are not supported.
+    _currentVTable = _VTable(numFields);
     _currentTableEndTail = _tail;
   }
 
@@ -467,8 +494,8 @@
 
   /// Writes a list of Structs to the buffer, returning the offset
   int writeListOfStructs(List<ObjectBuilder> structBuilders) {
-    _ensureNoVTable();
-    for (int i = structBuilders.length - 1; i >= 0; i--) {
+    assert(!_inVTable);
+    for (var i = structBuilders.length - 1; i >= 0; i--) {
       structBuilders[i].finish(this);
     }
     return endStructVector(structBuilders.length);
@@ -476,14 +503,14 @@
 
   /// Write the given list of [values].
   int writeList(List<int> values) {
-    _ensureNoVTable();
+    assert(!_inVTable);
     _prepare(_sizeofUint32, 1 + values.length);
-    final int result = _tail;
-    int tail = _tail;
-    _setUint32AtTail(_buf, tail, values.length);
+    final result = _tail;
+    var tail = _tail;
+    _setUint32AtTail(tail, values.length);
     tail -= _sizeofUint32;
-    for (int value in values) {
-      _setUint32AtTail(_buf, tail, tail - value);
+    for (var value in values) {
+      _setUint32AtTail(tail, tail - value);
       tail -= _sizeofUint32;
     }
     return result;
@@ -491,14 +518,14 @@
 
   /// Write the given list of 64-bit float [values].
   int writeListFloat64(List<double> values) {
-    _ensureNoVTable();
+    assert(!_inVTable);
     _prepare(_sizeofFloat64, values.length, additionalBytes: _sizeofUint32);
-    final int result = _tail;
-    int tail = _tail;
-    _setUint32AtTail(_buf, tail, values.length);
+    final result = _tail;
+    var tail = _tail;
+    _setUint32AtTail(tail, values.length);
     tail -= _sizeofUint32;
-    for (double value in values) {
-      _setFloat64AtTail(_buf, tail, value);
+    for (var value in values) {
+      _setFloat64AtTail(tail, value);
       tail -= _sizeofFloat64;
     }
     return result;
@@ -506,14 +533,14 @@
 
   /// Write the given list of 32-bit float [values].
   int writeListFloat32(List<double> values) {
-    _ensureNoVTable();
+    assert(!_inVTable);
     _prepare(_sizeofFloat32, 1 + values.length);
-    final int result = _tail;
-    int tail = _tail;
-    _setUint32AtTail(_buf, tail, values.length);
+    final result = _tail;
+    var tail = _tail;
+    _setUint32AtTail(tail, values.length);
     tail -= _sizeofUint32;
-    for (double value in values) {
-      _setFloat32AtTail(_buf, tail, value);
+    for (var value in values) {
+      _setFloat32AtTail(tail, value);
       tail -= _sizeofFloat32;
     }
     return result;
@@ -521,14 +548,14 @@
 
   /// Write the given list of signed 64-bit integer [values].
   int writeListInt64(List<int> values) {
-    _ensureNoVTable();
+    assert(!_inVTable);
     _prepare(_sizeofInt64, values.length, additionalBytes: _sizeofUint32);
-    final int result = _tail;
-    int tail = _tail;
-    _setUint32AtTail(_buf, tail, values.length);
+    final result = _tail;
+    var tail = _tail;
+    _setUint32AtTail(tail, values.length);
     tail -= _sizeofUint32;
-    for (int value in values) {
-      _setInt64AtTail(_buf, tail, value);
+    for (var value in values) {
+      _setInt64AtTail(tail, value);
       tail -= _sizeofInt64;
     }
     return result;
@@ -536,14 +563,14 @@
 
   /// Write the given list of signed 64-bit integer [values].
   int writeListUint64(List<int> values) {
-    _ensureNoVTable();
+    assert(!_inVTable);
     _prepare(_sizeofUint64, values.length, additionalBytes: _sizeofUint32);
-    final int result = _tail;
-    int tail = _tail;
-    _setUint32AtTail(_buf, tail, values.length);
+    final result = _tail;
+    var tail = _tail;
+    _setUint32AtTail(tail, values.length);
     tail -= _sizeofUint32;
-    for (int value in values) {
-      _setUint64AtTail(_buf, tail, value);
+    for (var value in values) {
+      _setUint64AtTail(tail, value);
       tail -= _sizeofUint64;
     }
     return result;
@@ -551,14 +578,14 @@
 
   /// Write the given list of signed 32-bit integer [values].
   int writeListInt32(List<int> values) {
-    _ensureNoVTable();
+    assert(!_inVTable);
     _prepare(_sizeofUint32, 1 + values.length);
-    final int result = _tail;
-    int tail = _tail;
-    _setUint32AtTail(_buf, tail, values.length);
+    final result = _tail;
+    var tail = _tail;
+    _setUint32AtTail(tail, values.length);
     tail -= _sizeofUint32;
-    for (int value in values) {
-      _setInt32AtTail(_buf, tail, value);
+    for (var value in values) {
+      _setInt32AtTail(tail, value);
       tail -= _sizeofInt32;
     }
     return result;
@@ -566,14 +593,14 @@
 
   /// Write the given list of unsigned 32-bit integer [values].
   int writeListUint32(List<int> values) {
-    _ensureNoVTable();
+    assert(!_inVTable);
     _prepare(_sizeofUint32, 1 + values.length);
-    final int result = _tail;
-    int tail = _tail;
-    _setUint32AtTail(_buf, tail, values.length);
+    final result = _tail;
+    var tail = _tail;
+    _setUint32AtTail(tail, values.length);
     tail -= _sizeofUint32;
-    for (int value in values) {
-      _setUint32AtTail(_buf, tail, value);
+    for (var value in values) {
+      _setUint32AtTail(tail, value);
       tail -= _sizeofUint32;
     }
     return result;
@@ -581,14 +608,14 @@
 
   /// Write the given list of signed 16-bit integer [values].
   int writeListInt16(List<int> values) {
-    _ensureNoVTable();
+    assert(!_inVTable);
     _prepare(_sizeofUint32, 1, additionalBytes: 2 * values.length);
-    final int result = _tail;
-    int tail = _tail;
-    _setUint32AtTail(_buf, tail, values.length);
+    final result = _tail;
+    var tail = _tail;
+    _setUint32AtTail(tail, values.length);
     tail -= _sizeofUint32;
-    for (int value in values) {
-      _setInt16AtTail(_buf, tail, value);
+    for (var value in values) {
+      _setInt16AtTail(tail, value);
       tail -= _sizeofInt16;
     }
     return result;
@@ -596,14 +623,14 @@
 
   /// Write the given list of unsigned 16-bit integer [values].
   int writeListUint16(List<int> values) {
-    _ensureNoVTable();
+    assert(!_inVTable);
     _prepare(_sizeofUint32, 1, additionalBytes: 2 * values.length);
-    final int result = _tail;
-    int tail = _tail;
-    _setUint32AtTail(_buf, tail, values.length);
+    final result = _tail;
+    var tail = _tail;
+    _setUint32AtTail(tail, values.length);
     tail -= _sizeofUint32;
-    for (int value in values) {
-      _setUint16AtTail(_buf, tail, value);
+    for (var value in values) {
+      _setUint16AtTail(tail, value);
       tail -= _sizeofUint16;
     }
     return result;
@@ -611,19 +638,19 @@
 
   /// Write the given list of bools as unsigend 8-bit integer [values].
   int writeListBool(List<bool> values) {
-    return writeListUint8(values?.map((b) => b ? 1 : 0)?.toList());
+    return writeListUint8(values.map((b) => b ? 1 : 0).toList());
   }
 
   /// Write the given list of signed 8-bit integer [values].
   int writeListInt8(List<int> values) {
-    _ensureNoVTable();
+    assert(!_inVTable);
     _prepare(_sizeofUint32, 1, additionalBytes: values.length);
-    final int result = _tail;
-    int tail = _tail;
-    _setUint32AtTail(_buf, tail, values.length);
+    final result = _tail;
+    var tail = _tail;
+    _setUint32AtTail(tail, values.length);
     tail -= _sizeofUint32;
-    for (int value in values) {
-      _setInt8AtTail(_buf, tail, value);
+    for (var value in values) {
+      _setInt8AtTail(tail, value);
       tail -= _sizeofUint8;
     }
     return result;
@@ -631,146 +658,187 @@
 
   /// Write the given list of unsigned 8-bit integer [values].
   int writeListUint8(List<int> values) {
-    _ensureNoVTable();
+    assert(!_inVTable);
     _prepare(_sizeofUint32, 1, additionalBytes: values.length);
-    final int result = _tail;
-    int tail = _tail;
-    _setUint32AtTail(_buf, tail, values.length);
+    final result = _tail;
+    var tail = _tail;
+    _setUint32AtTail(tail, values.length);
     tail -= _sizeofUint32;
-    for (int value in values) {
-      _setUint8AtTail(_buf, tail, value);
+    for (var value in values) {
+      _setUint8AtTail(tail, value);
       tail -= _sizeofUint8;
     }
     return result;
   }
 
-  /// Write the given string [value] and return its offset, or `null` if
-  /// the [value] is `null`.
-  int writeString(String value) {
-    _ensureNoVTable();
-    if (value != null) {
-      if (_strings != null) {
-        return _strings.putIfAbsent(value, () => _writeString(value));
-      } else {
-        return _writeString(value);
-      }
+  /// Write the given string [value] and return its offset.
+  ///
+  /// Dart strings are UTF-16 but must be stored as UTF-8 in FlatBuffers.
+  /// If the given string consists only of ASCII characters, you can indicate
+  /// enable [asciiOptimization]. In this mode, [writeString()] first tries to
+  /// copy the ASCII string directly to the output buffer and if that fails
+  /// (because there are no-ASCII characters in the string) it falls back and to
+  /// the default UTF-16 -> UTF-8 conversion (with slight performance penalty).
+  int writeString(String value, {bool asciiOptimization = false}) {
+    assert(!_inVTable);
+    if (_strings != null) {
+      return _strings!
+          .putIfAbsent(value, () => _writeString(value, asciiOptimization));
+    } else {
+      return _writeString(value, asciiOptimization);
     }
-    return null;
   }
 
-  int _writeString(String value) {
-    // TODO(scheglov) optimize for ASCII strings
-    List<int> bytes = utf8.encode(value);
-    int length = bytes.length;
+  int _writeString(String value, bool asciiOptimization) {
+    if (asciiOptimization) {
+      // [utf8.encode()] is slow (up to at least Dart SDK 2.13). If the given
+      // string is ASCII we can just write it directly, without any conversion.
+      final originalTail = _tail;
+      if (_tryWriteASCIIString(value)) return _tail;
+      // if non-ASCII: reset the output buffer position for [_writeUTFString()]
+      _tail = originalTail;
+    }
+    _writeUTFString(value);
+    return _tail;
+  }
+
+  // Try to write the string as ASCII, return false if there's a non-ascii char.
+  @pragma('vm:prefer-inline')
+  bool _tryWriteASCIIString(String value) {
+    _prepare(4, 1, additionalBytes: value.length + 1);
+    final length = value.length;
+    var offset = _buf.lengthInBytes - _tail + 4;
+    for (var i = 0; i < length; i++) {
+      // utf16 code unit, e.g. for '†' it's [0x20 0x20], which is 8224 decimal.
+      // ASCII characters go from 0x00 to 0x7F (which is 0 to 127 decimal).
+      final char = value.codeUnitAt(i);
+      if ((char & ~0x7F) != 0) {
+        return false;
+      }
+      _buf.setUint8(offset++, char);
+    }
+    _buf.setUint8(offset, 0); // trailing zero
+    _setUint32AtTail(_tail, value.length);
+    return true;
+  }
+
+  @pragma('vm:prefer-inline')
+  void _writeUTFString(String value) {
+    final bytes = utf8.encode(value) as Uint8List;
+    final length = bytes.length;
     _prepare(4, 1, additionalBytes: length + 1);
-    final int result = _tail;
-    _setUint32AtTail(_buf, _tail, length);
-    int offset = _buf.lengthInBytes - _tail + 4;
-    for (int i = 0; i < length; i++) {
+    _setUint32AtTail(_tail, length);
+    var offset = _buf.lengthInBytes - _tail + 4;
+    for (var i = 0; i < length; i++) {
       _buf.setUint8(offset++, bytes[i]);
     }
-    return result;
+    _buf.setUint8(offset, 0); // trailing zero
   }
 
-  /// Throw an exception if there is not currently a vtable.
-  void _ensureCurrentVTable() {
-    if (_currentVTable == null) {
-      throw new StateError('Start a table before adding values.');
-    }
-  }
-
-  /// Throw an exception if there is currently a vtable.
-  void _ensureNoVTable() {
-    if (_currentVTable != null) {
-      throw new StateError(
-          'Cannot write a non-scalar value while writing a table.');
-    }
-  }
+  /// Used to assert whether a "Table" is currently being built.
+  ///
+  /// If you hit `assert(!_inVTable())`, you're trying to add table fields
+  /// without starting a table with [Builder.startTable()].
+  ///
+  /// If you hit `assert(_inVTable())`, you're trying to construct a
+  /// Table/Vector/String during the construction of its parent table,
+  /// between the MyTableBuilder and [Builder.endTable()].
+  /// Move the creation of these sub-objects to before the MyTableBuilder to
+  /// not get this assert.
+  @pragma('vm:prefer-inline')
+  bool get _inVTable => _currentVTable != null;
 
   /// The number of bytes that have been written to the buffer so far.  The
   /// most recently written byte is this many bytes from the end of the buffer.
+  @pragma('vm:prefer-inline')
   int get offset => _tail;
 
   /// Zero-pads the buffer, which may be required for some struct layouts.
+  @pragma('vm:prefer-inline')
   void pad(int howManyBytes) {
-    for (int i = 0; i < howManyBytes; i++) putUint8(0);
+    for (var i = 0; i < howManyBytes; i++) {
+      putUint8(0);
+    }
   }
 
   /// Prepare for writing the given `count` of scalars of the given `size`.
   /// Additionally allocate the specified `additionalBytes`. Update the current
   /// tail pointer to point at the allocated space.
+  @pragma('vm:prefer-inline')
   void _prepare(int size, int count, {int additionalBytes = 0}) {
+    assert(!_finished);
     // Update the alignment.
     if (_maxAlign < size) {
       _maxAlign = size;
     }
     // Prepare amount of required space.
-    int dataSize = size * count + additionalBytes;
-    int alignDelta = (-(_tail + dataSize)) % size;
-    int bufSize = alignDelta + dataSize;
+    var dataSize = size * count + additionalBytes;
+    var alignDelta = (-(_tail + dataSize)) & (size - 1);
+    var bufSize = alignDelta + dataSize;
     // Ensure that we have the required amount of space.
     {
-      int oldCapacity = _buf.lengthInBytes;
+      var oldCapacity = _buf.lengthInBytes;
       if (_tail + bufSize > oldCapacity) {
-        int desiredNewCapacity = (oldCapacity + bufSize) * 2;
-        int deltaCapacity = desiredNewCapacity - oldCapacity;
-        deltaCapacity += (-deltaCapacity) % _maxAlign;
-        int newCapacity = oldCapacity + deltaCapacity;
-        ByteData newBuf = new ByteData(newCapacity);
-        newBuf.buffer
-            .asUint8List()
-            .setAll(deltaCapacity, _buf.buffer.asUint8List());
-        _buf = newBuf;
+        var desiredNewCapacity = (oldCapacity + bufSize) * 2;
+        var deltaCapacity = desiredNewCapacity - oldCapacity;
+        deltaCapacity += (-deltaCapacity) & (_maxAlign - 1);
+        var newCapacity = oldCapacity + deltaCapacity;
+        _buf = _allocator.resize(_buf, newCapacity, _tail, 0);
       }
     }
+
+    // zero out the added padding
+    for (var i = _tail + 1; i <= _tail + alignDelta; i++) {
+      _setUint8AtTail(i, 0);
+    }
+
     // Update the tail pointer.
     _tail += bufSize;
   }
 
   /// Record the offset of the given [field].
-  void _trackField(int field) {
-    _currentVTable.addField(field, _tail);
-  }
+  @pragma('vm:prefer-inline')
+  void _trackField(int field) => _currentVTable!.addField(field, _tail);
 
-  static void _setFloat64AtTail(ByteData _buf, int tail, double x) {
-    _buf.setFloat64(_buf.lengthInBytes - tail, x, Endian.little);
-  }
+  @pragma('vm:prefer-inline')
+  void _setFloat64AtTail(int tail, double x) =>
+      _buf.setFloat64(_buf.lengthInBytes - tail, x, Endian.little);
 
-  static void _setFloat32AtTail(ByteData _buf, int tail, double x) {
-    _buf.setFloat32(_buf.lengthInBytes - tail, x, Endian.little);
-  }
+  @pragma('vm:prefer-inline')
+  void _setFloat32AtTail(int tail, double x) =>
+      _buf.setFloat32(_buf.lengthInBytes - tail, x, Endian.little);
 
-  static void _setUint64AtTail(ByteData _buf, int tail, int x) {
-    _buf.setUint64(_buf.lengthInBytes - tail, x, Endian.little);
-  }
+  @pragma('vm:prefer-inline')
+  void _setUint64AtTail(int tail, int x) =>
+      _buf.setUint64(_buf.lengthInBytes - tail, x, Endian.little);
 
-  static void _setInt64AtTail(ByteData _buf, int tail, int x) {
-    _buf.setInt64(_buf.lengthInBytes - tail, x, Endian.little);
-  }
+  @pragma('vm:prefer-inline')
+  void _setInt64AtTail(int tail, int x) =>
+      _buf.setInt64(_buf.lengthInBytes - tail, x, Endian.little);
 
-  static void _setInt32AtTail(ByteData _buf, int tail, int x) {
-    _buf.setInt32(_buf.lengthInBytes - tail, x, Endian.little);
-  }
+  @pragma('vm:prefer-inline')
+  void _setInt32AtTail(int tail, int x) =>
+      _buf.setInt32(_buf.lengthInBytes - tail, x, Endian.little);
 
-  static void _setUint32AtTail(ByteData _buf, int tail, int x) {
-    _buf.setUint32(_buf.lengthInBytes - tail, x, Endian.little);
-  }
+  @pragma('vm:prefer-inline')
+  void _setUint32AtTail(int tail, int x) =>
+      _buf.setUint32(_buf.lengthInBytes - tail, x, Endian.little);
 
-  static void _setInt16AtTail(ByteData _buf, int tail, int x) {
-    _buf.setInt16(_buf.lengthInBytes - tail, x, Endian.little);
-  }
+  @pragma('vm:prefer-inline')
+  void _setInt16AtTail(int tail, int x) =>
+      _buf.setInt16(_buf.lengthInBytes - tail, x, Endian.little);
 
-  static void _setUint16AtTail(ByteData _buf, int tail, int x) {
-    _buf.setUint16(_buf.lengthInBytes - tail, x, Endian.little);
-  }
+  @pragma('vm:prefer-inline')
+  void _setUint16AtTail(int tail, int x) =>
+      _buf.setUint16(_buf.lengthInBytes - tail, x, Endian.little);
 
-  static void _setInt8AtTail(ByteData _buf, int tail, int x) {
-    _buf.setInt8(_buf.lengthInBytes - tail, x);
-  }
+  @pragma('vm:prefer-inline')
+  void _setInt8AtTail(int tail, int x) =>
+      _buf.setInt8(_buf.lengthInBytes - tail, x);
 
-  static void _setUint8AtTail(ByteData _buf, int tail, int x) {
-    _buf.setUint8(_buf.lengthInBytes - tail, x);
-  }
+  @pragma('vm:prefer-inline')
+  void _setUint8AtTail(int tail, int x) =>
+      _buf.setUint8(_buf.lengthInBytes - tail, x);
 }
 
 /// Reader of lists of boolean values.
@@ -780,11 +848,13 @@
   const BoolListReader();
 
   @override
+  @pragma('vm:prefer-inline')
   int get size => _sizeofUint32;
 
   @override
+  @pragma('vm:prefer-inline')
   List<bool> read(BufferContext bc, int offset) =>
-      new _FbBoolList(bc, bc.derefObject(offset));
+      _FbBoolList(bc, bc.derefObject(offset));
 }
 
 /// The reader of booleans.
@@ -792,9 +862,11 @@
   const BoolReader() : super();
 
   @override
+  @pragma('vm:prefer-inline')
   int get size => _sizeofUint8;
 
   @override
+  @pragma('vm:prefer-inline')
   bool read(BufferContext bc, int offset) => bc._getInt8(offset) != 0;
 }
 
@@ -805,31 +877,37 @@
   const Float64ListReader();
 
   @override
+  @pragma('vm:prefer-inline')
   int get size => _sizeofFloat64;
 
   @override
+  @pragma('vm:prefer-inline')
   List<double> read(BufferContext bc, int offset) =>
-      new _FbFloat64List(bc, bc.derefObject(offset));
+      _FbFloat64List(bc, bc.derefObject(offset));
 }
 
 class Float32ListReader extends Reader<List<double>> {
   const Float32ListReader();
 
   @override
+  @pragma('vm:prefer-inline')
   int get size => _sizeofFloat32;
 
   @override
+  @pragma('vm:prefer-inline')
   List<double> read(BufferContext bc, int offset) =>
-      new _FbFloat32List(bc, bc.derefObject(offset));
+      _FbFloat32List(bc, bc.derefObject(offset));
 }
 
 class Float64Reader extends Reader<double> {
   const Float64Reader();
 
   @override
+  @pragma('vm:prefer-inline')
   int get size => _sizeofFloat64;
 
   @override
+  @pragma('vm:prefer-inline')
   double read(BufferContext bc, int offset) => bc._getFloat64(offset);
 }
 
@@ -837,18 +915,23 @@
   const Float32Reader();
 
   @override
+  @pragma('vm:prefer-inline')
   int get size => _sizeofFloat32;
 
   @override
+  @pragma('vm:prefer-inline')
   double read(BufferContext bc, int offset) => bc._getFloat32(offset);
 }
 
 class Int64Reader extends Reader<int> {
   const Int64Reader() : super();
+
   @override
+  @pragma('vm:prefer-inline')
   int get size => _sizeofInt64;
 
   @override
+  @pragma('vm:prefer-inline')
   int read(BufferContext bc, int offset) => bc._getInt64(offset);
 }
 
@@ -857,9 +940,11 @@
   const Int32Reader() : super();
 
   @override
+  @pragma('vm:prefer-inline')
   int get size => _sizeofInt32;
 
   @override
+  @pragma('vm:prefer-inline')
   int read(BufferContext bc, int offset) => bc._getInt32(offset);
 }
 
@@ -868,9 +953,11 @@
   const Int16Reader() : super();
 
   @override
+  @pragma('vm:prefer-inline')
   int get size => _sizeofInt16;
 
   @override
+  @pragma('vm:prefer-inline')
   int read(BufferContext bc, int offset) => bc._getInt16(offset);
 }
 
@@ -879,26 +966,43 @@
   const Int8Reader() : super();
 
   @override
+  @pragma('vm:prefer-inline')
   int get size => _sizeofInt8;
 
   @override
+  @pragma('vm:prefer-inline')
   int read(BufferContext bc, int offset) => bc._getInt8(offset);
 }
 
-/// The reader of lists of objects.
-///
-/// The returned unmodifiable lists lazily read objects on access.
+/// The reader of lists of objects. Lazy by default - see [lazy].
 class ListReader<E> extends Reader<List<E>> {
   final Reader<E> _elementReader;
 
-  const ListReader(this._elementReader);
+  /// Enables lazy reading of the list
+  ///
+  /// If true, the returned unmodifiable list lazily reads objects on access.
+  /// Therefore, the underlying buffer must not change while accessing the list.
+  ///
+  /// If false, reads the whole list immediately on access.
+  final bool lazy;
+
+  const ListReader(this._elementReader, {this.lazy = true});
 
   @override
+  @pragma('vm:prefer-inline')
   int get size => _sizeofUint32;
 
   @override
-  List<E> read(BufferContext bc, int offset) =>
-      new _FbGenericList<E>(_elementReader, bc, bc.derefObject(offset));
+  List<E> read(BufferContext bc, int offset) {
+    final listOffset = bc.derefObject(offset);
+    return lazy
+        ? _FbGenericList<E>(_elementReader, bc, listOffset)
+        : List<E>.generate(
+            bc.buffer.getUint32(listOffset, Endian.little),
+            (int index) => _elementReader.read(
+                bc, listOffset + size + _elementReader.size * index),
+            growable: true);
+  }
 }
 
 /// Object that can read a value at a [BufferContext].
@@ -912,43 +1016,55 @@
   T read(BufferContext bc, int offset);
 
   /// Read the value of the given [field] in the given [object].
-  T vTableGet(BufferContext object, int offset, int field, [T defaultValue]) {
-    int vTableSOffset = object._getInt32(offset);
-    int vTableOffset = offset - vTableSOffset;
-    int vTableSize = object._getUint16(vTableOffset);
-    int vTableFieldOffset = field;
-    if (vTableFieldOffset < vTableSize) {
-      int fieldOffsetInObject =
-          object._getUint16(vTableOffset + vTableFieldOffset);
-      if (fieldOffsetInObject != 0) {
-        return read(object, offset + fieldOffsetInObject);
-      }
-    }
-    return defaultValue;
+  @pragma('vm:prefer-inline')
+  T vTableGet(BufferContext object, int offset, int field, T defaultValue) {
+    var fieldOffset = _vTableFieldOffset(object, offset, field);
+    return fieldOffset == 0 ? defaultValue : read(object, offset + fieldOffset);
+  }
+
+  /// Read the value of the given [field] in the given [object].
+  @pragma('vm:prefer-inline')
+  T? vTableGetNullable(BufferContext object, int offset, int field) {
+    var fieldOffset = _vTableFieldOffset(object, offset, field);
+    return fieldOffset == 0 ? null : read(object, offset + fieldOffset);
+  }
+
+  @pragma('vm:prefer-inline')
+  int _vTableFieldOffset(BufferContext object, int offset, int field) {
+    var vTableSOffset = object._getInt32(offset);
+    var vTableOffset = offset - vTableSOffset;
+    var vTableSize = object._getUint16(vTableOffset);
+    if (field >= vTableSize) return 0;
+    return object._getUint16(vTableOffset + field);
   }
 }
 
 /// The reader of string values.
 class StringReader extends Reader<String> {
-  const StringReader() : super();
+  final bool asciiOptimization;
+
+  const StringReader({this.asciiOptimization = false}) : super();
 
   @override
-  int get size => 4;
+  @pragma('vm:prefer-inline')
+  int get size => _sizeofUint32;
 
   @override
+  @pragma('vm:prefer-inline')
   String read(BufferContext bc, int offset) {
-    int strOffset = bc.derefObject(offset);
-    int length = bc._getUint32(strOffset);
-    Uint8List bytes = bc._asUint8LIst(strOffset + 4, length);
-    if (_isLatin(bytes)) {
-      return new String.fromCharCodes(bytes);
+    var strOffset = bc.derefObject(offset);
+    var length = bc._getUint32(strOffset);
+    var bytes = bc._asUint8List(strOffset + _sizeofUint32, length);
+    if (asciiOptimization && _isLatin(bytes)) {
+      return String.fromCharCodes(bytes);
     }
     return utf8.decode(bytes);
   }
 
+  @pragma('vm:prefer-inline')
   static bool _isLatin(Uint8List bytes) {
-    int length = bytes.length;
-    for (int i = 0; i < length; i++) {
+    var length = bytes.length;
+    for (var i = 0; i < length; i++) {
       if (bytes[i] > 127) {
         return false;
       }
@@ -964,8 +1080,9 @@
   /// Return the object at `offset`.
   T createObject(BufferContext bc, int offset);
 
-  T read(BufferContext bp, int offset) {
-    return createObject(bp, offset);
+  @override
+  T read(BufferContext bc, int offset) {
+    return createObject(bc, offset);
   }
 }
 
@@ -974,15 +1091,16 @@
   const TableReader();
 
   @override
+  @pragma('vm:prefer-inline')
   int get size => 4;
 
   /// Return the object at [offset].
   T createObject(BufferContext bc, int offset);
 
   @override
-  T read(BufferContext bp, int offset) {
-    int objectOffset = bp.derefObject(offset);
-    return createObject(bp, objectOffset);
+  T read(BufferContext bc, int offset) {
+    var objectOffset = bc.derefObject(offset);
+    return createObject(bc, objectOffset);
   }
 }
 
@@ -993,11 +1111,13 @@
   const Uint32ListReader();
 
   @override
+  @pragma('vm:prefer-inline')
   int get size => _sizeofUint32;
 
   @override
+  @pragma('vm:prefer-inline')
   List<int> read(BufferContext bc, int offset) =>
-      new _FbUint32List(bc, bc.derefObject(offset));
+      _FbUint32List(bc, bc.derefObject(offset));
 }
 
 /// The reader of unsigned 64-bit integers.
@@ -1007,9 +1127,11 @@
   const Uint64Reader() : super();
 
   @override
+  @pragma('vm:prefer-inline')
   int get size => _sizeofUint64;
 
   @override
+  @pragma('vm:prefer-inline')
   int read(BufferContext bc, int offset) => bc._getUint64(offset);
 }
 
@@ -1018,9 +1140,11 @@
   const Uint32Reader() : super();
 
   @override
+  @pragma('vm:prefer-inline')
   int get size => _sizeofUint32;
 
   @override
+  @pragma('vm:prefer-inline')
   int read(BufferContext bc, int offset) => bc._getUint32(offset);
 }
 
@@ -1031,11 +1155,13 @@
   const Uint16ListReader();
 
   @override
+  @pragma('vm:prefer-inline')
   int get size => _sizeofUint32;
 
   @override
+  @pragma('vm:prefer-inline')
   List<int> read(BufferContext bc, int offset) =>
-      new _FbUint16List(bc, bc.derefObject(offset));
+      _FbUint16List(bc, bc.derefObject(offset));
 }
 
 /// The reader of unsigned 32-bit integers.
@@ -1043,24 +1169,44 @@
   const Uint16Reader() : super();
 
   @override
+  @pragma('vm:prefer-inline')
   int get size => _sizeofUint16;
 
   @override
+  @pragma('vm:prefer-inline')
   int read(BufferContext bc, int offset) => bc._getUint16(offset);
 }
 
-/// Reader of lists of unsigned 8-bit integer values.
-///
-/// The returned unmodifiable lists lazily read values on access.
+/// Reader of unmodifiable binary data (a list of unsigned 8-bit integers).
 class Uint8ListReader extends Reader<List<int>> {
-  const Uint8ListReader();
+  /// Enables lazy reading of the list
+  ///
+  /// If true, the returned unmodifiable list lazily reads bytes on access.
+  /// Therefore, the underlying buffer must not change while accessing the list.
+  ///
+  /// If false, reads the whole list immediately as an Uint8List.
+  final bool lazy;
+
+  const Uint8ListReader({this.lazy = true});
 
   @override
+  @pragma('vm:prefer-inline')
   int get size => _sizeofUint32;
 
   @override
-  List<int> read(BufferContext bc, int offset) =>
-      new _FbUint8List(bc, bc.derefObject(offset));
+  @pragma('vm:prefer-inline')
+  List<int> read(BufferContext bc, int offset) {
+    final listOffset = bc.derefObject(offset);
+    if (lazy) return _FbUint8List(bc, listOffset);
+
+    final length = bc._getUint32(listOffset);
+    final result = Uint8List(length);
+    var pos = listOffset + _sizeofUint32;
+    for (var i = 0; i < length; i++, pos++) {
+      result[i] = bc._getUint8(pos);
+    }
+    return result;
+  }
 }
 
 /// The reader of unsigned 8-bit integers.
@@ -1068,20 +1214,53 @@
   const Uint8Reader() : super();
 
   @override
+  @pragma('vm:prefer-inline')
   int get size => _sizeofUint8;
 
   @override
+  @pragma('vm:prefer-inline')
   int read(BufferContext bc, int offset) => bc._getUint8(offset);
 }
 
+/// Reader of unmodifiable binary data (a list of signed 8-bit integers).
+class Int8ListReader extends Reader<List<int>> {
+  /// Enables lazy reading of the list
+  ///
+  /// If true, the returned unmodifiable list lazily reads bytes on access.
+  /// Therefore, the underlying buffer must not change while accessing the list.
+  ///
+  /// If false, reads the whole list immediately as an Uint8List.
+  final bool lazy;
+
+  const Int8ListReader({this.lazy = true});
+
+  @override
+  @pragma('vm:prefer-inline')
+  int get size => _sizeofUint32;
+
+  @override
+  @pragma('vm:prefer-inline')
+  List<int> read(BufferContext bc, int offset) {
+    final listOffset = bc.derefObject(offset);
+    if (lazy) return _FbUint8List(bc, listOffset);
+
+    final length = bc._getUint32(listOffset);
+    final result = Int8List(length);
+    var pos = listOffset + _sizeofUint32;
+    for (var i = 0; i < length; i++, pos++) {
+      result[i] = bc._getInt8(pos);
+    }
+    return result;
+  }
+}
+
 /// The list backed by 64-bit values - Uint64 length and Float64.
 class _FbFloat64List extends _FbList<double> {
   _FbFloat64List(BufferContext bc, int offset) : super(bc, offset);
 
   @override
-  double operator [](int i) {
-    return bc._getFloat64(offset + 4 + 8 * i);
-  }
+  @pragma('vm:prefer-inline')
+  double operator [](int i) => bc._getFloat64(offset + 4 + 8 * i);
 }
 
 /// The list backed by 32-bit values - Float32.
@@ -1089,29 +1268,29 @@
   _FbFloat32List(BufferContext bc, int offset) : super(bc, offset);
 
   @override
-  double operator [](int i) {
-    return bc._getFloat32(offset + 4 + 4 * i);
-  }
+  @pragma('vm:prefer-inline')
+  double operator [](int i) => bc._getFloat32(offset + 4 + 4 * i);
 }
 
 /// List backed by a generic object which may have any size.
 class _FbGenericList<E> extends _FbList<E> {
   final Reader<E> elementReader;
 
-  List<E> _items;
+  List<E?>? _items;
 
   _FbGenericList(this.elementReader, BufferContext bp, int offset)
       : super(bp, offset);
 
   @override
+  @pragma('vm:prefer-inline')
   E operator [](int i) {
-    _items ??= new List<E>(length);
-    E item = _items[i];
+    _items ??= List<E?>.filled(length, null);
+    var item = _items![i];
     if (item == null) {
       item = elementReader.read(bc, offset + 4 + elementReader.size * i);
-      _items[i] = item;
+      _items![i] = item;
     }
-    return item;
+    return item!;
   }
 }
 
@@ -1119,23 +1298,20 @@
 abstract class _FbList<E> extends Object with ListMixin<E> implements List<E> {
   final BufferContext bc;
   final int offset;
-  int _length;
+  int? _length;
 
   _FbList(this.bc, this.offset);
 
   @override
-  int get length {
-    _length ??= bc._getUint32(offset);
-    return _length;
-  }
+  @pragma('vm:prefer-inline')
+  int get length => _length ??= bc._getUint32(offset);
 
   @override
-  void set length(int i) =>
-      throw new StateError('Attempt to modify immutable list');
+  set length(int i) => throw StateError('Attempt to modify immutable list');
 
   @override
   void operator []=(int i, E e) =>
-      throw new StateError('Attempt to modify immutable list');
+      throw StateError('Attempt to modify immutable list');
 }
 
 /// List backed by 32-bit unsigned integers.
@@ -1143,9 +1319,8 @@
   _FbUint32List(BufferContext bc, int offset) : super(bc, offset);
 
   @override
-  int operator [](int i) {
-    return bc._getUint32(offset + 4 + 4 * i);
-  }
+  @pragma('vm:prefer-inline')
+  int operator [](int i) => bc._getUint32(offset + 4 + 4 * i);
 }
 
 /// List backed by 16-bit unsigned integers.
@@ -1153,9 +1328,8 @@
   _FbUint16List(BufferContext bc, int offset) : super(bc, offset);
 
   @override
-  int operator [](int i) {
-    return bc._getUint16(offset + 4 + 2 * i);
-  }
+  @pragma('vm:prefer-inline')
+  int operator [](int i) => bc._getUint16(offset + 4 + 2 * i);
 }
 
 /// List backed by 8-bit unsigned integers.
@@ -1163,9 +1337,17 @@
   _FbUint8List(BufferContext bc, int offset) : super(bc, offset);
 
   @override
-  int operator [](int i) {
-    return bc._getUint8(offset + 4 + i);
-  }
+  @pragma('vm:prefer-inline')
+  int operator [](int i) => bc._getUint8(offset + 4 + i);
+}
+
+/// List backed by 8-bit signed integers.
+class _FbInt8List extends _FbList<int> {
+  _FbInt8List(BufferContext bc, int offset) : super(bc, offset);
+
+  @override
+  @pragma('vm:prefer-inline')
+  int operator [](int i) => bc._getInt8(offset + 4 + i);
 }
 
 /// List backed by 8-bit unsigned integers.
@@ -1173,41 +1355,48 @@
   _FbBoolList(BufferContext bc, int offset) : super(bc, offset);
 
   @override
-  bool operator [](int i) {
-    return bc._getUint8(offset + 4 + i) == 1 ? true : false;
-  }
+  @pragma('vm:prefer-inline')
+  bool operator [](int i) => bc._getUint8(offset + 4 + i) == 1 ? true : false;
 }
 
 /// Class that describes the structure of a table.
 class _VTable {
   static const int _metadataLength = 4;
 
-  final List<int> fieldTails = <int>[];
-  final List<int> fieldOffsets = <int>[];
+  final int numFields;
+
+  // Note: fieldOffsets start as "tail offsets" and are then transformed by
+  // [computeFieldOffsets()] to actual offsets when a table is finished.
+  final Uint32List fieldOffsets;
+  bool offsetsComputed = false;
+
+  _VTable(this.numFields) : fieldOffsets = Uint32List(numFields);
 
   /// The size of the table that uses this VTable.
-  int tableSize;
+  int tableSize = 0;
 
-  /// The tail of this VTable.  It is used to share the same VTable between
+  /// The tail of this VTable. It is used to share the same VTable between
   /// multiple tables of identical structure.
-  int tail;
+  int tail = 0;
 
   int get _vTableSize => numOfUint16 * _sizeofUint16;
 
-  int get numOfUint16 => 1 + 1 + fieldTails.length;
+  int get numOfUint16 => 1 + 1 + numFields;
 
+  @pragma('vm:prefer-inline')
   void addField(int field, int offset) {
-    while (fieldTails.length <= field) {
-      fieldTails.add(null);
-    }
-    fieldTails[field] = offset;
+    assert(!offsetsComputed);
+    assert(offset > 0); // it's impossible for field to start at the buffer end
+    assert(offset <= 4294967295); // uint32 max
+    fieldOffsets[field] = offset;
   }
 
+  @pragma('vm:prefer-inline')
   bool _offsetsMatch(int vt2Start, ByteData buf) {
-    for (int i = 0; i < fieldOffsets.length; i++) {
+    assert(offsetsComputed);
+    for (var i = 0; i < numFields; i++) {
       if (fieldOffsets[i] !=
-          buf.getUint16(
-              vt2Start + _metadataLength + (2 * i), Endian.little)) {
+          buf.getUint16(vt2Start + _metadataLength + (2 * i), Endian.little)) {
         return false;
       }
     }
@@ -1215,17 +1404,22 @@
   }
 
   /// Fill the [fieldOffsets] field.
+  @pragma('vm:prefer-inline')
   void computeFieldOffsets(int tableTail) {
-    assert(fieldOffsets.isEmpty);
-    for (int fieldTail in fieldTails) {
-      int fieldOffset = fieldTail == null ? 0 : tableTail - fieldTail;
-      fieldOffsets.add(fieldOffset);
+    assert(!offsetsComputed);
+    offsetsComputed = true;
+    for (var i = 0; i < numFields; i++) {
+      if (fieldOffsets[i] != 0) {
+        fieldOffsets[i] = tableTail - fieldOffsets[i];
+      }
     }
   }
 
   /// Outputs this VTable to [buf], which is is expected to be aligned to 16-bit
   /// and have at least [numOfUint16] 16-bit words available.
+  @pragma('vm:prefer-inline')
   void output(ByteData buf, int bufOffset) {
+    assert(offsetsComputed);
     // VTable size.
     buf.setUint16(bufOffset, numOfUint16 * 2, Endian.little);
     bufOffset += 2;
@@ -1233,9 +1427,62 @@
     buf.setUint16(bufOffset, tableSize, Endian.little);
     bufOffset += 2;
     // Field offsets.
-    for (int fieldOffset in fieldOffsets) {
-      buf.setUint16(bufOffset, fieldOffset, Endian.little);
+    for (var i = 0; i < numFields; i++) {
+      buf.setUint16(bufOffset, fieldOffsets[i], Endian.little);
       bufOffset += 2;
     }
   }
 }
+
+/// The interface that [Builder] uses to allocate buffers for encoding.
+abstract class Allocator {
+  const Allocator();
+
+  /// Allocate a [ByteData] buffer of a given size.
+  ByteData allocate(int size);
+
+  /// Free the given [ByteData] buffer previously allocated by [allocate].
+  void deallocate(ByteData data);
+
+  /// Reallocate [newSize] bytes of memory, replacing the old [oldData]. This
+  /// grows downwards, and is intended specifically for use with [Builder].
+  /// Params [inUseBack] and [inUseFront] indicate how much of [oldData] is
+  /// actually in use at each end, and needs to be copied.
+  ByteData resize(
+      ByteData oldData, int newSize, int inUseBack, int inUseFront) {
+    final newData = allocate(newSize);
+    _copyDownward(oldData, newData, inUseBack, inUseFront);
+    deallocate(oldData);
+    return newData;
+  }
+
+  /// Called by [resize] to copy memory from [oldData] to [newData]. Only
+  /// memory of size [inUseFront] and [inUseBack] will be copied from the front
+  /// and back of the old memory allocation.
+  void _copyDownward(
+      ByteData oldData, ByteData newData, int inUseBack, int inUseFront) {
+    if (inUseBack != 0) {
+      newData.buffer.asUint8List().setAll(
+          newData.lengthInBytes - inUseBack,
+          oldData.buffer.asUint8List().getRange(
+              oldData.lengthInBytes - inUseBack, oldData.lengthInBytes));
+    }
+    if (inUseFront != 0) {
+      newData.buffer
+          .asUint8List()
+          .setAll(0, oldData.buffer.asUint8List().getRange(0, inUseFront));
+    }
+  }
+}
+
+class DefaultAllocator extends Allocator {
+  const DefaultAllocator();
+
+  @override
+  ByteData allocate(int size) => ByteData(size);
+
+  @override
+  void deallocate(ByteData data) {
+    // nothing to do, it's garbage-collected
+  }
+}
diff --git a/dart/lib/src/builder.dart b/dart/lib/src/builder.dart
index 5ce46dc..a0d47ed 100644
--- a/dart/lib/src/builder.dart
+++ b/dart/lib/src/builder.dart
@@ -5,38 +5,27 @@
 
 /// The main builder class for creation of a FlexBuffer.
 class Builder {
-  ByteData _buffer;
-  List<_StackValue> _stack;
-  List<_StackPointer> _stackPointers;
-  int _offset;
-  bool _finished;
-  Map<String, _StackValue> _stringCache;
-  Map<String, _StackValue> _keyCache;
-  Map<_KeysHash, _StackValue> _keyVectorCache;
-  Map<int, _StackValue> _indirectIntCache;
-  Map<double, _StackValue> _indirectDoubleCache;
+  final ByteData _buffer;
+  List<_StackValue> _stack = [];
+  List<_StackPointer> _stackPointers = [];
+  int _offset = 0;
+  bool _finished = false;
+  final Map<String, _StackValue> _stringCache = {};
+  final Map<String, _StackValue> _keyCache = {};
+  final Map<_KeysHash, _StackValue> _keyVectorCache = {};
+  final Map<int, _StackValue> _indirectIntCache = {};
+  final Map<double, _StackValue> _indirectDoubleCache = {};
 
   /// Instantiate the builder if you intent to gradually build up the buffer by calling
   /// add... methods and calling [finish] to receive the the resulting byte array.
   ///
   /// The default size of internal buffer is set to 2048. Provide a different value in order to avoid buffer copies.
-  Builder({int size = 2048}) {
-    _buffer = ByteData(size);
-    _stack = [];
-    _stackPointers = [];
-    _offset = 0;
-    _finished = false;
-    _stringCache = {};
-    _keyCache = {};
-    _keyVectorCache = {};
-    _indirectIntCache = {};
-    _indirectDoubleCache = {};
-  }
+  Builder({int size = 2048}) : _buffer = ByteData(size);
 
   /// Use this method in order to turn an object into a FlexBuffer directly.
   ///
   /// Use the manual instantiation of the [Builder] and gradual addition of values, if performance is more important than convenience.
-  static ByteBuffer buildFromObject(Object value) {
+  static ByteBuffer buildFromObject(Object? value) {
     final builder = Builder();
     builder._add(value);
     final buffer = builder.finish();
@@ -45,7 +34,7 @@
     return byteData.buffer;
   }
 
-  void _add(Object value) {
+  void _add(Object? value) {
     if (value == null) {
       addNull();
     } else if (value is bool) {
@@ -81,32 +70,32 @@
   /// Specifically useful when building up a vector where values can be null.
   void addNull() {
     _integrityCheckOnValueAddition();
-    _stack.add(_StackValue.WithNull());
+    _stack.add(_StackValue.withNull());
   }
 
   /// Adds a string value.
   void addInt(int value) {
     _integrityCheckOnValueAddition();
-    _stack.add(_StackValue.WithInt(value));
+    _stack.add(_StackValue.withInt(value));
   }
 
   /// Adds a bool value.
   void addBool(bool value) {
     _integrityCheckOnValueAddition();
-    _stack.add(_StackValue.WithBool(value));
+    _stack.add(_StackValue.withBool(value));
   }
 
   /// Adds a double value.
   void addDouble(double value) {
     _integrityCheckOnValueAddition();
-    _stack.add(_StackValue.WithDouble(value));
+    _stack.add(_StackValue.withDouble(value));
   }
 
   /// Adds a string value.
   void addString(String value) {
     _integrityCheckOnValueAddition();
     if (_stringCache.containsKey(value)) {
-      _stack.add(_stringCache[value]);
+      _stack.add(_stringCache[value]!);
       return;
     }
     final utf8String = utf8.encode(value);
@@ -118,7 +107,8 @@
     final newOffset = _newOffset(length + 1);
     _pushBuffer(utf8String);
     _offset = newOffset;
-    final stackValue = _StackValue.WithOffset(stringOffset, ValueType.String, bitWidth);
+    final stackValue =
+        _StackValue.withOffset(stringOffset, ValueType.String, bitWidth);
     _stack.add(stackValue);
     _stringCache[value] = stackValue;
   }
@@ -129,7 +119,7 @@
   void addKey(String value) {
     _integrityCheckOnKeyAddition();
     if (_keyCache.containsKey(value)) {
-      _stack.add(_keyCache[value]);
+      _stack.add(_keyCache[value]!);
       return;
     }
     final utf8String = utf8.encode(value);
@@ -138,7 +128,8 @@
     final newOffset = _newOffset(length + 1);
     _pushBuffer(utf8String);
     _offset = newOffset;
-    final stackValue = _StackValue.WithOffset(keyOffset, ValueType.Key, BitWidth.width8);
+    final stackValue =
+        _StackValue.withOffset(keyOffset, ValueType.Key, BitWidth.width8);
     _stack.add(stackValue);
     _keyCache[value] = stackValue;
   }
@@ -156,7 +147,8 @@
     final newOffset = _newOffset(length);
     _pushBuffer(value.asUint8List());
     _offset = newOffset;
-    final stackValue = _StackValue.WithOffset(blobOffset, ValueType.Blob, bitWidth);
+    final stackValue =
+        _StackValue.withOffset(blobOffset, ValueType.Blob, bitWidth);
     _stack.add(stackValue);
   }
 
@@ -169,15 +161,16 @@
   void addIntIndirectly(int value, {bool cache = false}) {
     _integrityCheckOnValueAddition();
     if (_indirectIntCache.containsKey(value)) {
-      _stack.add(_indirectIntCache[value]);
+      _stack.add(_indirectIntCache[value]!);
       return;
     }
-    final stackValue = _StackValue.WithInt(value);
+    final stackValue = _StackValue.withInt(value);
     final byteWidth = _align(stackValue.width);
     final newOffset = _newOffset(byteWidth);
     final valueOffset = _offset;
     _pushBuffer(stackValue.asU8List(stackValue.width));
-    final stackOffset = _StackValue.WithOffset(valueOffset, ValueType.IndirectInt, stackValue.width);
+    final stackOffset = _StackValue.withOffset(
+        valueOffset, ValueType.IndirectInt, stackValue.width);
     _stack.add(stackOffset);
     _offset = newOffset;
     if (cache) {
@@ -193,15 +186,16 @@
   void addDoubleIndirectly(double value, {bool cache = false}) {
     _integrityCheckOnValueAddition();
     if (cache && _indirectDoubleCache.containsKey(value)) {
-      _stack.add(_indirectDoubleCache[value]);
+      _stack.add(_indirectDoubleCache[value]!);
       return;
     }
-    final stackValue = _StackValue.WithDouble(value);
+    final stackValue = _StackValue.withDouble(value);
     final byteWidth = _align(stackValue.width);
     final newOffset = _newOffset(byteWidth);
     final valueOffset = _offset;
     _pushBuffer(stackValue.asU8List(stackValue.width));
-    final stackOffset = _StackValue.WithOffset(valueOffset, ValueType.IndirectFloat, stackValue.width);
+    final stackOffset = _StackValue.withOffset(
+        valueOffset, ValueType.IndirectFloat, stackValue.width);
     _stack.add(stackOffset);
     _offset = newOffset;
     if (cache) {
@@ -258,8 +252,10 @@
     tmp._offset = _offset;
     tmp._stack = List.from(_stack);
     tmp._stackPointers = List.from(_stackPointers);
-    tmp._buffer.buffer.asUint8List().setAll(0, _buffer.buffer.asUint8List(0, _offset));
-    for (var i = 0; i < tmp._stackPointers.length; i++){
+    tmp._buffer.buffer
+        .asUint8List()
+        .setAll(0, _buffer.buffer.asUint8List(0, _offset));
+    for (var i = 0; i < tmp._stackPointers.length; i++) {
       tmp.end();
     }
     final buffer = tmp.finish();
@@ -267,14 +263,15 @@
     bd.buffer.asUint8List().setAll(0, buffer);
     return bd.buffer;
   }
-  
+
   void _integrityCheckOnValueAddition() {
     if (_finished) {
       throw StateError('Adding values after finish is prohibited');
     }
     if (_stackPointers.isNotEmpty && _stackPointers.last.isVector == false) {
       if (_stack.last.type != ValueType.Key) {
-        throw StateError('Adding value to a map before adding a key is prohibited');
+        throw StateError(
+            'Adding value to a map before adding a key is prohibited');
       }
     }
   }
@@ -290,7 +287,8 @@
 
   void _finish() {
     if (_stack.length != 1) {
-      throw StateError('Stack has to be exactly 1, but is ${_stack.length}. You have to end all started vectors and maps, before calling [finish]');
+      throw StateError(
+          'Stack has to be exactly 1, but is ${_stack.length}. You have to end all started vectors and maps, before calling [finish]');
     }
     final value = _stack[0];
     final byteWidth = _align(value.elementWidth(_offset, 0));
@@ -299,8 +297,9 @@
     _writeUInt(byteWidth, 1);
     _finished = true;
   }
-  
-  _StackValue _createVector(int start, int vecLength, int step, [_StackValue keys]) {
+
+  _StackValue _createVector(int start, int vecLength, int step,
+      [_StackValue? keys]) {
     var bitWidth = BitWidthUtil.uwidth(vecLength);
     var prefixElements = 1;
     if (keys != null) {
@@ -327,7 +326,9 @@
       }
     }
     final byteWidth = _align(bitWidth);
-    final fix = typed & ValueTypeUtils.isNumber(vectorType) && vecLength >= 2 && vecLength <= 4;
+    final fix = typed & ValueTypeUtils.isNumber(vectorType) &&
+        vecLength >= 2 &&
+        vecLength <= 4;
     if (keys != null) {
       _writeStackValue(keys, byteWidth);
       _writeUInt(1 << keys.width.index, byteWidth);
@@ -345,13 +346,14 @@
       }
     }
     if (keys != null) {
-      return _StackValue.WithOffset(vecOffset, ValueType.Map, bitWidth);
+      return _StackValue.withOffset(vecOffset, ValueType.Map, bitWidth);
     }
     if (typed) {
-      final vType = ValueTypeUtils.toTypedVector(vectorType, fix ? vecLength : 0);
-      return _StackValue.WithOffset(vecOffset, vType, bitWidth);
+      final vType =
+          ValueTypeUtils.toTypedVector(vectorType, fix ? vecLength : 0);
+      return _StackValue.withOffset(vecOffset, vType, bitWidth);
     }
-    return _StackValue.WithOffset(vecOffset, ValueType.Vector, bitWidth);
+    return _StackValue.withOffset(vecOffset, ValueType.Vector, bitWidth);
   }
 
   void _endVector(_StackPointer pointer) {
@@ -363,12 +365,13 @@
 
   void _sortKeysAndEndMap(_StackPointer pointer) {
     if (((_stack.length - pointer.stackPosition) & 1) == 1) {
-      throw StateError('The stack needs to hold key value pairs (even number of elements). Check if you combined [addKey] with add... method calls properly.');
+      throw StateError(
+          'The stack needs to hold key value pairs (even number of elements). Check if you combined [addKey] with add... method calls properly.');
     }
 
     var sorted = true;
     for (var i = pointer.stackPosition; i < _stack.length - 2; i += 2) {
-      if (_shouldFlip(_stack[i], _stack[i+2])) {
+      if (_shouldFlip(_stack[i], _stack[i + 2])) {
         sorted = false;
         break;
       }
@@ -394,36 +397,38 @@
     }
     _endMap(pointer);
   }
-  
+
   void _endMap(_StackPointer pointer) {
     final vecLength = (_stack.length - pointer.stackPosition) >> 1;
     final offsets = <int>[];
     for (var i = pointer.stackPosition; i < _stack.length; i += 2) {
-      offsets.add(_stack[i].offset);
+      offsets.add(_stack[i].offset!);
     }
     final keysHash = _KeysHash(offsets);
-    var keysStackValue;
+    _StackValue? keysStackValue;
     if (_keyVectorCache.containsKey(keysHash)) {
       keysStackValue = _keyVectorCache[keysHash];
     } else {
       keysStackValue = _createVector(pointer.stackPosition, vecLength, 2);
       _keyVectorCache[keysHash] = keysStackValue;
     }
-    final vec = _createVector(pointer.stackPosition + 1, vecLength, 2, keysStackValue);
+    final vec =
+        _createVector(pointer.stackPosition + 1, vecLength, 2, keysStackValue);
     _stack.removeRange(pointer.stackPosition, _stack.length);
     _stack.add(vec);
   }
 
   bool _shouldFlip(_StackValue v1, _StackValue v2) {
     if (v1.type != ValueType.Key || v2.type != ValueType.Key) {
-      throw StateError('Stack values are not keys $v1 | $v2. Check if you combined [addKey] with add... method calls properly.');
+      throw StateError(
+          'Stack values are not keys $v1 | $v2. Check if you combined [addKey] with add... method calls properly.');
     }
 
-    var c1, c2;
+    late int c1, c2;
     var index = 0;
     do {
-      c1 = _buffer.getUint8(v1.offset + index);
-      c2 = _buffer.getUint8(v2.offset + index);
+      c1 = _buffer.getUint8(v1.offset! + index);
+      c2 = _buffer.getUint8(v2.offset! + index);
       if (c2 < c1) return true;
       if (c1 < c2) return false;
       index += 1;
@@ -440,11 +445,12 @@
   void _writeStackValue(_StackValue value, int byteWidth) {
     final newOffset = _newOffset(byteWidth);
     if (value.isOffset) {
-      final relativeOffset = _offset - value.offset;
+      final relativeOffset = _offset - value.offset!;
       if (byteWidth == 8 || relativeOffset < (1 << (byteWidth * 8))) {
         _writeUInt(relativeOffset, byteWidth);
       } else {
-        throw StateError('Unexpected size $byteWidth. This might be a bug. Please create an issue https://github.com/google/flatbuffers/issues/new');
+        throw StateError(
+            'Unexpected size $byteWidth. This might be a bug. Please create an issue https://github.com/google/flatbuffers/issues/new');
       }
     } else {
       _pushBuffer(value.asU8List(BitWidthUtil.fromByteWidth(byteWidth)));
@@ -467,16 +473,13 @@
     }
     if (prevSize < size) {
       final newBuf = ByteData(size);
-      newBuf.buffer
-          .asUint8List()
-          .setAll(0, _buffer.buffer.asUint8List());
+      newBuf.buffer.asUint8List().setAll(0, _buffer.buffer.asUint8List());
     }
     return newOffset;
   }
 
   void _pushInt(int value, BitWidth width) {
     switch (width) {
-
       case BitWidth.width8:
         _buffer.setInt8(_offset, value);
         break;
@@ -494,7 +497,6 @@
 
   void _pushUInt(int value, BitWidth width) {
     switch (width) {
-
       case BitWidth.width8:
         _buffer.setUint8(_offset, value);
         break;
@@ -516,37 +518,39 @@
 }
 
 class _StackValue {
-  Object _value;
-  int _offset;
-  ValueType _type;
-  BitWidth _width;
-  _StackValue.WithNull() {
-    _type = ValueType.Null;
-    _width = BitWidth.width8;
-  }
-  _StackValue.WithInt(int value) {
-    _type = value != null ? ValueType.Int : ValueType.Null;
-    _width = BitWidthUtil.width(value);
-    _value = value;
-  }
-  _StackValue.WithBool(bool value) {
-    _type = value != null ? ValueType.Bool : ValueType.Null;
-    _width = BitWidth.width8;
-    _value = value;
-  }
-  _StackValue.WithDouble(double value) {
-    _type = value != null ? ValueType.Float : ValueType.Null;
-    _width = BitWidthUtil.width(value);
-    _value = value;
-  }
-  _StackValue.WithOffset(int value, ValueType type, BitWidth width) {
-    _offset = value;
-    _type = type;
-    _width = width;
-  }
+  late Object _value;
+  int? _offset;
+  final ValueType _type;
+  final BitWidth _width;
+
+  _StackValue.withNull()
+      : _type = ValueType.Null,
+        _width = BitWidth.width8;
+
+  _StackValue.withInt(int value)
+      : _type = ValueType.Int,
+        _width = BitWidthUtil.width(value),
+        _value = value;
+
+  _StackValue.withBool(bool value)
+      : _type = ValueType.Bool,
+        _width = BitWidth.width8,
+        _value = value;
+
+  _StackValue.withDouble(double value)
+      : _type = ValueType.Float,
+        _width = BitWidthUtil.width(value),
+        _value = value;
+
+  _StackValue.withOffset(int value, ValueType type, BitWidth width)
+      : _offset = value,
+        _type = type,
+        _width = width;
 
   BitWidth storedWidth({BitWidth width = BitWidth.width8}) {
-    return ValueTypeUtils.isInline(_type) ? BitWidthUtil.max(_width, width) : _width;
+    return ValueTypeUtils.isInline(_type)
+        ? BitWidthUtil.max(_width, width)
+        : _width;
   }
 
   int storedPackedType({BitWidth width = BitWidth.width8}) {
@@ -555,16 +559,19 @@
 
   BitWidth elementWidth(int size, int index) {
     if (ValueTypeUtils.isInline(_type)) return _width;
-    for(var i = 0; i < 4; i++) {
+    final offset = _offset!;
+    for (var i = 0; i < 4; i++) {
       final width = 1 << i;
-      final offsetLoc = size + BitWidthUtil.paddingSize(size, width) + index * width;
-      final offset = offsetLoc - _offset;
-      final bitWidth = BitWidthUtil.uwidth(offset);
+      final bitWidth = BitWidthUtil.uwidth(size +
+          BitWidthUtil.paddingSize(size, width) +
+          index * width -
+          offset);
       if (1 << bitWidth.index == width) {
         return bitWidth;
       }
     }
-    throw StateError('Element is of unknown. Size: $size at index: $index. This might be a bug. Please create an issue https://github.com/google/flatbuffers/issues/new');
+    throw StateError(
+        'Element is of unknown. Size: $size at index: $index. This might be a bug. Please create an issue https://github.com/google/flatbuffers/issues/new');
   }
 
   List<int> asU8List(BitWidth width) {
@@ -572,30 +579,30 @@
       if (_type == ValueType.Float) {
         if (width == BitWidth.width32) {
           final result = ByteData(4);
-          result.setFloat32(0, _value, Endian.little);
+          result.setFloat32(0, _value as double, Endian.little);
           return result.buffer.asUint8List();
         } else {
           final result = ByteData(8);
-          result.setFloat64(0, _value, Endian.little);
+          result.setFloat64(0, _value as double, Endian.little);
           return result.buffer.asUint8List();
         }
       } else {
-        switch(width) {
+        switch (width) {
           case BitWidth.width8:
             final result = ByteData(1);
-            result.setInt8(0, _value);
+            result.setInt8(0, _value as int);
             return result.buffer.asUint8List();
           case BitWidth.width16:
             final result = ByteData(2);
-            result.setInt16(0, _value, Endian.little);
+            result.setInt16(0, _value as int, Endian.little);
             return result.buffer.asUint8List();
           case BitWidth.width32:
             final result = ByteData(4);
-            result.setInt32(0, _value, Endian.little);
+            result.setInt32(0, _value as int, Endian.little);
             return result.buffer.asUint8List();
           case BitWidth.width64:
             final result = ByteData(8);
-            result.setInt64(0, _value, Endian.little);
+            result.setInt64(0, _value as int, Endian.little);
             return result.buffer.asUint8List();
         }
       }
@@ -607,11 +614,12 @@
     }
     if (_type == ValueType.Bool) {
       final result = ByteData(1);
-      result.setInt8(0, _value ? 1 : 0);
+      result.setInt8(0, _value as bool ? 1 : 0);
       return result.buffer.asUint8List();
     }
 
-    throw StateError('Unexpected type: $_type. This might be a bug. Please create an issue https://github.com/google/flatbuffers/issues/new');
+    throw StateError(
+        'Unexpected type: $_type. This might be a bug. Please create an issue https://github.com/google/flatbuffers/issues/new');
   }
 
   ValueType get type {
@@ -625,7 +633,8 @@
   bool get isOffset {
     return !ValueTypeUtils.isInline(_type);
   }
-  int get offset => _offset;
+
+  int? get offset => _offset;
 
   bool get isFloat32 {
     return _type == ValueType.Float && _width == BitWidth.width32;
@@ -635,6 +644,7 @@
 class _StackPointer {
   int stackPosition;
   bool isVector;
+
   _StackPointer(this.stackPosition, this.isVector);
 }
 
diff --git a/dart/lib/src/reference.dart b/dart/lib/src/reference.dart
index 3954f06..e52d0b7 100644
--- a/dart/lib/src/reference.dart
+++ b/dart/lib/src/reference.dart
@@ -11,14 +11,15 @@
   final int _offset;
   final BitWidth _parentWidth;
   final String _path;
-  int _byteWidth;
-  ValueType _valueType;
-  int _length;
+  final int _byteWidth;
+  final ValueType _valueType;
+  int? _length;
 
-  Reference._(this._buffer, this._offset, this._parentWidth, int packedType, this._path) {
-    _byteWidth = 1 << (packedType & 3);
-    _valueType = ValueTypeUtils.fromInt(packedType >> 2);
-  }
+  Reference._(
+      this._buffer, this._offset, this._parentWidth, int packedType, this._path,
+      [int? byteWidth, ValueType? valueType])
+      : _byteWidth = byteWidth ?? 1 << (packedType & 3),
+        _valueType = valueType ?? ValueTypeUtils.fromInt(packedType >> 2);
 
   /// Use this method to access the root value of a FlexBuffer.
   static Reference fromBuffer(ByteBuffer buffer) {
@@ -30,31 +31,44 @@
     final byteWidth = byteData.getUint8(len - 1);
     final packedType = byteData.getUint8(len - 2);
     final offset = len - byteWidth - 2;
-    return Reference._(ByteData.view(buffer), offset, BitWidthUtil.fromByteWidth(byteWidth), packedType, "/");
+    return Reference._(ByteData.view(buffer), offset,
+        BitWidthUtil.fromByteWidth(byteWidth), packedType, "/");
   }
 
   /// Returns true if the underlying value is null.
   bool get isNull => _valueType == ValueType.Null;
+
   /// Returns true if the underlying value can be represented as [num].
-  bool get isNum => ValueTypeUtils.isNumber(_valueType) || ValueTypeUtils.isIndirectNumber(_valueType);
+  bool get isNum =>
+      ValueTypeUtils.isNumber(_valueType) ||
+      ValueTypeUtils.isIndirectNumber(_valueType);
+
   /// Returns true if the underlying value was encoded as a float (direct or indirect).
-  bool get isDouble => _valueType == ValueType.Float || _valueType == ValueType.IndirectFloat;
+  bool get isDouble =>
+      _valueType == ValueType.Float || _valueType == ValueType.IndirectFloat;
+
   /// Returns true if the underlying value was encoded as an int or uint (direct or indirect).
   bool get isInt => isNum && !isDouble;
+
   /// Returns true if the underlying value was encoded as a string or a key.
-  bool get isString => _valueType == ValueType.String || _valueType == ValueType.Key;
+  bool get isString =>
+      _valueType == ValueType.String || _valueType == ValueType.Key;
+
   /// Returns true if the underlying value was encoded as a bool.
   bool get isBool => _valueType == ValueType.Bool;
+
   /// Returns true if the underlying value was encoded as a blob.
   bool get isBlob => _valueType == ValueType.Blob;
+
   /// Returns true if the underlying value points to a vector.
   bool get isVector => ValueTypeUtils.isAVector(_valueType);
+
   /// Returns true if the underlying value points to a map.
   bool get isMap => _valueType == ValueType.Map;
 
   /// If this [isBool], returns the bool value. Otherwise, returns null.
-  bool get boolValue {
-    if(_valueType == ValueType.Bool) {
+  bool? get boolValue {
+    if (_valueType == ValueType.Bool) {
       return _readInt(_offset, _parentWidth) != 0;
     }
     return null;
@@ -63,7 +77,7 @@
   /// Returns an [int], if the underlying value can be represented as an int.
   ///
   /// Otherwise returns [null].
-  int get intValue {
+  int? get intValue {
     if (_valueType == ValueType.Int) {
       return _readInt(_offset, _parentWidth);
     }
@@ -82,7 +96,7 @@
   /// Returns [double], if the underlying value [isDouble].
   ///
   /// Otherwise returns [null].
-  double get doubleValue {
+  double? get doubleValue {
     if (_valueType == ValueType.Float) {
       return _readFloat(_offset, _parentWidth);
     }
@@ -95,12 +109,12 @@
   /// Returns [num], if the underlying value is numeric, be it int uint, or float (direct or indirect).
   ///
   /// Otherwise returns [null].
-  num get numValue => doubleValue ?? intValue;
+  num? get numValue => doubleValue ?? intValue;
 
   /// Returns [String] value or null otherwise.
-  /// 
-  /// This method performers a utf8 decoding, as FlexBuffers format stores strings in utf8 encoding. 
-  String get stringValue {
+  ///
+  /// This method performers a utf8 decoding, as FlexBuffers format stores strings in utf8 encoding.
+  String? get stringValue {
     if (_valueType == ValueType.String || _valueType == ValueType.Key) {
       return utf8.decode(_buffer.buffer.asUint8List(_indirect, length));
     }
@@ -108,7 +122,7 @@
   }
 
   /// Returns [Uint8List] value or null otherwise.
-  Uint8List get blobValue {
+  Uint8List? get blobValue {
     if (_valueType == ValueType.Blob) {
       return _buffer.buffer.asUint8List(_indirect, length);
     }
@@ -122,22 +136,31 @@
   Reference operator [](Object key) {
     if (key is int && ValueTypeUtils.isAVector(_valueType)) {
       final index = key;
-      if(index >= length || index < 0) {
-        throw ArgumentError('Key: [$key] is not applicable on: $_path of: $_valueType length: $length');
+      if (index >= length || index < 0) {
+        throw ArgumentError(
+            'Key: [$key] is not applicable on: $_path of: $_valueType length: $length');
       }
       final elementOffset = _indirect + index * _byteWidth;
-      final reference = Reference._(_buffer, elementOffset, BitWidthUtil.fromByteWidth(_byteWidth), 0, "$_path[$index]");
-      reference._byteWidth = 1;
+      int packedType = 0;
+      int? byteWidth;
+      ValueType? valueType;
       if (ValueTypeUtils.isTypedVector(_valueType)) {
-        reference._valueType = ValueTypeUtils.typedVectorElementType(_valueType);
-        return reference;
+        byteWidth = 1;
+        valueType = ValueTypeUtils.typedVectorElementType(_valueType);
+      } else if (ValueTypeUtils.isFixedTypedVector(_valueType)) {
+        byteWidth = 1;
+        valueType = ValueTypeUtils.fixedTypedVectorElementType(_valueType);
+      } else {
+        packedType = _buffer.getUint8(_indirect + length * _byteWidth + index);
       }
-      if(ValueTypeUtils.isFixedTypedVector(_valueType)) {
-        reference._valueType = ValueTypeUtils.fixedTypedVectorElementType(_valueType);
-        return reference;
-      }
-      final packedType = _buffer.getUint8(_indirect + length * _byteWidth + index);
-      return Reference._(_buffer, elementOffset, BitWidthUtil.fromByteWidth(_byteWidth), packedType, "$_path[$index]");
+      return Reference._(
+          _buffer,
+          elementOffset,
+          BitWidthUtil.fromByteWidth(_byteWidth),
+          packedType,
+          "$_path[$index]",
+          byteWidth,
+          valueType);
     }
     if (key is String && _valueType == ValueType.Map) {
       final index = _keyIndex(key);
@@ -145,13 +168,14 @@
         return _valueForIndexWithKey(index, key);
       }
     }
-    throw ArgumentError('Key: [$key] is not applicable on: $_path of: $_valueType');
+    throw ArgumentError(
+        'Key: [$key] is not applicable on: $_path of: $_valueType');
   }
 
   /// Get an iterable if the underlying flexBuffer value is a vector.
   /// Otherwise throws an exception.
   Iterable<Reference> get vectorIterable {
-    if(isVector == false) {
+    if (isVector == false) {
       throw UnsupportedError('Value is not a vector. It is: $_valueType');
     }
     return _VectorIterator(this);
@@ -160,7 +184,7 @@
   /// Get an iterable for keys if the underlying flexBuffer value is a map.
   /// Otherwise throws an exception.
   Iterable<String> get mapKeyIterable {
-    if(isMap == false) {
+    if (isMap == false) {
       throw UnsupportedError('Value is not a map. It is: $_valueType');
     }
     return _MapKeyIterator(this);
@@ -169,7 +193,7 @@
   /// Get an iterable for values if the underlying flexBuffer value is a map.
   /// Otherwise throws an exception.
   Iterable<Reference> get mapValueIterable {
-    if(isMap == false) {
+    if (isMap == false) {
       throw UnsupportedError('Value is not a map. It is: $_valueType');
     }
     return _MapValueIterator(this);
@@ -181,59 +205,62 @@
   /// If the underlying value is a vector, or map, the length reflects number of elements / element pairs.
   /// If the values is a string or a blob, the length reflects a number of bytes the value occupies (strings are encoded in utf8 format).
   int get length {
-    if (_length != null) {
-      return _length;
-    }
-    // needs to be checked before more generic isAVector
-    if(ValueTypeUtils.isFixedTypedVector(_valueType)) {
-      _length = ValueTypeUtils.fixedTypedVectorElementSize(_valueType);
-    } else if(_valueType == ValueType.Blob || ValueTypeUtils.isAVector(_valueType) || _valueType == ValueType.Map){
-      _length = _readUInt(_indirect - _byteWidth, BitWidthUtil.fromByteWidth(_byteWidth));
-    } else if (_valueType == ValueType.Null) {
-      _length = 0;
-    } else if (_valueType == ValueType.String) {
-      final indirect = _indirect;
-      var size_byte_width = _byteWidth;
-      var size = _readUInt(indirect - size_byte_width, BitWidthUtil.fromByteWidth(size_byte_width));
-      while (_buffer.getInt8(indirect + size) != 0) {
-        size_byte_width <<= 1;
-        size = _readUInt(indirect - size_byte_width, BitWidthUtil.fromByteWidth(size_byte_width));
+    if (_length == null) {
+      // needs to be checked before more generic isAVector
+      if (ValueTypeUtils.isFixedTypedVector(_valueType)) {
+        _length = ValueTypeUtils.fixedTypedVectorElementSize(_valueType);
+      } else if (_valueType == ValueType.Blob ||
+          ValueTypeUtils.isAVector(_valueType) ||
+          _valueType == ValueType.Map) {
+        _length = _readUInt(
+            _indirect - _byteWidth, BitWidthUtil.fromByteWidth(_byteWidth));
+      } else if (_valueType == ValueType.Null) {
+        _length = 0;
+      } else if (_valueType == ValueType.String) {
+        final indirect = _indirect;
+        var sizeByteWidth = _byteWidth;
+        var size = _readUInt(indirect - sizeByteWidth,
+            BitWidthUtil.fromByteWidth(sizeByteWidth));
+        while (_buffer.getInt8(indirect + size) != 0) {
+          sizeByteWidth <<= 1;
+          size = _readUInt(indirect - sizeByteWidth,
+              BitWidthUtil.fromByteWidth(sizeByteWidth));
+        }
+        _length = size;
+      } else if (_valueType == ValueType.Key) {
+        final indirect = _indirect;
+        var size = 1;
+        while (_buffer.getInt8(indirect + size) != 0) {
+          size += 1;
+        }
+        _length = size;
+      } else {
+        _length = 1;
       }
-      _length = size;
-    } else if (_valueType == ValueType.Key) {
-      final indirect = _indirect;
-      var size = 1;
-      while (_buffer.getInt8(indirect + size) != 0) {
-        size += 1;
-      }
-      _length = size;
-    } else {
-      _length = 1;
     }
-    return _length;
+    return _length!;
   }
 
-
   /// Returns a minified JSON representation of the underlying FlexBuffer value.
   ///
   /// This method involves materializing the entire object tree, which may be
   /// expensive. It is more efficient to work with [Reference] and access only the needed data.
   /// Blob values are represented as base64 encoded string.
   String get json {
-    if(_valueType == ValueType.Bool) {
-      return boolValue ? 'true' : 'false';
+    if (_valueType == ValueType.Bool) {
+      return boolValue! ? 'true' : 'false';
     }
     if (_valueType == ValueType.Null) {
       return 'null';
     }
-    if(ValueTypeUtils.isNumber(_valueType)) {
+    if (ValueTypeUtils.isNumber(_valueType)) {
       return jsonEncode(numValue);
     }
     if (_valueType == ValueType.String) {
       return jsonEncode(stringValue);
     }
     if (_valueType == ValueType.Blob) {
-      return jsonEncode(base64Encode(blobValue));
+      return jsonEncode(base64Encode(blobValue!));
     }
     if (ValueTypeUtils.isAVector(_valueType)) {
       final result = StringBuffer();
@@ -261,7 +288,8 @@
       result.write('}');
       return result.toString();
     }
-    throw UnsupportedError('Type: $_valueType is not supported for JSON conversion');
+    throw UnsupportedError(
+        'Type: $_valueType is not supported for JSON conversion');
   }
 
   /// Computes the indirect offset of the value.
@@ -316,16 +344,20 @@
   }
 
   void _validateOffset(int offset, BitWidth width) {
-    if (_offset < 0 || _buffer.lengthInBytes <= offset + width.index || offset & (BitWidthUtil.toByteWidth(width) - 1) != 0) {
+    if (_offset < 0 ||
+        _buffer.lengthInBytes <= offset + width.index ||
+        offset & (BitWidthUtil.toByteWidth(width) - 1) != 0) {
       throw StateError('Bad offset: $offset, width: $width');
     }
   }
 
-  int _keyIndex(String key) {
+  int? _keyIndex(String key) {
     final input = utf8.encode(key);
     final keysVectorOffset = _indirect - _byteWidth * 3;
-    final indirectOffset = keysVectorOffset - _readUInt(keysVectorOffset, BitWidthUtil.fromByteWidth(_byteWidth));
-    final byteWidth = _readUInt(keysVectorOffset + _byteWidth, BitWidthUtil.fromByteWidth(_byteWidth));
+    final indirectOffset = keysVectorOffset -
+        _readUInt(keysVectorOffset, BitWidthUtil.fromByteWidth(_byteWidth));
+    final byteWidth = _readUInt(
+        keysVectorOffset + _byteWidth, BitWidthUtil.fromByteWidth(_byteWidth));
     var low = 0;
     var high = length - 1;
     while (low <= high) {
@@ -341,9 +373,10 @@
     return null;
   }
 
-  int _diffKeys(List<int> input, int index, int indirect_offset, int byteWidth) {
-    final keyOffset = indirect_offset + index * byteWidth;
-    final keyIndirectOffset = keyOffset - _readUInt(keyOffset, BitWidthUtil.fromByteWidth(byteWidth));
+  int _diffKeys(List<int> input, int index, int indirectOffset, int byteWidth) {
+    final keyOffset = indirectOffset + index * byteWidth;
+    final keyIndirectOffset =
+        keyOffset - _readUInt(keyOffset, BitWidthUtil.fromByteWidth(byteWidth));
     for (var i = 0; i < input.length; i++) {
       final dif = input[i] - _buffer.getUint8(keyIndirectOffset + i);
       if (dif != 0) {
@@ -357,38 +390,42 @@
     final indirect = _indirect;
     final elementOffset = indirect + index * _byteWidth;
     final packedType = _buffer.getUint8(indirect + length * _byteWidth + index);
-    return Reference._(_buffer, elementOffset, BitWidthUtil.fromByteWidth(_byteWidth), packedType, "$_path/$key");
+    return Reference._(_buffer, elementOffset,
+        BitWidthUtil.fromByteWidth(_byteWidth), packedType, "$_path/$key");
   }
 
   Reference _valueForIndex(int index) {
     final indirect = _indirect;
     final elementOffset = indirect + index * _byteWidth;
     final packedType = _buffer.getUint8(indirect + length * _byteWidth + index);
-    return Reference._(_buffer, elementOffset, BitWidthUtil.fromByteWidth(_byteWidth), packedType, "$_path/[$index]");
+    return Reference._(_buffer, elementOffset,
+        BitWidthUtil.fromByteWidth(_byteWidth), packedType, "$_path/[$index]");
   }
 
   String _keyForIndex(int index) {
     final keysVectorOffset = _indirect - _byteWidth * 3;
-    final indirectOffset = keysVectorOffset - _readUInt(keysVectorOffset, BitWidthUtil.fromByteWidth(_byteWidth));
-    final byteWidth = _readUInt(keysVectorOffset + _byteWidth, BitWidthUtil.fromByteWidth(_byteWidth));
+    final indirectOffset = keysVectorOffset -
+        _readUInt(keysVectorOffset, BitWidthUtil.fromByteWidth(_byteWidth));
+    final byteWidth = _readUInt(
+        keysVectorOffset + _byteWidth, BitWidthUtil.fromByteWidth(_byteWidth));
     final keyOffset = indirectOffset + index * byteWidth;
-    final keyIndirectOffset = keyOffset - _readUInt(keyOffset, BitWidthUtil.fromByteWidth(byteWidth));
+    final keyIndirectOffset =
+        keyOffset - _readUInt(keyOffset, BitWidthUtil.fromByteWidth(byteWidth));
     var length = 0;
     while (_buffer.getUint8(keyIndirectOffset + length) != 0) {
       length += 1;
     }
     return utf8.decode(_buffer.buffer.asUint8List(keyIndirectOffset, length));
   }
-
 }
 
-class _VectorIterator with IterableMixin<Reference> implements Iterator<Reference> {
+class _VectorIterator
+    with IterableMixin<Reference>
+    implements Iterator<Reference> {
   final Reference _vector;
-  int index;
+  int index = -1;
 
-  _VectorIterator(this._vector) {
-    index = -1;
-  }
+  _VectorIterator(this._vector);
 
   @override
   Reference get current => _vector[index];
@@ -405,11 +442,9 @@
 
 class _MapKeyIterator with IterableMixin<String> implements Iterator<String> {
   final Reference _map;
-  int index;
+  int index = -1;
 
-  _MapKeyIterator(this._map) {
-    index = -1;
-  }
+  _MapKeyIterator(this._map);
 
   @override
   String get current => _map._keyForIndex(index);
@@ -424,13 +459,13 @@
   Iterator<String> get iterator => this;
 }
 
-class _MapValueIterator with IterableMixin<Reference> implements Iterator<Reference> {
+class _MapValueIterator
+    with IterableMixin<Reference>
+    implements Iterator<Reference> {
   final Reference _map;
-  int index;
+  int index = -1;
 
-  _MapValueIterator(this._map) {
-    index = -1;
-  }
+  _MapValueIterator(this._map);
 
   @override
   Reference get current => _map._valueForIndex(index);
diff --git a/dart/lib/src/types.dart b/dart/lib/src/types.dart
index 8aed272..f9eefd8 100644
--- a/dart/lib/src/types.dart
+++ b/dart/lib/src/types.dart
@@ -1,17 +1,13 @@
 import 'dart:typed_data';
 
 /// Represents the number of bits a value occupies.
-enum BitWidth {
-  width8,
-  width16,
-  width32,
-  width64
-}
+enum BitWidth { width8, width16, width32, width64 }
 
 class BitWidthUtil {
   static int toByteWidth(BitWidth self) {
     return 1 << self.index;
   }
+
   static BitWidth width(num value) {
     if (value.toInt() == value) {
       var v = value.toInt().abs();
@@ -20,8 +16,11 @@
       if (v >> 31 == 0) return BitWidth.width32;
       return BitWidth.width64;
     }
-    return value == _toF32(value) ? BitWidth.width32 : BitWidth.width64;
+    return value == _toF32(value as double)
+        ? BitWidth.width32
+        : BitWidth.width64;
   }
+
   static BitWidth uwidth(num value) {
     if (value.toInt() == value) {
       var v = value.toInt().abs();
@@ -30,8 +29,11 @@
       if (v >> 32 == 0) return BitWidth.width32;
       return BitWidth.width64;
     }
-    return value == _toF32(value) ? BitWidth.width32 : BitWidth.width64;
+    return value == _toF32(value as double)
+        ? BitWidth.width32
+        : BitWidth.width64;
   }
+
   static BitWidth fromByteWidth(int value) {
     if (value == 1) {
       return BitWidth.width8;
@@ -45,11 +47,13 @@
     if (value == 8) {
       return BitWidth.width64;
     }
-    throw Exception('Unexpected value ${value}');
+    throw Exception('Unexpected value $value');
   }
+
   static int paddingSize(int bufSize, int scalarSize) {
     return (~bufSize + 1) & (scalarSize - 1);
   }
+
   static double _toF32(double value) {
     var bdata = ByteData(4);
     bdata.setFloat32(0, value);
@@ -66,15 +70,36 @@
 
 /// Represents all internal FlexBuffer types.
 enum ValueType {
-  Null, Int, UInt, Float,
-  Key, String, IndirectInt, IndirectUInt, IndirectFloat,
-  Map, Vector, VectorInt, VectorUInt, VectorFloat, VectorKey,
-  @Deprecated('VectorString is deprecated due to a flaw in the binary format (https://github.com/google/flatbuffers/issues/5627)')
+  Null,
+  Int,
+  UInt,
+  Float,
+  Key,
+  String,
+  IndirectInt,
+  IndirectUInt,
+  IndirectFloat,
+  Map,
+  Vector,
+  VectorInt,
+  VectorUInt,
+  VectorFloat,
+  VectorKey,
+  @Deprecated(
+      'VectorString is deprecated due to a flaw in the binary format (https://github.com/google/flatbuffers/issues/5627)')
   VectorString,
-  VectorInt2, VectorUInt2, VectorFloat2,
-  VectorInt3, VectorUInt3, VectorFloat3,
-  VectorInt4, VectorUInt4, VectorFloat4,
-  Blob, Bool, VectorBool
+  VectorInt2,
+  VectorUInt2,
+  VectorFloat2,
+  VectorInt3,
+  VectorUInt3,
+  VectorFloat3,
+  VectorInt4,
+  VectorUInt4,
+  VectorFloat4,
+  Blob,
+  Bool,
+  VectorBool
 }
 
 class ValueTypeUtils {
@@ -89,71 +114,70 @@
   }
 
   static bool isInline(ValueType self) {
-    return self == ValueType.Bool
-        || toInt(self) <= toInt(ValueType.Float);
+    return self == ValueType.Bool || toInt(self) <= toInt(ValueType.Float);
   }
 
   static bool isNumber(ValueType self) {
-    return toInt(self) >= toInt(ValueType.Int)
-        && toInt(self) <= toInt(ValueType.Float);
+    return toInt(self) >= toInt(ValueType.Int) &&
+        toInt(self) <= toInt(ValueType.Float);
   }
 
   static bool isIndirectNumber(ValueType self) {
-    return toInt(self) >= toInt(ValueType.IndirectInt)
-        && toInt(self) <= toInt(ValueType.IndirectFloat);
+    return toInt(self) >= toInt(ValueType.IndirectInt) &&
+        toInt(self) <= toInt(ValueType.IndirectFloat);
   }
 
   static bool isTypedVectorElement(ValueType self) {
     return self == ValueType.Bool ||
-        (
-            toInt(self) >= toInt(ValueType.Int)
-            && toInt(self) <= toInt(ValueType.String)
-        );
+        (toInt(self) >= toInt(ValueType.Int) &&
+            toInt(self) <= toInt(ValueType.String));
   }
 
   static bool isTypedVector(ValueType self) {
     return self == ValueType.VectorBool ||
-        (
-          toInt(self) >= toInt(ValueType.VectorInt)
-              && toInt(self) <= toInt(ValueType.VectorString)
-        );
+        (toInt(self) >= toInt(ValueType.VectorInt) &&
+            toInt(self) <= toInt(ValueType.VectorString));
   }
 
   static bool isFixedTypedVector(ValueType self) {
-    return (
-            toInt(self) >= toInt(ValueType.VectorInt2)
-                && toInt(self) <= toInt(ValueType.VectorFloat4)
-        );
+    return (toInt(self) >= toInt(ValueType.VectorInt2) &&
+        toInt(self) <= toInt(ValueType.VectorFloat4));
   }
 
   static bool isAVector(ValueType self) {
-    return (
-        isTypedVector(self) || isFixedTypedVector(self) || self == ValueType.Vector
-    );
+    return (isTypedVector(self) ||
+        isFixedTypedVector(self) ||
+        self == ValueType.Vector);
   }
 
   static ValueType toTypedVector(ValueType self, int length) {
     if (length == 0) {
-      return ValueTypeUtils.fromInt(toInt(self) - toInt(ValueType.Int) + toInt(ValueType.VectorInt));
+      return ValueTypeUtils.fromInt(
+          toInt(self) - toInt(ValueType.Int) + toInt(ValueType.VectorInt));
     }
     if (length == 2) {
-      return ValueTypeUtils.fromInt(toInt(self) - toInt(ValueType.Int) + toInt(ValueType.VectorInt2));
+      return ValueTypeUtils.fromInt(
+          toInt(self) - toInt(ValueType.Int) + toInt(ValueType.VectorInt2));
     }
     if (length == 3) {
-      return ValueTypeUtils.fromInt(toInt(self) - toInt(ValueType.Int) + toInt(ValueType.VectorInt3));
+      return ValueTypeUtils.fromInt(
+          toInt(self) - toInt(ValueType.Int) + toInt(ValueType.VectorInt3));
     }
     if (length == 4) {
-      return ValueTypeUtils.fromInt(toInt(self) - toInt(ValueType.Int) + toInt(ValueType.VectorInt4));
+      return ValueTypeUtils.fromInt(
+          toInt(self) - toInt(ValueType.Int) + toInt(ValueType.VectorInt4));
     }
     throw Exception('unexpected length ' + length.toString());
   }
 
   static ValueType typedVectorElementType(ValueType self) {
-    return ValueTypeUtils.fromInt(toInt(self) - toInt(ValueType.VectorInt) + toInt(ValueType.Int));
+    return ValueTypeUtils.fromInt(
+        toInt(self) - toInt(ValueType.VectorInt) + toInt(ValueType.Int));
   }
 
   static ValueType fixedTypedVectorElementType(ValueType self) {
-    return ValueTypeUtils.fromInt((toInt(self) - toInt(ValueType.VectorInt2)) % 3 + toInt(ValueType.Int));
+    return ValueTypeUtils.fromInt(
+        (toInt(self) - toInt(ValueType.VectorInt2)) % 3 + toInt(ValueType.Int));
   }
 
   static int fixedTypedVectorElementSize(ValueType self) {
diff --git a/dart/publish.sh b/dart/publish.sh
index 167a4a3..bda43ba 100755
--- a/dart/publish.sh
+++ b/dart/publish.sh
@@ -17,12 +17,20 @@
 # Note to pub consumers: this file is used to assist with publishing the
 # pub package from the flatbuffers repository and is not meant for general use.
 # As pub does not currently provide a way to exclude files, it is included here.
+set -e
 
-command -v pub >/dev/null 2>&1 || { echo >&2 "Require `pub` but it's not installed.  Aborting."; exit 1; }
+command -v dart >/dev/null 2>&1 || { echo >&2 "Require `dart` but it's not installed.  Aborting."; exit 1; }
 
-cp ../samples/monster.fbs example/
-cp ../tests/monster_test.fbs test/
-pub publish
+pushd ../tests
+./DartTest.sh
+popd
+
+pushd ../samples
+./dart_sample.sh
+popd
+
+dart pub publish
 
 rm example/monster.fbs
-rm test/monster_test.fbs
\ No newline at end of file
+rm test/*.fbs
+rm -rf test/sub
diff --git a/dart/pubspec.yaml b/dart/pubspec.yaml
index 78a7bf1..ae86570 100644
--- a/dart/pubspec.yaml
+++ b/dart/pubspec.yaml
@@ -1,20 +1,15 @@
 name: flat_buffers
-version: 1.12.0
-description: >
-  FlatBuffers reading and writing library for Dart.  Use the flatc compiler to
-  generate Dart classes for a FlatBuffers schema, and this library to assist with
-  reading and writing the binary format.
-
-  Based on original work by Konstantin Scheglov and Paul Berry of the Dart SDK team.
-authors:
-- Dan Field <dfield@gmail.com>
-- Konstantin Scheglov
-- Paul Berry
+version: 2.0.5
+description: FlatBuffers reading and writing library for Dart. Based on original work by Konstantin Scheglov and Paul Berry of the Dart SDK team.
 homepage: https://github.com/google/flatbuffers
 documentation: https://google.github.io/flatbuffers/index.html
-dev_dependencies:
-  test: ^1.3.0
-  test_reflective_loader: ^0.1.4
-  path: ^1.5.1
+
 environment:
-  sdk: '>=2.0.0-dev.28.0 <3.0.0'
\ No newline at end of file
+  sdk: '>=2.12.0 <3.0.0'
+
+dev_dependencies:
+  test: ^1.17.7
+  test_reflective_loader: ^0.2.0
+  path: ^1.8.0
+  lints: ^1.0.1
+
diff --git a/dart/test/flat_buffers_test.dart b/dart/test/flat_buffers_test.dart
index be500f2..8cee6b2 100644
--- a/dart/test/flat_buffers_test.dart
+++ b/dart/test/flat_buffers_test.dart
@@ -12,10 +12,12 @@
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
 import './monster_test_my_game.example_generated.dart' as example;
+import './monster_test_my_game.example2_generated.dart' as example2;
 
 main() {
   defineReflectiveSuite(() {
     defineReflectiveTests(BuilderTest);
+    defineReflectiveTests(ObjectAPITest);
     defineReflectiveTests(CheckOtherLangaugesData);
     defineReflectiveTests(GeneratorTest);
   });
@@ -28,34 +30,35 @@
 @reflectiveTest
 class CheckOtherLangaugesData {
   test_cppData() async {
-    List<int> data = await new io.File(path.join(
-      path.dirname(io.Platform.script.path),
+    List<int> data = await io.File(path.join(
+      path.context.current,
+      'test',
       'monsterdata_test.mon',
     )).readAsBytes();
-    example.Monster mon = new example.Monster(data);
+    example.Monster mon = example.Monster(data);
     expect(mon.hp, 80);
     expect(mon.mana, 150);
     expect(mon.name, 'MyMonster');
-    expect(mon.pos.x, 1.0);
-    expect(mon.pos.y, 2.0);
-    expect(mon.pos.z, 3.0);
-    expect(mon.pos.test1, 3.0);
-    expect(mon.pos.test2.value, 2.0);
-    expect(mon.pos.test3.a, 5);
-    expect(mon.pos.test3.b, 6);
-    expect(mon.testType.value, example.AnyTypeId.Monster.value);
+    expect(mon.pos!.x, 1.0);
+    expect(mon.pos!.y, 2.0);
+    expect(mon.pos!.z, 3.0);
+    expect(mon.pos!.test1, 3.0);
+    expect(mon.pos!.test2.value, 2.0);
+    expect(mon.pos!.test3.a, 5);
+    expect(mon.pos!.test3.b, 6);
+    expect(mon.testType!.value, example.AnyTypeId.Monster.value);
     expect(mon.test is example.Monster, true);
     final monster2 = mon.test as example.Monster;
     expect(monster2.name, "Fred");
 
-    expect(mon.inventory.length, 5);
-    expect(mon.inventory.reduce((cur, next) => cur + next), 10);
-    expect(mon.test4.length, 2);
-    expect(
-        mon.test4[0].a + mon.test4[0].b + mon.test4[1].a + mon.test4[1].b, 100);
-    expect(mon.testarrayofstring.length, 2);
-    expect(mon.testarrayofstring[0], "test1");
-    expect(mon.testarrayofstring[1], "test2");
+    expect(mon.inventory!.length, 5);
+    expect(mon.inventory!.reduce((cur, next) => cur + next), 10);
+    final test4 = mon.test4!;
+    expect(test4.length, 2);
+    expect(test4[0].a + test4[0].b + test4[1].a + test4[1].b, 100);
+    expect(mon.testarrayofstring!.length, 2);
+    expect(mon.testarrayofstring![0], "test1");
+    expect(mon.testarrayofstring![1], "test2");
 
     // this will fail if accessing any field fails.
     expect(
@@ -65,7 +68,7 @@
       'mana: 150, hp: 80, name: MyMonster, inventory: [0, 1, 2, 3, 4], '
       'color: Color{value: 8}, testType: AnyTypeId{value: 1}, '
       'test: Monster{pos: null, mana: 150, hp: 100, name: Fred, '
-      'inventory: null, color: Color{value: 8}, testType: AnyTypeId{value: 0}, '
+      'inventory: null, color: Color{value: 8}, testType: null, '
       'test: null, test4: null, testarrayofstring: null, '
       'testarrayoftables: null, enemy: null, testnestedflatbuffer: null, '
       'testempty: null, testbool: false, testhashs32Fnv1: 0, '
@@ -79,13 +82,16 @@
       'vectorOfWeakReferences: null, vectorOfStrongReferrables: null, '
       'coOwningReference: 0, vectorOfCoOwningReferences: null, '
       'nonOwningReference: 0, vectorOfNonOwningReferences: null, '
-      'anyUniqueType: AnyUniqueAliasesTypeId{value: 0}, anyUnique: null, '
-      'anyAmbiguousType: AnyAmbiguousAliasesTypeId{value: 0}, '
-      'anyAmbiguous: null, vectorOfEnums: null, signedEnum: Race{value: -1}}, '
+      'anyUniqueType: null, anyUnique: null, anyAmbiguousType: null, '
+      'anyAmbiguous: null, vectorOfEnums: null, signedEnum: Race{value: -1}, '
+      'testrequirednestedflatbuffer: null, scalarKeySortedTables: null, '
+      'nativeInline: null, '
+      'longEnumNonEnumDefault: LongEnum{value: 0}, '
+      'longEnumNormalDefault: LongEnum{value: 2}}, '
       'test4: [Test{a: 10, b: 20}, Test{a: 30, b: 40}], '
       'testarrayofstring: [test1, test2], testarrayoftables: null, '
       'enemy: Monster{pos: null, mana: 150, hp: 100, name: Fred, '
-      'inventory: null, color: Color{value: 8}, testType: AnyTypeId{value: 0}, '
+      'inventory: null, color: Color{value: 8}, testType: null, '
       'test: null, test4: null, testarrayofstring: null, '
       'testarrayoftables: null, enemy: null, testnestedflatbuffer: null, '
       'testempty: null, testbool: false, testhashs32Fnv1: 0, '
@@ -99,9 +105,12 @@
       'vectorOfWeakReferences: null, vectorOfStrongReferrables: null, '
       'coOwningReference: 0, vectorOfCoOwningReferences: null, '
       'nonOwningReference: 0, vectorOfNonOwningReferences: null, '
-      'anyUniqueType: AnyUniqueAliasesTypeId{value: 0}, anyUnique: null, '
-      'anyAmbiguousType: AnyAmbiguousAliasesTypeId{value: 0}, '
-      'anyAmbiguous: null, vectorOfEnums: null, signedEnum: Race{value: -1}}, '
+      'anyUniqueType: null, anyUnique: null, anyAmbiguousType: null, '
+      'anyAmbiguous: null, vectorOfEnums: null, signedEnum: Race{value: -1}, '
+      'testrequirednestedflatbuffer: null, scalarKeySortedTables: null, '
+      'nativeInline: null, '
+      'longEnumNonEnumDefault: LongEnum{value: 0}, '
+      'longEnumNormalDefault: LongEnum{value: 2}}, '
       'testnestedflatbuffer: null, testempty: null, testbool: true, '
       'testhashs32Fnv1: -579221183, testhashu32Fnv1: 3715746113, '
       'testhashs64Fnv1: 7930699090847568257, '
@@ -110,7 +119,9 @@
       'testhashs64Fnv1a: 4898026182817603057, '
       'testhashu64Fnv1a: 4898026182817603057, '
       'testarrayofbools: [true, false, true], testf: 3.14159, testf2: 3.0, '
-      'testf3: 0.0, testarrayofstring2: null, testarrayofsortedstruct: null, '
+      'testf3: 0.0, testarrayofstring2: null, testarrayofsortedstruct: ['
+      'Ability{id: 0, distance: 45}, Ability{id: 1, distance: 21}, '
+      'Ability{id: 5, distance: 12}], '
       'flex: null, test5: [Test{a: 10, b: 20}, Test{a: 30, b: 40}], '
       'vectorOfLongs: [1, 100, 10000, 1000000, 100000000], '
       'vectorOfDoubles: [-1.7976931348623157e+308, 0.0, 1.7976931348623157e+308], '
@@ -119,21 +130,46 @@
       'vectorOfStrongReferrables: null, coOwningReference: 0, '
       'vectorOfCoOwningReferences: null, nonOwningReference: 0, '
       'vectorOfNonOwningReferences: null, '
-      'anyUniqueType: AnyUniqueAliasesTypeId{value: 0}, anyUnique: null, '
-      'anyAmbiguousType: AnyAmbiguousAliasesTypeId{value: 0}, '
-      'anyAmbiguous: null, vectorOfEnums: null, signedEnum: Race{value: -1}}',
+      'anyUniqueType: null, anyUnique: null, '
+      'anyAmbiguousType: null, '
+      'anyAmbiguous: null, vectorOfEnums: null, signedEnum: Race{value: -1}, '
+      'testrequirednestedflatbuffer: null, scalarKeySortedTables: [Stat{id: '
+      'miss, val: 0, count: 0}, Stat{id: hit, val: 10, count: 1}], '
+      'nativeInline: Test{a: 1, b: 2}, '
+      'longEnumNonEnumDefault: LongEnum{value: 0}, '
+      'longEnumNormalDefault: LongEnum{value: 2}}',
     );
   }
 }
 
+/// Test a custom, fixed-memory allocator (no actual allocations performed)
+class CustomAllocator extends Allocator {
+  final _memory = ByteData(10 * 1024);
+  int _used = 0;
+
+  Uint8List buffer(int size) => _memory.buffer.asUint8List(_used - size, size);
+
+  @override
+  ByteData allocate(int size) {
+    if (size > _memory.lengthInBytes) {
+      throw UnsupportedError('Trying to allocate too much');
+    }
+    _used = size;
+    return ByteData.sublistView(_memory, 0, size);
+  }
+
+  @override
+  void deallocate(ByteData _) {}
+}
+
 @reflectiveTest
 class BuilderTest {
-  void test_monsterBuilder() {
-    final fbBuilder = new Builder();
+  void test_monsterBuilder([Builder? builder]) {
+    final fbBuilder = builder ?? Builder();
     final str = fbBuilder.writeString('MyMonster');
 
     fbBuilder.writeString('test1');
-    fbBuilder.writeString('test2');
+    fbBuilder.writeString('test2', asciiOptimization: true);
     final testArrayOfString = fbBuilder.endStructVector(2);
 
     final fred = fbBuilder.writeString('Fred');
@@ -141,12 +177,12 @@
     final List<int> treasure = [0, 1, 2, 3, 4];
     final inventory = fbBuilder.writeListUint8(treasure);
 
-    final monBuilder = new example.MonsterBuilder(fbBuilder)
+    final monBuilder = example.MonsterBuilder(fbBuilder)
       ..begin()
       ..addNameOffset(fred);
     final mon2 = monBuilder.finish();
 
-    final testBuilder = new example.TestBuilder(fbBuilder);
+    final testBuilder = example.TestBuilder(fbBuilder);
     testBuilder.finish(10, 20);
     testBuilder.finish(30, 40);
     final test4 = fbBuilder.endStructVector(2);
@@ -154,7 +190,7 @@
     monBuilder
       ..begin()
       ..addPos(
-        new example.Vec3Builder(fbBuilder).finish(
+        example.Vec3Builder(fbBuilder).finish(
           1.0,
           2.0,
           3.0,
@@ -174,50 +210,51 @@
     fbBuilder.finish(mon);
   }
 
-  void test_error_addInt32_withoutStartTable() {
-    Builder builder = new Builder();
+  void test_error_addInt32_withoutStartTable([Builder? builder]) {
+    builder ??= Builder();
     expect(() {
-      builder.addInt32(0, 0);
-    }, throwsStateError);
+      builder!.addInt32(0, 0);
+    }, throwsA(isA<AssertionError>()));
   }
 
   void test_error_addOffset_withoutStartTable() {
-    Builder builder = new Builder();
+    Builder builder = Builder();
     expect(() {
       builder.addOffset(0, 0);
-    }, throwsStateError);
+    }, throwsA(isA<AssertionError>()));
   }
 
   void test_error_endTable_withoutStartTable() {
-    Builder builder = new Builder();
+    Builder builder = Builder();
     expect(() {
       builder.endTable();
-    }, throwsStateError);
+    }, throwsA(isA<AssertionError>()));
   }
 
   void test_error_startTable_duringTable() {
-    Builder builder = new Builder();
-    builder.startTable();
+    Builder builder = Builder();
+    builder.startTable(0);
     expect(() {
-      builder.startTable();
-    }, throwsStateError);
+      builder.startTable(0);
+    }, throwsA(isA<AssertionError>()));
   }
 
   void test_error_writeString_duringTable() {
-    Builder builder = new Builder();
-    builder.startTable();
+    Builder builder = Builder();
+    builder.startTable(1);
     expect(() {
       builder.writeString('12345');
-    }, throwsStateError);
+    }, throwsA(isA<AssertionError>()));
   }
 
   void test_file_identifier() {
     Uint8List byteList;
     {
-      Builder builder = new Builder(initialSize: 0);
-      builder.startTable();
+      Builder builder = Builder(initialSize: 0);
+      builder.startTable(0);
       int offset = builder.endTable();
-      byteList = builder.finish(offset, 'Az~ÿ');
+      builder.finish(offset, 'Az~ÿ');
+      byteList = builder.buffer;
     }
     // Convert byteList to a ByteData so that we can read data from it.
     ByteData byteData = byteList.buffer.asByteData(byteList.offsetInBytes);
@@ -240,31 +277,46 @@
   }
 
   void test_low() {
-    Builder builder = new Builder(initialSize: 0);
-    expect((builder..putUint8(1)).lowFinish(), [1]);
-    expect((builder..putUint32(2)).lowFinish(), [2, 0, 0, 0, 0, 0, 0, 1]);
-    expect((builder..putUint8(3)).lowFinish(),
-        [0, 0, 0, 3, 2, 0, 0, 0, 0, 0, 0, 1]);
-    expect((builder..putUint8(4)).lowFinish(),
-        [0, 0, 4, 3, 2, 0, 0, 0, 0, 0, 0, 1]);
-    expect((builder..putUint8(5)).lowFinish(),
-        [0, 5, 4, 3, 2, 0, 0, 0, 0, 0, 0, 1]);
-    expect((builder..putUint32(6)).lowFinish(),
+    final allocator = CustomAllocator();
+    final builder = Builder(initialSize: 0, allocator: allocator);
+
+    builder.putUint8(1);
+    expect(allocator.buffer(builder.size()), [1]);
+
+    builder.putUint32(2);
+    expect(allocator.buffer(builder.size()), [2, 0, 0, 0, 0, 0, 0, 1]);
+
+    builder.putUint8(3);
+    expect(
+        allocator.buffer(builder.size()), [0, 0, 0, 3, 2, 0, 0, 0, 0, 0, 0, 1]);
+
+    builder.putUint8(4);
+    expect(
+        allocator.buffer(builder.size()), [0, 0, 4, 3, 2, 0, 0, 0, 0, 0, 0, 1]);
+
+    builder.putUint8(5);
+    expect(
+        allocator.buffer(builder.size()), [0, 5, 4, 3, 2, 0, 0, 0, 0, 0, 0, 1]);
+
+    builder.putUint32(6);
+    expect(allocator.buffer(builder.size()),
         [6, 0, 0, 0, 0, 5, 4, 3, 2, 0, 0, 0, 0, 0, 0, 1]);
   }
 
   void test_table_default() {
     List<int> byteList;
     {
-      Builder builder = new Builder(initialSize: 0);
-      builder.startTable();
+      final builder = Builder(initialSize: 0, allocator: CustomAllocator());
+      builder.startTable(2);
       builder.addInt32(0, 10, 10);
       builder.addInt32(1, 20, 10);
       int offset = builder.endTable();
-      byteList = builder.finish(offset);
+      builder.finish(offset);
+      byteList = builder.buffer;
+      expect(builder.size(), byteList.length);
     }
     // read and verify
-    BufferContext buffer = new BufferContext.fromBytes(byteList);
+    BufferContext buffer = BufferContext.fromBytes(byteList);
     int objectOffset = buffer.derefObject(0);
     // was not written, so uses the new default value
     expect(
@@ -278,15 +330,16 @@
         20);
   }
 
-  void test_table_format() {
+  void test_table_format([Builder? builder]) {
     Uint8List byteList;
     {
-      Builder builder = new Builder(initialSize: 0);
-      builder.startTable();
+      builder ??= Builder(initialSize: 0);
+      builder.startTable(3);
       builder.addInt32(0, 10);
       builder.addInt32(1, 20);
       builder.addInt32(2, 30);
-      byteList = builder.finish(builder.endTable());
+      builder.finish(builder.endTable());
+      byteList = builder.buffer;
     }
     // Convert byteList to a ByteData so that we can read data from it.
     ByteData byteData = byteList.buffer.asByteData(byteList.offsetInBytes);
@@ -315,30 +368,37 @@
     String unicodeString = 'Проба пера';
     List<int> byteList;
     {
-      Builder builder = new Builder(initialSize: 0);
-      int latinStringOffset = builder.writeString(latinString);
-      int unicodeStringOffset = builder.writeString(unicodeString);
-      builder.startTable();
+      Builder builder = Builder(initialSize: 0);
+      int? latinStringOffset =
+          builder.writeString(latinString, asciiOptimization: true);
+      int? unicodeStringOffset =
+          builder.writeString(unicodeString, asciiOptimization: true);
+      builder.startTable(2);
       builder.addOffset(0, latinStringOffset);
       builder.addOffset(1, unicodeStringOffset);
       int offset = builder.endTable();
-      byteList = builder.finish(offset);
+      builder.finish(offset);
+      byteList = builder.buffer;
     }
     // read and verify
-    BufferContext buf = new BufferContext.fromBytes(byteList);
+    BufferContext buf = BufferContext.fromBytes(byteList);
     int objectOffset = buf.derefObject(0);
-    expect(const StringReader().vTableGet(buf, objectOffset, indexToField(0)),
+    expect(
+        const StringReader()
+            .vTableGetNullable(buf, objectOffset, indexToField(0)),
         latinString);
-    expect(const StringReader().vTableGet(buf, objectOffset, indexToField(1)),
+    expect(
+        const StringReader(asciiOptimization: true)
+            .vTableGetNullable(buf, objectOffset, indexToField(1)),
         unicodeString);
   }
 
-  void test_table_types() {
+  void test_table_types([Builder? builder]) {
     List<int> byteList;
     {
-      Builder builder = new Builder(initialSize: 0);
-      int stringOffset = builder.writeString('12345');
-      builder.startTable();
+      builder ??= Builder(initialSize: 0);
+      int? stringOffset = builder.writeString('12345');
+      builder.startTable(7);
       builder.addBool(0, true);
       builder.addInt8(1, 10);
       builder.addInt32(2, 20);
@@ -347,24 +407,39 @@
       builder.addUint32(5, 0x9ABCDEF0);
       builder.addUint8(6, 0x9A);
       int offset = builder.endTable();
-      byteList = builder.finish(offset);
+      builder.finish(offset);
+      byteList = builder.buffer;
     }
     // read and verify
-    BufferContext buf = new BufferContext.fromBytes(byteList);
+    BufferContext buf = BufferContext.fromBytes(byteList);
     int objectOffset = buf.derefObject(0);
     expect(
-        const BoolReader().vTableGet(buf, objectOffset, indexToField(0)), true);
+        const BoolReader()
+            .vTableGetNullable(buf, objectOffset, indexToField(0)),
+        true);
     expect(
-        const Int8Reader().vTableGet(buf, objectOffset, indexToField(1)), 10);
+        const Int8Reader()
+            .vTableGetNullable(buf, objectOffset, indexToField(1)),
+        10);
     expect(
-        const Int32Reader().vTableGet(buf, objectOffset, indexToField(2)), 20);
-    expect(const StringReader().vTableGet(buf, objectOffset, indexToField(3)),
+        const Int32Reader()
+            .vTableGetNullable(buf, objectOffset, indexToField(2)),
+        20);
+    expect(
+        const StringReader()
+            .vTableGetNullable(buf, objectOffset, indexToField(3)),
         '12345');
     expect(
-        const Int32Reader().vTableGet(buf, objectOffset, indexToField(4)), 40);
-    expect(const Uint32Reader().vTableGet(buf, objectOffset, indexToField(5)),
+        const Int32Reader()
+            .vTableGetNullable(buf, objectOffset, indexToField(4)),
+        40);
+    expect(
+        const Uint32Reader()
+            .vTableGetNullable(buf, objectOffset, indexToField(5)),
         0x9ABCDEF0);
-    expect(const Uint8Reader().vTableGet(buf, objectOffset, indexToField(6)),
+    expect(
+        const Uint8Reader()
+            .vTableGetNullable(buf, objectOffset, indexToField(6)),
         0x9A);
   }
 
@@ -373,12 +448,13 @@
     // write
     List<int> byteList;
     {
-      Builder builder = new Builder(initialSize: 0);
+      Builder builder = Builder(initialSize: 0);
       int offset = builder.writeListUint32(values);
-      byteList = builder.finish(offset);
+      builder.finish(offset);
+      byteList = builder.buffer;
     }
     // read and verify
-    BufferContext buf = new BufferContext.fromBytes(byteList);
+    BufferContext buf = BufferContext.fromBytes(byteList);
     List<int> items = const Uint32ListReader().read(buf, 0);
     expect(items, hasLength(4));
     expect(items, orderedEquals(values));
@@ -389,16 +465,17 @@
       // write
       List<int> byteList;
       {
-        Builder builder = new Builder(initialSize: 0);
-        List<bool> values = new List<bool>.filled(len, false);
+        Builder builder = Builder(initialSize: 0);
+        List<bool> values = List<bool>.filled(len, false);
         for (int bit in trueBits) {
           values[bit] = true;
         }
         int offset = builder.writeListBool(values);
-        byteList = builder.finish(offset);
+        builder.finish(offset);
+        byteList = builder.buffer;
       }
       // read and verify
-      BufferContext buf = new BufferContext.fromBytes(byteList);
+      BufferContext buf = BufferContext.fromBytes(byteList);
       List<bool> items = const BoolListReader().read(buf, 0);
       expect(items, hasLength(len));
       for (int i = 0; i < items.length; i++) {
@@ -417,25 +494,26 @@
     verifyListBooleans(33, <int>[1, 2, 24, 25, 31, 32]);
     verifyListBooleans(63, <int>[]);
     verifyListBooleans(63, <int>[0, 1, 2, 61, 62]);
-    verifyListBooleans(63, new List<int>.generate(63, (i) => i));
+    verifyListBooleans(63, List<int>.generate(63, (i) => i));
     verifyListBooleans(64, <int>[]);
     verifyListBooleans(64, <int>[0, 1, 2, 61, 62, 63]);
     verifyListBooleans(64, <int>[1, 2, 62]);
     verifyListBooleans(64, <int>[0, 1, 2, 63]);
-    verifyListBooleans(64, new List<int>.generate(64, (i) => i));
+    verifyListBooleans(64, List<int>.generate(64, (i) => i));
     verifyListBooleans(100, <int>[0, 3, 30, 60, 90, 99]);
   }
 
   void test_writeList_ofInt32() {
     List<int> byteList;
     {
-      Builder builder = new Builder(initialSize: 0);
+      Builder builder = Builder(initialSize: 0);
       int offset = builder.writeListInt32(<int>[1, 2, 3, 4, 5]);
-      byteList = builder.finish(offset);
+      builder.finish(offset);
+      byteList = builder.buffer;
     }
     // read and verify
-    BufferContext buf = new BufferContext.fromBytes(byteList);
-    List<int> items = const ListReader<int>(const Int32Reader()).read(buf, 0);
+    BufferContext buf = BufferContext.fromBytes(byteList);
+    List<int> items = const ListReader<int>(Int32Reader()).read(buf, 0);
     expect(items, hasLength(5));
     expect(items, orderedEquals(<int>[1, 2, 3, 4, 5]));
   }
@@ -445,13 +523,14 @@
     // write
     List<int> byteList;
     {
-      Builder builder = new Builder(initialSize: 0);
+      Builder builder = Builder(initialSize: 0);
       int offset = builder.writeListFloat64(values);
-      byteList = builder.finish(offset);
+      builder.finish(offset);
+      byteList = builder.buffer;
     }
 
     // read and verify
-    BufferContext buf = new BufferContext.fromBytes(byteList);
+    BufferContext buf = BufferContext.fromBytes(byteList);
     List<double> items = const Float64ListReader().read(buf, 0);
 
     expect(items, hasLength(values.length));
@@ -465,12 +544,13 @@
     // write
     List<int> byteList;
     {
-      Builder builder = new Builder(initialSize: 0);
+      Builder builder = Builder(initialSize: 0);
       int offset = builder.writeListFloat32(values);
-      byteList = builder.finish(offset);
+      builder.finish(offset);
+      byteList = builder.buffer;
     }
     // read and verify
-    BufferContext buf = new BufferContext.fromBytes(byteList);
+    BufferContext buf = BufferContext.fromBytes(byteList);
     List<double> items = const Float32ListReader().read(buf, 0);
     expect(items, hasLength(5));
     for (int i = 0; i < values.length; i++) {
@@ -478,14 +558,14 @@
     }
   }
 
-  void test_writeList_ofObjects() {
+  void test_writeList_ofObjects([Builder? builder]) {
     List<int> byteList;
     {
-      Builder builder = new Builder(initialSize: 0);
+      builder ??= Builder(initialSize: 0);
       // write the object #1
       int object1;
       {
-        builder.startTable();
+        builder.startTable(2);
         builder.addInt32(0, 10);
         builder.addInt32(1, 20);
         object1 = builder.endTable();
@@ -493,19 +573,20 @@
       // write the object #1
       int object2;
       {
-        builder.startTable();
+        builder.startTable(2);
         builder.addInt32(0, 100);
         builder.addInt32(1, 200);
         object2 = builder.endTable();
       }
       // write the list
       int offset = builder.writeList([object1, object2]);
-      byteList = builder.finish(offset);
+      builder.finish(offset);
+      byteList = builder.buffer;
     }
     // read and verify
-    BufferContext buf = new BufferContext.fromBytes(byteList);
+    BufferContext buf = BufferContext.fromBytes(byteList);
     List<TestPointImpl> items =
-        const ListReader<TestPointImpl>(const TestPointReader()).read(buf, 0);
+        const ListReader<TestPointImpl>(TestPointReader()).read(buf, 0);
     expect(items, hasLength(2));
     expect(items[0].x, 10);
     expect(items[0].y, 20);
@@ -516,36 +597,37 @@
   void test_writeList_ofStrings_asRoot() {
     List<int> byteList;
     {
-      Builder builder = new Builder(initialSize: 0);
-      int str1 = builder.writeString('12345');
-      int str2 = builder.writeString('ABC');
+      Builder builder = Builder(initialSize: 0);
+      int? str1 = builder.writeString('12345');
+      int? str2 = builder.writeString('ABC');
       int offset = builder.writeList([str1, str2]);
-      byteList = builder.finish(offset);
+      builder.finish(offset);
+      byteList = builder.buffer;
     }
     // read and verify
-    BufferContext buf = new BufferContext.fromBytes(byteList);
-    List<String> items =
-        const ListReader<String>(const StringReader()).read(buf, 0);
+    BufferContext buf = BufferContext.fromBytes(byteList);
+    List<String> items = const ListReader<String>(StringReader()).read(buf, 0);
     expect(items, hasLength(2));
     expect(items, contains('12345'));
     expect(items, contains('ABC'));
   }
 
-  void test_writeList_ofStrings_inObject() {
+  void test_writeList_ofStrings_inObject([Builder? builder]) {
     List<int> byteList;
     {
-      Builder builder = new Builder(initialSize: 0);
+      builder ??= Builder(initialSize: 0);
       int listOffset = builder.writeList(
           [builder.writeString('12345'), builder.writeString('ABC')]);
-      builder.startTable();
+      builder.startTable(1);
       builder.addOffset(0, listOffset);
       int offset = builder.endTable();
-      byteList = builder.finish(offset);
+      builder.finish(offset);
+      byteList = builder.buffer;
     }
     // read and verify
-    BufferContext buf = new BufferContext.fromBytes(byteList);
-    StringListWrapperImpl reader = new StringListWrapperReader().read(buf, 0);
-    List<String> items = reader.items;
+    BufferContext buf = BufferContext.fromBytes(byteList);
+    StringListWrapperImpl reader = StringListWrapperReader().read(buf, 0);
+    List<String>? items = reader.items;
     expect(items, hasLength(2));
     expect(items, contains('12345'));
     expect(items, contains('ABC'));
@@ -554,12 +636,13 @@
   void test_writeList_ofUint32() {
     List<int> byteList;
     {
-      Builder builder = new Builder(initialSize: 0);
+      Builder builder = Builder(initialSize: 0);
       int offset = builder.writeListUint32(<int>[1, 2, 0x9ABCDEF0]);
-      byteList = builder.finish(offset);
+      builder.finish(offset);
+      byteList = builder.buffer;
     }
     // read and verify
-    BufferContext buf = new BufferContext.fromBytes(byteList);
+    BufferContext buf = BufferContext.fromBytes(byteList);
     List<int> items = const Uint32ListReader().read(buf, 0);
     expect(items, hasLength(3));
     expect(items, orderedEquals(<int>[1, 2, 0x9ABCDEF0]));
@@ -568,12 +651,13 @@
   void test_writeList_ofUint16() {
     List<int> byteList;
     {
-      Builder builder = new Builder(initialSize: 0);
+      Builder builder = Builder(initialSize: 0);
       int offset = builder.writeListUint16(<int>[1, 2, 60000]);
-      byteList = builder.finish(offset);
+      builder.finish(offset);
+      byteList = builder.buffer;
     }
     // read and verify
-    BufferContext buf = new BufferContext.fromBytes(byteList);
+    BufferContext buf = BufferContext.fromBytes(byteList);
     List<int> items = const Uint16ListReader().read(buf, 0);
     expect(items, hasLength(3));
     expect(items, orderedEquals(<int>[1, 2, 60000]));
@@ -582,15 +666,188 @@
   void test_writeList_ofUint8() {
     List<int> byteList;
     {
-      Builder builder = new Builder(initialSize: 0);
-      int offset = builder.writeListUint8(<int>[1, 2, 3, 4, 0x9A]);
-      byteList = builder.finish(offset);
+      Builder builder = Builder(initialSize: 0);
+      int offset = builder.writeListUint8(<int>[1, 2, 3, 4, 0x9A, 0xFA]);
+      builder.finish(offset);
+      byteList = builder.buffer;
     }
     // read and verify
-    BufferContext buf = new BufferContext.fromBytes(byteList);
-    List<int> items = const Uint8ListReader().read(buf, 0);
-    expect(items, hasLength(5));
-    expect(items, orderedEquals(<int>[1, 2, 3, 4, 0x9A]));
+    BufferContext buf = BufferContext.fromBytes(byteList);
+    const buffOffset = 8; // 32-bit offset to the list, + 32-bit length
+    for (final lazy in [true, false]) {
+      List<int> items = Uint8ListReader(lazy: lazy).read(buf, 0);
+      expect(items, hasLength(6));
+      expect(items, orderedEquals(<int>[1, 2, 3, 4, 0x9A, 0xFA]));
+
+      // overwrite the buffer to verify the laziness
+      buf.buffer.setUint8(buffOffset + 1, 99);
+      expect(items, orderedEquals(<int>[1, lazy ? 99 : 2, 3, 4, 0x9A, 0xFA]));
+
+      // restore the previous value for the next loop
+      buf.buffer.setUint8(buffOffset + 1, 2);
+    }
+  }
+
+  void test_reset() {
+    // We'll run a selection of tests , reusing the builder between them.
+    final testCases = <void Function(Builder?)>[
+      test_monsterBuilder,
+      test_error_addInt32_withoutStartTable,
+      test_table_format,
+      test_table_types,
+      test_writeList_ofObjects,
+      test_writeList_ofStrings_inObject
+    ];
+
+    // Execute all test cases in all permutations of their order.
+    // To do that, we generate permutations of test case indexes.
+    final testCasesPermutations =
+        _permutationsOf(List.generate(testCases.length, (index) => index));
+    expect(testCasesPermutations.length, _factorial(testCases.length));
+
+    for (var indexes in testCasesPermutations) {
+      // print the order so failures are reproducible
+      printOnFailure('Running reset() test cases in order: $indexes');
+
+      Builder? builder;
+      for (var index in indexes) {
+        if (builder == null) {
+          // Initial size small enough so at least one test case increases it.
+          // On the other hand, it's large enough so that some test cases don't.
+          builder = Builder(initialSize: 32);
+        } else {
+          builder.reset();
+        }
+        testCases[index](builder);
+      }
+    }
+  }
+
+  // Generate permutations of the given list
+  List<List<T>> _permutationsOf<T>(List<T> source) {
+    final result = <List<T>>[];
+
+    void permutate(List<T> items, int startAt) {
+      for (var i = startAt; i < items.length; i++) {
+        List<T> permutation = items.toList(growable: false);
+        permutation[i] = items[startAt];
+        permutation[startAt] = items[i];
+
+        // add the current list upon reaching the end
+        if (startAt == items.length - 1) {
+          result.add(items);
+        } else {
+          permutate(permutation, startAt + 1);
+        }
+      }
+    }
+
+    permutate(source, 0);
+    return result;
+  }
+
+  // a very simple implementation of n!
+  int _factorial(int n) {
+    var result = 1;
+    for (var i = 2; i <= n; i++) {
+      result *= i;
+    }
+    return result;
+  }
+}
+
+@reflectiveTest
+class ObjectAPITest {
+  void test_tableStat() {
+    final object1 = example.StatT(count: 3, id: "foo", val: 4);
+    expect(object1 is Packable, isTrue);
+    final fbb = Builder();
+    fbb.finish(object1.pack(fbb));
+    final object2 = example.Stat(fbb.buffer).unpack();
+    expect(object2.count, object1.count);
+    expect(object2.id, object1.id);
+    expect(object2.val, object1.val);
+    expect(object2.toString(), object1.toString());
+  }
+
+  void test_tableMonster() {
+    final monster = example.MonsterT()
+      ..pos = example.Vec3T(
+          x: 1,
+          y: 2,
+          z: 3,
+          test1: 4.0,
+          test2: example.Color.Red,
+          test3: example.TestT(a: 1, b: 2))
+      ..mana = 2
+      ..name = 'Monstrous'
+      ..inventory = [24, 42]
+      ..color = example.Color.Green
+      // TODO be smarter for unions and automatically set the `type` field?
+      ..testType = example.AnyTypeId.MyGame_Example2_Monster
+      ..test = example2.MonsterT()
+      ..test4 = [example.TestT(a: 3, b: 4), example.TestT(a: 5, b: 6)]
+      ..testarrayofstring = ["foo", "bar"]
+      ..testarrayoftables = [example.MonsterT(name: 'Oof')]
+      ..enemy = example.MonsterT(name: 'Enemy')
+      ..testarrayofbools = [false, true, false]
+      ..testf = 42.24
+      ..testarrayofsortedstruct = [
+        example.AbilityT(id: 1, distance: 5),
+        example.AbilityT(id: 3, distance: 7)
+      ]
+      ..vectorOfLongs = [5, 6, 7]
+      ..vectorOfDoubles = [8.9, 9.0, 10.1, 11.2]
+      ..anyAmbiguousType = example.AnyAmbiguousAliasesTypeId.M2
+      ..anyAmbiguous = null
+      ..vectorOfEnums = [example.Color.Blue, example.Color.Green]
+      ..signedEnum = example.Race.None;
+
+    final fbBuilder = Builder();
+    final offset = monster.pack(fbBuilder);
+    expect(offset, isNonZero);
+    fbBuilder.finish(offset);
+    final data = fbBuilder.buffer;
+
+    // TODO currently broken because of struct builder issue, see #6688
+    // final monster2 = example.Monster(data); // Monster (reader)
+    // expect(
+    //     // map Monster => MonsterT, Vec3 => Vec3T, ...
+    //     monster2.toString().replaceAllMapped(
+    //         RegExp('([a-zA-z0-9]+){'), (match) => match.group(1) + 'T{'),
+    //     monster.toString());
+    //
+    // final monster3 = monster2.unpack(); // MonsterT
+    // expect(monster3.toString(), monster.toString());
+  }
+
+  void test_Lists() {
+    // Ensure unpack() reads lists eagerly by reusing the same builder and
+    // overwriting data. Why: because standard reader reads lists lazily...
+    final fbb = Builder();
+
+    final object1 = example.TypeAliasesT(v8: [1, 2, 3], vf64: [5, 6]);
+    fbb.finish(object1.pack(fbb));
+    final object1Read = example.TypeAliases(fbb.buffer).unpack();
+
+    // overwrite the original buffer by writing to the same builder
+    fbb.reset();
+    final object2 = example.TypeAliasesT(v8: [7, 8, 9], vf64: [10, 11]);
+    fbb.finish(object2.pack(fbb));
+    final object2Read = example.TypeAliases(fbb.buffer).unpack();
+
+    // this is fine even with lazy lists:
+    expect(object2.toString(), object2Read.toString());
+
+    // this fails with lazy lists:
+    expect(object1.toString(), object1Read.toString());
+
+    // empty list must be serialized as such (were stored NULL before v2.0)
+    fbb.reset();
+    final object3 = example.TypeAliasesT(v8: [], vf64: null);
+    fbb.finish(object3.pack(fbb));
+    final object3Read = example.TypeAliases(fbb.buffer).unpack();
+    expect(object3.toString(), object3Read.toString());
   }
 }
 
@@ -600,8 +857,8 @@
 
   StringListWrapperImpl(this.bp, this.offset);
 
-  List<String> get items => const ListReader<String>(const StringReader())
-      .vTableGet(bp, offset, indexToField(0));
+  List<String>? get items => const ListReader<String>(StringReader())
+      .vTableGetNullable(bp, offset, indexToField(0));
 }
 
 class StringListWrapperReader extends TableReader<StringListWrapperImpl> {
@@ -609,7 +866,7 @@
 
   @override
   StringListWrapperImpl createObject(BufferContext object, int offset) {
-    return new StringListWrapperImpl(object, offset);
+    return StringListWrapperImpl(object, offset);
   }
 }
 
@@ -629,7 +886,7 @@
 
   @override
   TestPointImpl createObject(BufferContext object, int offset) {
-    return new TestPointImpl(object, offset);
+    return TestPointImpl(object, offset);
   }
 }
 
@@ -639,7 +896,9 @@
     expect(example.Color.values, same(example.Color.values));
     expect(example.Race.values, same(example.Race.values));
     expect(example.AnyTypeId.values, same(example.AnyTypeId.values));
-    expect(example.AnyUniqueAliasesTypeId.values, same(example.AnyUniqueAliasesTypeId.values));
-    expect(example.AnyAmbiguousAliasesTypeId.values, same(example.AnyAmbiguousAliasesTypeId.values));
+    expect(example.AnyUniqueAliasesTypeId.values,
+        same(example.AnyUniqueAliasesTypeId.values));
+    expect(example.AnyAmbiguousAliasesTypeId.values,
+        same(example.AnyAmbiguousAliasesTypeId.values));
   }
 }
diff --git a/dart/test/flex_builder_test.dart b/dart/test/flex_builder_test.dart
index 5a1c1a8..66e6638 100644
--- a/dart/test/flex_builder_test.dart
+++ b/dart/test/flex_builder_test.dart
@@ -58,18 +58,18 @@
     {
       var flx = Builder();
       flx.addString('hello 😱');
-      expect(flx.finish(), [10, 104, 101, 108, 108, 111, 32, 240, 159, 152, 177, 0, 11, 20, 1]);
+      expect(flx.finish(),
+          [10, 104, 101, 108, 108, 111, 32, 240, 159, 152, 177, 0, 11, 20, 1]);
     }
   });
 
-  test('build vector', (){
+  test('build vector', () {
     {
       var flx = Builder()
         ..startVector()
         ..addInt(1)
         ..addInt(2)
-        ..end()
-      ;
+        ..end();
       expect(flx.finish(), [1, 2, 2, 64, 1]);
     }
     {
@@ -77,8 +77,7 @@
         ..startVector()
         ..addInt(-1)
         ..addInt(256)
-        ..end()
-      ;
+        ..end();
       expect(flx.finish(), [255, 255, 0, 1, 4, 65, 1]);
     }
     {
@@ -86,8 +85,7 @@
         ..startVector()
         ..addInt(-45)
         ..addInt(256000)
-        ..end()
-      ;
+        ..end();
       expect(flx.finish(), [211, 255, 255, 255, 0, 232, 3, 0, 8, 66, 1]);
     }
     {
@@ -95,9 +93,28 @@
         ..startVector()
         ..addDouble(1.1)
         ..addDouble(-256)
-        ..end()
-      ;
-      expect(flx.finish(), [154, 153, 153, 153, 153, 153, 241, 63, 0, 0, 0, 0, 0, 0, 112, 192, 16, 75, 1]);
+        ..end();
+      expect(flx.finish(), [
+        154,
+        153,
+        153,
+        153,
+        153,
+        153,
+        241,
+        63,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        112,
+        192,
+        16,
+        75,
+        1
+      ]);
     }
     {
       var flx = Builder()
@@ -105,8 +122,7 @@
         ..addInt(1)
         ..addInt(2)
         ..addInt(4)
-        ..end()
-      ;
+        ..end();
       expect(flx.finish(), [1, 2, 4, 3, 76, 1]);
     }
     {
@@ -115,19 +131,17 @@
         ..addInt(-1)
         ..addInt(256)
         ..addInt(4)
-        ..end()
-      ;
+        ..end();
       expect(flx.finish(), [255, 255, 0, 1, 4, 0, 6, 77, 1]);
     }
     {
       var flx = Builder()
         ..startVector()
-          ..startVector()
-          ..addInt(61)
-          ..end()
-        ..addInt(64)
+        ..startVector()
+        ..addInt(61)
         ..end()
-      ;
+        ..addInt(64)
+        ..end();
       expect(flx.finish(), [1, 61, 2, 2, 64, 44, 4, 4, 40, 1]);
     }
     {
@@ -136,9 +150,31 @@
         ..addString('foo')
         ..addString('bar')
         ..addString('baz')
-        ..end()
-      ;
-      expect(flx.finish(), [3, 102, 111, 111, 0, 3, 98, 97, 114, 0, 3, 98, 97, 122, 0, 3, 15, 11, 7, 3, 60, 1]);
+        ..end();
+      expect(flx.finish(), [
+        3,
+        102,
+        111,
+        111,
+        0,
+        3,
+        98,
+        97,
+        114,
+        0,
+        3,
+        98,
+        97,
+        122,
+        0,
+        3,
+        15,
+        11,
+        7,
+        3,
+        60,
+        1
+      ]);
     }
     {
       var flx = Builder()
@@ -149,9 +185,34 @@
         ..addString('foo')
         ..addString('bar')
         ..addString('baz')
-        ..end()
-      ;
-      expect(flx.finish(), [3, 102, 111, 111, 0, 3, 98, 97, 114, 0, 3, 98, 97, 122, 0, 6, 15, 11, 7, 18, 14, 10, 6, 60, 1]);
+        ..end();
+      expect(flx.finish(), [
+        3,
+        102,
+        111,
+        111,
+        0,
+        3,
+        98,
+        97,
+        114,
+        0,
+        3,
+        98,
+        97,
+        122,
+        0,
+        6,
+        15,
+        11,
+        7,
+        18,
+        14,
+        10,
+        6,
+        60,
+        1
+      ]);
     }
     {
       var flx = Builder()
@@ -159,8 +220,7 @@
         ..addBool(true)
         ..addBool(false)
         ..addBool(true)
-        ..end()
-      ;
+        ..end();
       expect(flx.finish(), [3, 1, 0, 1, 3, 144, 1]);
     }
     {
@@ -171,29 +231,83 @@
         ..addInt(-5)
         ..addDouble(1.3)
         ..addBool(true)
-        ..end()
-      ;
+        ..end();
       expect(flx.finish(), [
-        3, 102, 111, 111, 0, 0, 0, 0,
-        5, 0, 0, 0, 0, 0, 0, 0,
-        15, 0, 0, 0, 0, 0, 0, 0,
-        1, 0, 0, 0, 0, 0, 0, 0,
-        251, 255, 255, 255, 255, 255, 255, 255,
-        205, 204, 204, 204, 204, 204, 244, 63,
-        1, 0, 0, 0, 0, 0, 0, 0,
-        20, 4, 4, 15, 104, 45, 43, 1]);
+        3,
+        102,
+        111,
+        111,
+        0,
+        0,
+        0,
+        0,
+        5,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        15,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        1,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        251,
+        255,
+        255,
+        255,
+        255,
+        255,
+        255,
+        255,
+        205,
+        204,
+        204,
+        204,
+        204,
+        204,
+        244,
+        63,
+        1,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        20,
+        4,
+        4,
+        15,
+        104,
+        45,
+        43,
+        1
+      ]);
     }
   });
 
-  test('build map', ()
-  {
+  test('build map', () {
     {
       var flx = Builder()
         ..startMap()
         ..addKey('a')
         ..addInt(12)
-        ..end()
-      ;
+        ..end();
       expect(flx.finish(), [97, 0, 1, 3, 1, 1, 1, 12, 4, 2, 36, 1]);
     }
     {
@@ -203,105 +317,270 @@
         ..addInt(12)
         ..addKey('')
         ..addInt(45)
-        ..end()
-      ;
-      expect(flx.finish(), [97, 0, 0, 2, 2, 5, 2, 1, 2, 45, 12, 4, 4, 4, 36, 1]);
+        ..end();
+      expect(
+          flx.finish(), [97, 0, 0, 2, 2, 5, 2, 1, 2, 45, 12, 4, 4, 4, 36, 1]);
     }
     {
       var flx = Builder()
         ..startVector()
-          ..startMap()
-            ..addKey('something')
-            ..addInt(12)
-          ..end()
-          ..startMap()
-            ..addKey('something')
-            ..addInt(45)
-          ..end()
+        ..startMap()
+        ..addKey('something')
+        ..addInt(12)
         ..end()
-      ;
-      expect(flx.finish(), [115, 111, 109, 101, 116, 104, 105, 110, 103, 0,
-        1, 11, 1, 1, 1, 12, 4, 6, 1, 1, 45, 4, 2, 8, 4, 36, 36, 4, 40, 1]);
+        ..startMap()
+        ..addKey('something')
+        ..addInt(45)
+        ..end()
+        ..end();
+      expect(flx.finish(), [
+        115,
+        111,
+        109,
+        101,
+        116,
+        104,
+        105,
+        110,
+        103,
+        0,
+        1,
+        11,
+        1,
+        1,
+        1,
+        12,
+        4,
+        6,
+        1,
+        1,
+        45,
+        4,
+        2,
+        8,
+        4,
+        36,
+        36,
+        4,
+        40,
+        1
+      ]);
     }
   });
 
-  test('build blob', ()
-  {
+  test('build blob', () {
     {
-      var flx = Builder()
-        ..addBlob(Uint8List.fromList([1, 2, 3]).buffer)
-      ;
+      var flx = Builder()..addBlob(Uint8List.fromList([1, 2, 3]).buffer);
       expect(flx.finish(), [3, 1, 2, 3, 3, 100, 1]);
     }
   });
 
-  test('build from object', (){
-    expect(Builder.buildFromObject(Uint8List.fromList([1, 2, 3]).buffer).asUint8List(), [3, 1, 2, 3, 3, 100, 1]);
+  test('build from object', () {
+    expect(
+        Builder.buildFromObject(Uint8List.fromList([1, 2, 3]).buffer)
+            .asUint8List(),
+        [3, 1, 2, 3, 3, 100, 1]);
     expect(Builder.buildFromObject(null).asUint8List(), [0, 0, 1]);
     expect(Builder.buildFromObject(true).asUint8List(), [1, 104, 1]);
     expect(Builder.buildFromObject(false).asUint8List(), [0, 104, 1]);
     expect(Builder.buildFromObject(25).asUint8List(), [25, 4, 1]);
     expect(Builder.buildFromObject(-250).asUint8List(), [6, 255, 5, 2]);
-    expect(Builder.buildFromObject(-2.50).asUint8List(), [0, 0, 32, 192, 14, 4]);
-    expect(Builder.buildFromObject('Maxim').asUint8List(), [5, 77, 97, 120, 105, 109, 0, 6, 20, 1]);
-    expect(Builder.buildFromObject([1, 3.3, 'max', true, null, false]).asUint8List(), [
-      3, 109, 97, 120, 0, 0, 0, 0,
-      6, 0, 0, 0, 0, 0, 0, 0,
-      1, 0, 0, 0, 0, 0, 0, 0,
-      102, 102, 102, 102, 102, 102, 10, 64,
-      31, 0, 0, 0, 0, 0, 0, 0,
-      1, 0, 0, 0, 0, 0, 0, 0,
-      0, 0, 0, 0, 0, 0, 0, 0,
-      0, 0, 0, 0, 0, 0, 0, 0,
-      4, 15, 20, 104, 0, 104, 54, 43, 1
-    ]);
-    expect(Builder.buildFromObject([{'something':12}, {'something': 45}]).asUint8List(), [
-      115, 111, 109, 101, 116, 104, 105, 110, 103, 0,
-      1, 11, 1, 1, 1, 12, 4, 6, 1, 1, 45, 4, 2, 8, 4, 36, 36, 4, 40, 1
-    ]);
+    expect(
+        Builder.buildFromObject(-2.50).asUint8List(), [0, 0, 32, 192, 14, 4]);
+    expect(Builder.buildFromObject('Maxim').asUint8List(),
+        [5, 77, 97, 120, 105, 109, 0, 6, 20, 1]);
+    expect(
+        Builder.buildFromObject([1, 3.3, 'max', true, null, false])
+            .asUint8List(),
+        [
+          3,
+          109,
+          97,
+          120,
+          0,
+          0,
+          0,
+          0,
+          6,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          1,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          102,
+          102,
+          102,
+          102,
+          102,
+          102,
+          10,
+          64,
+          31,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          1,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          4,
+          15,
+          20,
+          104,
+          0,
+          104,
+          54,
+          43,
+          1
+        ]);
+    expect(
+        Builder.buildFromObject([
+          {'something': 12},
+          {'something': 45}
+        ]).asUint8List(),
+        [
+          115,
+          111,
+          109,
+          101,
+          116,
+          104,
+          105,
+          110,
+          103,
+          0,
+          1,
+          11,
+          1,
+          1,
+          1,
+          12,
+          4,
+          6,
+          1,
+          1,
+          45,
+          4,
+          2,
+          8,
+          4,
+          36,
+          36,
+          4,
+          40,
+          1
+        ]);
   });
 
-  test('add double indirectly', (){
-    var flx = Builder()
-      ..addDoubleIndirectly(0.1)
-    ;
+  test('add double indirectly', () {
+    var flx = Builder()..addDoubleIndirectly(0.1);
     expect(flx.finish(), [154, 153, 153, 153, 153, 153, 185, 63, 8, 35, 1]);
   });
 
-  test('add double indirectly to vector with cache', (){
+  test('add double indirectly to vector with cache', () {
     var flx = Builder()
       ..startVector()
       ..addDoubleIndirectly(0.1, cache: true)
       ..addDoubleIndirectly(0.1, cache: true)
       ..addDoubleIndirectly(0.1, cache: true)
       ..addDoubleIndirectly(0.1, cache: true)
-      ..end()
-    ;
-    expect(flx.finish(), [154, 153, 153, 153, 153, 153, 185, 63,
-      4, 9, 10, 11, 12, 35, 35, 35, 35, 8, 40, 1]);
+      ..end();
+    expect(flx.finish(), [
+      154,
+      153,
+      153,
+      153,
+      153,
+      153,
+      185,
+      63,
+      4,
+      9,
+      10,
+      11,
+      12,
+      35,
+      35,
+      35,
+      35,
+      8,
+      40,
+      1
+    ]);
   });
 
-  test('add int indirectly', (){
-    var flx = Builder()
-      ..addIntIndirectly(2345234523452345)
-    ;
+  test('add int indirectly', () {
+    var flx = Builder()..addIntIndirectly(2345234523452345);
     expect(flx.finish(), [185, 115, 175, 118, 250, 84, 8, 0, 8, 27, 1]);
   });
 
-  test('add int indirectly to vector with cache', (){
+  test('add int indirectly to vector with cache', () {
     var flx = Builder()
       ..startVector()
       ..addIntIndirectly(2345234523452345, cache: true)
       ..addIntIndirectly(2345234523452345, cache: true)
       ..addIntIndirectly(2345234523452345, cache: true)
       ..addIntIndirectly(2345234523452345, cache: true)
-      ..end()
-    ;
-    expect(flx.finish(), [185, 115, 175, 118, 250, 84, 8, 0,
-      4, 9, 10, 11, 12, 27, 27, 27, 27, 8, 40, 1]);
+      ..end();
+    expect(flx.finish(), [
+      185,
+      115,
+      175,
+      118,
+      250,
+      84,
+      8,
+      0,
+      4,
+      9,
+      10,
+      11,
+      12,
+      27,
+      27,
+      27,
+      27,
+      8,
+      40,
+      1
+    ]);
   });
 
-  test('snapshot', (){
+  test('snapshot', () {
     var flx = Builder();
     flx.startVector();
     flx.addInt(12);
@@ -312,4 +591,3 @@
     expect(flx.snapshot().asUint8List(), [12, 24, 45, 3, 76, 1]);
   });
 }
-
diff --git a/dart/test/flex_reader_test.dart b/dart/test/flex_reader_test.dart
index ec30367..875b1c1 100644
--- a/dart/test/flex_reader_test.dart
+++ b/dart/test/flex_reader_test.dart
@@ -21,55 +21,68 @@
     expect(Reference.fromBuffer(b([255, 251, 5, 2])).intValue, -1025);
     expect(Reference.fromBuffer(b([1, 4, 9, 2])).intValue, 1025);
     expect(Reference.fromBuffer(b([255, 255, 255, 127, 6, 4])).intValue,
-      2147483647);
+        2147483647);
+    expect(Reference.fromBuffer(b([0, 0, 0, 128, 6, 4])).intValue, -2147483648);
     expect(
-      Reference.fromBuffer(b([0, 0, 0, 128, 6, 4])).intValue, -2147483648);
+        Reference.fromBuffer(b([255, 255, 255, 255, 0, 0, 0, 0, 7, 8]))
+            .intValue,
+        4294967295);
     expect(
-      Reference.fromBuffer(b([255, 255, 255, 255, 0, 0, 0, 0, 7, 8]))
-        .intValue,
-      4294967295);
-    expect(
-      Reference.fromBuffer(b([255, 255, 255, 255, 255, 255, 255, 127, 7, 8]))
-        .intValue,
-      9223372036854775807);
+        Reference.fromBuffer(b([255, 255, 255, 255, 255, 255, 255, 127, 7, 8]))
+            .intValue,
+        9223372036854775807);
     expect(Reference.fromBuffer(b([0, 0, 0, 0, 0, 0, 0, 128, 7, 8])).intValue,
-      -9223372036854775808);
+        -9223372036854775808);
     // Dart does not really support UInt64
 //      expect(FlxValue.fromBuffer(b([255, 255, 255, 255, 255, 255, 255, 255, 11, 8])).intValue, 18446744073709551615);
   });
   test('double value', () {
     expect(Reference.fromBuffer(b([0, 0, 144, 64, 14, 4])).doubleValue, 4.5);
     expect(Reference.fromBuffer(b([205, 204, 204, 61, 14, 4])).doubleValue,
-      closeTo(.1, .001));
+        closeTo(.1, .001));
     expect(
-      Reference.fromBuffer(b([154, 153, 153, 153, 153, 153, 185, 63, 15, 8]))
-        .doubleValue,
-      .1);
+        Reference.fromBuffer(b([154, 153, 153, 153, 153, 153, 185, 63, 15, 8]))
+            .doubleValue,
+        .1);
   });
   test('num value', () {
     expect(Reference.fromBuffer(b([0, 0, 144, 64, 14, 4])).numValue, 4.5);
     expect(Reference.fromBuffer(b([205, 204, 204, 61, 14, 4])).numValue,
-      closeTo(.1, .001));
+        closeTo(.1, .001));
     expect(
-      Reference.fromBuffer(b([154, 153, 153, 153, 153, 153, 185, 63, 15, 8]))
-        .numValue,
-      .1);
+        Reference.fromBuffer(b([154, 153, 153, 153, 153, 153, 185, 63, 15, 8]))
+            .numValue,
+        .1);
     expect(Reference.fromBuffer(b([255, 251, 5, 2])).numValue, -1025);
   });
   test('string value', () {
     expect(
-      Reference.fromBuffer(b([5, 77, 97, 120, 105, 109, 0, 6, 20, 1]))
-        .stringValue,
-      'Maxim');
+        Reference.fromBuffer(b([5, 77, 97, 120, 105, 109, 0, 6, 20, 1]))
+            .stringValue,
+        'Maxim');
     expect(
-      Reference.fromBuffer(b([
-        10, 104, 101, 108, 108, 111, 32, 240, 159, 152, 177, 0, 11, 20, 1
-      ])).stringValue,
-      'hello 😱');
+        Reference.fromBuffer(b([
+          10,
+          104,
+          101,
+          108,
+          108,
+          111,
+          32,
+          240,
+          159,
+          152,
+          177,
+          0,
+          11,
+          20,
+          1
+        ])).stringValue,
+        'hello 😱');
   });
   test('blob value', () {
     expect(
-      Reference.fromBuffer(b([3, 1, 2, 3, 3, 100, 1])).blobValue, [1, 2, 3]);
+        Reference.fromBuffer(b([3, 1, 2, 3, 3, 100, 1])).blobValue, [1, 2, 3]);
   });
   test('bool vector', () {
     var flx = Reference.fromBuffer(b([3, 1, 0, 1, 3, 144, 1]));
@@ -81,27 +94,92 @@
     testNumbers([3, 1, 2, 3, 3, 44, 1], [1, 2, 3]);
     testNumbers([3, 255, 2, 3, 3, 44, 1], [-1, 2, 3]);
     testNumbers([3, 0, 1, 0, 43, 2, 3, 0, 6, 45, 1], [1, 555, 3]);
-    testNumbers(
-      [3, 0, 0, 0, 1, 0, 0, 0, 204, 216, 0, 0, 3, 0, 0, 0, 12, 46, 1],
-      [1, 55500, 3]);
+    testNumbers([3, 0, 0, 0, 1, 0, 0, 0, 204, 216, 0, 0, 3, 0, 0, 0, 12, 46, 1],
+        [1, 55500, 3]);
     testNumbers([
-      3, 0, 0, 0, 0, 0, 0, 0,
-      1, 0, 0, 0, 0, 0, 0, 0,
-      172, 128, 94, 239, 12, 0, 0, 0,
-      3, 0, 0, 0, 0, 0, 0, 0,
-      24, 47, 1
-    ], [1, 55555555500, 3
+      3,
+      0,
+      0,
+      0,
+      0,
+      0,
+      0,
+      0,
+      1,
+      0,
+      0,
+      0,
+      0,
+      0,
+      0,
+      0,
+      172,
+      128,
+      94,
+      239,
+      12,
+      0,
+      0,
+      0,
+      3,
+      0,
+      0,
+      0,
+      0,
+      0,
+      0,
+      0,
+      24,
+      47,
+      1
+    ], [
+      1,
+      55555555500,
+      3
     ]);
     testNumbers(
-      [3, 0, 0, 0, 0, 0, 192, 63, 0, 0, 32, 64, 0, 0, 96, 64, 12, 54, 1],
-      [1.5, 2.5, 3.5]);
+        [3, 0, 0, 0, 0, 0, 192, 63, 0, 0, 32, 64, 0, 0, 96, 64, 12, 54, 1],
+        [1.5, 2.5, 3.5]);
     testNumbers([
-      3, 0, 0, 0, 0, 0, 0, 0,
-      154, 153, 153, 153, 153, 153, 241, 63,
-      154, 153, 153, 153, 153, 153, 1, 64,
-      102, 102, 102, 102, 102, 102, 10, 64,
-      24, 55, 1
-    ], [1.1, 2.2, 3.3
+      3,
+      0,
+      0,
+      0,
+      0,
+      0,
+      0,
+      0,
+      154,
+      153,
+      153,
+      153,
+      153,
+      153,
+      241,
+      63,
+      154,
+      153,
+      153,
+      153,
+      153,
+      153,
+      1,
+      64,
+      102,
+      102,
+      102,
+      102,
+      102,
+      102,
+      10,
+      64,
+      24,
+      55,
+      1
+    ], [
+      1.1,
+      2.2,
+      3.3
     ]);
   });
   test('number vector, fixed type', () {
@@ -109,11 +187,28 @@
     testNumbers([255, 255, 0, 1, 4, 65, 1], [-1, 256]);
     testNumbers([211, 255, 255, 255, 0, 232, 3, 0, 8, 66, 1], [-45, 256000]);
     testNumbers([
-      211, 255, 255, 255, 255, 255, 255, 255,
-      255, 255, 255, 255, 255, 255, 255, 127,
-      16, 67, 1
+      211,
+      255,
+      255,
+      255,
+      255,
+      255,
+      255,
+      255,
+      255,
+      255,
+      255,
+      255,
+      255,
+      255,
+      255,
+      127,
+      16,
+      67,
+      1
     ], [
-      -45, 9223372036854775807
+      -45,
+      9223372036854775807
     ]);
 
     testNumbers([1, 2, 2, 68, 1], [1, 2]);
@@ -122,85 +217,326 @@
 
     testNumbers([205, 204, 140, 63, 0, 0, 0, 192, 8, 74, 1], [1.1, -2]);
     testNumbers([
-      154, 153, 153, 153, 153, 153, 241, 63,
-      0, 0, 0, 0, 0, 0, 112, 192,
-      16, 75, 1
+      154,
+      153,
+      153,
+      153,
+      153,
+      153,
+      241,
+      63,
+      0,
+      0,
+      0,
+      0,
+      0,
+      0,
+      112,
+      192,
+      16,
+      75,
+      1
     ], [
-      1.1, -256
+      1.1,
+      -256
     ]);
 
     testNumbers([211, 255, 255, 255, 0, 232, 3, 0, 4, 0, 0, 0, 12, 78, 1],
-      [-45, 256000, 4]);
+        [-45, 256000, 4]);
 
     testNumbers([
-      211, 255, 255, 255, 255, 255, 255, 255,
-      255, 255, 255, 255, 255, 255, 255, 127,
-      4, 0, 0, 0, 0, 0, 0, 0,
-      9, 0, 0, 0, 0, 0, 0, 0,
-      32, 91, 1
+      211,
+      255,
+      255,
+      255,
+      255,
+      255,
+      255,
+      255,
+      255,
+      255,
+      255,
+      255,
+      255,
+      255,
+      255,
+      127,
+      4,
+      0,
+      0,
+      0,
+      0,
+      0,
+      0,
+      0,
+      9,
+      0,
+      0,
+      0,
+      0,
+      0,
+      0,
+      0,
+      32,
+      91,
+      1
     ], [
-      -45, 9223372036854775807, 4, 9
+      -45,
+      9223372036854775807,
+      4,
+      9
     ]);
 
     testNumbers([
-      45, 0, 0, 0, 0, 0, 0, 0,
-      255, 255, 255, 255, 255, 255, 255, 127,
-      4, 0, 0, 0, 0, 0, 0, 0,
-      9, 0, 0, 0, 0, 0, 0, 0,
-      32, 95, 1
+      45,
+      0,
+      0,
+      0,
+      0,
+      0,
+      0,
+      0,
+      255,
+      255,
+      255,
+      255,
+      255,
+      255,
+      255,
+      127,
+      4,
+      0,
+      0,
+      0,
+      0,
+      0,
+      0,
+      0,
+      9,
+      0,
+      0,
+      0,
+      0,
+      0,
+      0,
+      0,
+      32,
+      95,
+      1
     ], [
-      45, 9223372036854775807, 4, 9
+      45,
+      9223372036854775807,
+      4,
+      9
     ]);
 
     testNumbers([
-      154, 153, 153, 153, 153, 153, 241, 63,
-      0, 0, 0, 0, 0, 0, 112, 64,
-      0, 0, 0, 0, 0, 0, 16, 64,
-      24, 87, 1
+      154,
+      153,
+      153,
+      153,
+      153,
+      153,
+      241,
+      63,
+      0,
+      0,
+      0,
+      0,
+      0,
+      0,
+      112,
+      64,
+      0,
+      0,
+      0,
+      0,
+      0,
+      0,
+      16,
+      64,
+      24,
+      87,
+      1
     ], [
-      1.1, 256, 4
+      1.1,
+      256,
+      4
     ]);
 
     testNumbers([
-      154, 153, 153, 153, 153, 153, 241, 63,
-      0, 0, 0, 0, 0, 0, 112, 64,
-      0, 0, 0, 0, 0, 0, 16, 64,
-      0, 0, 0, 0, 0, 0, 34, 64,
-      32, 99, 1
+      154,
+      153,
+      153,
+      153,
+      153,
+      153,
+      241,
+      63,
+      0,
+      0,
+      0,
+      0,
+      0,
+      0,
+      112,
+      64,
+      0,
+      0,
+      0,
+      0,
+      0,
+      0,
+      16,
+      64,
+      0,
+      0,
+      0,
+      0,
+      0,
+      0,
+      34,
+      64,
+      32,
+      99,
+      1
     ], [
-      1.1, 256, 4, 9
+      1.1,
+      256,
+      4,
+      9
     ]);
   });
   test('string vector', () {
     testStrings([
-      3, 102, 111, 111, 0,
-      3, 98, 97, 114, 0,
-      3, 98, 97, 122, 0,
-      3, 15, 11, 7,
-      3, 60, 1
+      3,
+      102,
+      111,
+      111,
+      0,
+      3,
+      98,
+      97,
+      114,
+      0,
+      3,
+      98,
+      97,
+      122,
+      0,
+      3,
+      15,
+      11,
+      7,
+      3,
+      60,
+      1
     ], [
-      'foo', 'bar', 'baz'
+      'foo',
+      'bar',
+      'baz'
     ]);
     testStrings([
-      3, 102, 111, 111, 0,
-      3, 98, 97, 114, 0,
-      3, 98, 97, 122, 0,
-      6, 15, 11, 7, 18, 14, 10,
-      6, 60, 1
+      3,
+      102,
+      111,
+      111,
+      0,
+      3,
+      98,
+      97,
+      114,
+      0,
+      3,
+      98,
+      97,
+      122,
+      0,
+      6,
+      15,
+      11,
+      7,
+      18,
+      14,
+      10,
+      6,
+      60,
+      1
     ], [
-      'foo', 'bar', 'baz', 'foo', 'bar', 'baz'
+      'foo',
+      'bar',
+      'baz',
+      'foo',
+      'bar',
+      'baz'
     ]);
   });
   test('mixed vector', () {
     var flx = Reference.fromBuffer(b([
-      3, 102, 111, 111, 0, 0, 0, 0,
-      5, 0, 0, 0, 0, 0, 0, 0,
-      15, 0, 0, 0, 0, 0, 0, 0,
-      1, 0, 0, 0, 0, 0, 0, 0,
-      251, 255, 255, 255, 255, 255, 255, 255,
-      205, 204, 204, 204, 204, 204, 244, 63,
-      1, 0, 0, 0, 0, 0, 0, 0,
-      20, 4, 4, 15, 104, 45, 43, 1
+      3,
+      102,
+      111,
+      111,
+      0,
+      0,
+      0,
+      0,
+      5,
+      0,
+      0,
+      0,
+      0,
+      0,
+      0,
+      0,
+      15,
+      0,
+      0,
+      0,
+      0,
+      0,
+      0,
+      0,
+      1,
+      0,
+      0,
+      0,
+      0,
+      0,
+      0,
+      0,
+      251,
+      255,
+      255,
+      255,
+      255,
+      255,
+      255,
+      255,
+      205,
+      204,
+      204,
+      204,
+      204,
+      204,
+      244,
+      63,
+      1,
+      0,
+      0,
+      0,
+      0,
+      0,
+      0,
+      0,
+      20,
+      4,
+      4,
+      15,
+      104,
+      45,
+      43,
+      1
     ]));
     expect(flx.length, 5);
     expect(flx[0].stringValue, 'foo');
@@ -216,7 +552,8 @@
     expect(flx['a'].numValue, 12);
   });
   test('two value map', () {
-    var flx = Reference.fromBuffer(b([0, 97, 0, 2, 4, 4, 2, 1, 2, 45, 12, 4, 4, 4, 36, 1]));
+    var flx = Reference.fromBuffer(
+        b([0, 97, 0, 2, 4, 4, 2, 1, 2, 45, 12, 4, 4, 4, 36, 1]));
     expect(flx.length, 2);
     expect(flx['a'].numValue, 12);
     expect(flx[''].numValue, 45);
@@ -239,45 +576,239 @@
     expect(flx['address']['zip'].stringValue, '12345');
     expect(flx['address']['countryCode'].stringValue, 'XX');
 
-    expect(() => flx['address']['country'].stringValue,
-      throwsA(predicate((e) => e is ArgumentError && e.message == 'Key: [country] is not applicable on: //address of: ValueType.Map')));
-    expect(() => flx['address']['countryCode'][0],
-      throwsA(predicate((e) => e is ArgumentError && e.message == 'Key: [0] is not applicable on: //address/countryCode of: ValueType.String')));
-    expect(() => flx[1],
-      throwsA(predicate((e) => e is ArgumentError && e.message == 'Key: [1] is not applicable on: / of: ValueType.Map')));
-    expect(() => flx['flags'][4],
-      throwsA(predicate((e) => e is ArgumentError && e.message == 'Key: [4] is not applicable on: //flags of: ValueType.VectorBool length: 4')));
-    expect(() => flx['flags'][-1],
-      throwsA(predicate((e) => e is ArgumentError && e.message == 'Key: [-1] is not applicable on: //flags of: ValueType.VectorBool length: 4')));
+    expect(
+        () => flx['address']['country'].stringValue,
+        throwsA(predicate((dynamic e) =>
+            e is ArgumentError &&
+            e.message ==
+                'Key: [country] is not applicable on: //address of: ValueType.Map')));
+    expect(
+        () => flx['address']['countryCode'][0],
+        throwsA(predicate((dynamic e) =>
+            e is ArgumentError &&
+            e.message ==
+                'Key: [0] is not applicable on: //address/countryCode of: ValueType.String')));
+    expect(
+        () => flx[1],
+        throwsA(predicate((dynamic e) =>
+            e is ArgumentError &&
+            e.message ==
+                'Key: [1] is not applicable on: / of: ValueType.Map')));
+    expect(
+        () => flx['flags'][4],
+        throwsA(predicate((dynamic e) =>
+            e is ArgumentError &&
+            e.message ==
+                'Key: [4] is not applicable on: //flags of: ValueType.VectorBool length: 4')));
+    expect(
+        () => flx['flags'][-1],
+        throwsA(predicate((dynamic e) =>
+            e is ArgumentError &&
+            e.message ==
+                'Key: [-1] is not applicable on: //flags of: ValueType.VectorBool length: 4')));
   });
   test('complex map to json', () {
     var flx = complexMap();
-    expect(flx.json, '{"address":{"city":"Bla","countryCode":"XX","zip":"12345"},"age":35,"flags":[true,false,true,true],"name":"Maxim","weight":72.5}');
+    expect(flx.json,
+        '{"address":{"city":"Bla","countryCode":"XX","zip":"12345"},"age":35,"flags":[true,false,true,true],"name":"Maxim","weight":72.5}');
   });
 
   test('complex map iterators', () {
     var flx = complexMap();
-    expect(flx.mapKeyIterable.map((e) => e).toList(), ['address', 'age', 'flags', 'name', 'weight']);
-    expect(flx.mapValueIterable.map((e) => e.json).toList(), [flx['address'].json, flx['age'].json, flx['flags'].json, flx['name'].json, flx['weight'].json]);
-    expect(flx['flags'].vectorIterable.map((e) => e.boolValue).toList(), [true, false, true, true]);
+    expect(flx.mapKeyIterable.map((e) => e).toList(),
+        ['address', 'age', 'flags', 'name', 'weight']);
+    expect(flx.mapValueIterable.map((e) => e.json).toList(), [
+      flx['address'].json,
+      flx['age'].json,
+      flx['flags'].json,
+      flx['name'].json,
+      flx['weight'].json
+    ]);
+    expect(flx['flags'].vectorIterable.map((e) => e.boolValue).toList(),
+        [true, false, true, true]);
   });
 
-  test('bug where offest were stored as int instead of uint', (){
-    const data = [99, 104, 97, 110, 110, 101, 108, 115, 95, 105, 110, 0,
-      100, 105, 108, 97, 116, 105, 111, 110, 95, 104, 101, 105, 103, 104, 116, 95, 102, 97, 99, 116, 111, 114, 0,
-      100, 105, 108, 97, 116, 105, 111, 110, 95, 119, 105, 100, 116, 104, 95, 102, 97, 99, 116, 111, 114, 0,
-      102, 117, 115, 101, 100, 95, 97, 99, 116, 105, 118, 97, 116, 105, 111, 110, 95, 102, 117, 110, 99, 116, 105, 111, 110, 0,
-      112, 97, 100, 95, 118, 97, 108, 117, 101, 115, 0, 112, 97, 100, 100, 105, 110, 103, 0,
-      115, 116, 114, 105, 100, 101, 95, 104, 101, 105, 103, 104, 116, 0,
-      115, 116, 114, 105, 100, 101, 95, 119, 105, 100, 116, 104, 0,
-      8, 130, 119, 97, 76, 51, 41, 34, 21, 8, 1, 8, 64, 1, 1, 1, 1, 0, 1, 1, 4, 4, 4, 4, 4, 4, 4, 4, 16, 36, 1];
+  test('bug where offest were stored as int instead of uint', () {
+    const data = [
+      99,
+      104,
+      97,
+      110,
+      110,
+      101,
+      108,
+      115,
+      95,
+      105,
+      110,
+      0,
+      100,
+      105,
+      108,
+      97,
+      116,
+      105,
+      111,
+      110,
+      95,
+      104,
+      101,
+      105,
+      103,
+      104,
+      116,
+      95,
+      102,
+      97,
+      99,
+      116,
+      111,
+      114,
+      0,
+      100,
+      105,
+      108,
+      97,
+      116,
+      105,
+      111,
+      110,
+      95,
+      119,
+      105,
+      100,
+      116,
+      104,
+      95,
+      102,
+      97,
+      99,
+      116,
+      111,
+      114,
+      0,
+      102,
+      117,
+      115,
+      101,
+      100,
+      95,
+      97,
+      99,
+      116,
+      105,
+      118,
+      97,
+      116,
+      105,
+      111,
+      110,
+      95,
+      102,
+      117,
+      110,
+      99,
+      116,
+      105,
+      111,
+      110,
+      0,
+      112,
+      97,
+      100,
+      95,
+      118,
+      97,
+      108,
+      117,
+      101,
+      115,
+      0,
+      112,
+      97,
+      100,
+      100,
+      105,
+      110,
+      103,
+      0,
+      115,
+      116,
+      114,
+      105,
+      100,
+      101,
+      95,
+      104,
+      101,
+      105,
+      103,
+      104,
+      116,
+      0,
+      115,
+      116,
+      114,
+      105,
+      100,
+      101,
+      95,
+      119,
+      105,
+      100,
+      116,
+      104,
+      0,
+      8,
+      130,
+      119,
+      97,
+      76,
+      51,
+      41,
+      34,
+      21,
+      8,
+      1,
+      8,
+      64,
+      1,
+      1,
+      1,
+      1,
+      0,
+      1,
+      1,
+      4,
+      4,
+      4,
+      4,
+      4,
+      4,
+      4,
+      4,
+      16,
+      36,
+      1
+    ];
     var flx = Reference.fromBuffer(b(data));
-    expect(flx.json, '{"channels_in":64,"dilation_height_factor":1,"dilation_width_factor":1,"fused_activation_function":1,"pad_values":1,"padding":0,"stride_height":1,"stride_width":1}');
-    const object = {"channels_in":64,"dilation_height_factor":1,"dilation_width_factor":1,"fused_activation_function":1,"pad_values":1,"padding":0,"stride_height":1,"stride_width":1};
+    expect(flx.json,
+        '{"channels_in":64,"dilation_height_factor":1,"dilation_width_factor":1,"fused_activation_function":1,"pad_values":1,"padding":0,"stride_height":1,"stride_width":1}');
+    const object = {
+      "channels_in": 64,
+      "dilation_height_factor": 1,
+      "dilation_width_factor": 1,
+      "fused_activation_function": 1,
+      "pad_values": 1,
+      "padding": 0,
+      "stride_height": 1,
+      "stride_width": 1
+    };
     var data1 = Builder.buildFromObject(object).asUint8List();
     expect(data1.length, data.length);
     var flx1 = Reference.fromBuffer(b(data1));
-    expect(flx1.json, '{"channels_in":64,"dilation_height_factor":1,"dilation_width_factor":1,"fused_activation_function":1,"pad_values":1,"padding":0,"stride_height":1,"stride_width":1}');
+    expect(flx1.json,
+        '{"channels_in":64,"dilation_height_factor":1,"dilation_width_factor":1,"fused_activation_function":1,"pad_values":1,"padding":0,"stride_height":1,"stride_width":1}');
   });
 }
 
@@ -302,7 +833,7 @@
   }
 }
 
-Reference complexMap(){
+Reference complexMap() {
 //  {
 //    "age": 35,
 //    "flags": [True, False, True, True],
@@ -315,20 +846,145 @@
 //    }
 //  }
   return Reference.fromBuffer(b([
-  97, 100, 100, 114, 101, 115, 115, 0,
-      99, 105, 116, 121, 0, 3, 66, 108, 97, 0,
-      99, 111, 117, 110, 116, 114, 121, 67, 111, 100, 101, 0,
-      2, 88, 88, 0,
-      122, 105, 112, 0,
-      5, 49, 50, 51, 52, 53, 0,
-      3, 38, 29, 14, 3, 1, 3, 38, 22, 15, 20, 20, 20,
-      97, 103, 101, 0,
-      102, 108, 97, 103, 115, 0,
-      4, 1, 0, 1, 1,
-      110, 97, 109, 101, 0,
-      5, 77, 97, 120, 105, 109, 0,
-      119, 101, 105, 103, 104, 116, 0,
-      5, 93, 36, 33, 23, 12, 0, 0, 7, 0, 0, 0, 1, 0, 0, 0, 5, 0, 0, 0, 60, 0, 0, 0, 35, 0, 0, 0, 51, 0, 0, 0, 45,
-      0, 0, 0, 0, 0, 145, 66, 36, 4, 144, 20, 14, 25, 38, 1
+    97,
+    100,
+    100,
+    114,
+    101,
+    115,
+    115,
+    0,
+    99,
+    105,
+    116,
+    121,
+    0,
+    3,
+    66,
+    108,
+    97,
+    0,
+    99,
+    111,
+    117,
+    110,
+    116,
+    114,
+    121,
+    67,
+    111,
+    100,
+    101,
+    0,
+    2,
+    88,
+    88,
+    0,
+    122,
+    105,
+    112,
+    0,
+    5,
+    49,
+    50,
+    51,
+    52,
+    53,
+    0,
+    3,
+    38,
+    29,
+    14,
+    3,
+    1,
+    3,
+    38,
+    22,
+    15,
+    20,
+    20,
+    20,
+    97,
+    103,
+    101,
+    0,
+    102,
+    108,
+    97,
+    103,
+    115,
+    0,
+    4,
+    1,
+    0,
+    1,
+    1,
+    110,
+    97,
+    109,
+    101,
+    0,
+    5,
+    77,
+    97,
+    120,
+    105,
+    109,
+    0,
+    119,
+    101,
+    105,
+    103,
+    104,
+    116,
+    0,
+    5,
+    93,
+    36,
+    33,
+    23,
+    12,
+    0,
+    0,
+    7,
+    0,
+    0,
+    0,
+    1,
+    0,
+    0,
+    0,
+    5,
+    0,
+    0,
+    0,
+    60,
+    0,
+    0,
+    0,
+    35,
+    0,
+    0,
+    0,
+    51,
+    0,
+    0,
+    0,
+    45,
+    0,
+    0,
+    0,
+    0,
+    0,
+    145,
+    66,
+    36,
+    4,
+    144,
+    20,
+    14,
+    25,
+    38,
+    1
   ]));
 }
diff --git a/dart/test/flex_types_test.dart b/dart/test/flex_types_test.dart
index 16235f6..76ce070 100644
--- a/dart/test/flex_types_test.dart
+++ b/dart/test/flex_types_test.dart
@@ -48,69 +48,116 @@
     expect(ValueTypeUtils.isFixedTypedVector(ValueType.VectorInt), isFalse);
   });
   test('to typed vector', () {
-    expect(ValueTypeUtils.toTypedVector(ValueType.Int,0), equals(ValueType.VectorInt));
-    expect(ValueTypeUtils.toTypedVector(ValueType.UInt,0), equals(ValueType.VectorUInt));
-    expect(ValueTypeUtils.toTypedVector(ValueType.Bool,0), equals(ValueType.VectorBool));
-    expect(ValueTypeUtils.toTypedVector(ValueType.Float,0), equals(ValueType.VectorFloat));
-    expect(ValueTypeUtils.toTypedVector(ValueType.Key,0), equals(ValueType.VectorKey));
-    expect(ValueTypeUtils.toTypedVector(ValueType.String,0), equals(ValueType.VectorString));
+    expect(ValueTypeUtils.toTypedVector(ValueType.Int, 0),
+        equals(ValueType.VectorInt));
+    expect(ValueTypeUtils.toTypedVector(ValueType.UInt, 0),
+        equals(ValueType.VectorUInt));
+    expect(ValueTypeUtils.toTypedVector(ValueType.Bool, 0),
+        equals(ValueType.VectorBool));
+    expect(ValueTypeUtils.toTypedVector(ValueType.Float, 0),
+        equals(ValueType.VectorFloat));
+    expect(ValueTypeUtils.toTypedVector(ValueType.Key, 0),
+        equals(ValueType.VectorKey));
+    expect(ValueTypeUtils.toTypedVector(ValueType.String, 0),
+        equals(ValueType.VectorString));
 
-    expect(ValueTypeUtils.toTypedVector(ValueType.Int,2), equals(ValueType.VectorInt2));
-    expect(ValueTypeUtils.toTypedVector(ValueType.UInt,2), equals(ValueType.VectorUInt2));
-    expect(ValueTypeUtils.toTypedVector(ValueType.Float,2), equals(ValueType.VectorFloat2));
+    expect(ValueTypeUtils.toTypedVector(ValueType.Int, 2),
+        equals(ValueType.VectorInt2));
+    expect(ValueTypeUtils.toTypedVector(ValueType.UInt, 2),
+        equals(ValueType.VectorUInt2));
+    expect(ValueTypeUtils.toTypedVector(ValueType.Float, 2),
+        equals(ValueType.VectorFloat2));
 
-    expect(ValueTypeUtils.toTypedVector(ValueType.Int,3), equals(ValueType.VectorInt3));
-    expect(ValueTypeUtils.toTypedVector(ValueType.UInt,3), equals(ValueType.VectorUInt3));
-    expect(ValueTypeUtils.toTypedVector(ValueType.Float,3), equals(ValueType.VectorFloat3));
+    expect(ValueTypeUtils.toTypedVector(ValueType.Int, 3),
+        equals(ValueType.VectorInt3));
+    expect(ValueTypeUtils.toTypedVector(ValueType.UInt, 3),
+        equals(ValueType.VectorUInt3));
+    expect(ValueTypeUtils.toTypedVector(ValueType.Float, 3),
+        equals(ValueType.VectorFloat3));
 
-    expect(ValueTypeUtils.toTypedVector(ValueType.Int,4), equals(ValueType.VectorInt4));
-    expect(ValueTypeUtils.toTypedVector(ValueType.UInt,4), equals(ValueType.VectorUInt4));
-    expect(ValueTypeUtils.toTypedVector(ValueType.Float,4), equals(ValueType.VectorFloat4));
+    expect(ValueTypeUtils.toTypedVector(ValueType.Int, 4),
+        equals(ValueType.VectorInt4));
+    expect(ValueTypeUtils.toTypedVector(ValueType.UInt, 4),
+        equals(ValueType.VectorUInt4));
+    expect(ValueTypeUtils.toTypedVector(ValueType.Float, 4),
+        equals(ValueType.VectorFloat4));
   });
   test('typed vector element type', () {
-    expect(ValueTypeUtils.typedVectorElementType(ValueType.VectorInt), equals(ValueType.Int));
-    expect(ValueTypeUtils.typedVectorElementType(ValueType.VectorUInt), equals(ValueType.UInt));
-    expect(ValueTypeUtils.typedVectorElementType(ValueType.VectorFloat), equals(ValueType.Float));
-    expect(ValueTypeUtils.typedVectorElementType(ValueType.VectorString), equals(ValueType.String));
-    expect(ValueTypeUtils.typedVectorElementType(ValueType.VectorKey), equals(ValueType.Key));
-    expect(ValueTypeUtils.typedVectorElementType(ValueType.VectorBool), equals(ValueType.Bool));
+    expect(ValueTypeUtils.typedVectorElementType(ValueType.VectorInt),
+        equals(ValueType.Int));
+    expect(ValueTypeUtils.typedVectorElementType(ValueType.VectorUInt),
+        equals(ValueType.UInt));
+    expect(ValueTypeUtils.typedVectorElementType(ValueType.VectorFloat),
+        equals(ValueType.Float));
+    expect(ValueTypeUtils.typedVectorElementType(ValueType.VectorString),
+        equals(ValueType.String));
+    expect(ValueTypeUtils.typedVectorElementType(ValueType.VectorKey),
+        equals(ValueType.Key));
+    expect(ValueTypeUtils.typedVectorElementType(ValueType.VectorBool),
+        equals(ValueType.Bool));
   });
   test('fixed typed vector element type', () {
-    expect(ValueTypeUtils.fixedTypedVectorElementType(ValueType.VectorInt2), equals(ValueType.Int));
-    expect(ValueTypeUtils.fixedTypedVectorElementType(ValueType.VectorInt3), equals(ValueType.Int));
-    expect(ValueTypeUtils.fixedTypedVectorElementType(ValueType.VectorInt4), equals(ValueType.Int));
+    expect(ValueTypeUtils.fixedTypedVectorElementType(ValueType.VectorInt2),
+        equals(ValueType.Int));
+    expect(ValueTypeUtils.fixedTypedVectorElementType(ValueType.VectorInt3),
+        equals(ValueType.Int));
+    expect(ValueTypeUtils.fixedTypedVectorElementType(ValueType.VectorInt4),
+        equals(ValueType.Int));
 
-    expect(ValueTypeUtils.fixedTypedVectorElementType(ValueType.VectorUInt2), equals(ValueType.UInt));
-    expect(ValueTypeUtils.fixedTypedVectorElementType(ValueType.VectorUInt3), equals(ValueType.UInt));
-    expect(ValueTypeUtils.fixedTypedVectorElementType(ValueType.VectorUInt4), equals(ValueType.UInt));
+    expect(ValueTypeUtils.fixedTypedVectorElementType(ValueType.VectorUInt2),
+        equals(ValueType.UInt));
+    expect(ValueTypeUtils.fixedTypedVectorElementType(ValueType.VectorUInt3),
+        equals(ValueType.UInt));
+    expect(ValueTypeUtils.fixedTypedVectorElementType(ValueType.VectorUInt4),
+        equals(ValueType.UInt));
 
-    expect(ValueTypeUtils.fixedTypedVectorElementType(ValueType.VectorFloat2), equals(ValueType.Float));
-    expect(ValueTypeUtils.fixedTypedVectorElementType(ValueType.VectorFloat3), equals(ValueType.Float));
-    expect(ValueTypeUtils.fixedTypedVectorElementType(ValueType.VectorFloat4), equals(ValueType.Float));
+    expect(ValueTypeUtils.fixedTypedVectorElementType(ValueType.VectorFloat2),
+        equals(ValueType.Float));
+    expect(ValueTypeUtils.fixedTypedVectorElementType(ValueType.VectorFloat3),
+        equals(ValueType.Float));
+    expect(ValueTypeUtils.fixedTypedVectorElementType(ValueType.VectorFloat4),
+        equals(ValueType.Float));
   });
   test('fixed typed vector element size', () {
-    expect(ValueTypeUtils.fixedTypedVectorElementSize(ValueType.VectorInt2), equals(2));
-    expect(ValueTypeUtils.fixedTypedVectorElementSize(ValueType.VectorInt3), equals(3));
-    expect(ValueTypeUtils.fixedTypedVectorElementSize(ValueType.VectorInt4), equals(4));
+    expect(ValueTypeUtils.fixedTypedVectorElementSize(ValueType.VectorInt2),
+        equals(2));
+    expect(ValueTypeUtils.fixedTypedVectorElementSize(ValueType.VectorInt3),
+        equals(3));
+    expect(ValueTypeUtils.fixedTypedVectorElementSize(ValueType.VectorInt4),
+        equals(4));
 
-    expect(ValueTypeUtils.fixedTypedVectorElementSize(ValueType.VectorUInt2), equals(2));
-    expect(ValueTypeUtils.fixedTypedVectorElementSize(ValueType.VectorUInt3), equals(3));
-    expect(ValueTypeUtils.fixedTypedVectorElementSize(ValueType.VectorUInt4), equals(4));
+    expect(ValueTypeUtils.fixedTypedVectorElementSize(ValueType.VectorUInt2),
+        equals(2));
+    expect(ValueTypeUtils.fixedTypedVectorElementSize(ValueType.VectorUInt3),
+        equals(3));
+    expect(ValueTypeUtils.fixedTypedVectorElementSize(ValueType.VectorUInt4),
+        equals(4));
 
-    expect(ValueTypeUtils.fixedTypedVectorElementSize(ValueType.VectorFloat2), equals(2));
-    expect(ValueTypeUtils.fixedTypedVectorElementSize(ValueType.VectorFloat3), equals(3));
-    expect(ValueTypeUtils.fixedTypedVectorElementSize(ValueType.VectorFloat4), equals(4));
+    expect(ValueTypeUtils.fixedTypedVectorElementSize(ValueType.VectorFloat2),
+        equals(2));
+    expect(ValueTypeUtils.fixedTypedVectorElementSize(ValueType.VectorFloat3),
+        equals(3));
+    expect(ValueTypeUtils.fixedTypedVectorElementSize(ValueType.VectorFloat4),
+        equals(4));
   });
   test('packed type', () {
-    expect(ValueTypeUtils.packedType(ValueType.Null, BitWidth.width8), equals(0));
-    expect(ValueTypeUtils.packedType(ValueType.Null, BitWidth.width16), equals(1));
-    expect(ValueTypeUtils.packedType(ValueType.Null, BitWidth.width32), equals(2));
-    expect(ValueTypeUtils.packedType(ValueType.Null, BitWidth.width64), equals(3));
+    expect(
+        ValueTypeUtils.packedType(ValueType.Null, BitWidth.width8), equals(0));
+    expect(
+        ValueTypeUtils.packedType(ValueType.Null, BitWidth.width16), equals(1));
+    expect(
+        ValueTypeUtils.packedType(ValueType.Null, BitWidth.width32), equals(2));
+    expect(
+        ValueTypeUtils.packedType(ValueType.Null, BitWidth.width64), equals(3));
 
-    expect(ValueTypeUtils.packedType(ValueType.Int, BitWidth.width8), equals(4));
-    expect(ValueTypeUtils.packedType(ValueType.Int, BitWidth.width16), equals(5));
-    expect(ValueTypeUtils.packedType(ValueType.Int, BitWidth.width32), equals(6));
-    expect(ValueTypeUtils.packedType(ValueType.Int, BitWidth.width64), equals(7));
+    expect(
+        ValueTypeUtils.packedType(ValueType.Int, BitWidth.width8), equals(4));
+    expect(
+        ValueTypeUtils.packedType(ValueType.Int, BitWidth.width16), equals(5));
+    expect(
+        ValueTypeUtils.packedType(ValueType.Int, BitWidth.width32), equals(6));
+    expect(
+        ValueTypeUtils.packedType(ValueType.Int, BitWidth.width64), equals(7));
   });
   test('bit width', () {
     expect(BitWidthUtil.width(0), BitWidth.width8);
diff --git a/dart/test/monster_test.fbs b/dart/test/monster_test.fbs
new file mode 100644
index 0000000..fdd5acf
--- /dev/null
+++ b/dart/test/monster_test.fbs
@@ -0,0 +1,154 @@
+// test schema file
+
+include "include_test1.fbs";
+
+namespace MyGame;
+
+table InParentNamespace {}
+
+namespace MyGame.Example2;
+
+table Monster {}  // Test having same name as below, but in different namespace.
+
+namespace MyGame.Example;
+
+attribute "priority";
+
+/// Composite components of Monster color.
+enum Color:ubyte (bit_flags) {
+  Red = 0, // color Red = (1u << 0)
+  /// \brief color Green
+  /// Green is bit_flag with value (1u << 1)
+  Green,
+  /// \brief color Blue (1u << 3)
+  Blue = 3,
+}
+
+enum Race:byte {
+  None = -1,
+  Human = 0,
+  Dwarf,
+  Elf,
+}
+
+union Any { Monster, TestSimpleTableWithEnum, MyGame.Example2.Monster }
+
+union AnyUniqueAliases { M: Monster, TS: TestSimpleTableWithEnum, M2: MyGame.Example2.Monster }
+union AnyAmbiguousAliases { M1: Monster, M2: Monster, M3: Monster }
+
+struct Test { a:short; b:byte; }
+
+table TestSimpleTableWithEnum (csharp_partial, private) {
+  color: Color = Green;
+}
+
+struct Vec3 (force_align: 8) {
+  x:float;
+  y:float;
+  z:float;
+  test1:double;
+  test2:Color;
+  test3:Test;
+}
+
+struct Ability {
+  id:uint(key);
+  distance:uint;
+}
+
+struct StructOfStructs {
+  a: Ability;
+  b: Test;
+  c: Ability;
+}
+
+table Stat {
+  id:string;
+  val:long;
+  count:ushort (key);
+}
+
+table Referrable {
+  id:ulong(key, hash:"fnv1a_64");
+}
+
+/// an example documentation comment: "monster object"
+table Monster {
+  pos:Vec3 (id: 0);
+  hp:short = 100 (id: 2);
+  mana:short = 150 (id: 1);
+  name:string (id: 3, key);
+  color:Color = Blue (id: 6);
+  inventory:[ubyte] (id: 5);
+  friendly:bool = false (deprecated, priority: 1, id: 4);
+  /// an example documentation comment: this will end up in the generated code
+  /// multiline too
+  testarrayoftables:[Monster] (id: 11);
+  testarrayofstring:[string] (id: 10);
+  testarrayofstring2:[string] (id: 28);
+  testarrayofbools:[bool] (id: 24);
+  testarrayofsortedstruct:[Ability] (id: 29);
+  enemy:MyGame.Example.Monster (id:12);  // Test referring by full namespace.
+  test:Any (id: 8);
+  test4:[Test] (id: 9);
+  test5:[Test] (id: 31);
+  testnestedflatbuffer:[ubyte] (id:13, nested_flatbuffer: "Monster");
+  testempty:Stat (id:14);
+  testbool:bool (id:15);
+  testhashs32_fnv1:int (id:16, hash:"fnv1_32");
+  testhashu32_fnv1:uint (id:17, hash:"fnv1_32");
+  testhashs64_fnv1:long (id:18, hash:"fnv1_64");
+  testhashu64_fnv1:ulong (id:19, hash:"fnv1_64");
+  testhashs32_fnv1a:int (id:20, hash:"fnv1a_32");
+  testhashu32_fnv1a:uint (id:21, hash:"fnv1a_32", cpp_type:"Stat");
+  testhashs64_fnv1a:long (id:22, hash:"fnv1a_64");
+  testhashu64_fnv1a:ulong (id:23, hash:"fnv1a_64");
+  testf:float = 3.14159 (id:25);
+  testf2:float = 3 (id:26);
+  testf3:float (id:27);
+  flex:[ubyte] (id:30, flexbuffer);
+  vector_of_longs:[long] (id:32);
+  vector_of_doubles:[double] (id:33);
+  parent_namespace_test:InParentNamespace (id:34);
+  vector_of_referrables:[Referrable](id:35);
+  single_weak_reference:ulong(id:36, hash:"fnv1a_64", cpp_type:"ReferrableT");
+  vector_of_weak_references:[ulong](id:37, hash:"fnv1a_64", cpp_type:"ReferrableT");
+  vector_of_strong_referrables:[Referrable](id:38, cpp_ptr_type:"default_ptr_type");                 //was shared_ptr
+  co_owning_reference:ulong(id:39, hash:"fnv1a_64", cpp_type:"ReferrableT", cpp_ptr_type:"naked");  //was shared_ptr as well
+  vector_of_co_owning_references:[ulong](id:40, hash:"fnv1a_64", cpp_type:"ReferrableT", cpp_ptr_type:"default_ptr_type", cpp_ptr_type_get:".get()");  //was shared_ptr
+  non_owning_reference:ulong(id:41, hash:"fnv1a_64", cpp_type:"ReferrableT", cpp_ptr_type:"naked", cpp_ptr_type_get:"");                              //was weak_ptr
+  vector_of_non_owning_references:[ulong](id:42, hash:"fnv1a_64", cpp_type:"ReferrableT", cpp_ptr_type:"naked", cpp_ptr_type_get:"");                 //was weak_ptr
+  any_unique:AnyUniqueAliases(id:44);
+  any_ambiguous:AnyAmbiguousAliases (id:46);
+  vector_of_enums:[Color] (id:47);
+  signed_enum:Race = None (id:48);
+  testrequirednestedflatbuffer:[ubyte] (id:49, nested_flatbuffer: "Monster");
+  scalar_key_sorted_tables:[Stat] (id: 50);
+}
+
+table TypeAliases {
+    i8:int8;
+    u8:uint8;
+    i16:int16;
+    u16:uint16;
+    i32:int32;
+    u32:uint32;
+    i64:int64;
+    u64:uint64;
+    f32:float32;
+    f64:float64;
+    v8:[int8];
+    vf64:[float64];
+}
+
+rpc_service MonsterStorage {
+  Store(Monster):Stat (streaming: "none");
+  Retrieve(Stat):Monster (streaming: "server", idempotent);
+  GetMaxHitPoint(Monster):Stat (streaming: "client");
+  GetMinMaxHitPoints(Monster):Stat (streaming: "bidi");
+}
+
+root_type Monster;
+
+file_identifier "MONS";
+file_extension "mon";
diff --git a/dart/test/monster_test_my_game.example2_generated.dart b/dart/test/monster_test_my_game.example2_generated.dart
index eed14bc..24ccf72 100644
--- a/dart/test/monster_test_my_game.example2_generated.dart
+++ b/dart/test/monster_test_my_game.example2_generated.dart
@@ -1,5 +1,5 @@
 // automatically generated by the FlatBuffers compiler, do not modify
-// ignore_for_file: unused_import, unused_field, unused_local_variable
+// ignore_for_file: unused_import, unused_field, unused_element, unused_local_variable
 
 library my_game.example2;
 
@@ -12,11 +12,11 @@
 class Monster {
   Monster._(this._bc, this._bcOffset);
   factory Monster(List<int> bytes) {
-    fb.BufferContext rootRef = new fb.BufferContext.fromBytes(bytes);
+    final rootRef = fb.BufferContext.fromBytes(bytes);
     return reader.read(rootRef, 0);
   }
 
-  static const fb.Reader<Monster> reader = const _MonsterReader();
+  static const fb.Reader<Monster> reader = _MonsterReader();
 
   final fb.BufferContext _bc;
   final int _bcOffset;
@@ -26,6 +26,26 @@
   String toString() {
     return 'Monster{}';
   }
+
+  MonsterT unpack() => MonsterT();
+
+  static int pack(fb.Builder fbBuilder, MonsterT? object) {
+    if (object == null) return 0;
+    return object.pack(fbBuilder);
+  }
+}
+
+class MonsterT implements fb.Packable {
+  @override
+  int pack(fb.Builder fbBuilder) {
+    fbBuilder.startTable(0);
+    return fbBuilder.endTable();
+  }
+
+  @override
+  String toString() {
+    return 'MonsterT{}';
+  }
 }
 
 class _MonsterReader extends fb.TableReader<Monster> {
@@ -33,7 +53,7 @@
 
   @override
   Monster createObject(fb.BufferContext bc, int offset) => 
-    new Monster._(bc, offset);
+    Monster._(bc, offset);
 }
 
 class MonsterObjectBuilder extends fb.ObjectBuilder {
@@ -42,19 +62,16 @@
 
   /// Finish building, and store into the [fbBuilder].
   @override
-  int finish(
-    fb.Builder fbBuilder) {
-    assert(fbBuilder != null);
-
-    fbBuilder.startTable();
+  int finish(fb.Builder fbBuilder) {
+    fbBuilder.startTable(0);
     return fbBuilder.endTable();
   }
 
   /// Convenience method to serialize to byte list.
   @override
-  Uint8List toBytes([String fileIdentifier]) {
-    fb.Builder fbBuilder = new fb.Builder();
-    int offset = finish(fbBuilder);
-    return fbBuilder.finish(offset, fileIdentifier);
+  Uint8List toBytes([String? fileIdentifier]) {
+    final fbBuilder = fb.Builder(deduplicateTables: false);
+    fbBuilder.finish(finish(fbBuilder), fileIdentifier);
+    return fbBuilder.buffer;
   }
 }
diff --git a/dart/test/monster_test_my_game.example_generated.dart b/dart/test/monster_test_my_game.example_generated.dart
index 7921892..8db82e3 100644
--- a/dart/test/monster_test_my_game.example_generated.dart
+++ b/dart/test/monster_test_my_game.example_generated.dart
@@ -1,5 +1,5 @@
 // automatically generated by the FlatBuffers compiler, do not modify
-// ignore_for_file: unused_import, unused_field, unused_local_variable
+// ignore_for_file: unused_import, unused_field, unused_element, unused_local_variable
 
 library my_game.example;
 
@@ -15,26 +15,32 @@
   const Color._(this.value);
 
   factory Color.fromValue(int value) {
-    if (value == null) value = 0;
-    if (!values.containsKey(value)) {
-      throw new StateError('Invalid value $value for bit flag enum Color');
+    final result = values[value];
+    if (result == null) {
+      throw StateError('Invalid value $value for bit flag enum Color');
     }
-    return values[value];
+    return result;
   }
 
+  static Color? _createOrNull(int? value) => 
+      value == null ? null : Color.fromValue(value);
+
   static bool containsValue(int value) => values.containsKey(value);
 
-  static const Color Red = const Color._(1);
+  static const Color Red = Color._(1);
 
   ///  \brief color Green
   ///  Green is bit_flag with value (1u << 1)
-  static const Color Green = const Color._(2);
+  static const Color Green = Color._(2);
 
   ///  \brief color Blue (1u << 3)
-  static const Color Blue = const Color._(8);
-  static const values = {1: Red,2: Green,8: Blue,};
+  static const Color Blue = Color._(8);
+  static const Map<int, Color> values = {
+    1: Red,
+    2: Green,
+    8: Blue};
 
-  static const fb.Reader<Color> reader = const _ColorReader();
+  static const fb.Reader<Color> reader = _ColorReader();
 
   @override
   String toString() {
@@ -50,7 +56,7 @@
 
   @override
   Color read(fb.BufferContext bc, int offset) =>
-      new Color.fromValue(const fb.Uint8Reader().read(bc, offset));
+      Color.fromValue(const fb.Uint8Reader().read(bc, offset));
 }
 
 class Race {
@@ -58,24 +64,31 @@
   const Race._(this.value);
 
   factory Race.fromValue(int value) {
-    if (value == null) value = 0;
-    if (!values.containsKey(value)) {
-      throw new StateError('Invalid value $value for bit flag enum Race');
+    final result = values[value];
+    if (result == null) {
+      throw StateError('Invalid value $value for bit flag enum Race');
     }
-    return values[value];
+    return result;
   }
 
+  static Race? _createOrNull(int? value) => 
+      value == null ? null : Race.fromValue(value);
+
   static const int minValue = -1;
   static const int maxValue = 2;
   static bool containsValue(int value) => values.containsKey(value);
 
-  static const Race None = const Race._(-1);
-  static const Race Human = const Race._(0);
-  static const Race Dwarf = const Race._(1);
-  static const Race Elf = const Race._(2);
-  static const values = {-1: None,0: Human,1: Dwarf,2: Elf,};
+  static const Race None = Race._(-1);
+  static const Race Human = Race._(0);
+  static const Race Dwarf = Race._(1);
+  static const Race Elf = Race._(2);
+  static const Map<int, Race> values = {
+    -1: None,
+    0: Human,
+    1: Dwarf,
+    2: Elf};
 
-  static const fb.Reader<Race> reader = const _RaceReader();
+  static const fb.Reader<Race> reader = _RaceReader();
 
   @override
   String toString() {
@@ -91,7 +104,7 @@
 
   @override
   Race read(fb.BufferContext bc, int offset) =>
-      new Race.fromValue(const fb.Int8Reader().read(bc, offset));
+      Race.fromValue(const fb.Int8Reader().read(bc, offset));
 }
 
 class AnyTypeId {
@@ -99,24 +112,31 @@
   const AnyTypeId._(this.value);
 
   factory AnyTypeId.fromValue(int value) {
-    if (value == null) value = 0;
-    if (!values.containsKey(value)) {
-      throw new StateError('Invalid value $value for bit flag enum AnyTypeId');
+    final result = values[value];
+    if (result == null) {
+      throw StateError('Invalid value $value for bit flag enum AnyTypeId');
     }
-    return values[value];
+    return result;
   }
 
+  static AnyTypeId? _createOrNull(int? value) => 
+      value == null ? null : AnyTypeId.fromValue(value);
+
   static const int minValue = 0;
   static const int maxValue = 3;
   static bool containsValue(int value) => values.containsKey(value);
 
-  static const AnyTypeId NONE = const AnyTypeId._(0);
-  static const AnyTypeId Monster = const AnyTypeId._(1);
-  static const AnyTypeId TestSimpleTableWithEnum = const AnyTypeId._(2);
-  static const AnyTypeId MyGame_Example2_Monster = const AnyTypeId._(3);
-  static const values = {0: NONE,1: Monster,2: TestSimpleTableWithEnum,3: MyGame_Example2_Monster,};
+  static const AnyTypeId NONE = AnyTypeId._(0);
+  static const AnyTypeId Monster = AnyTypeId._(1);
+  static const AnyTypeId TestSimpleTableWithEnum = AnyTypeId._(2);
+  static const AnyTypeId MyGame_Example2_Monster = AnyTypeId._(3);
+  static const Map<int, AnyTypeId> values = {
+    0: NONE,
+    1: Monster,
+    2: TestSimpleTableWithEnum,
+    3: MyGame_Example2_Monster};
 
-  static const fb.Reader<AnyTypeId> reader = const _AnyTypeIdReader();
+  static const fb.Reader<AnyTypeId> reader = _AnyTypeIdReader();
 
   @override
   String toString() {
@@ -132,7 +152,7 @@
 
   @override
   AnyTypeId read(fb.BufferContext bc, int offset) =>
-      new AnyTypeId.fromValue(const fb.Uint8Reader().read(bc, offset));
+      AnyTypeId.fromValue(const fb.Uint8Reader().read(bc, offset));
 }
 
 class AnyUniqueAliasesTypeId {
@@ -140,24 +160,31 @@
   const AnyUniqueAliasesTypeId._(this.value);
 
   factory AnyUniqueAliasesTypeId.fromValue(int value) {
-    if (value == null) value = 0;
-    if (!values.containsKey(value)) {
-      throw new StateError('Invalid value $value for bit flag enum AnyUniqueAliasesTypeId');
+    final result = values[value];
+    if (result == null) {
+      throw StateError('Invalid value $value for bit flag enum AnyUniqueAliasesTypeId');
     }
-    return values[value];
+    return result;
   }
 
+  static AnyUniqueAliasesTypeId? _createOrNull(int? value) => 
+      value == null ? null : AnyUniqueAliasesTypeId.fromValue(value);
+
   static const int minValue = 0;
   static const int maxValue = 3;
   static bool containsValue(int value) => values.containsKey(value);
 
-  static const AnyUniqueAliasesTypeId NONE = const AnyUniqueAliasesTypeId._(0);
-  static const AnyUniqueAliasesTypeId M = const AnyUniqueAliasesTypeId._(1);
-  static const AnyUniqueAliasesTypeId TS = const AnyUniqueAliasesTypeId._(2);
-  static const AnyUniqueAliasesTypeId M2 = const AnyUniqueAliasesTypeId._(3);
-  static const values = {0: NONE,1: M,2: TS,3: M2,};
+  static const AnyUniqueAliasesTypeId NONE = AnyUniqueAliasesTypeId._(0);
+  static const AnyUniqueAliasesTypeId M = AnyUniqueAliasesTypeId._(1);
+  static const AnyUniqueAliasesTypeId TS = AnyUniqueAliasesTypeId._(2);
+  static const AnyUniqueAliasesTypeId M2 = AnyUniqueAliasesTypeId._(3);
+  static const Map<int, AnyUniqueAliasesTypeId> values = {
+    0: NONE,
+    1: M,
+    2: TS,
+    3: M2};
 
-  static const fb.Reader<AnyUniqueAliasesTypeId> reader = const _AnyUniqueAliasesTypeIdReader();
+  static const fb.Reader<AnyUniqueAliasesTypeId> reader = _AnyUniqueAliasesTypeIdReader();
 
   @override
   String toString() {
@@ -173,7 +200,7 @@
 
   @override
   AnyUniqueAliasesTypeId read(fb.BufferContext bc, int offset) =>
-      new AnyUniqueAliasesTypeId.fromValue(const fb.Uint8Reader().read(bc, offset));
+      AnyUniqueAliasesTypeId.fromValue(const fb.Uint8Reader().read(bc, offset));
 }
 
 class AnyAmbiguousAliasesTypeId {
@@ -181,24 +208,31 @@
   const AnyAmbiguousAliasesTypeId._(this.value);
 
   factory AnyAmbiguousAliasesTypeId.fromValue(int value) {
-    if (value == null) value = 0;
-    if (!values.containsKey(value)) {
-      throw new StateError('Invalid value $value for bit flag enum AnyAmbiguousAliasesTypeId');
+    final result = values[value];
+    if (result == null) {
+      throw StateError('Invalid value $value for bit flag enum AnyAmbiguousAliasesTypeId');
     }
-    return values[value];
+    return result;
   }
 
+  static AnyAmbiguousAliasesTypeId? _createOrNull(int? value) => 
+      value == null ? null : AnyAmbiguousAliasesTypeId.fromValue(value);
+
   static const int minValue = 0;
   static const int maxValue = 3;
   static bool containsValue(int value) => values.containsKey(value);
 
-  static const AnyAmbiguousAliasesTypeId NONE = const AnyAmbiguousAliasesTypeId._(0);
-  static const AnyAmbiguousAliasesTypeId M1 = const AnyAmbiguousAliasesTypeId._(1);
-  static const AnyAmbiguousAliasesTypeId M2 = const AnyAmbiguousAliasesTypeId._(2);
-  static const AnyAmbiguousAliasesTypeId M3 = const AnyAmbiguousAliasesTypeId._(3);
-  static const values = {0: NONE,1: M1,2: M2,3: M3,};
+  static const AnyAmbiguousAliasesTypeId NONE = AnyAmbiguousAliasesTypeId._(0);
+  static const AnyAmbiguousAliasesTypeId M1 = AnyAmbiguousAliasesTypeId._(1);
+  static const AnyAmbiguousAliasesTypeId M2 = AnyAmbiguousAliasesTypeId._(2);
+  static const AnyAmbiguousAliasesTypeId M3 = AnyAmbiguousAliasesTypeId._(3);
+  static const Map<int, AnyAmbiguousAliasesTypeId> values = {
+    0: NONE,
+    1: M1,
+    2: M2,
+    3: M3};
 
-  static const fb.Reader<AnyAmbiguousAliasesTypeId> reader = const _AnyAmbiguousAliasesTypeIdReader();
+  static const fb.Reader<AnyAmbiguousAliasesTypeId> reader = _AnyAmbiguousAliasesTypeIdReader();
 
   @override
   String toString() {
@@ -214,13 +248,13 @@
 
   @override
   AnyAmbiguousAliasesTypeId read(fb.BufferContext bc, int offset) =>
-      new AnyAmbiguousAliasesTypeId.fromValue(const fb.Uint8Reader().read(bc, offset));
+      AnyAmbiguousAliasesTypeId.fromValue(const fb.Uint8Reader().read(bc, offset));
 }
 
 class Test {
   Test._(this._bc, this._bcOffset);
 
-  static const fb.Reader<Test> reader = const _TestReader();
+  static const fb.Reader<Test> reader = _TestReader();
 
   final fb.BufferContext _bc;
   final int _bcOffset;
@@ -232,6 +266,37 @@
   String toString() {
     return 'Test{a: $a, b: $b}';
   }
+
+  TestT unpack() => TestT(
+      a: a,
+      b: b);
+
+  static int pack(fb.Builder fbBuilder, TestT? object) {
+    if (object == null) return 0;
+    return object.pack(fbBuilder);
+  }
+}
+
+class TestT implements fb.Packable {
+  int a;
+  int b;
+
+  TestT({
+      required this.a,
+      required this.b});
+
+  @override
+  int pack(fb.Builder fbBuilder) {
+    fbBuilder.pad(1);
+    fbBuilder.putInt8(b);
+    fbBuilder.putInt16(a);
+    return fbBuilder.offset;
+  }
+
+  @override
+  String toString() {
+    return 'TestT{a: $a, b: $b}';
+  }
 }
 
 class _TestReader extends fb.StructReader<Test> {
@@ -242,13 +307,11 @@
 
   @override
   Test createObject(fb.BufferContext bc, int offset) => 
-    new Test._(bc, offset);
+    Test._(bc, offset);
 }
 
 class TestBuilder {
-  TestBuilder(this.fbBuilder) {
-    assert(fbBuilder != null);
-  }
+  TestBuilder(this.fbBuilder);
 
   final fb.Builder fbBuilder;
 
@@ -266,18 +329,15 @@
   final int _b;
 
   TestObjectBuilder({
-    int a,
-    int b,
+    required int a,
+    required int b,
   })
       : _a = a,
         _b = b;
 
   /// Finish building, and store into the [fbBuilder].
   @override
-  int finish(
-    fb.Builder fbBuilder) {
-    assert(fbBuilder != null);
-
+  int finish(fb.Builder fbBuilder) {
     fbBuilder.pad(1);
     fbBuilder.putInt8(_b);
     fbBuilder.putInt16(_a);
@@ -286,30 +346,57 @@
 
   /// Convenience method to serialize to byte list.
   @override
-  Uint8List toBytes([String fileIdentifier]) {
-    fb.Builder fbBuilder = new fb.Builder();
-    int offset = finish(fbBuilder);
-    return fbBuilder.finish(offset, fileIdentifier);
+  Uint8List toBytes([String? fileIdentifier]) {
+    final fbBuilder = fb.Builder(deduplicateTables: false);
+    fbBuilder.finish(finish(fbBuilder), fileIdentifier);
+    return fbBuilder.buffer;
   }
 }
 class TestSimpleTableWithEnum {
   TestSimpleTableWithEnum._(this._bc, this._bcOffset);
   factory TestSimpleTableWithEnum(List<int> bytes) {
-    fb.BufferContext rootRef = new fb.BufferContext.fromBytes(bytes);
+    final rootRef = fb.BufferContext.fromBytes(bytes);
     return reader.read(rootRef, 0);
   }
 
-  static const fb.Reader<TestSimpleTableWithEnum> reader = const _TestSimpleTableWithEnumReader();
+  static const fb.Reader<TestSimpleTableWithEnum> reader = _TestSimpleTableWithEnumReader();
 
   final fb.BufferContext _bc;
   final int _bcOffset;
 
-  Color get color => new Color.fromValue(const fb.Uint8Reader().vTableGet(_bc, _bcOffset, 4, 2));
+  Color get color => Color.fromValue(const fb.Uint8Reader().vTableGet(_bc, _bcOffset, 4, 2));
 
   @override
   String toString() {
     return 'TestSimpleTableWithEnum{color: $color}';
   }
+
+  TestSimpleTableWithEnumT unpack() => TestSimpleTableWithEnumT(
+      color: color);
+
+  static int pack(fb.Builder fbBuilder, TestSimpleTableWithEnumT? object) {
+    if (object == null) return 0;
+    return object.pack(fbBuilder);
+  }
+}
+
+class TestSimpleTableWithEnumT implements fb.Packable {
+  Color color;
+
+  TestSimpleTableWithEnumT({
+      this.color = Color.Green});
+
+  @override
+  int pack(fb.Builder fbBuilder) {
+    fbBuilder.startTable(1);
+    fbBuilder.addUint8(0, color.value);
+    return fbBuilder.endTable();
+  }
+
+  @override
+  String toString() {
+    return 'TestSimpleTableWithEnumT{color: $color}';
+  }
 }
 
 class _TestSimpleTableWithEnumReader extends fb.TableReader<TestSimpleTableWithEnum> {
@@ -317,21 +404,19 @@
 
   @override
   TestSimpleTableWithEnum createObject(fb.BufferContext bc, int offset) => 
-    new TestSimpleTableWithEnum._(bc, offset);
+    TestSimpleTableWithEnum._(bc, offset);
 }
 
 class TestSimpleTableWithEnumBuilder {
-  TestSimpleTableWithEnumBuilder(this.fbBuilder) {
-    assert(fbBuilder != null);
-  }
+  TestSimpleTableWithEnumBuilder(this.fbBuilder);
 
   final fb.Builder fbBuilder;
 
   void begin() {
-    fbBuilder.startTable();
+    fbBuilder.startTable(1);
   }
 
-  int addColor(Color color) {
+  int addColor(Color? color) {
     fbBuilder.addUint8(0, color?.value);
     return fbBuilder.offset;
   }
@@ -342,36 +427,33 @@
 }
 
 class TestSimpleTableWithEnumObjectBuilder extends fb.ObjectBuilder {
-  final Color _color;
+  final Color? _color;
 
   TestSimpleTableWithEnumObjectBuilder({
-    Color color,
+    Color? color,
   })
       : _color = color;
 
   /// Finish building, and store into the [fbBuilder].
   @override
-  int finish(
-    fb.Builder fbBuilder) {
-    assert(fbBuilder != null);
-
-    fbBuilder.startTable();
+  int finish(fb.Builder fbBuilder) {
+    fbBuilder.startTable(1);
     fbBuilder.addUint8(0, _color?.value);
     return fbBuilder.endTable();
   }
 
   /// Convenience method to serialize to byte list.
   @override
-  Uint8List toBytes([String fileIdentifier]) {
-    fb.Builder fbBuilder = new fb.Builder();
-    int offset = finish(fbBuilder);
-    return fbBuilder.finish(offset, fileIdentifier);
+  Uint8List toBytes([String? fileIdentifier]) {
+    final fbBuilder = fb.Builder(deduplicateTables: false);
+    fbBuilder.finish(finish(fbBuilder), fileIdentifier);
+    return fbBuilder.buffer;
   }
 }
 class Vec3 {
   Vec3._(this._bc, this._bcOffset);
 
-  static const fb.Reader<Vec3> reader = const _Vec3Reader();
+  static const fb.Reader<Vec3> reader = _Vec3Reader();
 
   final fb.BufferContext _bc;
   final int _bcOffset;
@@ -380,13 +462,62 @@
   double get y => const fb.Float32Reader().read(_bc, _bcOffset + 4);
   double get z => const fb.Float32Reader().read(_bc, _bcOffset + 8);
   double get test1 => const fb.Float64Reader().read(_bc, _bcOffset + 16);
-  Color get test2 => new Color.fromValue(const fb.Uint8Reader().read(_bc, _bcOffset + 24));
+  Color get test2 => Color.fromValue(const fb.Uint8Reader().read(_bc, _bcOffset + 24));
   Test get test3 => Test.reader.read(_bc, _bcOffset + 26);
 
   @override
   String toString() {
     return 'Vec3{x: $x, y: $y, z: $z, test1: $test1, test2: $test2, test3: $test3}';
   }
+
+  Vec3T unpack() => Vec3T(
+      x: x,
+      y: y,
+      z: z,
+      test1: test1,
+      test2: test2,
+      test3: test3.unpack());
+
+  static int pack(fb.Builder fbBuilder, Vec3T? object) {
+    if (object == null) return 0;
+    return object.pack(fbBuilder);
+  }
+}
+
+class Vec3T implements fb.Packable {
+  double x;
+  double y;
+  double z;
+  double test1;
+  Color test2;
+  TestT test3;
+
+  Vec3T({
+      required this.x,
+      required this.y,
+      required this.z,
+      required this.test1,
+      required this.test2,
+      required this.test3});
+
+  @override
+  int pack(fb.Builder fbBuilder) {
+    fbBuilder.pad(2);
+    test3.pack(fbBuilder);
+    fbBuilder.pad(1);
+    fbBuilder.putUint8(test2.value);
+    fbBuilder.putFloat64(test1);
+    fbBuilder.pad(4);
+    fbBuilder.putFloat32(z);
+    fbBuilder.putFloat32(y);
+    fbBuilder.putFloat32(x);
+    return fbBuilder.offset;
+  }
+
+  @override
+  String toString() {
+    return 'Vec3T{x: $x, y: $y, z: $z, test1: $test1, test2: $test2, test3: $test3}';
+  }
 }
 
 class _Vec3Reader extends fb.StructReader<Vec3> {
@@ -397,13 +528,11 @@
 
   @override
   Vec3 createObject(fb.BufferContext bc, int offset) => 
-    new Vec3._(bc, offset);
+    Vec3._(bc, offset);
 }
 
 class Vec3Builder {
-  Vec3Builder(this.fbBuilder) {
-    assert(fbBuilder != null);
-  }
+  Vec3Builder(this.fbBuilder);
 
   final fb.Builder fbBuilder;
 
@@ -411,7 +540,7 @@
     fbBuilder.pad(2);
     test3();
     fbBuilder.pad(1);
-    fbBuilder.putUint8(test2?.value);
+    fbBuilder.putUint8(test2.value);
     fbBuilder.putFloat64(test1);
     fbBuilder.pad(4);
     fbBuilder.putFloat32(z);
@@ -431,12 +560,12 @@
   final TestObjectBuilder _test3;
 
   Vec3ObjectBuilder({
-    double x,
-    double y,
-    double z,
-    double test1,
-    Color test2,
-    TestObjectBuilder test3,
+    required double x,
+    required double y,
+    required double z,
+    required double test1,
+    required Color test2,
+    required TestObjectBuilder test3,
   })
       : _x = x,
         _y = y,
@@ -447,14 +576,11 @@
 
   /// Finish building, and store into the [fbBuilder].
   @override
-  int finish(
-    fb.Builder fbBuilder) {
-    assert(fbBuilder != null);
-
+  int finish(fb.Builder fbBuilder) {
     fbBuilder.pad(2);
     _test3.finish(fbBuilder);
     fbBuilder.pad(1);
-    fbBuilder.putUint8(_test2?.value);
+    fbBuilder.putUint8(_test2.value);
     fbBuilder.putFloat64(_test1);
     fbBuilder.pad(4);
     fbBuilder.putFloat32(_z);
@@ -465,16 +591,16 @@
 
   /// Convenience method to serialize to byte list.
   @override
-  Uint8List toBytes([String fileIdentifier]) {
-    fb.Builder fbBuilder = new fb.Builder();
-    int offset = finish(fbBuilder);
-    return fbBuilder.finish(offset, fileIdentifier);
+  Uint8List toBytes([String? fileIdentifier]) {
+    final fbBuilder = fb.Builder(deduplicateTables: false);
+    fbBuilder.finish(finish(fbBuilder), fileIdentifier);
+    return fbBuilder.buffer;
   }
 }
 class Ability {
   Ability._(this._bc, this._bcOffset);
 
-  static const fb.Reader<Ability> reader = const _AbilityReader();
+  static const fb.Reader<Ability> reader = _AbilityReader();
 
   final fb.BufferContext _bc;
   final int _bcOffset;
@@ -486,6 +612,36 @@
   String toString() {
     return 'Ability{id: $id, distance: $distance}';
   }
+
+  AbilityT unpack() => AbilityT(
+      id: id,
+      distance: distance);
+
+  static int pack(fb.Builder fbBuilder, AbilityT? object) {
+    if (object == null) return 0;
+    return object.pack(fbBuilder);
+  }
+}
+
+class AbilityT implements fb.Packable {
+  int id;
+  int distance;
+
+  AbilityT({
+      required this.id,
+      required this.distance});
+
+  @override
+  int pack(fb.Builder fbBuilder) {
+    fbBuilder.putUint32(distance);
+    fbBuilder.putUint32(id);
+    return fbBuilder.offset;
+  }
+
+  @override
+  String toString() {
+    return 'AbilityT{id: $id, distance: $distance}';
+  }
 }
 
 class _AbilityReader extends fb.StructReader<Ability> {
@@ -496,13 +652,11 @@
 
   @override
   Ability createObject(fb.BufferContext bc, int offset) => 
-    new Ability._(bc, offset);
+    Ability._(bc, offset);
 }
 
 class AbilityBuilder {
-  AbilityBuilder(this.fbBuilder) {
-    assert(fbBuilder != null);
-  }
+  AbilityBuilder(this.fbBuilder);
 
   final fb.Builder fbBuilder;
 
@@ -519,18 +673,15 @@
   final int _distance;
 
   AbilityObjectBuilder({
-    int id,
-    int distance,
+    required int id,
+    required int distance,
   })
       : _id = id,
         _distance = distance;
 
   /// Finish building, and store into the [fbBuilder].
   @override
-  int finish(
-    fb.Builder fbBuilder) {
-    assert(fbBuilder != null);
-
+  int finish(fb.Builder fbBuilder) {
     fbBuilder.putUint32(_distance);
     fbBuilder.putUint32(_id);
     return fbBuilder.offset;
@@ -538,25 +689,133 @@
 
   /// Convenience method to serialize to byte list.
   @override
-  Uint8List toBytes([String fileIdentifier]) {
-    fb.Builder fbBuilder = new fb.Builder();
-    int offset = finish(fbBuilder);
-    return fbBuilder.finish(offset, fileIdentifier);
+  Uint8List toBytes([String? fileIdentifier]) {
+    final fbBuilder = fb.Builder(deduplicateTables: false);
+    fbBuilder.finish(finish(fbBuilder), fileIdentifier);
+    return fbBuilder.buffer;
+  }
+}
+class StructOfStructs {
+  StructOfStructs._(this._bc, this._bcOffset);
+
+  static const fb.Reader<StructOfStructs> reader = _StructOfStructsReader();
+
+  final fb.BufferContext _bc;
+  final int _bcOffset;
+
+  Ability get a => Ability.reader.read(_bc, _bcOffset + 0);
+  Test get b => Test.reader.read(_bc, _bcOffset + 8);
+  Ability get c => Ability.reader.read(_bc, _bcOffset + 12);
+
+  @override
+  String toString() {
+    return 'StructOfStructs{a: $a, b: $b, c: $c}';
+  }
+
+  StructOfStructsT unpack() => StructOfStructsT(
+      a: a.unpack(),
+      b: b.unpack(),
+      c: c.unpack());
+
+  static int pack(fb.Builder fbBuilder, StructOfStructsT? object) {
+    if (object == null) return 0;
+    return object.pack(fbBuilder);
+  }
+}
+
+class StructOfStructsT implements fb.Packable {
+  AbilityT a;
+  TestT b;
+  AbilityT c;
+
+  StructOfStructsT({
+      required this.a,
+      required this.b,
+      required this.c});
+
+  @override
+  int pack(fb.Builder fbBuilder) {
+    c.pack(fbBuilder);
+    b.pack(fbBuilder);
+    a.pack(fbBuilder);
+    return fbBuilder.offset;
+  }
+
+  @override
+  String toString() {
+    return 'StructOfStructsT{a: $a, b: $b, c: $c}';
+  }
+}
+
+class _StructOfStructsReader extends fb.StructReader<StructOfStructs> {
+  const _StructOfStructsReader();
+
+  @override
+  int get size => 20;
+
+  @override
+  StructOfStructs createObject(fb.BufferContext bc, int offset) => 
+    StructOfStructs._(bc, offset);
+}
+
+class StructOfStructsBuilder {
+  StructOfStructsBuilder(this.fbBuilder);
+
+  final fb.Builder fbBuilder;
+
+  int finish(fb.StructBuilder a, fb.StructBuilder b, fb.StructBuilder c) {
+    c();
+    b();
+    a();
+    return fbBuilder.offset;
+  }
+
+}
+
+class StructOfStructsObjectBuilder extends fb.ObjectBuilder {
+  final AbilityObjectBuilder _a;
+  final TestObjectBuilder _b;
+  final AbilityObjectBuilder _c;
+
+  StructOfStructsObjectBuilder({
+    required AbilityObjectBuilder a,
+    required TestObjectBuilder b,
+    required AbilityObjectBuilder c,
+  })
+      : _a = a,
+        _b = b,
+        _c = c;
+
+  /// Finish building, and store into the [fbBuilder].
+  @override
+  int finish(fb.Builder fbBuilder) {
+    _c.finish(fbBuilder);
+    _b.finish(fbBuilder);
+    _a.finish(fbBuilder);
+    return fbBuilder.offset;
+  }
+
+  /// Convenience method to serialize to byte list.
+  @override
+  Uint8List toBytes([String? fileIdentifier]) {
+    final fbBuilder = fb.Builder(deduplicateTables: false);
+    fbBuilder.finish(finish(fbBuilder), fileIdentifier);
+    return fbBuilder.buffer;
   }
 }
 class Stat {
   Stat._(this._bc, this._bcOffset);
   factory Stat(List<int> bytes) {
-    fb.BufferContext rootRef = new fb.BufferContext.fromBytes(bytes);
+    final rootRef = fb.BufferContext.fromBytes(bytes);
     return reader.read(rootRef, 0);
   }
 
-  static const fb.Reader<Stat> reader = const _StatReader();
+  static const fb.Reader<Stat> reader = _StatReader();
 
   final fb.BufferContext _bc;
   final int _bcOffset;
 
-  String get id => const fb.StringReader().vTableGet(_bc, _bcOffset, 4, null);
+  String? get id => const fb.StringReader().vTableGetNullable(_bc, _bcOffset, 4);
   int get val => const fb.Int64Reader().vTableGet(_bc, _bcOffset, 6, 0);
   int get count => const fb.Uint16Reader().vTableGet(_bc, _bcOffset, 8, 0);
 
@@ -564,6 +823,43 @@
   String toString() {
     return 'Stat{id: $id, val: $val, count: $count}';
   }
+
+  StatT unpack() => StatT(
+      id: id,
+      val: val,
+      count: count);
+
+  static int pack(fb.Builder fbBuilder, StatT? object) {
+    if (object == null) return 0;
+    return object.pack(fbBuilder);
+  }
+}
+
+class StatT implements fb.Packable {
+  String? id;
+  int val;
+  int count;
+
+  StatT({
+      this.id,
+      this.val = 0,
+      this.count = 0});
+
+  @override
+  int pack(fb.Builder fbBuilder) {
+    final int? idOffset = id == null ? null
+        : fbBuilder.writeString(id!);
+    fbBuilder.startTable(3);
+    fbBuilder.addOffset(0, idOffset);
+    fbBuilder.addInt64(1, val);
+    fbBuilder.addUint16(2, count);
+    return fbBuilder.endTable();
+  }
+
+  @override
+  String toString() {
+    return 'StatT{id: $id, val: $val, count: $count}';
+  }
 }
 
 class _StatReader extends fb.TableReader<Stat> {
@@ -571,29 +867,27 @@
 
   @override
   Stat createObject(fb.BufferContext bc, int offset) => 
-    new Stat._(bc, offset);
+    Stat._(bc, offset);
 }
 
 class StatBuilder {
-  StatBuilder(this.fbBuilder) {
-    assert(fbBuilder != null);
-  }
+  StatBuilder(this.fbBuilder);
 
   final fb.Builder fbBuilder;
 
   void begin() {
-    fbBuilder.startTable();
+    fbBuilder.startTable(3);
   }
 
-  int addIdOffset(int offset) {
+  int addIdOffset(int? offset) {
     fbBuilder.addOffset(0, offset);
     return fbBuilder.offset;
   }
-  int addVal(int val) {
+  int addVal(int? val) {
     fbBuilder.addInt64(1, val);
     return fbBuilder.offset;
   }
-  int addCount(int count) {
+  int addCount(int? count) {
     fbBuilder.addUint16(2, count);
     return fbBuilder.offset;
   }
@@ -604,14 +898,14 @@
 }
 
 class StatObjectBuilder extends fb.ObjectBuilder {
-  final String _id;
-  final int _val;
-  final int _count;
+  final String? _id;
+  final int? _val;
+  final int? _count;
 
   StatObjectBuilder({
-    String id,
-    int val,
-    int count,
+    String? id,
+    int? val,
+    int? count,
   })
       : _id = id,
         _val = val,
@@ -619,15 +913,11 @@
 
   /// Finish building, and store into the [fbBuilder].
   @override
-  int finish(
-    fb.Builder fbBuilder) {
-    assert(fbBuilder != null);
-    final int idOffset = fbBuilder.writeString(_id);
-
-    fbBuilder.startTable();
-    if (idOffset != null) {
-      fbBuilder.addOffset(0, idOffset);
-    }
+  int finish(fb.Builder fbBuilder) {
+    final int? idOffset = _id == null ? null
+        : fbBuilder.writeString(_id!);
+    fbBuilder.startTable(3);
+    fbBuilder.addOffset(0, idOffset);
     fbBuilder.addInt64(1, _val);
     fbBuilder.addUint16(2, _count);
     return fbBuilder.endTable();
@@ -635,20 +925,20 @@
 
   /// Convenience method to serialize to byte list.
   @override
-  Uint8List toBytes([String fileIdentifier]) {
-    fb.Builder fbBuilder = new fb.Builder();
-    int offset = finish(fbBuilder);
-    return fbBuilder.finish(offset, fileIdentifier);
+  Uint8List toBytes([String? fileIdentifier]) {
+    final fbBuilder = fb.Builder(deduplicateTables: false);
+    fbBuilder.finish(finish(fbBuilder), fileIdentifier);
+    return fbBuilder.buffer;
   }
 }
 class Referrable {
   Referrable._(this._bc, this._bcOffset);
   factory Referrable(List<int> bytes) {
-    fb.BufferContext rootRef = new fb.BufferContext.fromBytes(bytes);
+    final rootRef = fb.BufferContext.fromBytes(bytes);
     return reader.read(rootRef, 0);
   }
 
-  static const fb.Reader<Referrable> reader = const _ReferrableReader();
+  static const fb.Reader<Referrable> reader = _ReferrableReader();
 
   final fb.BufferContext _bc;
   final int _bcOffset;
@@ -659,6 +949,33 @@
   String toString() {
     return 'Referrable{id: $id}';
   }
+
+  ReferrableT unpack() => ReferrableT(
+      id: id);
+
+  static int pack(fb.Builder fbBuilder, ReferrableT? object) {
+    if (object == null) return 0;
+    return object.pack(fbBuilder);
+  }
+}
+
+class ReferrableT implements fb.Packable {
+  int id;
+
+  ReferrableT({
+      this.id = 0});
+
+  @override
+  int pack(fb.Builder fbBuilder) {
+    fbBuilder.startTable(1);
+    fbBuilder.addUint64(0, id);
+    return fbBuilder.endTable();
+  }
+
+  @override
+  String toString() {
+    return 'ReferrableT{id: $id}';
+  }
 }
 
 class _ReferrableReader extends fb.TableReader<Referrable> {
@@ -666,21 +983,19 @@
 
   @override
   Referrable createObject(fb.BufferContext bc, int offset) => 
-    new Referrable._(bc, offset);
+    Referrable._(bc, offset);
 }
 
 class ReferrableBuilder {
-  ReferrableBuilder(this.fbBuilder) {
-    assert(fbBuilder != null);
-  }
+  ReferrableBuilder(this.fbBuilder);
 
   final fb.Builder fbBuilder;
 
   void begin() {
-    fbBuilder.startTable();
+    fbBuilder.startTable(1);
   }
 
-  int addId(int id) {
+  int addId(int? id) {
     fbBuilder.addUint64(0, id);
     return fbBuilder.offset;
   }
@@ -691,68 +1006,65 @@
 }
 
 class ReferrableObjectBuilder extends fb.ObjectBuilder {
-  final int _id;
+  final int? _id;
 
   ReferrableObjectBuilder({
-    int id,
+    int? id,
   })
       : _id = id;
 
   /// Finish building, and store into the [fbBuilder].
   @override
-  int finish(
-    fb.Builder fbBuilder) {
-    assert(fbBuilder != null);
-
-    fbBuilder.startTable();
+  int finish(fb.Builder fbBuilder) {
+    fbBuilder.startTable(1);
     fbBuilder.addUint64(0, _id);
     return fbBuilder.endTable();
   }
 
   /// Convenience method to serialize to byte list.
   @override
-  Uint8List toBytes([String fileIdentifier]) {
-    fb.Builder fbBuilder = new fb.Builder();
-    int offset = finish(fbBuilder);
-    return fbBuilder.finish(offset, fileIdentifier);
+  Uint8List toBytes([String? fileIdentifier]) {
+    final fbBuilder = fb.Builder(deduplicateTables: false);
+    fbBuilder.finish(finish(fbBuilder), fileIdentifier);
+    return fbBuilder.buffer;
   }
 }
 ///  an example documentation comment: "monster object"
 class Monster {
   Monster._(this._bc, this._bcOffset);
   factory Monster(List<int> bytes) {
-    fb.BufferContext rootRef = new fb.BufferContext.fromBytes(bytes);
+    final rootRef = fb.BufferContext.fromBytes(bytes);
     return reader.read(rootRef, 0);
   }
 
-  static const fb.Reader<Monster> reader = const _MonsterReader();
+  static const fb.Reader<Monster> reader = _MonsterReader();
 
   final fb.BufferContext _bc;
   final int _bcOffset;
 
-  Vec3 get pos => Vec3.reader.vTableGet(_bc, _bcOffset, 4, null);
+  Vec3? get pos => Vec3.reader.vTableGetNullable(_bc, _bcOffset, 4);
   int get mana => const fb.Int16Reader().vTableGet(_bc, _bcOffset, 6, 150);
   int get hp => const fb.Int16Reader().vTableGet(_bc, _bcOffset, 8, 100);
-  String get name => const fb.StringReader().vTableGet(_bc, _bcOffset, 10, null);
-  List<int> get inventory => const fb.ListReader<int>(const fb.Uint8Reader()).vTableGet(_bc, _bcOffset, 14, null);
-  Color get color => new Color.fromValue(const fb.Uint8Reader().vTableGet(_bc, _bcOffset, 16, 8));
-  AnyTypeId get testType => new AnyTypeId.fromValue(const fb.Uint8Reader().vTableGet(_bc, _bcOffset, 18, 0));
+  String? get name => const fb.StringReader().vTableGetNullable(_bc, _bcOffset, 10);
+  List<int>? get inventory => const fb.Uint8ListReader().vTableGetNullable(_bc, _bcOffset, 14);
+  Color get color => Color.fromValue(const fb.Uint8Reader().vTableGet(_bc, _bcOffset, 16, 8));
+  AnyTypeId? get testType => AnyTypeId._createOrNull(const fb.Uint8Reader().vTableGetNullable(_bc, _bcOffset, 18));
   dynamic get test {
     switch (testType?.value) {
-      case 1: return Monster.reader.vTableGet(_bc, _bcOffset, 20, null);
-      case 2: return TestSimpleTableWithEnum.reader.vTableGet(_bc, _bcOffset, 20, null);
-      case 3: return my_game_example2.Monster.reader.vTableGet(_bc, _bcOffset, 20, null);
+      case 1: return Monster.reader.vTableGetNullable(_bc, _bcOffset, 20);
+      case 2: return TestSimpleTableWithEnum.reader.vTableGetNullable(_bc, _bcOffset, 20);
+      case 3: return my_game_example2.Monster.reader.vTableGetNullable(_bc, _bcOffset, 20);
       default: return null;
     }
   }
-  List<Test> get test4 => const fb.ListReader<Test>(Test.reader).vTableGet(_bc, _bcOffset, 22, null);
-  List<String> get testarrayofstring => const fb.ListReader<String>(const fb.StringReader()).vTableGet(_bc, _bcOffset, 24, null);
+  List<Test>? get test4 => const fb.ListReader<Test>(Test.reader).vTableGetNullable(_bc, _bcOffset, 22);
+  List<String>? get testarrayofstring => const fb.ListReader<String>(fb.StringReader()).vTableGetNullable(_bc, _bcOffset, 24);
   ///  an example documentation comment: this will end up in the generated code
   ///  multiline too
-  List<Monster> get testarrayoftables => const fb.ListReader<Monster>(Monster.reader).vTableGet(_bc, _bcOffset, 26, null);
-  Monster get enemy => Monster.reader.vTableGet(_bc, _bcOffset, 28, null);
-  List<int> get testnestedflatbuffer => const fb.ListReader<int>(const fb.Uint8Reader()).vTableGet(_bc, _bcOffset, 30, null);
-  Stat get testempty => Stat.reader.vTableGet(_bc, _bcOffset, 32, null);
+  List<Monster>? get testarrayoftables => const fb.ListReader<Monster>(Monster.reader).vTableGetNullable(_bc, _bcOffset, 26);
+  Monster? get enemy => Monster.reader.vTableGetNullable(_bc, _bcOffset, 28);
+  List<int>? get testnestedflatbuffer => const fb.Uint8ListReader().vTableGetNullable(_bc, _bcOffset, 30);
+  Stat? get testempty => Stat.reader.vTableGetNullable(_bc, _bcOffset, 32);
   bool get testbool => const fb.BoolReader().vTableGet(_bc, _bcOffset, 34, false);
   int get testhashs32Fnv1 => const fb.Int32Reader().vTableGet(_bc, _bcOffset, 36, 0);
   int get testhashu32Fnv1 => const fb.Uint32Reader().vTableGet(_bc, _bcOffset, 38, 0);
@@ -762,49 +1074,336 @@
   int get testhashu32Fnv1a => const fb.Uint32Reader().vTableGet(_bc, _bcOffset, 46, 0);
   int get testhashs64Fnv1a => const fb.Int64Reader().vTableGet(_bc, _bcOffset, 48, 0);
   int get testhashu64Fnv1a => const fb.Uint64Reader().vTableGet(_bc, _bcOffset, 50, 0);
-  List<bool> get testarrayofbools => const fb.ListReader<bool>(const fb.BoolReader()).vTableGet(_bc, _bcOffset, 52, null);
+  List<bool>? get testarrayofbools => const fb.ListReader<bool>(fb.BoolReader()).vTableGetNullable(_bc, _bcOffset, 52);
   double get testf => const fb.Float32Reader().vTableGet(_bc, _bcOffset, 54, 3.14159);
   double get testf2 => const fb.Float32Reader().vTableGet(_bc, _bcOffset, 56, 3.0);
   double get testf3 => const fb.Float32Reader().vTableGet(_bc, _bcOffset, 58, 0.0);
-  List<String> get testarrayofstring2 => const fb.ListReader<String>(const fb.StringReader()).vTableGet(_bc, _bcOffset, 60, null);
-  List<Ability> get testarrayofsortedstruct => const fb.ListReader<Ability>(Ability.reader).vTableGet(_bc, _bcOffset, 62, null);
-  List<int> get flex => const fb.ListReader<int>(const fb.Uint8Reader()).vTableGet(_bc, _bcOffset, 64, null);
-  List<Test> get test5 => const fb.ListReader<Test>(Test.reader).vTableGet(_bc, _bcOffset, 66, null);
-  List<int> get vectorOfLongs => const fb.ListReader<int>(const fb.Int64Reader()).vTableGet(_bc, _bcOffset, 68, null);
-  List<double> get vectorOfDoubles => const fb.ListReader<double>(const fb.Float64Reader()).vTableGet(_bc, _bcOffset, 70, null);
-  my_game.InParentNamespace get parentNamespaceTest => my_game.InParentNamespace.reader.vTableGet(_bc, _bcOffset, 72, null);
-  List<Referrable> get vectorOfReferrables => const fb.ListReader<Referrable>(Referrable.reader).vTableGet(_bc, _bcOffset, 74, null);
+  List<String>? get testarrayofstring2 => const fb.ListReader<String>(fb.StringReader()).vTableGetNullable(_bc, _bcOffset, 60);
+  List<Ability>? get testarrayofsortedstruct => const fb.ListReader<Ability>(Ability.reader).vTableGetNullable(_bc, _bcOffset, 62);
+  List<int>? get flex => const fb.Uint8ListReader().vTableGetNullable(_bc, _bcOffset, 64);
+  List<Test>? get test5 => const fb.ListReader<Test>(Test.reader).vTableGetNullable(_bc, _bcOffset, 66);
+  List<int>? get vectorOfLongs => const fb.ListReader<int>(fb.Int64Reader()).vTableGetNullable(_bc, _bcOffset, 68);
+  List<double>? get vectorOfDoubles => const fb.ListReader<double>(fb.Float64Reader()).vTableGetNullable(_bc, _bcOffset, 70);
+  my_game.InParentNamespace? get parentNamespaceTest => my_game.InParentNamespace.reader.vTableGetNullable(_bc, _bcOffset, 72);
+  List<Referrable>? get vectorOfReferrables => const fb.ListReader<Referrable>(Referrable.reader).vTableGetNullable(_bc, _bcOffset, 74);
   int get singleWeakReference => const fb.Uint64Reader().vTableGet(_bc, _bcOffset, 76, 0);
-  List<int> get vectorOfWeakReferences => const fb.ListReader<int>(const fb.Uint64Reader()).vTableGet(_bc, _bcOffset, 78, null);
-  List<Referrable> get vectorOfStrongReferrables => const fb.ListReader<Referrable>(Referrable.reader).vTableGet(_bc, _bcOffset, 80, null);
+  List<int>? get vectorOfWeakReferences => const fb.ListReader<int>(fb.Uint64Reader()).vTableGetNullable(_bc, _bcOffset, 78);
+  List<Referrable>? get vectorOfStrongReferrables => const fb.ListReader<Referrable>(Referrable.reader).vTableGetNullable(_bc, _bcOffset, 80);
   int get coOwningReference => const fb.Uint64Reader().vTableGet(_bc, _bcOffset, 82, 0);
-  List<int> get vectorOfCoOwningReferences => const fb.ListReader<int>(const fb.Uint64Reader()).vTableGet(_bc, _bcOffset, 84, null);
+  List<int>? get vectorOfCoOwningReferences => const fb.ListReader<int>(fb.Uint64Reader()).vTableGetNullable(_bc, _bcOffset, 84);
   int get nonOwningReference => const fb.Uint64Reader().vTableGet(_bc, _bcOffset, 86, 0);
-  List<int> get vectorOfNonOwningReferences => const fb.ListReader<int>(const fb.Uint64Reader()).vTableGet(_bc, _bcOffset, 88, null);
-  AnyUniqueAliasesTypeId get anyUniqueType => new AnyUniqueAliasesTypeId.fromValue(const fb.Uint8Reader().vTableGet(_bc, _bcOffset, 90, 0));
+  List<int>? get vectorOfNonOwningReferences => const fb.ListReader<int>(fb.Uint64Reader()).vTableGetNullable(_bc, _bcOffset, 88);
+  AnyUniqueAliasesTypeId? get anyUniqueType => AnyUniqueAliasesTypeId._createOrNull(const fb.Uint8Reader().vTableGetNullable(_bc, _bcOffset, 90));
   dynamic get anyUnique {
     switch (anyUniqueType?.value) {
-      case 1: return Monster.reader.vTableGet(_bc, _bcOffset, 92, null);
-      case 2: return TestSimpleTableWithEnum.reader.vTableGet(_bc, _bcOffset, 92, null);
-      case 3: return my_game_example2.Monster.reader.vTableGet(_bc, _bcOffset, 92, null);
+      case 1: return Monster.reader.vTableGetNullable(_bc, _bcOffset, 92);
+      case 2: return TestSimpleTableWithEnum.reader.vTableGetNullable(_bc, _bcOffset, 92);
+      case 3: return my_game_example2.Monster.reader.vTableGetNullable(_bc, _bcOffset, 92);
       default: return null;
     }
   }
-  AnyAmbiguousAliasesTypeId get anyAmbiguousType => new AnyAmbiguousAliasesTypeId.fromValue(const fb.Uint8Reader().vTableGet(_bc, _bcOffset, 94, 0));
+  AnyAmbiguousAliasesTypeId? get anyAmbiguousType => AnyAmbiguousAliasesTypeId._createOrNull(const fb.Uint8Reader().vTableGetNullable(_bc, _bcOffset, 94));
   dynamic get anyAmbiguous {
     switch (anyAmbiguousType?.value) {
-      case 1: return Monster.reader.vTableGet(_bc, _bcOffset, 96, null);
-      case 2: return Monster.reader.vTableGet(_bc, _bcOffset, 96, null);
-      case 3: return Monster.reader.vTableGet(_bc, _bcOffset, 96, null);
+      case 1: return Monster.reader.vTableGetNullable(_bc, _bcOffset, 96);
+      case 2: return Monster.reader.vTableGetNullable(_bc, _bcOffset, 96);
+      case 3: return Monster.reader.vTableGetNullable(_bc, _bcOffset, 96);
       default: return null;
     }
   }
-  List<Color> get vectorOfEnums => const fb.ListReader<Color>(Color.reader).vTableGet(_bc, _bcOffset, 98, null);
-  Race get signedEnum => new Race.fromValue(const fb.Int8Reader().vTableGet(_bc, _bcOffset, 100, -1));
+  List<Color>? get vectorOfEnums => const fb.ListReader<Color>(Color.reader).vTableGetNullable(_bc, _bcOffset, 98);
+  Race get signedEnum => Race.fromValue(const fb.Int8Reader().vTableGet(_bc, _bcOffset, 100, -1));
+  List<int>? get testrequirednestedflatbuffer => const fb.Uint8ListReader().vTableGetNullable(_bc, _bcOffset, 102);
+  List<Stat>? get scalarKeySortedTables => const fb.ListReader<Stat>(Stat.reader).vTableGetNullable(_bc, _bcOffset, 104);
 
   @override
   String toString() {
-    return 'Monster{pos: $pos, mana: $mana, hp: $hp, name: $name, inventory: $inventory, color: $color, testType: $testType, test: $test, test4: $test4, testarrayofstring: $testarrayofstring, testarrayoftables: $testarrayoftables, enemy: $enemy, testnestedflatbuffer: $testnestedflatbuffer, testempty: $testempty, testbool: $testbool, testhashs32Fnv1: $testhashs32Fnv1, testhashu32Fnv1: $testhashu32Fnv1, testhashs64Fnv1: $testhashs64Fnv1, testhashu64Fnv1: $testhashu64Fnv1, testhashs32Fnv1a: $testhashs32Fnv1a, testhashu32Fnv1a: $testhashu32Fnv1a, testhashs64Fnv1a: $testhashs64Fnv1a, testhashu64Fnv1a: $testhashu64Fnv1a, testarrayofbools: $testarrayofbools, testf: $testf, testf2: $testf2, testf3: $testf3, testarrayofstring2: $testarrayofstring2, testarrayofsortedstruct: $testarrayofsortedstruct, flex: $flex, test5: $test5, vectorOfLongs: $vectorOfLongs, vectorOfDoubles: $vectorOfDoubles, parentNamespaceTest: $parentNamespaceTest, vectorOfReferrables: $vectorOfReferrables, singleWeakReference: $singleWeakReference, vectorOfWeakReferences: $vectorOfWeakReferences, vectorOfStrongReferrables: $vectorOfStrongReferrables, coOwningReference: $coOwningReference, vectorOfCoOwningReferences: $vectorOfCoOwningReferences, nonOwningReference: $nonOwningReference, vectorOfNonOwningReferences: $vectorOfNonOwningReferences, anyUniqueType: $anyUniqueType, anyUnique: $anyUnique, anyAmbiguousType: $anyAmbiguousType, anyAmbiguous: $anyAmbiguous, vectorOfEnums: $vectorOfEnums, signedEnum: $signedEnum}';
+    return 'Monster{pos: $pos, mana: $mana, hp: $hp, name: $name, inventory: $inventory, color: $color, testType: $testType, test: $test, test4: $test4, testarrayofstring: $testarrayofstring, testarrayoftables: $testarrayoftables, enemy: $enemy, testnestedflatbuffer: $testnestedflatbuffer, testempty: $testempty, testbool: $testbool, testhashs32Fnv1: $testhashs32Fnv1, testhashu32Fnv1: $testhashu32Fnv1, testhashs64Fnv1: $testhashs64Fnv1, testhashu64Fnv1: $testhashu64Fnv1, testhashs32Fnv1a: $testhashs32Fnv1a, testhashu32Fnv1a: $testhashu32Fnv1a, testhashs64Fnv1a: $testhashs64Fnv1a, testhashu64Fnv1a: $testhashu64Fnv1a, testarrayofbools: $testarrayofbools, testf: $testf, testf2: $testf2, testf3: $testf3, testarrayofstring2: $testarrayofstring2, testarrayofsortedstruct: $testarrayofsortedstruct, flex: $flex, test5: $test5, vectorOfLongs: $vectorOfLongs, vectorOfDoubles: $vectorOfDoubles, parentNamespaceTest: $parentNamespaceTest, vectorOfReferrables: $vectorOfReferrables, singleWeakReference: $singleWeakReference, vectorOfWeakReferences: $vectorOfWeakReferences, vectorOfStrongReferrables: $vectorOfStrongReferrables, coOwningReference: $coOwningReference, vectorOfCoOwningReferences: $vectorOfCoOwningReferences, nonOwningReference: $nonOwningReference, vectorOfNonOwningReferences: $vectorOfNonOwningReferences, anyUniqueType: $anyUniqueType, anyUnique: $anyUnique, anyAmbiguousType: $anyAmbiguousType, anyAmbiguous: $anyAmbiguous, vectorOfEnums: $vectorOfEnums, signedEnum: $signedEnum, testrequirednestedflatbuffer: $testrequirednestedflatbuffer, scalarKeySortedTables: $scalarKeySortedTables}';
+  }
+
+  MonsterT unpack() => MonsterT(
+      pos: pos?.unpack(),
+      mana: mana,
+      hp: hp,
+      name: name,
+      inventory: const fb.Uint8ListReader(lazy: false).vTableGetNullable(_bc, _bcOffset, 14),
+      color: color,
+      testType: testType,
+      test: test,
+      test4: test4?.map((e) => e.unpack()).toList(),
+      testarrayofstring: const fb.ListReader<String>(fb.StringReader(), lazy: false).vTableGetNullable(_bc, _bcOffset, 24),
+      testarrayoftables: testarrayoftables?.map((e) => e.unpack()).toList(),
+      enemy: enemy?.unpack(),
+      testnestedflatbuffer: const fb.Uint8ListReader(lazy: false).vTableGetNullable(_bc, _bcOffset, 30),
+      testempty: testempty?.unpack(),
+      testbool: testbool,
+      testhashs32Fnv1: testhashs32Fnv1,
+      testhashu32Fnv1: testhashu32Fnv1,
+      testhashs64Fnv1: testhashs64Fnv1,
+      testhashu64Fnv1: testhashu64Fnv1,
+      testhashs32Fnv1a: testhashs32Fnv1a,
+      testhashu32Fnv1a: testhashu32Fnv1a,
+      testhashs64Fnv1a: testhashs64Fnv1a,
+      testhashu64Fnv1a: testhashu64Fnv1a,
+      testarrayofbools: const fb.ListReader<bool>(fb.BoolReader(), lazy: false).vTableGetNullable(_bc, _bcOffset, 52),
+      testf: testf,
+      testf2: testf2,
+      testf3: testf3,
+      testarrayofstring2: const fb.ListReader<String>(fb.StringReader(), lazy: false).vTableGetNullable(_bc, _bcOffset, 60),
+      testarrayofsortedstruct: testarrayofsortedstruct?.map((e) => e.unpack()).toList(),
+      flex: const fb.Uint8ListReader(lazy: false).vTableGetNullable(_bc, _bcOffset, 64),
+      test5: test5?.map((e) => e.unpack()).toList(),
+      vectorOfLongs: const fb.ListReader<int>(fb.Int64Reader(), lazy: false).vTableGetNullable(_bc, _bcOffset, 68),
+      vectorOfDoubles: const fb.ListReader<double>(fb.Float64Reader(), lazy: false).vTableGetNullable(_bc, _bcOffset, 70),
+      parentNamespaceTest: parentNamespaceTest?.unpack(),
+      vectorOfReferrables: vectorOfReferrables?.map((e) => e.unpack()).toList(),
+      singleWeakReference: singleWeakReference,
+      vectorOfWeakReferences: const fb.ListReader<int>(fb.Uint64Reader(), lazy: false).vTableGetNullable(_bc, _bcOffset, 78),
+      vectorOfStrongReferrables: vectorOfStrongReferrables?.map((e) => e.unpack()).toList(),
+      coOwningReference: coOwningReference,
+      vectorOfCoOwningReferences: const fb.ListReader<int>(fb.Uint64Reader(), lazy: false).vTableGetNullable(_bc, _bcOffset, 84),
+      nonOwningReference: nonOwningReference,
+      vectorOfNonOwningReferences: const fb.ListReader<int>(fb.Uint64Reader(), lazy: false).vTableGetNullable(_bc, _bcOffset, 88),
+      anyUniqueType: anyUniqueType,
+      anyUnique: anyUnique,
+      anyAmbiguousType: anyAmbiguousType,
+      anyAmbiguous: anyAmbiguous,
+      vectorOfEnums: const fb.ListReader<Color>(Color.reader, lazy: false).vTableGetNullable(_bc, _bcOffset, 98),
+      signedEnum: signedEnum,
+      testrequirednestedflatbuffer: const fb.Uint8ListReader(lazy: false).vTableGetNullable(_bc, _bcOffset, 102),
+      scalarKeySortedTables: scalarKeySortedTables?.map((e) => e.unpack()).toList());
+
+  static int pack(fb.Builder fbBuilder, MonsterT? object) {
+    if (object == null) return 0;
+    return object.pack(fbBuilder);
+  }
+}
+
+///  an example documentation comment: "monster object"
+class MonsterT implements fb.Packable {
+  Vec3T? pos;
+  int mana;
+  int hp;
+  String? name;
+  List<int>? inventory;
+  Color color;
+  AnyTypeId? testType;
+  dynamic test;
+  List<TestT>? test4;
+  List<String>? testarrayofstring;
+  ///  an example documentation comment: this will end up in the generated code
+  ///  multiline too
+  List<MonsterT>? testarrayoftables;
+  MonsterT? enemy;
+  List<int>? testnestedflatbuffer;
+  StatT? testempty;
+  bool testbool;
+  int testhashs32Fnv1;
+  int testhashu32Fnv1;
+  int testhashs64Fnv1;
+  int testhashu64Fnv1;
+  int testhashs32Fnv1a;
+  int testhashu32Fnv1a;
+  int testhashs64Fnv1a;
+  int testhashu64Fnv1a;
+  List<bool>? testarrayofbools;
+  double testf;
+  double testf2;
+  double testf3;
+  List<String>? testarrayofstring2;
+  List<AbilityT>? testarrayofsortedstruct;
+  List<int>? flex;
+  List<TestT>? test5;
+  List<int>? vectorOfLongs;
+  List<double>? vectorOfDoubles;
+  my_game.InParentNamespaceT? parentNamespaceTest;
+  List<ReferrableT>? vectorOfReferrables;
+  int singleWeakReference;
+  List<int>? vectorOfWeakReferences;
+  List<ReferrableT>? vectorOfStrongReferrables;
+  int coOwningReference;
+  List<int>? vectorOfCoOwningReferences;
+  int nonOwningReference;
+  List<int>? vectorOfNonOwningReferences;
+  AnyUniqueAliasesTypeId? anyUniqueType;
+  dynamic anyUnique;
+  AnyAmbiguousAliasesTypeId? anyAmbiguousType;
+  dynamic anyAmbiguous;
+  List<Color>? vectorOfEnums;
+  Race signedEnum;
+  List<int>? testrequirednestedflatbuffer;
+  List<StatT>? scalarKeySortedTables;
+
+  MonsterT({
+      this.pos,
+      this.mana = 150,
+      this.hp = 100,
+      this.name,
+      this.inventory,
+      this.color = Color.Blue,
+      this.testType,
+      this.test,
+      this.test4,
+      this.testarrayofstring,
+      this.testarrayoftables,
+      this.enemy,
+      this.testnestedflatbuffer,
+      this.testempty,
+      this.testbool = false,
+      this.testhashs32Fnv1 = 0,
+      this.testhashu32Fnv1 = 0,
+      this.testhashs64Fnv1 = 0,
+      this.testhashu64Fnv1 = 0,
+      this.testhashs32Fnv1a = 0,
+      this.testhashu32Fnv1a = 0,
+      this.testhashs64Fnv1a = 0,
+      this.testhashu64Fnv1a = 0,
+      this.testarrayofbools,
+      this.testf = 3.14159,
+      this.testf2 = 3.0,
+      this.testf3 = 0.0,
+      this.testarrayofstring2,
+      this.testarrayofsortedstruct,
+      this.flex,
+      this.test5,
+      this.vectorOfLongs,
+      this.vectorOfDoubles,
+      this.parentNamespaceTest,
+      this.vectorOfReferrables,
+      this.singleWeakReference = 0,
+      this.vectorOfWeakReferences,
+      this.vectorOfStrongReferrables,
+      this.coOwningReference = 0,
+      this.vectorOfCoOwningReferences,
+      this.nonOwningReference = 0,
+      this.vectorOfNonOwningReferences,
+      this.anyUniqueType,
+      this.anyUnique,
+      this.anyAmbiguousType,
+      this.anyAmbiguous,
+      this.vectorOfEnums,
+      this.signedEnum = Race.None,
+      this.testrequirednestedflatbuffer,
+      this.scalarKeySortedTables});
+
+  @override
+  int pack(fb.Builder fbBuilder) {
+    final int? nameOffset = name == null ? null
+        : fbBuilder.writeString(name!);
+    final int? inventoryOffset = inventory == null ? null
+        : fbBuilder.writeListUint8(inventory!);
+    final int? testOffset = test?.pack(fbBuilder);
+    int? test4Offset;
+    if (test4 != null) {
+      for (var e in test4!) { e.pack(fbBuilder); }
+      test4Offset = fbBuilder.endStructVector(test4!.length);
+    }
+    final int? testarrayofstringOffset = testarrayofstring == null ? null
+        : fbBuilder.writeList(testarrayofstring!.map(fbBuilder.writeString).toList());
+    final int? testarrayoftablesOffset = testarrayoftables == null ? null
+        : fbBuilder.writeList(testarrayoftables!.map((b) => b.pack(fbBuilder)).toList());
+    final int? enemyOffset = enemy?.pack(fbBuilder);
+    final int? testnestedflatbufferOffset = testnestedflatbuffer == null ? null
+        : fbBuilder.writeListUint8(testnestedflatbuffer!);
+    final int? testemptyOffset = testempty?.pack(fbBuilder);
+    final int? testarrayofboolsOffset = testarrayofbools == null ? null
+        : fbBuilder.writeListBool(testarrayofbools!);
+    final int? testarrayofstring2Offset = testarrayofstring2 == null ? null
+        : fbBuilder.writeList(testarrayofstring2!.map(fbBuilder.writeString).toList());
+    int? testarrayofsortedstructOffset;
+    if (testarrayofsortedstruct != null) {
+      for (var e in testarrayofsortedstruct!) { e.pack(fbBuilder); }
+      testarrayofsortedstructOffset = fbBuilder.endStructVector(testarrayofsortedstruct!.length);
+    }
+    final int? flexOffset = flex == null ? null
+        : fbBuilder.writeListUint8(flex!);
+    int? test5Offset;
+    if (test5 != null) {
+      for (var e in test5!) { e.pack(fbBuilder); }
+      test5Offset = fbBuilder.endStructVector(test5!.length);
+    }
+    final int? vectorOfLongsOffset = vectorOfLongs == null ? null
+        : fbBuilder.writeListInt64(vectorOfLongs!);
+    final int? vectorOfDoublesOffset = vectorOfDoubles == null ? null
+        : fbBuilder.writeListFloat64(vectorOfDoubles!);
+    final int? parentNamespaceTestOffset = parentNamespaceTest?.pack(fbBuilder);
+    final int? vectorOfReferrablesOffset = vectorOfReferrables == null ? null
+        : fbBuilder.writeList(vectorOfReferrables!.map((b) => b.pack(fbBuilder)).toList());
+    final int? vectorOfWeakReferencesOffset = vectorOfWeakReferences == null ? null
+        : fbBuilder.writeListUint64(vectorOfWeakReferences!);
+    final int? vectorOfStrongReferrablesOffset = vectorOfStrongReferrables == null ? null
+        : fbBuilder.writeList(vectorOfStrongReferrables!.map((b) => b.pack(fbBuilder)).toList());
+    final int? vectorOfCoOwningReferencesOffset = vectorOfCoOwningReferences == null ? null
+        : fbBuilder.writeListUint64(vectorOfCoOwningReferences!);
+    final int? vectorOfNonOwningReferencesOffset = vectorOfNonOwningReferences == null ? null
+        : fbBuilder.writeListUint64(vectorOfNonOwningReferences!);
+    final int? anyUniqueOffset = anyUnique?.pack(fbBuilder);
+    final int? anyAmbiguousOffset = anyAmbiguous?.pack(fbBuilder);
+    final int? vectorOfEnumsOffset = vectorOfEnums == null ? null
+        : fbBuilder.writeListUint8(vectorOfEnums!.map((f) => f.value).toList());
+    final int? testrequirednestedflatbufferOffset = testrequirednestedflatbuffer == null ? null
+        : fbBuilder.writeListUint8(testrequirednestedflatbuffer!);
+    final int? scalarKeySortedTablesOffset = scalarKeySortedTables == null ? null
+        : fbBuilder.writeList(scalarKeySortedTables!.map((b) => b.pack(fbBuilder)).toList());
+    fbBuilder.startTable(50);
+    if (pos != null) {
+      fbBuilder.addStruct(0, pos!.pack(fbBuilder));
+    }
+    fbBuilder.addInt16(1, mana);
+    fbBuilder.addInt16(2, hp);
+    fbBuilder.addOffset(3, nameOffset);
+    fbBuilder.addOffset(5, inventoryOffset);
+    fbBuilder.addUint8(6, color.value);
+    fbBuilder.addUint8(7, testType?.value);
+    fbBuilder.addOffset(8, testOffset);
+    fbBuilder.addOffset(9, test4Offset);
+    fbBuilder.addOffset(10, testarrayofstringOffset);
+    fbBuilder.addOffset(11, testarrayoftablesOffset);
+    fbBuilder.addOffset(12, enemyOffset);
+    fbBuilder.addOffset(13, testnestedflatbufferOffset);
+    fbBuilder.addOffset(14, testemptyOffset);
+    fbBuilder.addBool(15, testbool);
+    fbBuilder.addInt32(16, testhashs32Fnv1);
+    fbBuilder.addUint32(17, testhashu32Fnv1);
+    fbBuilder.addInt64(18, testhashs64Fnv1);
+    fbBuilder.addUint64(19, testhashu64Fnv1);
+    fbBuilder.addInt32(20, testhashs32Fnv1a);
+    fbBuilder.addUint32(21, testhashu32Fnv1a);
+    fbBuilder.addInt64(22, testhashs64Fnv1a);
+    fbBuilder.addUint64(23, testhashu64Fnv1a);
+    fbBuilder.addOffset(24, testarrayofboolsOffset);
+    fbBuilder.addFloat32(25, testf);
+    fbBuilder.addFloat32(26, testf2);
+    fbBuilder.addFloat32(27, testf3);
+    fbBuilder.addOffset(28, testarrayofstring2Offset);
+    fbBuilder.addOffset(29, testarrayofsortedstructOffset);
+    fbBuilder.addOffset(30, flexOffset);
+    fbBuilder.addOffset(31, test5Offset);
+    fbBuilder.addOffset(32, vectorOfLongsOffset);
+    fbBuilder.addOffset(33, vectorOfDoublesOffset);
+    fbBuilder.addOffset(34, parentNamespaceTestOffset);
+    fbBuilder.addOffset(35, vectorOfReferrablesOffset);
+    fbBuilder.addUint64(36, singleWeakReference);
+    fbBuilder.addOffset(37, vectorOfWeakReferencesOffset);
+    fbBuilder.addOffset(38, vectorOfStrongReferrablesOffset);
+    fbBuilder.addUint64(39, coOwningReference);
+    fbBuilder.addOffset(40, vectorOfCoOwningReferencesOffset);
+    fbBuilder.addUint64(41, nonOwningReference);
+    fbBuilder.addOffset(42, vectorOfNonOwningReferencesOffset);
+    fbBuilder.addUint8(43, anyUniqueType?.value);
+    fbBuilder.addOffset(44, anyUniqueOffset);
+    fbBuilder.addUint8(45, anyAmbiguousType?.value);
+    fbBuilder.addOffset(46, anyAmbiguousOffset);
+    fbBuilder.addOffset(47, vectorOfEnumsOffset);
+    fbBuilder.addInt8(48, signedEnum.value);
+    fbBuilder.addOffset(49, testrequirednestedflatbufferOffset);
+    fbBuilder.addOffset(50, scalarKeySortedTablesOffset);
+    return fbBuilder.endTable();
+  }
+
+  @override
+  String toString() {
+    return 'MonsterT{pos: $pos, mana: $mana, hp: $hp, name: $name, inventory: $inventory, color: $color, testType: $testType, test: $test, test4: $test4, testarrayofstring: $testarrayofstring, testarrayoftables: $testarrayoftables, enemy: $enemy, testnestedflatbuffer: $testnestedflatbuffer, testempty: $testempty, testbool: $testbool, testhashs32Fnv1: $testhashs32Fnv1, testhashu32Fnv1: $testhashu32Fnv1, testhashs64Fnv1: $testhashs64Fnv1, testhashu64Fnv1: $testhashu64Fnv1, testhashs32Fnv1a: $testhashs32Fnv1a, testhashu32Fnv1a: $testhashu32Fnv1a, testhashs64Fnv1a: $testhashs64Fnv1a, testhashu64Fnv1a: $testhashu64Fnv1a, testarrayofbools: $testarrayofbools, testf: $testf, testf2: $testf2, testf3: $testf3, testarrayofstring2: $testarrayofstring2, testarrayofsortedstruct: $testarrayofsortedstruct, flex: $flex, test5: $test5, vectorOfLongs: $vectorOfLongs, vectorOfDoubles: $vectorOfDoubles, parentNamespaceTest: $parentNamespaceTest, vectorOfReferrables: $vectorOfReferrables, singleWeakReference: $singleWeakReference, vectorOfWeakReferences: $vectorOfWeakReferences, vectorOfStrongReferrables: $vectorOfStrongReferrables, coOwningReference: $coOwningReference, vectorOfCoOwningReferences: $vectorOfCoOwningReferences, nonOwningReference: $nonOwningReference, vectorOfNonOwningReferences: $vectorOfNonOwningReferences, anyUniqueType: $anyUniqueType, anyUnique: $anyUnique, anyAmbiguousType: $anyAmbiguousType, anyAmbiguous: $anyAmbiguous, vectorOfEnums: $vectorOfEnums, signedEnum: $signedEnum, testrequirednestedflatbuffer: $testrequirednestedflatbuffer, scalarKeySortedTables: $scalarKeySortedTables}';
   }
 }
 
@@ -813,212 +1412,218 @@
 
   @override
   Monster createObject(fb.BufferContext bc, int offset) => 
-    new Monster._(bc, offset);
+    Monster._(bc, offset);
 }
 
 class MonsterBuilder {
-  MonsterBuilder(this.fbBuilder) {
-    assert(fbBuilder != null);
-  }
+  MonsterBuilder(this.fbBuilder);
 
   final fb.Builder fbBuilder;
 
   void begin() {
-    fbBuilder.startTable();
+    fbBuilder.startTable(50);
   }
 
   int addPos(int offset) {
     fbBuilder.addStruct(0, offset);
     return fbBuilder.offset;
   }
-  int addMana(int mana) {
+  int addMana(int? mana) {
     fbBuilder.addInt16(1, mana);
     return fbBuilder.offset;
   }
-  int addHp(int hp) {
+  int addHp(int? hp) {
     fbBuilder.addInt16(2, hp);
     return fbBuilder.offset;
   }
-  int addNameOffset(int offset) {
+  int addNameOffset(int? offset) {
     fbBuilder.addOffset(3, offset);
     return fbBuilder.offset;
   }
-  int addInventoryOffset(int offset) {
+  int addInventoryOffset(int? offset) {
     fbBuilder.addOffset(5, offset);
     return fbBuilder.offset;
   }
-  int addColor(Color color) {
+  int addColor(Color? color) {
     fbBuilder.addUint8(6, color?.value);
     return fbBuilder.offset;
   }
-  int addTestType(AnyTypeId testType) {
+  int addTestType(AnyTypeId? testType) {
     fbBuilder.addUint8(7, testType?.value);
     return fbBuilder.offset;
   }
-  int addTestOffset(int offset) {
+  int addTestOffset(int? offset) {
     fbBuilder.addOffset(8, offset);
     return fbBuilder.offset;
   }
-  int addTest4Offset(int offset) {
+  int addTest4Offset(int? offset) {
     fbBuilder.addOffset(9, offset);
     return fbBuilder.offset;
   }
-  int addTestarrayofstringOffset(int offset) {
+  int addTestarrayofstringOffset(int? offset) {
     fbBuilder.addOffset(10, offset);
     return fbBuilder.offset;
   }
-  int addTestarrayoftablesOffset(int offset) {
+  int addTestarrayoftablesOffset(int? offset) {
     fbBuilder.addOffset(11, offset);
     return fbBuilder.offset;
   }
-  int addEnemyOffset(int offset) {
+  int addEnemyOffset(int? offset) {
     fbBuilder.addOffset(12, offset);
     return fbBuilder.offset;
   }
-  int addTestnestedflatbufferOffset(int offset) {
+  int addTestnestedflatbufferOffset(int? offset) {
     fbBuilder.addOffset(13, offset);
     return fbBuilder.offset;
   }
-  int addTestemptyOffset(int offset) {
+  int addTestemptyOffset(int? offset) {
     fbBuilder.addOffset(14, offset);
     return fbBuilder.offset;
   }
-  int addTestbool(bool testbool) {
+  int addTestbool(bool? testbool) {
     fbBuilder.addBool(15, testbool);
     return fbBuilder.offset;
   }
-  int addTesthashs32Fnv1(int testhashs32Fnv1) {
+  int addTesthashs32Fnv1(int? testhashs32Fnv1) {
     fbBuilder.addInt32(16, testhashs32Fnv1);
     return fbBuilder.offset;
   }
-  int addTesthashu32Fnv1(int testhashu32Fnv1) {
+  int addTesthashu32Fnv1(int? testhashu32Fnv1) {
     fbBuilder.addUint32(17, testhashu32Fnv1);
     return fbBuilder.offset;
   }
-  int addTesthashs64Fnv1(int testhashs64Fnv1) {
+  int addTesthashs64Fnv1(int? testhashs64Fnv1) {
     fbBuilder.addInt64(18, testhashs64Fnv1);
     return fbBuilder.offset;
   }
-  int addTesthashu64Fnv1(int testhashu64Fnv1) {
+  int addTesthashu64Fnv1(int? testhashu64Fnv1) {
     fbBuilder.addUint64(19, testhashu64Fnv1);
     return fbBuilder.offset;
   }
-  int addTesthashs32Fnv1a(int testhashs32Fnv1a) {
+  int addTesthashs32Fnv1a(int? testhashs32Fnv1a) {
     fbBuilder.addInt32(20, testhashs32Fnv1a);
     return fbBuilder.offset;
   }
-  int addTesthashu32Fnv1a(int testhashu32Fnv1a) {
+  int addTesthashu32Fnv1a(int? testhashu32Fnv1a) {
     fbBuilder.addUint32(21, testhashu32Fnv1a);
     return fbBuilder.offset;
   }
-  int addTesthashs64Fnv1a(int testhashs64Fnv1a) {
+  int addTesthashs64Fnv1a(int? testhashs64Fnv1a) {
     fbBuilder.addInt64(22, testhashs64Fnv1a);
     return fbBuilder.offset;
   }
-  int addTesthashu64Fnv1a(int testhashu64Fnv1a) {
+  int addTesthashu64Fnv1a(int? testhashu64Fnv1a) {
     fbBuilder.addUint64(23, testhashu64Fnv1a);
     return fbBuilder.offset;
   }
-  int addTestarrayofboolsOffset(int offset) {
+  int addTestarrayofboolsOffset(int? offset) {
     fbBuilder.addOffset(24, offset);
     return fbBuilder.offset;
   }
-  int addTestf(double testf) {
+  int addTestf(double? testf) {
     fbBuilder.addFloat32(25, testf);
     return fbBuilder.offset;
   }
-  int addTestf2(double testf2) {
+  int addTestf2(double? testf2) {
     fbBuilder.addFloat32(26, testf2);
     return fbBuilder.offset;
   }
-  int addTestf3(double testf3) {
+  int addTestf3(double? testf3) {
     fbBuilder.addFloat32(27, testf3);
     return fbBuilder.offset;
   }
-  int addTestarrayofstring2Offset(int offset) {
+  int addTestarrayofstring2Offset(int? offset) {
     fbBuilder.addOffset(28, offset);
     return fbBuilder.offset;
   }
-  int addTestarrayofsortedstructOffset(int offset) {
+  int addTestarrayofsortedstructOffset(int? offset) {
     fbBuilder.addOffset(29, offset);
     return fbBuilder.offset;
   }
-  int addFlexOffset(int offset) {
+  int addFlexOffset(int? offset) {
     fbBuilder.addOffset(30, offset);
     return fbBuilder.offset;
   }
-  int addTest5Offset(int offset) {
+  int addTest5Offset(int? offset) {
     fbBuilder.addOffset(31, offset);
     return fbBuilder.offset;
   }
-  int addVectorOfLongsOffset(int offset) {
+  int addVectorOfLongsOffset(int? offset) {
     fbBuilder.addOffset(32, offset);
     return fbBuilder.offset;
   }
-  int addVectorOfDoublesOffset(int offset) {
+  int addVectorOfDoublesOffset(int? offset) {
     fbBuilder.addOffset(33, offset);
     return fbBuilder.offset;
   }
-  int addParentNamespaceTestOffset(int offset) {
+  int addParentNamespaceTestOffset(int? offset) {
     fbBuilder.addOffset(34, offset);
     return fbBuilder.offset;
   }
-  int addVectorOfReferrablesOffset(int offset) {
+  int addVectorOfReferrablesOffset(int? offset) {
     fbBuilder.addOffset(35, offset);
     return fbBuilder.offset;
   }
-  int addSingleWeakReference(int singleWeakReference) {
+  int addSingleWeakReference(int? singleWeakReference) {
     fbBuilder.addUint64(36, singleWeakReference);
     return fbBuilder.offset;
   }
-  int addVectorOfWeakReferencesOffset(int offset) {
+  int addVectorOfWeakReferencesOffset(int? offset) {
     fbBuilder.addOffset(37, offset);
     return fbBuilder.offset;
   }
-  int addVectorOfStrongReferrablesOffset(int offset) {
+  int addVectorOfStrongReferrablesOffset(int? offset) {
     fbBuilder.addOffset(38, offset);
     return fbBuilder.offset;
   }
-  int addCoOwningReference(int coOwningReference) {
+  int addCoOwningReference(int? coOwningReference) {
     fbBuilder.addUint64(39, coOwningReference);
     return fbBuilder.offset;
   }
-  int addVectorOfCoOwningReferencesOffset(int offset) {
+  int addVectorOfCoOwningReferencesOffset(int? offset) {
     fbBuilder.addOffset(40, offset);
     return fbBuilder.offset;
   }
-  int addNonOwningReference(int nonOwningReference) {
+  int addNonOwningReference(int? nonOwningReference) {
     fbBuilder.addUint64(41, nonOwningReference);
     return fbBuilder.offset;
   }
-  int addVectorOfNonOwningReferencesOffset(int offset) {
+  int addVectorOfNonOwningReferencesOffset(int? offset) {
     fbBuilder.addOffset(42, offset);
     return fbBuilder.offset;
   }
-  int addAnyUniqueType(AnyUniqueAliasesTypeId anyUniqueType) {
+  int addAnyUniqueType(AnyUniqueAliasesTypeId? anyUniqueType) {
     fbBuilder.addUint8(43, anyUniqueType?.value);
     return fbBuilder.offset;
   }
-  int addAnyUniqueOffset(int offset) {
+  int addAnyUniqueOffset(int? offset) {
     fbBuilder.addOffset(44, offset);
     return fbBuilder.offset;
   }
-  int addAnyAmbiguousType(AnyAmbiguousAliasesTypeId anyAmbiguousType) {
+  int addAnyAmbiguousType(AnyAmbiguousAliasesTypeId? anyAmbiguousType) {
     fbBuilder.addUint8(45, anyAmbiguousType?.value);
     return fbBuilder.offset;
   }
-  int addAnyAmbiguousOffset(int offset) {
+  int addAnyAmbiguousOffset(int? offset) {
     fbBuilder.addOffset(46, offset);
     return fbBuilder.offset;
   }
-  int addVectorOfEnumsOffset(int offset) {
+  int addVectorOfEnumsOffset(int? offset) {
     fbBuilder.addOffset(47, offset);
     return fbBuilder.offset;
   }
-  int addSignedEnum(Race signedEnum) {
+  int addSignedEnum(Race? signedEnum) {
     fbBuilder.addInt8(48, signedEnum?.value);
     return fbBuilder.offset;
   }
+  int addTestrequirednestedflatbufferOffset(int? offset) {
+    fbBuilder.addOffset(49, offset);
+    return fbBuilder.offset;
+  }
+  int addScalarKeySortedTablesOffset(int? offset) {
+    fbBuilder.addOffset(50, offset);
+    return fbBuilder.offset;
+  }
 
   int finish() {
     return fbBuilder.endTable();
@@ -1026,104 +1631,108 @@
 }
 
 class MonsterObjectBuilder extends fb.ObjectBuilder {
-  final Vec3ObjectBuilder _pos;
-  final int _mana;
-  final int _hp;
-  final String _name;
-  final List<int> _inventory;
-  final Color _color;
-  final AnyTypeId _testType;
+  final Vec3ObjectBuilder? _pos;
+  final int? _mana;
+  final int? _hp;
+  final String? _name;
+  final List<int>? _inventory;
+  final Color? _color;
+  final AnyTypeId? _testType;
   final dynamic _test;
-  final List<TestObjectBuilder> _test4;
-  final List<String> _testarrayofstring;
-  final List<MonsterObjectBuilder> _testarrayoftables;
-  final MonsterObjectBuilder _enemy;
-  final List<int> _testnestedflatbuffer;
-  final StatObjectBuilder _testempty;
-  final bool _testbool;
-  final int _testhashs32Fnv1;
-  final int _testhashu32Fnv1;
-  final int _testhashs64Fnv1;
-  final int _testhashu64Fnv1;
-  final int _testhashs32Fnv1a;
-  final int _testhashu32Fnv1a;
-  final int _testhashs64Fnv1a;
-  final int _testhashu64Fnv1a;
-  final List<bool> _testarrayofbools;
-  final double _testf;
-  final double _testf2;
-  final double _testf3;
-  final List<String> _testarrayofstring2;
-  final List<AbilityObjectBuilder> _testarrayofsortedstruct;
-  final List<int> _flex;
-  final List<TestObjectBuilder> _test5;
-  final List<int> _vectorOfLongs;
-  final List<double> _vectorOfDoubles;
-  final my_game.InParentNamespaceObjectBuilder _parentNamespaceTest;
-  final List<ReferrableObjectBuilder> _vectorOfReferrables;
-  final int _singleWeakReference;
-  final List<int> _vectorOfWeakReferences;
-  final List<ReferrableObjectBuilder> _vectorOfStrongReferrables;
-  final int _coOwningReference;
-  final List<int> _vectorOfCoOwningReferences;
-  final int _nonOwningReference;
-  final List<int> _vectorOfNonOwningReferences;
-  final AnyUniqueAliasesTypeId _anyUniqueType;
+  final List<TestObjectBuilder>? _test4;
+  final List<String>? _testarrayofstring;
+  final List<MonsterObjectBuilder>? _testarrayoftables;
+  final MonsterObjectBuilder? _enemy;
+  final List<int>? _testnestedflatbuffer;
+  final StatObjectBuilder? _testempty;
+  final bool? _testbool;
+  final int? _testhashs32Fnv1;
+  final int? _testhashu32Fnv1;
+  final int? _testhashs64Fnv1;
+  final int? _testhashu64Fnv1;
+  final int? _testhashs32Fnv1a;
+  final int? _testhashu32Fnv1a;
+  final int? _testhashs64Fnv1a;
+  final int? _testhashu64Fnv1a;
+  final List<bool>? _testarrayofbools;
+  final double? _testf;
+  final double? _testf2;
+  final double? _testf3;
+  final List<String>? _testarrayofstring2;
+  final List<AbilityObjectBuilder>? _testarrayofsortedstruct;
+  final List<int>? _flex;
+  final List<TestObjectBuilder>? _test5;
+  final List<int>? _vectorOfLongs;
+  final List<double>? _vectorOfDoubles;
+  final my_game.InParentNamespaceObjectBuilder? _parentNamespaceTest;
+  final List<ReferrableObjectBuilder>? _vectorOfReferrables;
+  final int? _singleWeakReference;
+  final List<int>? _vectorOfWeakReferences;
+  final List<ReferrableObjectBuilder>? _vectorOfStrongReferrables;
+  final int? _coOwningReference;
+  final List<int>? _vectorOfCoOwningReferences;
+  final int? _nonOwningReference;
+  final List<int>? _vectorOfNonOwningReferences;
+  final AnyUniqueAliasesTypeId? _anyUniqueType;
   final dynamic _anyUnique;
-  final AnyAmbiguousAliasesTypeId _anyAmbiguousType;
+  final AnyAmbiguousAliasesTypeId? _anyAmbiguousType;
   final dynamic _anyAmbiguous;
-  final List<Color> _vectorOfEnums;
-  final Race _signedEnum;
+  final List<Color>? _vectorOfEnums;
+  final Race? _signedEnum;
+  final List<int>? _testrequirednestedflatbuffer;
+  final List<StatObjectBuilder>? _scalarKeySortedTables;
 
   MonsterObjectBuilder({
-    Vec3ObjectBuilder pos,
-    int mana,
-    int hp,
-    String name,
-    List<int> inventory,
-    Color color,
-    AnyTypeId testType,
+    Vec3ObjectBuilder? pos,
+    int? mana,
+    int? hp,
+    String? name,
+    List<int>? inventory,
+    Color? color,
+    AnyTypeId? testType,
     dynamic test,
-    List<TestObjectBuilder> test4,
-    List<String> testarrayofstring,
-    List<MonsterObjectBuilder> testarrayoftables,
-    MonsterObjectBuilder enemy,
-    List<int> testnestedflatbuffer,
-    StatObjectBuilder testempty,
-    bool testbool,
-    int testhashs32Fnv1,
-    int testhashu32Fnv1,
-    int testhashs64Fnv1,
-    int testhashu64Fnv1,
-    int testhashs32Fnv1a,
-    int testhashu32Fnv1a,
-    int testhashs64Fnv1a,
-    int testhashu64Fnv1a,
-    List<bool> testarrayofbools,
-    double testf,
-    double testf2,
-    double testf3,
-    List<String> testarrayofstring2,
-    List<AbilityObjectBuilder> testarrayofsortedstruct,
-    List<int> flex,
-    List<TestObjectBuilder> test5,
-    List<int> vectorOfLongs,
-    List<double> vectorOfDoubles,
-    my_game.InParentNamespaceObjectBuilder parentNamespaceTest,
-    List<ReferrableObjectBuilder> vectorOfReferrables,
-    int singleWeakReference,
-    List<int> vectorOfWeakReferences,
-    List<ReferrableObjectBuilder> vectorOfStrongReferrables,
-    int coOwningReference,
-    List<int> vectorOfCoOwningReferences,
-    int nonOwningReference,
-    List<int> vectorOfNonOwningReferences,
-    AnyUniqueAliasesTypeId anyUniqueType,
+    List<TestObjectBuilder>? test4,
+    List<String>? testarrayofstring,
+    List<MonsterObjectBuilder>? testarrayoftables,
+    MonsterObjectBuilder? enemy,
+    List<int>? testnestedflatbuffer,
+    StatObjectBuilder? testempty,
+    bool? testbool,
+    int? testhashs32Fnv1,
+    int? testhashu32Fnv1,
+    int? testhashs64Fnv1,
+    int? testhashu64Fnv1,
+    int? testhashs32Fnv1a,
+    int? testhashu32Fnv1a,
+    int? testhashs64Fnv1a,
+    int? testhashu64Fnv1a,
+    List<bool>? testarrayofbools,
+    double? testf,
+    double? testf2,
+    double? testf3,
+    List<String>? testarrayofstring2,
+    List<AbilityObjectBuilder>? testarrayofsortedstruct,
+    List<int>? flex,
+    List<TestObjectBuilder>? test5,
+    List<int>? vectorOfLongs,
+    List<double>? vectorOfDoubles,
+    my_game.InParentNamespaceObjectBuilder? parentNamespaceTest,
+    List<ReferrableObjectBuilder>? vectorOfReferrables,
+    int? singleWeakReference,
+    List<int>? vectorOfWeakReferences,
+    List<ReferrableObjectBuilder>? vectorOfStrongReferrables,
+    int? coOwningReference,
+    List<int>? vectorOfCoOwningReferences,
+    int? nonOwningReference,
+    List<int>? vectorOfNonOwningReferences,
+    AnyUniqueAliasesTypeId? anyUniqueType,
     dynamic anyUnique,
-    AnyAmbiguousAliasesTypeId anyAmbiguousType,
+    AnyAmbiguousAliasesTypeId? anyAmbiguousType,
     dynamic anyAmbiguous,
-    List<Color> vectorOfEnums,
-    Race signedEnum,
+    List<Color>? vectorOfEnums,
+    Race? signedEnum,
+    List<int>? testrequirednestedflatbuffer,
+    List<StatObjectBuilder>? scalarKeySortedTables,
   })
       : _pos = pos,
         _mana = mana,
@@ -1172,110 +1781,78 @@
         _anyAmbiguousType = anyAmbiguousType,
         _anyAmbiguous = anyAmbiguous,
         _vectorOfEnums = vectorOfEnums,
-        _signedEnum = signedEnum;
+        _signedEnum = signedEnum,
+        _testrequirednestedflatbuffer = testrequirednestedflatbuffer,
+        _scalarKeySortedTables = scalarKeySortedTables;
 
   /// Finish building, and store into the [fbBuilder].
   @override
-  int finish(
-    fb.Builder fbBuilder) {
-    assert(fbBuilder != null);
-    final int nameOffset = fbBuilder.writeString(_name);
-    final int inventoryOffset = _inventory?.isNotEmpty == true
-        ? fbBuilder.writeListUint8(_inventory)
-        : null;
-    final int testOffset = _test?.getOrCreateOffset(fbBuilder);
-    final int test4Offset = _test4?.isNotEmpty == true
-        ? fbBuilder.writeListOfStructs(_test4)
-        : null;
-    final int testarrayofstringOffset = _testarrayofstring?.isNotEmpty == true
-        ? fbBuilder.writeList(_testarrayofstring.map((b) => fbBuilder.writeString(b)).toList())
-        : null;
-    final int testarrayoftablesOffset = _testarrayoftables?.isNotEmpty == true
-        ? fbBuilder.writeList(_testarrayoftables.map((b) => b.getOrCreateOffset(fbBuilder)).toList())
-        : null;
-    final int enemyOffset = _enemy?.getOrCreateOffset(fbBuilder);
-    final int testnestedflatbufferOffset = _testnestedflatbuffer?.isNotEmpty == true
-        ? fbBuilder.writeListUint8(_testnestedflatbuffer)
-        : null;
-    final int testemptyOffset = _testempty?.getOrCreateOffset(fbBuilder);
-    final int testarrayofboolsOffset = _testarrayofbools?.isNotEmpty == true
-        ? fbBuilder.writeListBool(_testarrayofbools)
-        : null;
-    final int testarrayofstring2Offset = _testarrayofstring2?.isNotEmpty == true
-        ? fbBuilder.writeList(_testarrayofstring2.map((b) => fbBuilder.writeString(b)).toList())
-        : null;
-    final int testarrayofsortedstructOffset = _testarrayofsortedstruct?.isNotEmpty == true
-        ? fbBuilder.writeListOfStructs(_testarrayofsortedstruct)
-        : null;
-    final int flexOffset = _flex?.isNotEmpty == true
-        ? fbBuilder.writeListUint8(_flex)
-        : null;
-    final int test5Offset = _test5?.isNotEmpty == true
-        ? fbBuilder.writeListOfStructs(_test5)
-        : null;
-    final int vectorOfLongsOffset = _vectorOfLongs?.isNotEmpty == true
-        ? fbBuilder.writeListInt64(_vectorOfLongs)
-        : null;
-    final int vectorOfDoublesOffset = _vectorOfDoubles?.isNotEmpty == true
-        ? fbBuilder.writeListFloat64(_vectorOfDoubles)
-        : null;
-    final int parentNamespaceTestOffset = _parentNamespaceTest?.getOrCreateOffset(fbBuilder);
-    final int vectorOfReferrablesOffset = _vectorOfReferrables?.isNotEmpty == true
-        ? fbBuilder.writeList(_vectorOfReferrables.map((b) => b.getOrCreateOffset(fbBuilder)).toList())
-        : null;
-    final int vectorOfWeakReferencesOffset = _vectorOfWeakReferences?.isNotEmpty == true
-        ? fbBuilder.writeListUint64(_vectorOfWeakReferences)
-        : null;
-    final int vectorOfStrongReferrablesOffset = _vectorOfStrongReferrables?.isNotEmpty == true
-        ? fbBuilder.writeList(_vectorOfStrongReferrables.map((b) => b.getOrCreateOffset(fbBuilder)).toList())
-        : null;
-    final int vectorOfCoOwningReferencesOffset = _vectorOfCoOwningReferences?.isNotEmpty == true
-        ? fbBuilder.writeListUint64(_vectorOfCoOwningReferences)
-        : null;
-    final int vectorOfNonOwningReferencesOffset = _vectorOfNonOwningReferences?.isNotEmpty == true
-        ? fbBuilder.writeListUint64(_vectorOfNonOwningReferences)
-        : null;
-    final int anyUniqueOffset = _anyUnique?.getOrCreateOffset(fbBuilder);
-    final int anyAmbiguousOffset = _anyAmbiguous?.getOrCreateOffset(fbBuilder);
-    final int vectorOfEnumsOffset = _vectorOfEnums?.isNotEmpty == true
-        ? fbBuilder.writeListUint8(_vectorOfEnums.map((f) => f.value))
-        : null;
-
-    fbBuilder.startTable();
+  int finish(fb.Builder fbBuilder) {
+    final int? nameOffset = _name == null ? null
+        : fbBuilder.writeString(_name!);
+    final int? inventoryOffset = _inventory == null ? null
+        : fbBuilder.writeListUint8(_inventory!);
+    final int? testOffset = _test?.getOrCreateOffset(fbBuilder);
+    final int? test4Offset = _test4 == null ? null
+        : fbBuilder.writeListOfStructs(_test4!);
+    final int? testarrayofstringOffset = _testarrayofstring == null ? null
+        : fbBuilder.writeList(_testarrayofstring!.map(fbBuilder.writeString).toList());
+    final int? testarrayoftablesOffset = _testarrayoftables == null ? null
+        : fbBuilder.writeList(_testarrayoftables!.map((b) => b.getOrCreateOffset(fbBuilder)).toList());
+    final int? enemyOffset = _enemy?.getOrCreateOffset(fbBuilder);
+    final int? testnestedflatbufferOffset = _testnestedflatbuffer == null ? null
+        : fbBuilder.writeListUint8(_testnestedflatbuffer!);
+    final int? testemptyOffset = _testempty?.getOrCreateOffset(fbBuilder);
+    final int? testarrayofboolsOffset = _testarrayofbools == null ? null
+        : fbBuilder.writeListBool(_testarrayofbools!);
+    final int? testarrayofstring2Offset = _testarrayofstring2 == null ? null
+        : fbBuilder.writeList(_testarrayofstring2!.map(fbBuilder.writeString).toList());
+    final int? testarrayofsortedstructOffset = _testarrayofsortedstruct == null ? null
+        : fbBuilder.writeListOfStructs(_testarrayofsortedstruct!);
+    final int? flexOffset = _flex == null ? null
+        : fbBuilder.writeListUint8(_flex!);
+    final int? test5Offset = _test5 == null ? null
+        : fbBuilder.writeListOfStructs(_test5!);
+    final int? vectorOfLongsOffset = _vectorOfLongs == null ? null
+        : fbBuilder.writeListInt64(_vectorOfLongs!);
+    final int? vectorOfDoublesOffset = _vectorOfDoubles == null ? null
+        : fbBuilder.writeListFloat64(_vectorOfDoubles!);
+    final int? parentNamespaceTestOffset = _parentNamespaceTest?.getOrCreateOffset(fbBuilder);
+    final int? vectorOfReferrablesOffset = _vectorOfReferrables == null ? null
+        : fbBuilder.writeList(_vectorOfReferrables!.map((b) => b.getOrCreateOffset(fbBuilder)).toList());
+    final int? vectorOfWeakReferencesOffset = _vectorOfWeakReferences == null ? null
+        : fbBuilder.writeListUint64(_vectorOfWeakReferences!);
+    final int? vectorOfStrongReferrablesOffset = _vectorOfStrongReferrables == null ? null
+        : fbBuilder.writeList(_vectorOfStrongReferrables!.map((b) => b.getOrCreateOffset(fbBuilder)).toList());
+    final int? vectorOfCoOwningReferencesOffset = _vectorOfCoOwningReferences == null ? null
+        : fbBuilder.writeListUint64(_vectorOfCoOwningReferences!);
+    final int? vectorOfNonOwningReferencesOffset = _vectorOfNonOwningReferences == null ? null
+        : fbBuilder.writeListUint64(_vectorOfNonOwningReferences!);
+    final int? anyUniqueOffset = _anyUnique?.getOrCreateOffset(fbBuilder);
+    final int? anyAmbiguousOffset = _anyAmbiguous?.getOrCreateOffset(fbBuilder);
+    final int? vectorOfEnumsOffset = _vectorOfEnums == null ? null
+        : fbBuilder.writeListUint8(_vectorOfEnums!.map((f) => f.value).toList());
+    final int? testrequirednestedflatbufferOffset = _testrequirednestedflatbuffer == null ? null
+        : fbBuilder.writeListUint8(_testrequirednestedflatbuffer!);
+    final int? scalarKeySortedTablesOffset = _scalarKeySortedTables == null ? null
+        : fbBuilder.writeList(_scalarKeySortedTables!.map((b) => b.getOrCreateOffset(fbBuilder)).toList());
+    fbBuilder.startTable(50);
     if (_pos != null) {
-      fbBuilder.addStruct(0, _pos.finish(fbBuilder));
+      fbBuilder.addStruct(0, _pos!.finish(fbBuilder));
     }
     fbBuilder.addInt16(1, _mana);
     fbBuilder.addInt16(2, _hp);
-    if (nameOffset != null) {
-      fbBuilder.addOffset(3, nameOffset);
-    }
-    if (inventoryOffset != null) {
-      fbBuilder.addOffset(5, inventoryOffset);
-    }
+    fbBuilder.addOffset(3, nameOffset);
+    fbBuilder.addOffset(5, inventoryOffset);
     fbBuilder.addUint8(6, _color?.value);
     fbBuilder.addUint8(7, _testType?.value);
-    if (testOffset != null) {
-      fbBuilder.addOffset(8, testOffset);
-    }
-    if (test4Offset != null) {
-      fbBuilder.addOffset(9, test4Offset);
-    }
-    if (testarrayofstringOffset != null) {
-      fbBuilder.addOffset(10, testarrayofstringOffset);
-    }
-    if (testarrayoftablesOffset != null) {
-      fbBuilder.addOffset(11, testarrayoftablesOffset);
-    }
-    if (enemyOffset != null) {
-      fbBuilder.addOffset(12, enemyOffset);
-    }
-    if (testnestedflatbufferOffset != null) {
-      fbBuilder.addOffset(13, testnestedflatbufferOffset);
-    }
-    if (testemptyOffset != null) {
-      fbBuilder.addOffset(14, testemptyOffset);
-    }
+    fbBuilder.addOffset(8, testOffset);
+    fbBuilder.addOffset(9, test4Offset);
+    fbBuilder.addOffset(10, testarrayofstringOffset);
+    fbBuilder.addOffset(11, testarrayoftablesOffset);
+    fbBuilder.addOffset(12, enemyOffset);
+    fbBuilder.addOffset(13, testnestedflatbufferOffset);
+    fbBuilder.addOffset(14, testemptyOffset);
     fbBuilder.addBool(15, _testbool);
     fbBuilder.addInt32(16, _testhashs32Fnv1);
     fbBuilder.addUint32(17, _testhashu32Fnv1);
@@ -1285,82 +1862,52 @@
     fbBuilder.addUint32(21, _testhashu32Fnv1a);
     fbBuilder.addInt64(22, _testhashs64Fnv1a);
     fbBuilder.addUint64(23, _testhashu64Fnv1a);
-    if (testarrayofboolsOffset != null) {
-      fbBuilder.addOffset(24, testarrayofboolsOffset);
-    }
+    fbBuilder.addOffset(24, testarrayofboolsOffset);
     fbBuilder.addFloat32(25, _testf);
     fbBuilder.addFloat32(26, _testf2);
     fbBuilder.addFloat32(27, _testf3);
-    if (testarrayofstring2Offset != null) {
-      fbBuilder.addOffset(28, testarrayofstring2Offset);
-    }
-    if (testarrayofsortedstructOffset != null) {
-      fbBuilder.addOffset(29, testarrayofsortedstructOffset);
-    }
-    if (flexOffset != null) {
-      fbBuilder.addOffset(30, flexOffset);
-    }
-    if (test5Offset != null) {
-      fbBuilder.addOffset(31, test5Offset);
-    }
-    if (vectorOfLongsOffset != null) {
-      fbBuilder.addOffset(32, vectorOfLongsOffset);
-    }
-    if (vectorOfDoublesOffset != null) {
-      fbBuilder.addOffset(33, vectorOfDoublesOffset);
-    }
-    if (parentNamespaceTestOffset != null) {
-      fbBuilder.addOffset(34, parentNamespaceTestOffset);
-    }
-    if (vectorOfReferrablesOffset != null) {
-      fbBuilder.addOffset(35, vectorOfReferrablesOffset);
-    }
+    fbBuilder.addOffset(28, testarrayofstring2Offset);
+    fbBuilder.addOffset(29, testarrayofsortedstructOffset);
+    fbBuilder.addOffset(30, flexOffset);
+    fbBuilder.addOffset(31, test5Offset);
+    fbBuilder.addOffset(32, vectorOfLongsOffset);
+    fbBuilder.addOffset(33, vectorOfDoublesOffset);
+    fbBuilder.addOffset(34, parentNamespaceTestOffset);
+    fbBuilder.addOffset(35, vectorOfReferrablesOffset);
     fbBuilder.addUint64(36, _singleWeakReference);
-    if (vectorOfWeakReferencesOffset != null) {
-      fbBuilder.addOffset(37, vectorOfWeakReferencesOffset);
-    }
-    if (vectorOfStrongReferrablesOffset != null) {
-      fbBuilder.addOffset(38, vectorOfStrongReferrablesOffset);
-    }
+    fbBuilder.addOffset(37, vectorOfWeakReferencesOffset);
+    fbBuilder.addOffset(38, vectorOfStrongReferrablesOffset);
     fbBuilder.addUint64(39, _coOwningReference);
-    if (vectorOfCoOwningReferencesOffset != null) {
-      fbBuilder.addOffset(40, vectorOfCoOwningReferencesOffset);
-    }
+    fbBuilder.addOffset(40, vectorOfCoOwningReferencesOffset);
     fbBuilder.addUint64(41, _nonOwningReference);
-    if (vectorOfNonOwningReferencesOffset != null) {
-      fbBuilder.addOffset(42, vectorOfNonOwningReferencesOffset);
-    }
+    fbBuilder.addOffset(42, vectorOfNonOwningReferencesOffset);
     fbBuilder.addUint8(43, _anyUniqueType?.value);
-    if (anyUniqueOffset != null) {
-      fbBuilder.addOffset(44, anyUniqueOffset);
-    }
+    fbBuilder.addOffset(44, anyUniqueOffset);
     fbBuilder.addUint8(45, _anyAmbiguousType?.value);
-    if (anyAmbiguousOffset != null) {
-      fbBuilder.addOffset(46, anyAmbiguousOffset);
-    }
-    if (vectorOfEnumsOffset != null) {
-      fbBuilder.addOffset(47, vectorOfEnumsOffset);
-    }
+    fbBuilder.addOffset(46, anyAmbiguousOffset);
+    fbBuilder.addOffset(47, vectorOfEnumsOffset);
     fbBuilder.addInt8(48, _signedEnum?.value);
+    fbBuilder.addOffset(49, testrequirednestedflatbufferOffset);
+    fbBuilder.addOffset(50, scalarKeySortedTablesOffset);
     return fbBuilder.endTable();
   }
 
   /// Convenience method to serialize to byte list.
   @override
-  Uint8List toBytes([String fileIdentifier]) {
-    fb.Builder fbBuilder = new fb.Builder();
-    int offset = finish(fbBuilder);
-    return fbBuilder.finish(offset, fileIdentifier);
+  Uint8List toBytes([String? fileIdentifier]) {
+    final fbBuilder = fb.Builder(deduplicateTables: false);
+    fbBuilder.finish(finish(fbBuilder), fileIdentifier);
+    return fbBuilder.buffer;
   }
 }
 class TypeAliases {
   TypeAliases._(this._bc, this._bcOffset);
   factory TypeAliases(List<int> bytes) {
-    fb.BufferContext rootRef = new fb.BufferContext.fromBytes(bytes);
+    final rootRef = fb.BufferContext.fromBytes(bytes);
     return reader.read(rootRef, 0);
   }
 
-  static const fb.Reader<TypeAliases> reader = const _TypeAliasesReader();
+  static const fb.Reader<TypeAliases> reader = _TypeAliasesReader();
 
   final fb.BufferContext _bc;
   final int _bcOffset;
@@ -1375,13 +1922,88 @@
   int get u64 => const fb.Uint64Reader().vTableGet(_bc, _bcOffset, 18, 0);
   double get f32 => const fb.Float32Reader().vTableGet(_bc, _bcOffset, 20, 0.0);
   double get f64 => const fb.Float64Reader().vTableGet(_bc, _bcOffset, 22, 0.0);
-  List<int> get v8 => const fb.ListReader<int>(const fb.Int8Reader()).vTableGet(_bc, _bcOffset, 24, null);
-  List<double> get vf64 => const fb.ListReader<double>(const fb.Float64Reader()).vTableGet(_bc, _bcOffset, 26, null);
+  List<int>? get v8 => const fb.Int8ListReader().vTableGetNullable(_bc, _bcOffset, 24);
+  List<double>? get vf64 => const fb.ListReader<double>(fb.Float64Reader()).vTableGetNullable(_bc, _bcOffset, 26);
 
   @override
   String toString() {
     return 'TypeAliases{i8: $i8, u8: $u8, i16: $i16, u16: $u16, i32: $i32, u32: $u32, i64: $i64, u64: $u64, f32: $f32, f64: $f64, v8: $v8, vf64: $vf64}';
   }
+
+  TypeAliasesT unpack() => TypeAliasesT(
+      i8: i8,
+      u8: u8,
+      i16: i16,
+      u16: u16,
+      i32: i32,
+      u32: u32,
+      i64: i64,
+      u64: u64,
+      f32: f32,
+      f64: f64,
+      v8: const fb.Int8ListReader(lazy: false).vTableGetNullable(_bc, _bcOffset, 24),
+      vf64: const fb.ListReader<double>(fb.Float64Reader(), lazy: false).vTableGetNullable(_bc, _bcOffset, 26));
+
+  static int pack(fb.Builder fbBuilder, TypeAliasesT? object) {
+    if (object == null) return 0;
+    return object.pack(fbBuilder);
+  }
+}
+
+class TypeAliasesT implements fb.Packable {
+  int i8;
+  int u8;
+  int i16;
+  int u16;
+  int i32;
+  int u32;
+  int i64;
+  int u64;
+  double f32;
+  double f64;
+  List<int>? v8;
+  List<double>? vf64;
+
+  TypeAliasesT({
+      this.i8 = 0,
+      this.u8 = 0,
+      this.i16 = 0,
+      this.u16 = 0,
+      this.i32 = 0,
+      this.u32 = 0,
+      this.i64 = 0,
+      this.u64 = 0,
+      this.f32 = 0.0,
+      this.f64 = 0.0,
+      this.v8,
+      this.vf64});
+
+  @override
+  int pack(fb.Builder fbBuilder) {
+    final int? v8Offset = v8 == null ? null
+        : fbBuilder.writeListInt8(v8!);
+    final int? vf64Offset = vf64 == null ? null
+        : fbBuilder.writeListFloat64(vf64!);
+    fbBuilder.startTable(12);
+    fbBuilder.addInt8(0, i8);
+    fbBuilder.addUint8(1, u8);
+    fbBuilder.addInt16(2, i16);
+    fbBuilder.addUint16(3, u16);
+    fbBuilder.addInt32(4, i32);
+    fbBuilder.addUint32(5, u32);
+    fbBuilder.addInt64(6, i64);
+    fbBuilder.addUint64(7, u64);
+    fbBuilder.addFloat32(8, f32);
+    fbBuilder.addFloat64(9, f64);
+    fbBuilder.addOffset(10, v8Offset);
+    fbBuilder.addOffset(11, vf64Offset);
+    return fbBuilder.endTable();
+  }
+
+  @override
+  String toString() {
+    return 'TypeAliasesT{i8: $i8, u8: $u8, i16: $i16, u16: $u16, i32: $i32, u32: $u32, i64: $i64, u64: $u64, f32: $f32, f64: $f64, v8: $v8, vf64: $vf64}';
+  }
 }
 
 class _TypeAliasesReader extends fb.TableReader<TypeAliases> {
@@ -1389,65 +2011,63 @@
 
   @override
   TypeAliases createObject(fb.BufferContext bc, int offset) => 
-    new TypeAliases._(bc, offset);
+    TypeAliases._(bc, offset);
 }
 
 class TypeAliasesBuilder {
-  TypeAliasesBuilder(this.fbBuilder) {
-    assert(fbBuilder != null);
-  }
+  TypeAliasesBuilder(this.fbBuilder);
 
   final fb.Builder fbBuilder;
 
   void begin() {
-    fbBuilder.startTable();
+    fbBuilder.startTable(12);
   }
 
-  int addI8(int i8) {
+  int addI8(int? i8) {
     fbBuilder.addInt8(0, i8);
     return fbBuilder.offset;
   }
-  int addU8(int u8) {
+  int addU8(int? u8) {
     fbBuilder.addUint8(1, u8);
     return fbBuilder.offset;
   }
-  int addI16(int i16) {
+  int addI16(int? i16) {
     fbBuilder.addInt16(2, i16);
     return fbBuilder.offset;
   }
-  int addU16(int u16) {
+  int addU16(int? u16) {
     fbBuilder.addUint16(3, u16);
     return fbBuilder.offset;
   }
-  int addI32(int i32) {
+  int addI32(int? i32) {
     fbBuilder.addInt32(4, i32);
     return fbBuilder.offset;
   }
-  int addU32(int u32) {
+  int addU32(int? u32) {
     fbBuilder.addUint32(5, u32);
     return fbBuilder.offset;
   }
-  int addI64(int i64) {
+  int addI64(int? i64) {
     fbBuilder.addInt64(6, i64);
     return fbBuilder.offset;
   }
-  int addU64(int u64) {
+  int addU64(int? u64) {
     fbBuilder.addUint64(7, u64);
     return fbBuilder.offset;
   }
-  int addF32(double f32) {
+  int addF32(double? f32) {
     fbBuilder.addFloat32(8, f32);
     return fbBuilder.offset;
   }
-  int addF64(double f64) {
+  int addF64(double? f64) {
     fbBuilder.addFloat64(9, f64);
     return fbBuilder.offset;
   }
-  int addV8Offset(int offset) {
+  int addV8Offset(int? offset) {
     fbBuilder.addOffset(10, offset);
     return fbBuilder.offset;
   }
-  int addVf64Offset(int offset) {
+  int addVf64Offset(int? offset) {
     fbBuilder.addOffset(11, offset);
     return fbBuilder.offset;
   }
@@ -1458,32 +2078,32 @@
 }
 
 class TypeAliasesObjectBuilder extends fb.ObjectBuilder {
-  final int _i8;
-  final int _u8;
-  final int _i16;
-  final int _u16;
-  final int _i32;
-  final int _u32;
-  final int _i64;
-  final int _u64;
-  final double _f32;
-  final double _f64;
-  final List<int> _v8;
-  final List<double> _vf64;
+  final int? _i8;
+  final int? _u8;
+  final int? _i16;
+  final int? _u16;
+  final int? _i32;
+  final int? _u32;
+  final int? _i64;
+  final int? _u64;
+  final double? _f32;
+  final double? _f64;
+  final List<int>? _v8;
+  final List<double>? _vf64;
 
   TypeAliasesObjectBuilder({
-    int i8,
-    int u8,
-    int i16,
-    int u16,
-    int i32,
-    int u32,
-    int i64,
-    int u64,
-    double f32,
-    double f64,
-    List<int> v8,
-    List<double> vf64,
+    int? i8,
+    int? u8,
+    int? i16,
+    int? u16,
+    int? i32,
+    int? u32,
+    int? i64,
+    int? u64,
+    double? f32,
+    double? f64,
+    List<int>? v8,
+    List<double>? vf64,
   })
       : _i8 = i8,
         _u8 = u8,
@@ -1500,17 +2120,12 @@
 
   /// Finish building, and store into the [fbBuilder].
   @override
-  int finish(
-    fb.Builder fbBuilder) {
-    assert(fbBuilder != null);
-    final int v8Offset = _v8?.isNotEmpty == true
-        ? fbBuilder.writeListInt8(_v8)
-        : null;
-    final int vf64Offset = _vf64?.isNotEmpty == true
-        ? fbBuilder.writeListFloat64(_vf64)
-        : null;
-
-    fbBuilder.startTable();
+  int finish(fb.Builder fbBuilder) {
+    final int? v8Offset = _v8 == null ? null
+        : fbBuilder.writeListInt8(_v8!);
+    final int? vf64Offset = _vf64 == null ? null
+        : fbBuilder.writeListFloat64(_vf64!);
+    fbBuilder.startTable(12);
     fbBuilder.addInt8(0, _i8);
     fbBuilder.addUint8(1, _u8);
     fbBuilder.addInt16(2, _i16);
@@ -1521,20 +2136,16 @@
     fbBuilder.addUint64(7, _u64);
     fbBuilder.addFloat32(8, _f32);
     fbBuilder.addFloat64(9, _f64);
-    if (v8Offset != null) {
-      fbBuilder.addOffset(10, v8Offset);
-    }
-    if (vf64Offset != null) {
-      fbBuilder.addOffset(11, vf64Offset);
-    }
+    fbBuilder.addOffset(10, v8Offset);
+    fbBuilder.addOffset(11, vf64Offset);
     return fbBuilder.endTable();
   }
 
   /// Convenience method to serialize to byte list.
   @override
-  Uint8List toBytes([String fileIdentifier]) {
-    fb.Builder fbBuilder = new fb.Builder();
-    int offset = finish(fbBuilder);
-    return fbBuilder.finish(offset, fileIdentifier);
+  Uint8List toBytes([String? fileIdentifier]) {
+    final fbBuilder = fb.Builder(deduplicateTables: false);
+    fbBuilder.finish(finish(fbBuilder), fileIdentifier);
+    return fbBuilder.buffer;
   }
 }
diff --git a/dart/test/monster_test_my_game_generated.dart b/dart/test/monster_test_my_game_generated.dart
index abd538c..70e256c 100644
--- a/dart/test/monster_test_my_game_generated.dart
+++ b/dart/test/monster_test_my_game_generated.dart
@@ -1,5 +1,5 @@
 // automatically generated by the FlatBuffers compiler, do not modify
-// ignore_for_file: unused_import, unused_field, unused_local_variable
+// ignore_for_file: unused_import, unused_field, unused_element, unused_local_variable
 
 library my_game;
 
@@ -12,11 +12,11 @@
 class InParentNamespace {
   InParentNamespace._(this._bc, this._bcOffset);
   factory InParentNamespace(List<int> bytes) {
-    fb.BufferContext rootRef = new fb.BufferContext.fromBytes(bytes);
+    final rootRef = fb.BufferContext.fromBytes(bytes);
     return reader.read(rootRef, 0);
   }
 
-  static const fb.Reader<InParentNamespace> reader = const _InParentNamespaceReader();
+  static const fb.Reader<InParentNamespace> reader = _InParentNamespaceReader();
 
   final fb.BufferContext _bc;
   final int _bcOffset;
@@ -26,6 +26,26 @@
   String toString() {
     return 'InParentNamespace{}';
   }
+
+  InParentNamespaceT unpack() => InParentNamespaceT();
+
+  static int pack(fb.Builder fbBuilder, InParentNamespaceT? object) {
+    if (object == null) return 0;
+    return object.pack(fbBuilder);
+  }
+}
+
+class InParentNamespaceT implements fb.Packable {
+  @override
+  int pack(fb.Builder fbBuilder) {
+    fbBuilder.startTable(0);
+    return fbBuilder.endTable();
+  }
+
+  @override
+  String toString() {
+    return 'InParentNamespaceT{}';
+  }
 }
 
 class _InParentNamespaceReader extends fb.TableReader<InParentNamespace> {
@@ -33,7 +53,7 @@
 
   @override
   InParentNamespace createObject(fb.BufferContext bc, int offset) => 
-    new InParentNamespace._(bc, offset);
+    InParentNamespace._(bc, offset);
 }
 
 class InParentNamespaceObjectBuilder extends fb.ObjectBuilder {
@@ -42,19 +62,16 @@
 
   /// Finish building, and store into the [fbBuilder].
   @override
-  int finish(
-    fb.Builder fbBuilder) {
-    assert(fbBuilder != null);
-
-    fbBuilder.startTable();
+  int finish(fb.Builder fbBuilder) {
+    fbBuilder.startTable(0);
     return fbBuilder.endTable();
   }
 
   /// Convenience method to serialize to byte list.
   @override
-  Uint8List toBytes([String fileIdentifier]) {
-    fb.Builder fbBuilder = new fb.Builder();
-    int offset = finish(fbBuilder);
-    return fbBuilder.finish(offset, fileIdentifier);
+  Uint8List toBytes([String? fileIdentifier]) {
+    final fbBuilder = fb.Builder(deduplicateTables: false);
+    fbBuilder.finish(finish(fbBuilder), fileIdentifier);
+    return fbBuilder.buffer;
   }
 }
diff --git a/dart/test/monsterdata_test.mon b/dart/test/monsterdata_test.mon
new file mode 100644
index 0000000..cd52947
--- /dev/null
+++ b/dart/test/monsterdata_test.mon
Binary files differ