Merge commit '6dccd64de51ea960cb6f0d975768c874814b4c75' into HEAD

Update flatbuffers. Relevant merge tasks:
* A field got added to reflection.fbs; this had fallout in
  reflection_generated.h and the logger_test shas.
* Resolved merge conflict in rust/flatbuffers/src/lib.rs
* Reverted upstream change that made Table rust struct members private.
* FlatBufferBuilder Create*Vector calls now include alignment.
* nim codegen got added; needed to update to use scoped enums.

Main fix that motivated this update is
https://github.com/google/flatbuffers/pull/7588

Change-Id: I6bbe5d56846f426fa5f2a82c4f2bc77be2b93bb0
Signed-off-by: James Kuszmaul <james.kuszmaul@bluerivertech.com>
diff --git a/third_party/flatbuffers/src/BUILD.bazel b/third_party/flatbuffers/src/BUILD.bazel
index 8110be4..e8c3ffb 100644
--- a/third_party/flatbuffers/src/BUILD.bazel
+++ b/third_party/flatbuffers/src/BUILD.bazel
@@ -39,6 +39,8 @@
         "bfbs_gen.h",
         "bfbs_gen_lua.cpp",
         "bfbs_gen_lua.h",
+        "bfbs_gen_nim.cpp",
+        "bfbs_gen_nim.h",
         "bfbs_namer.h",
         "binary_annotator.cpp",
         "binary_annotator.h",
@@ -62,6 +64,8 @@
         "bfbs_gen.h",
         "bfbs_gen_lua.cpp",
         "bfbs_gen_lua.h",
+        "bfbs_gen_nim.cpp",
+        "bfbs_gen_nim.h",
         "bfbs_namer.h",
         "flatc_main.cpp",
         "idl_gen_cpp.cpp",
diff --git a/third_party/flatbuffers/src/annotated_binary_text_gen.cpp b/third_party/flatbuffers/src/annotated_binary_text_gen.cpp
index ec30b1d..1c7a4dd 100644
--- a/third_party/flatbuffers/src/annotated_binary_text_gen.cpp
+++ b/third_party/flatbuffers/src/annotated_binary_text_gen.cpp
@@ -1,5 +1,6 @@
 #include "annotated_binary_text_gen.h"
 
+#include <algorithm>
 #include <sstream>
 #include <string>
 
diff --git a/third_party/flatbuffers/src/bfbs_gen.h b/third_party/flatbuffers/src/bfbs_gen.h
index 63220e8..8e3c6f3 100644
--- a/third_party/flatbuffers/src/bfbs_gen.h
+++ b/third_party/flatbuffers/src/bfbs_gen.h
@@ -38,8 +38,9 @@
   for (auto it = objects->cbegin(); it != objects->cend(); ++it) { func(*it); }
 }
 
-static void ForAllEnumValues(const reflection::Enum *enum_def,
-                      std::function<void(const reflection::EnumVal *)> func) {
+static void ForAllEnumValues(
+    const reflection::Enum *enum_def,
+    std::function<void(const reflection::EnumVal *)> func) {
   for (auto it = enum_def->values()->cbegin(); it != enum_def->values()->cend();
        ++it) {
     func(*it);
@@ -91,7 +92,7 @@
   return base_type == reflection::BaseType::Vector;
 }
 
-} // namespace
+}  // namespace
 
 // A concrete base Flatbuffer Generator that specific language generators can
 // derive from.
@@ -130,17 +131,29 @@
   }
 
  protected:
-  const reflection::Object *GetObject(const reflection::Type *type) const {
-    if (type->index() >= 0 && IsStructOrTable(type->base_type())) {
+  // GetObject returns the underlying object struct of the given type
+  // if element_type is true and GetObject is a list of objects then
+  // GetObject will correctly return the object struct of the vector's elements
+  const reflection::Object *GetObject(const reflection::Type *type,
+                                      bool element_type = false) const {
+    const reflection::BaseType base_type =
+        element_type ? type->element() : type->base_type();
+    if (type->index() >= 0 && IsStructOrTable(base_type)) {
       return GetObjectByIndex(type->index());
     }
     return nullptr;
   }
 
-  const reflection::Enum *GetEnum(const reflection::Type *type) const {
+  // GetEnum returns the underlying enum struct of the given type
+  // if element_type is true and GetEnum is a list of enums then
+  // GetEnum will correctly return the enum struct of the vector's elements
+  const reflection::Enum *GetEnum(const reflection::Type *type,
+                                  bool element_type = false) const {
+    const reflection::BaseType base_type =
+        element_type ? type->element() : type->base_type();
     // TODO(derekbailey): it would be better to have a explicit list of allowed
     // base types, instead of negating Obj types.
-    if (type->index() >= 0 && !IsStructOrTable(type->base_type())) {
+    if (type->index() >= 0 && !IsStructOrTable(base_type)) {
       return GetEnumByIndex(type->index());
     }
     return nullptr;
diff --git a/third_party/flatbuffers/src/bfbs_gen_lua.cpp b/third_party/flatbuffers/src/bfbs_gen_lua.cpp
index e9623d4..1bfe8b2 100644
--- a/third_party/flatbuffers/src/bfbs_gen_lua.cpp
+++ b/third_party/flatbuffers/src/bfbs_gen_lua.cpp
@@ -175,7 +175,7 @@
         // Skip writing deprecated fields altogether.
         if (field->deprecated()) { return; }
 
-        const std::string field_name = namer_.Field(field->name()->str());
+        const std::string field_name = namer_.Field(*field);
         const r::BaseType base_type = field->type()->base_type();
 
         // Generate some fixed strings so we don't repeat outselves later.
@@ -367,9 +367,8 @@
         ForAllFields(object, /*reverse=*/false, [&](const r::Field *field) {
           if (field->deprecated()) { return; }
 
-          const std::string field_name = namer_.Field(field->name()->str());
-          const std::string variable_name =
-              namer_.Variable(field->name()->str());
+          const std::string field_name = namer_.Field(*field);
+          const std::string variable_name = namer_.Variable(*field);
 
           code += "function " + object_name + ".Add" + field_name +
                   "(builder, " + variable_name + ")\n";
@@ -428,9 +427,9 @@
       if (IsStructOrTable(field->type()->base_type())) {
         const r::Object *field_object = GetObject(field->type());
         signature += GenerateStructBuilderArgs(
-            field_object, prefix + namer_.Variable(field->name()->str()) + "_");
+            field_object, prefix + namer_.Variable(*field) + "_");
       } else {
-        signature += ", " + prefix + namer_.Variable(field->name()->str());
+        signature += ", " + prefix + namer_.Variable(*field);
       }
     });
     return signature;
@@ -451,11 +450,11 @@
       }
       if (IsStructOrTable(field->type()->base_type())) {
         const r::Object *field_object = GetObject(field->type());
-        code += AppendStructBuilderBody(
-            field_object, prefix + namer_.Variable(field->name()->str()) + "_");
+        code += AppendStructBuilderBody(field_object,
+                                        prefix + namer_.Variable(*field) + "_");
       } else {
         code += "  builder:Prepend" + GenerateMethod(field) + "(" + prefix +
-                namer_.Variable(field->name()->str()) + ")\n";
+                namer_.Variable(*field) + ")\n";
       }
     });
 
diff --git a/third_party/flatbuffers/src/bfbs_gen_nim.cpp b/third_party/flatbuffers/src/bfbs_gen_nim.cpp
new file mode 100644
index 0000000..dcd4cde
--- /dev/null
+++ b/third_party/flatbuffers/src/bfbs_gen_nim.cpp
@@ -0,0 +1,651 @@
+/*
+ * Copyright 2021 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "bfbs_gen_nim.h"
+
+#include <cstdint>
+#include <map>
+#include <memory>
+#include <string>
+#include <unordered_set>
+#include <vector>
+
+// Ensure no includes to flatc internals. bfbs_gen.h and generator.h are OK.
+#include "bfbs_gen.h"
+#include "bfbs_namer.h"
+#include "flatbuffers/bfbs_generator.h"
+
+// The intermediate representation schema.
+#include "flatbuffers/reflection.h"
+#include "flatbuffers/reflection_generated.h"
+
+namespace flatbuffers {
+namespace {
+
+// To reduce typing
+namespace r = ::reflection;
+
+std::set<std::string> NimKeywords() {
+  return {
+    "addr",      "and",     "as",        "asm",      "bind",   "block",
+    "break",     "case",    "cast",      "concept",  "const",  "continue",
+    "converter", "defer",   "discard",   "distinct", "div",    "do",
+    "elif",      "else",    "end",       "enum",     "except", "export",
+    "finally",   "for",     "from",      "func",     "if",     "import",
+    "in",        "include", "interface", "is",       "isnot",  "iterator",
+    "let",       "macro",   "method",    "mixin",    "mod",    "nil",
+    "not",       "notin",   "object",    "of",       "or",     "out",
+    "proc",      "ptr",     "raise",     "ref",      "return", "shl",
+    "shr",       "static",  "template",  "try",      "tuple",  "type",
+    "using",     "var",     "when",      "while",    "xor",    "yield",
+  };
+}
+
+Namer::Config NimDefaultConfig() {
+  return { /*types=*/Case::kUpperCamel,
+           /*constants=*/Case::kUpperCamel,
+           /*methods=*/Case::kLowerCamel,
+           /*functions=*/Case::kUpperCamel,
+           /*fields=*/Case::kLowerCamel,
+           /*variable=*/Case::kLowerCamel,
+           /*variants=*/Case::kUpperCamel,
+           /*enum_variant_seperator=*/".",
+           /*escape_keywords=*/Namer::Config::Escape::AfterConvertingCase,
+           /*namespaces=*/Case::kKeep,
+           /*namespace_seperator=*/"/",
+           /*object_prefix=*/"",
+           /*object_suffix=*/"T",
+           /*keyword_prefix=*/"",
+           /*keyword_suffix=*/"_",
+           /*filenames=*/Case::kKeep,
+           /*directories=*/Case::kKeep,
+           /*output_path=*/"",
+           /*filename_suffix=*/"",
+           /*filename_extension=*/".nim" };
+}
+
+const std::string Indent = "  ";
+const std::string Export = "*";
+const std::set<std::string> builtin_types = {
+  "uint8",   "uint8",  "bool",   "int8",  "uint8",   "int16",
+  "uint16",  "int32",  "uint32", "int64", "uint64",  "float32",
+  "float64", "string", "int",    "uint",  "uoffset", "Builder"
+};
+
+class NimBfbsGenerator : public BaseBfbsGenerator {
+ public:
+  explicit NimBfbsGenerator(const std::string &flatc_version)
+      : BaseBfbsGenerator(),
+        keywords_(),
+        imports_(),
+        current_obj_(nullptr),
+        current_enum_(nullptr),
+        flatc_version_(flatc_version),
+        namer_(NimDefaultConfig(), NimKeywords()) {}
+
+  GeneratorStatus GenerateFromSchema(const r::Schema *schema)
+      FLATBUFFERS_OVERRIDE {
+    ForAllEnums(schema->enums(), [&](const r::Enum *enum_def) {
+      StartCodeBlock(enum_def);
+      GenerateEnum(enum_def);
+    });
+    ForAllObjects(schema->objects(), [&](const r::Object *object) {
+      StartCodeBlock(object);
+      GenerateObject(object);
+    });
+    return OK;
+  }
+
+  uint64_t SupportedAdvancedFeatures() const FLATBUFFERS_OVERRIDE {
+    return static_cast<uint64_t>(r::AdvancedFeatures::AdvancedArrayFeatures) |
+           static_cast<uint64_t>(r::AdvancedFeatures::AdvancedUnionFeatures) |
+           static_cast<uint64_t>(r::AdvancedFeatures::OptionalScalars) |
+           static_cast<uint64_t>(r::AdvancedFeatures::DefaultVectorsAndStrings);
+  }
+
+ protected:
+  void GenerateEnum(const r::Enum *enum_def) {
+    std::string code;
+
+    std::string ns;
+    const std::string enum_name = namer_.Type(namer_.Denamespace(enum_def, ns));
+    const std::string enum_type =
+        GenerateTypeBasic(enum_def->underlying_type());
+
+    GenerateDocumentation(enum_def->documentation(), "", code);
+    code += "type " + enum_name + Export + "{.pure.} = enum\n";
+
+    ForAllEnumValues(enum_def, [&](const reflection::EnumVal *enum_val) {
+      GenerateDocumentation(enum_val->documentation(), "  ", code);
+      code += "  " + namer_.Variant(enum_val->name()->str()) + " = " +
+              NumToString(enum_val->value()) + "." + enum_type + ",\n";
+    });
+
+    EmitCodeBlock(code, enum_name, ns, enum_def->declaration_file()->str());
+  }
+
+  void GenerateObject(const r::Object *object) {
+    // Register the main flatbuffers module.
+    RegisterImports("flatbuffers", "");
+    std::string code;
+
+    std::string ns;
+    const std::string object_name = namer_.Type(namer_.Denamespace(object, ns));
+
+    GenerateDocumentation(object->documentation(), "", code);
+    code += "type " + object_name + "* = object of FlatObj\n";
+
+    // Create all the field accessors.
+    ForAllFields(object, /*reverse=*/false, [&](const r::Field *field) {
+      // Skip writing deprecated fields altogether.
+      if (field->deprecated()) { return; }
+
+      const std::string field_name = namer_.Field(*field);
+      const r::BaseType base_type = field->type()->base_type();
+      std::string field_type = GenerateType(field->type());
+
+      if (field->optional() && !object->is_struct()) {
+        RegisterImports("std/options", "");
+        field_type = "Option[" + field_type + "]";
+      }
+
+      const std::string offset_prefix =
+          "let o = self.tab.Offset(" + NumToString(field->offset()) + ")\n";
+      const std::string offset_prefix_2 = "if o != 0:\n";
+
+      if (IsScalar(base_type) || base_type == r::BaseType::String ||
+          base_type == r::BaseType::Obj || base_type == r::BaseType::Union) {
+        GenerateDocumentation(field->documentation(), "", code);
+
+        std::string getter_signature = "func " + namer_.Method(field_name) +
+                                       "*(self: " + object_name +
+                                       "): " + field_type + " =\n";
+        std::string getter_code;
+        std::string setter_signature =
+            "func `" + namer_.Method(field_name + "=") + "`*(self: var " +
+            object_name + ", n: " + field_type + "): bool =\n";
+        std::string setter_code;
+
+        if (base_type == r::BaseType::Obj || base_type == r::BaseType::Union ||
+            field->type()->index() >= 0) {
+          RegisterImports(object, field);
+        }
+
+        if (object->is_struct()) {
+          std::string field_getter =
+              GenerateGetter(field->type(), NumToString(field->offset()));
+          getter_code += "  return " + field_getter + "\n";
+
+          if (IsScalar(base_type)) {
+            setter_code += "  return self.tab.Mutate(self.tab.Pos + " +
+                           NumToString(field->offset()) + ", n)\n";
+          }
+        } else {
+          // Table accessors
+          getter_code += "  " + offset_prefix;
+          getter_code += "  " + offset_prefix_2;
+          std::string field_getter = GenerateGetter(field->type(), "o");
+          if (field->optional()) {
+            field_getter = "some(" + field_getter + ")";
+          }
+          getter_code += "    return " + field_getter + "\n";
+          if (!field->optional()) {
+            getter_code += "  return " + DefaultValue(field) + "\n";
+          }
+
+          if (IsScalar(base_type)) {
+            setter_code += "  return self.tab.MutateSlot(" +
+                           NumToString(field->offset()) + ", n)\n";
+          }
+        }
+        code += getter_signature + getter_code;
+        if (IsScalar(base_type)) { code += setter_signature + setter_code; }
+      } else if (base_type == r::BaseType::Array ||
+                 base_type == r::BaseType::Vector) {
+        const r::BaseType vector_base_type = field->type()->element();
+        uint32_t element_size = field->type()->element_size();
+
+        if (vector_base_type == r::BaseType::Obj ||
+            vector_base_type == r::BaseType::Union ||
+            field->type()->index() >= 0) {
+          RegisterImports(object, field, true);
+        }
+
+        // Get vector length:
+        code += "func " + namer_.Method(field_name + "Length") +
+                "*(self: " + object_name + "): int = \n";
+        code += "  " + offset_prefix;
+        code += "  " + offset_prefix_2;
+        code += "    return self.tab.VectorLen(o)\n";
+
+        // Get single vector field:
+        code += "func " + namer_.Method(field_name) + "*(self: " + object_name +
+                ", j: int): " + GenerateType(field->type(), true) + " = \n";
+        code += "  " + offset_prefix;
+        code += "  " + offset_prefix_2;
+        code += "    var x = self.tab.Vector(o)\n";
+        code +=
+            "    x += j.uoffset * " + NumToString(element_size) + ".uoffset\n";
+        code += "    return " + GenerateGetter(field->type(), "x", true) + "\n";
+
+        // Get entire vector:
+        code += "func " + namer_.Method(field_name) + "*(self: " + object_name +
+                "): " + GenerateType(field->type()) + " = \n";
+        code += "  let len = self." + field_name + "Length\n";
+        code += "  for i in countup(0, len - 1):\n";
+        code += "    result.add(self." + field_name + "(i))\n";
+
+        (void)IsSingleByte(vector_base_type);  // unnused function warning
+      }
+    });
+
+    // Create all the builders
+    if (object->is_struct()) {
+      code += "proc " + namer_.Function(object_name + "Create") +
+              "*(self: var Builder";
+      code += GenerateStructBuilderArgs(object);
+      code += "): uoffset =\n";
+      code += AppendStructBuilderBody(object);
+      code += "  return self.Offset()\n";
+    } else {
+      // Table builders
+      code += "proc " + namer_.Function(object_name + "Start") +
+              "*(builder: var Builder) =\n";
+      code += "  builder.StartObject(" + NumToString(object->fields()->size()) +
+              ")\n";
+
+      ForAllFields(object, /*reverse=*/false, [&](const r::Field *field) {
+        if (field->deprecated()) { return; }
+
+        const std::string field_name = namer_.Field(*field);
+        const std::string variable_name = namer_.Variable(*field);
+        const std::string variable_type = GenerateTypeBasic(field->type());
+
+        code += "proc " + namer_.Function(object_name + "Add" + field_name) +
+                "*(builder: var Builder, " + variable_name + ": " +
+                variable_type + ") =\n";
+        code += "  builder.Prepend" + GenerateMethod(field) + "Slot(" +
+                NumToString(field->id()) + ", " + variable_name + ", default(" +
+                variable_type + "))\n";
+
+        if (IsVector(field->type()->base_type())) {
+          code += "proc " +
+                  namer_.Function(object_name + "Start" + field_name) +
+                  "Vector*(builder: var Builder, numElems: uoffset) =\n";
+
+          const int32_t element_size = field->type()->element_size();
+          int32_t alignment = element_size;
+          if (IsStruct(field->type(), /*use_element=*/true)) {
+            alignment = GetObjectByIndex(field->type()->index())->minalign();
+          }
+
+          code += "  builder.StartVector(" + NumToString(element_size) +
+                  ", numElems, " + NumToString(alignment) + ")\n";
+        }
+      });
+
+      code += "proc " + namer_.Function(object_name + "End") +
+              "*(builder: var Builder): uoffset =\n";
+      code += "  return builder.EndObject()\n";
+    }
+    EmitCodeBlock(code, object_name, ns, object->declaration_file()->str());
+  }
+
+ private:
+  void GenerateDocumentation(
+      const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>
+          *documentation,
+      std::string indent, std::string &code) const {
+    flatbuffers::ForAllDocumentation(
+        documentation, [&](const flatbuffers::String *str) {
+          code += indent + "# " + str->str() + "\n";
+        });
+  }
+
+  std::string GenerateStructBuilderArgs(const r::Object *object,
+                                        std::string prefix = "") const {
+    std::string signature;
+    ForAllFields(object, /*reverse=*/false, [&](const r::Field *field) {
+      if (IsStructOrTable(field->type()->base_type())) {
+        const r::Object *field_object = GetObject(field->type());
+        signature += GenerateStructBuilderArgs(
+            field_object, prefix + namer_.Variable(*field) + "_");
+      } else {
+        signature += ", " + prefix + namer_.Variable(*field) + ": " +
+                     GenerateType(field->type());
+      }
+    });
+    return signature;
+  }
+
+  std::string AppendStructBuilderBody(const r::Object *object,
+                                      std::string prefix = "") const {
+    std::string code;
+    code += "  self.Prep(" + NumToString(object->minalign()) + ", " +
+            NumToString(object->bytesize()) + ")\n";
+
+    // We need to reverse the order we iterate over, since we build the
+    // buffer backwards.
+    ForAllFields(object, /*reverse=*/true, [&](const r::Field *field) {
+      const int32_t num_padding_bytes = field->padding();
+      if (num_padding_bytes) {
+        code += "  self.Pad(" + NumToString(num_padding_bytes) + ")\n";
+      }
+      if (IsStructOrTable(field->type()->base_type())) {
+        const r::Object *field_object = GetObject(field->type());
+        code += AppendStructBuilderBody(field_object,
+                                        prefix + namer_.Variable(*field) + "_");
+      } else {
+        code += "  self.Prepend(" + prefix + namer_.Variable(*field) + ")\n";
+      }
+    });
+
+    return code;
+  }
+
+  std::string GenerateMethod(const r::Field *field) const {
+    const r::BaseType base_type = field->type()->base_type();
+    if (IsStructOrTable(base_type)) { return "Struct"; }
+    return "";
+  }
+
+  std::string GenerateGetter(const r::Type *type, const std::string &offsetval,
+                             bool element_type = false) const {
+    const r::BaseType base_type =
+        element_type ? type->element() : type->base_type();
+    std::string offset = offsetval;
+    if (!element_type) { offset = "self.tab.Pos + " + offset; }
+    switch (base_type) {
+      case r::BaseType::String: return "self.tab.String(" + offset + ")";
+      case r::BaseType::Union: return "self.tab.Union(" + offsetval + ")";
+      case r::BaseType::Obj: {
+        return GenerateType(type, element_type) +
+               "(tab: Vtable(Bytes: self.tab.Bytes, Pos: " + offset + "))";
+      }
+      case r::BaseType::Vector: return GenerateGetter(type, offsetval, true);
+      default:
+        const r::Enum *type_enum = GetEnum(type, element_type);
+        if (type_enum != nullptr) {
+          return GenerateType(type, element_type) + "(" + "Get[" +
+                 GenerateType(base_type) + "](self.tab, " + offset + ")" + ")";
+        } else {
+          return "Get[" + GenerateType(base_type) + "](self.tab, " + offset +
+                 ")";
+        }
+    }
+  }
+
+  std::string Denamespace(const std::string &s, std::string &importns,
+                          std::string &ns) const {
+    if (builtin_types.find(s) != builtin_types.end()) { return s; }
+    std::string type = namer_.Type(namer_.Denamespace(s, ns));
+    importns = ns.empty() ? type : ns + "." + type;
+    std::replace(importns.begin(), importns.end(), '.', '_');
+    return type;
+  }
+
+  std::string Denamespace(const std::string &s, std::string &importns) const {
+    std::string ns;
+    return Denamespace(s, importns, ns);
+  }
+
+  std::string Denamespace(const std::string &s) const {
+    std::string importns;
+    return Denamespace(s, importns);
+  }
+
+  std::string GenerateType(const r::Type *type, bool element_type = false,
+                           bool enum_inner = false) const {
+    const r::BaseType base_type =
+        element_type ? type->element() : type->base_type();
+    if (IsScalar(base_type) && !enum_inner) {
+      const r::Enum *type_enum = GetEnum(type, element_type);
+      if (type_enum != nullptr) {
+        std::string importns;
+        std::string type_name = Denamespace(type_enum->name()->str(), importns);
+        return importns + "." + type_name;
+      }
+    }
+    if (IsScalar(base_type)) { return Denamespace(GenerateType(base_type)); }
+    switch (base_type) {
+      case r::BaseType::String: return "string";
+      case r::BaseType::Vector: {
+        return "seq[" + GenerateType(type, true) + "]";
+      }
+      case r::BaseType::Union: return "Vtable";
+      case r::BaseType::Obj: {
+        const r::Object *type_obj = GetObject(type, element_type);
+        std::string importns;
+        std::string type_name = Denamespace(type_obj->name()->str(), importns);
+        if (type_obj == current_obj_) {
+          return type_name;
+        } else {
+          return importns + "." + type_name;
+        }
+      }
+      default: return "uoffset";
+    }
+  }
+
+  std::string GenerateTypeBasic(const r::Type *type,
+                                bool element_type = false) const {
+    const r::BaseType base_type =
+        element_type ? type->element() : type->base_type();
+    if (IsScalar(base_type)) {
+      return GenerateType(base_type);
+    } else {
+      return "uoffset";
+    }
+  }
+
+  std::string GenerateType(const r::BaseType base_type) const {
+    switch (base_type) {
+      case r::BaseType::None: return "uint8";
+      case r::BaseType::UType: return "uint8";
+      case r::BaseType::Bool: return "bool";
+      case r::BaseType::Byte: return "int8";
+      case r::BaseType::UByte: return "uint8";
+      case r::BaseType::Short: return "int16";
+      case r::BaseType::UShort: return "uint16";
+      case r::BaseType::Int: return "int32";
+      case r::BaseType::UInt: return "uint32";
+      case r::BaseType::Long: return "int64";
+      case r::BaseType::ULong: return "uint64";
+      case r::BaseType::Float: return "float32";
+      case r::BaseType::Double: return "float64";
+      case r::BaseType::String: return "string";
+      default: return r::EnumNameBaseType(base_type);
+    }
+  }
+
+  std::string DefaultValue(const r::Field *field) const {
+    const r::BaseType base_type = field->type()->base_type();
+    if (IsFloatingPoint(base_type)) {
+      if (field->default_real() != field->default_real()) {
+        return "NaN";
+      } else if (field->default_real() == std::numeric_limits<double>::infinity()) {
+        return "Inf";
+      } else if (field->default_real() == -std::numeric_limits<double>::infinity()) {
+        return "-Inf";
+      }
+      return NumToString(field->default_real());
+    }
+    if (IsBool(base_type)) {
+      return field->default_integer() ? "true" : "false";
+    }
+    if (IsScalar(base_type)) {
+      const r::Enum *type_enum = GetEnum(field->type());
+      if (type_enum != nullptr) {
+        return "type(result)(" + NumToString((field->default_integer())) + ")";
+      }
+      return NumToString((field->default_integer()));
+    }
+    if (base_type == r::BaseType::String) { return "\"\""; }
+    // represents offsets
+    return "0";
+  }
+
+  void StartCodeBlock(const reflection::Enum *enum_def) {
+    current_enum_ = enum_def;
+    current_obj_ = nullptr;
+    imports_.clear();
+  }
+
+  void StartCodeBlock(const reflection::Object *object) {
+    current_enum_ = nullptr;
+    current_obj_ = object;
+    imports_.clear();
+  }
+
+  std::vector<std::string> StringSplit(const std::string orig_str,
+                                       const std::string token) {
+    std::vector<std::string> result;
+    std::string str = orig_str;
+    while (str.size()) {
+      size_t index = str.find(token);
+      if (index != std::string::npos) {
+        result.push_back(str.substr(0, index));
+        str = str.substr(index + token.size());
+        if (str.size() == 0) result.push_back(str);
+      } else {
+        result.push_back(str);
+        str = "";
+      }
+    }
+    return result;
+  }
+
+  std::string GetRelativePathFromNamespace(const std::string &relative_to,
+                                           const std::string &str2) {
+    std::vector<std::string> relative_to_vec = StringSplit(relative_to, ".");
+    std::vector<std::string> str2_vec = StringSplit(str2, ".");
+    while (relative_to_vec.size() > 0 && str2_vec.size() > 0) {
+      if (relative_to_vec[0] == str2_vec[0]) {
+        relative_to_vec.erase(relative_to_vec.begin());
+        str2_vec.erase(str2_vec.begin());
+      } else {
+        break;
+      }
+    }
+    relative_to_vec.pop_back();
+    for (size_t i = 0; i < relative_to_vec.size(); ++i) {
+      str2_vec.insert(str2_vec.begin(), std::string(".."));
+    }
+
+    std::string new_path;
+    for (size_t i = 0; i < str2_vec.size(); ++i) {
+      new_path += str2_vec[i];
+      if (i != str2_vec.size() - 1) { new_path += "/"; }
+    }
+    return new_path;
+  }
+
+  void RegisterImports(const r::Object *object, const r::Field *field,
+                       bool use_element = false) {
+    std::string importns;
+    std::string type_name;
+
+    const r::BaseType type =
+        use_element ? field->type()->element() : field->type()->base_type();
+
+    if (IsStructOrTable(type)) {
+      const r::Object *object_def = GetObjectByIndex(field->type()->index());
+      if (object_def == current_obj_) { return; }
+      std::string ns;
+      type_name = Denamespace(object_def->name()->str(), importns, ns);
+      type_name = ns.empty() ? type_name : ns + "." + type_name;
+    } else {
+      const r::Enum *enum_def = GetEnumByIndex(field->type()->index());
+      if (enum_def == current_enum_) { return; }
+      std::string ns;
+      type_name = Denamespace(enum_def->name()->str(), importns, ns);
+      type_name = ns.empty() ? type_name : ns + "." + type_name;
+    }
+
+    std::string import_path =
+        GetRelativePathFromNamespace(object->name()->str(), type_name);
+    std::replace(type_name.begin(), type_name.end(), '.', '_');
+    RegisterImports(import_path, importns);
+  }
+
+  void RegisterImports(const std::string &local_name,
+                       const std::string &imports_name) {
+    imports_[local_name] = imports_name;
+  }
+
+  void EmitCodeBlock(const std::string &code_block, const std::string &name,
+                     const std::string &ns, const std::string &declaring_file) {
+    const std::string full_qualified_name = ns.empty() ? name : ns + "." + name;
+
+    std::string code = "#[ " + full_qualified_name + "\n";
+    code +=
+        "  Automatically generated by the FlatBuffers compiler, do not "
+        "modify.\n";
+    code += "  Or modify. I'm a message, not a cop.\n";
+    code += "\n";
+    code += "  flatc version: " + flatc_version_ + "\n";
+    code += "\n";
+    code += "  Declared by  : " + declaring_file + "\n";
+    if (schema_->root_table() != nullptr) {
+      const std::string root_type = schema_->root_table()->name()->str();
+      const std::string root_file =
+          schema_->root_table()->declaration_file()->str();
+      code += "  Rooting type : " + root_type + " (" + root_file + ")\n";
+    }
+    code += "]#\n\n";
+
+    if (!imports_.empty()) {
+      for (auto it = imports_.cbegin(); it != imports_.cend(); ++it) {
+        if (it->second.empty()) {
+          code += "import " + it->first + "\n";
+        } else {
+          code += "import " + it->first + " as " + it->second + "\n";
+        }
+      }
+      code += "\n";
+    }
+    code += code_block;
+
+    // Namespaces are '.' deliminted, so replace it with the path separator.
+    std::string path = ns;
+
+    if (ns.empty()) {
+      path = ".";
+    } else {
+      std::replace(path.begin(), path.end(), '.', '/');
+    }
+
+    // TODO(derekbailey): figure out a save file without depending on util.h
+    EnsureDirExists(path);
+    const std::string file_name = path + "/" + namer_.File(name);
+    SaveFile(file_name.c_str(), code, false);
+  }
+
+  std::unordered_set<std::string> keywords_;
+  std::map<std::string, std::string> imports_;
+  const r::Object *current_obj_;
+  const r::Enum *current_enum_;
+  const std::string flatc_version_;
+  const BfbsNamer namer_;
+};
+}  // namespace
+
+std::unique_ptr<BfbsGenerator> NewNimBfbsGenerator(
+    const std::string &flatc_version) {
+  return std::unique_ptr<NimBfbsGenerator>(new NimBfbsGenerator(flatc_version));
+}
+
+}  // namespace flatbuffers
diff --git a/third_party/flatbuffers/src/bfbs_gen_nim.h b/third_party/flatbuffers/src/bfbs_gen_nim.h
new file mode 100644
index 0000000..80be16d
--- /dev/null
+++ b/third_party/flatbuffers/src/bfbs_gen_nim.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2021 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef FLATBUFFERS_BFBS_GEN_NIM_H_
+#define FLATBUFFERS_BFBS_GEN_NIM_H_
+
+#include <memory>
+#include <string>
+
+#include "flatbuffers/bfbs_generator.h"
+
+namespace flatbuffers {
+
+// Constructs a new Nim Code generator.
+std::unique_ptr<BfbsGenerator> NewNimBfbsGenerator(
+    const std::string &flatc_version);
+
+}  // namespace flatbuffers
+
+#endif  // FLATBUFFERS_BFBS_GEN_NIM_H_
diff --git a/third_party/flatbuffers/src/bfbs_namer.h b/third_party/flatbuffers/src/bfbs_namer.h
index 2c6e724..ef6c6c5 100644
--- a/third_party/flatbuffers/src/bfbs_namer.h
+++ b/third_party/flatbuffers/src/bfbs_namer.h
@@ -36,6 +36,14 @@
   std::string Denamespace(T t, const char delimiter = '.') const {
     return Namer::Denamespace(t->name()->c_str(), delimiter);
   }
+
+  virtual std::string Field(const ::reflection::Field &f) const {
+    return Field(f.name()->str());
+  }
+
+  virtual std::string Variable(const ::reflection::Field &f) const {
+    return Variable(f.name()->str());
+  }
 };
 
 }  // namespace flatbuffers
diff --git a/third_party/flatbuffers/src/binary_annotator.cpp b/third_party/flatbuffers/src/binary_annotator.cpp
index 2a94abc..92d4391 100644
--- a/third_party/flatbuffers/src/binary_annotator.cpp
+++ b/third_party/flatbuffers/src/binary_annotator.cpp
@@ -1,5 +1,6 @@
 #include "binary_annotator.h"
 
+#include <algorithm>
 #include <limits>
 #include <string>
 #include <vector>
@@ -1451,4 +1452,4 @@
                                              it->second.regions.back().length;
 }
 
-}  // namespace flatbuffers
\ No newline at end of file
+}  // namespace flatbuffers
diff --git a/third_party/flatbuffers/src/flatc.cpp b/third_party/flatbuffers/src/flatc.cpp
index 1d12a17..40a538f 100644
--- a/third_party/flatbuffers/src/flatc.cpp
+++ b/third_party/flatbuffers/src/flatc.cpp
@@ -16,6 +16,8 @@
 
 #include "flatbuffers/flatc.h"
 
+#include <algorithm>
+#include <limits>
 #include <list>
 #include <sstream>
 
@@ -88,7 +90,7 @@
     "--no-prefix." },
   { "", "swift-implementation-only", "",
     "Adds a @_implementationOnly to swift imports" },
-  { "", "gen-inclues", "",
+  { "", "gen-includes", "",
     "(deprecated), this is the default behavior. If the original behavior is "
     "required (no include statements) use --no-includes." },
   { "", "no-includes", "",
@@ -215,14 +217,14 @@
     "Allows (de)serialization of JSON text in the Object API. (requires "
     "--gen-object-api)." },
   { "", "json-nested-bytes", "",
-    "Allow a nested_flatbuffer field to be parsed as a vector of bytes"
+    "Allow a nested_flatbuffer field to be parsed as a vector of bytes "
     "in JSON, which is unsafe unless checked by a verifier afterwards." },
   { "", "ts-flat-files", "",
     "Only generated one typescript file per .fbs file." },
   { "", "annotate", "SCHEMA",
     "Annotate the provided BINARY_FILE with the specified SCHEMA file." },
   { "", "no-leak-private-annotation", "",
-    "Prevents multiple type of annotations within a Fbs SCHEMA file."
+    "Prevents multiple type of annotations within a Fbs SCHEMA file. "
     "Currently this is required to generate private types in Rust" },
 };
 
diff --git a/third_party/flatbuffers/src/flatc_main.cpp b/third_party/flatbuffers/src/flatc_main.cpp
index b4c4251..f2aa781 100644
--- a/third_party/flatbuffers/src/flatc_main.cpp
+++ b/third_party/flatbuffers/src/flatc_main.cpp
@@ -18,6 +18,7 @@
 #include <memory>
 
 #include "bfbs_gen_lua.h"
+#include "bfbs_gen_nim.h"
 #include "flatbuffers/base.h"
 #include "flatbuffers/flatc.h"
 #include "flatbuffers/util.h"
@@ -56,6 +57,8 @@
 
   std::unique_ptr<flatbuffers::BfbsGenerator> bfbs_gen_lua =
       flatbuffers::NewLuaBfbsGenerator(flatbuffers_version);
+  std::unique_ptr<flatbuffers::BfbsGenerator> bfbs_gen_nim =
+      flatbuffers::NewNimBfbsGenerator(flatbuffers_version);
 
   g_program_name = argv[0];
 
@@ -142,6 +145,10 @@
       flatbuffers::FlatCOption{ "", "swift", "",
                                 "Generate Swift files for tables/structs" },
       nullptr, nullptr, nullptr },
+    { nullptr, "Nim", true, nullptr, flatbuffers::IDLOptions::kNim,
+      flatbuffers::FlatCOption{ "", "nim", "",
+                                "Generate Nim files for tables/structs" },
+      nullptr, bfbs_gen_nim.get(), nullptr },
   };
 
   flatbuffers::FlatCompiler::InitParams params;
diff --git a/third_party/flatbuffers/src/idl_gen_cpp.cpp b/third_party/flatbuffers/src/idl_gen_cpp.cpp
index c1a0198..aeb16fd 100644
--- a/third_party/flatbuffers/src/idl_gen_cpp.cpp
+++ b/third_party/flatbuffers/src/idl_gen_cpp.cpp
@@ -16,6 +16,7 @@
 
 // independent from idl_parser, since this code is not needed for most clients
 
+#include <limits>
 #include <string>
 #include <unordered_set>
 
diff --git a/third_party/flatbuffers/src/idl_gen_csharp.cpp b/third_party/flatbuffers/src/idl_gen_csharp.cpp
index fa67eaf..ab36bd9 100644
--- a/third_party/flatbuffers/src/idl_gen_csharp.cpp
+++ b/third_party/flatbuffers/src/idl_gen_csharp.cpp
@@ -655,7 +655,7 @@
       // Force compile time error if not using the same version runtime.
       code += "  public static void ValidateVersion() {";
       code += " FlatBufferConstants.";
-      code += "FLATBUFFERS_2_0_8(); ";
+      code += "FLATBUFFERS_22_10_26(); ";
       code += "}\n";
 
       // Generate a special accessor for the table that when used as the root
diff --git a/third_party/flatbuffers/src/idl_gen_dart.cpp b/third_party/flatbuffers/src/idl_gen_dart.cpp
index 0bf230d..ada5956 100644
--- a/third_party/flatbuffers/src/idl_gen_dart.cpp
+++ b/third_party/flatbuffers/src/idl_gen_dart.cpp
@@ -16,6 +16,7 @@
 
 // independent from idl_parser, since this code is not needed for most clients
 #include <cassert>
+#include <cmath>
 
 #include "flatbuffers/code_generators.h"
 #include "flatbuffers/flatbuffers.h"
@@ -721,16 +722,17 @@
     if (!value.constant.empty() && value.constant != "0") {
       if (IsBool(value.type.base_type)) {
         return "true";
-      } else if (value.constant == "nan" || value.constant == "+nan" ||
-                 value.constant == "-nan") {
-        return "double.nan";
-      } else if (value.constant == "inf" || value.constant == "+inf") {
-        return "double.infinity";
-      } else if (value.constant == "-inf") {
-        return "double.negativeInfinity";
-      } else {
-        return value.constant;
       }
+      if (IsScalar(value.type.base_type)) {
+        if (StringIsFlatbufferNan(value.constant)) {
+          return "double.nan";
+        } else if (StringIsFlatbufferPositiveInfinity(value.constant)) {
+          return "double.infinity";
+        } else if (StringIsFlatbufferNegativeInfinity(value.constant)) {
+          return "double.negativeInfinity";
+        }
+      }
+      return value.constant;
     } else if (IsBool(value.type.base_type)) {
       return "false";
     } else if (IsScalar(value.type.base_type) && !IsUnion(value.type)) {
diff --git a/third_party/flatbuffers/src/idl_gen_fbs.cpp b/third_party/flatbuffers/src/idl_gen_fbs.cpp
index 782557f..9c58dc4 100644
--- a/third_party/flatbuffers/src/idl_gen_fbs.cpp
+++ b/third_party/flatbuffers/src/idl_gen_fbs.cpp
@@ -137,6 +137,7 @@
         schema += "  " + field.name + ":" + GenType(field.value.type);
         if (field.value.constant != "0") schema += " = " + field.value.constant;
         if (field.IsRequired()) schema += " (required)";
+        if (field.key) schema += " (key)";
         schema += ";\n";
       }
     }
diff --git a/third_party/flatbuffers/src/idl_gen_go.cpp b/third_party/flatbuffers/src/idl_gen_go.cpp
index 51e018a..33917ff 100644
--- a/third_party/flatbuffers/src/idl_gen_go.cpp
+++ b/third_party/flatbuffers/src/idl_gen_go.cpp
@@ -16,6 +16,8 @@
 
 // independent from idl_parser, since this code is not needed for most clients
 
+#include <algorithm>
+#include <cmath>
 #include <sstream>
 #include <string>
 
@@ -101,6 +103,7 @@
     for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
          ++it) {
       tracked_imported_namespaces_.clear();
+      needs_math_import_ = false;
       needs_imports = false;
       std::string enumcode;
       GenEnum(**it, &enumcode);
@@ -120,6 +123,7 @@
     for (auto it = parser_.structs_.vec.begin();
          it != parser_.structs_.vec.end(); ++it) {
       tracked_imported_namespaces_.clear();
+      needs_math_import_ = false;
       std::string declcode;
       GenStruct(**it, &declcode);
       if (parser_.opts.one_file) {
@@ -153,6 +157,7 @@
     }
   };
   std::set<const Namespace *, NamespacePtrLess> tracked_imported_namespaces_;
+  bool needs_math_import_ = false;
 
   // Most field accessors need to retrieve and test the field offset first,
   // this is the prefix code for that.
@@ -1276,6 +1281,23 @@
     switch (field.value.type.base_type) {
       case BASE_TYPE_BOOL:
         return field.value.constant == "0" ? "false" : "true";
+      case BASE_TYPE_FLOAT:
+      case BASE_TYPE_DOUBLE: {
+        const std::string float_type =
+            field.value.type.base_type == BASE_TYPE_FLOAT ? "float32"
+                                                          : "float64";
+        if (StringIsFlatbufferNan(field.value.constant)) {
+          needs_math_import_ = true;
+          return float_type + "(math.NaN())";
+        } else if (StringIsFlatbufferPositiveInfinity(field.value.constant)) {
+          needs_math_import_ = true;
+          return float_type + "(math.Inf(1))";
+        } else if (StringIsFlatbufferNegativeInfinity(field.value.constant)) {
+          needs_math_import_ = true;
+          return float_type + "(math.Inf(-1))";
+        }
+        return field.value.constant;
+      }
       default: return field.value.constant;
     }
   }
@@ -1329,6 +1351,8 @@
     if (needs_imports) {
       code += "import (\n";
       if (is_enum) { code += "\t\"strconv\"\n\n"; }
+      // math is needed to support non-finite scalar default values.
+      if (needs_math_import_) { code += "\t\"math\"\n\n"; }
       if (!parser_.opts.go_import.empty()) {
         code += "\tflatbuffers \"" + parser_.opts.go_import + "\"\n";
       } else {
@@ -1345,6 +1369,10 @@
       code += ")\n\n";
     } else {
       if (is_enum) { code += "import \"strconv\"\n\n"; }
+      if (needs_math_import_) {
+        // math is needed to support non-finite scalar default values.
+        code += "import \"math\"\n\n";
+      }
     }
   }
 
diff --git a/third_party/flatbuffers/src/idl_gen_java.cpp b/third_party/flatbuffers/src/idl_gen_java.cpp
index 6ee97aa..a35950f 100644
--- a/third_party/flatbuffers/src/idl_gen_java.cpp
+++ b/third_party/flatbuffers/src/idl_gen_java.cpp
@@ -397,6 +397,10 @@
       code += " ";
       code += namer_.Variant(ev) + " = ";
       code += enum_def.ToString(ev);
+      if (enum_def.underlying_type.base_type == BASE_TYPE_LONG ||
+          enum_def.underlying_type.base_type == BASE_TYPE_ULONG) {
+        code += "L";
+      }
       code += ";\n";
     }
 
@@ -665,7 +669,7 @@
       // Force compile time error if not using the same version runtime.
       code += "  public static void ValidateVersion() {";
       code += " Constants.";
-      code += "FLATBUFFERS_2_0_8(); ";
+      code += "FLATBUFFERS_22_10_26(); ";
       code += "}\n";
 
       // Generate a special accessor for the table that when used as the root
@@ -1889,6 +1893,7 @@
           }
         } else {
           code += " " + name + " = ";
+          code += SourceCast(field_type);
           code += "_o";
           for (size_t i = 0; i < array_lengths.size(); ++i) {
             code += "." + namer_.Method("get", array_lengths[i].name) + "()";
diff --git a/third_party/flatbuffers/src/idl_gen_json_schema.cpp b/third_party/flatbuffers/src/idl_gen_json_schema.cpp
index 5cb6a9d..796d1e2 100644
--- a/third_party/flatbuffers/src/idl_gen_json_schema.cpp
+++ b/third_party/flatbuffers/src/idl_gen_json_schema.cpp
@@ -14,7 +14,9 @@
  * limitations under the License.
  */
 
+#include <algorithm>
 #include <iostream>
+#include <limits>
 
 #include "flatbuffers/code_generators.h"
 #include "flatbuffers/idl.h"
diff --git a/third_party/flatbuffers/src/idl_gen_kotlin.cpp b/third_party/flatbuffers/src/idl_gen_kotlin.cpp
index 102e24d..57ec7b7 100644
--- a/third_party/flatbuffers/src/idl_gen_kotlin.cpp
+++ b/third_party/flatbuffers/src/idl_gen_kotlin.cpp
@@ -505,7 +505,7 @@
           // runtime.
           GenerateFunOneLine(
               writer, "validateVersion", "", "",
-              [&]() { writer += "Constants.FLATBUFFERS_2_0_8()"; },
+              [&]() { writer += "Constants.FLATBUFFERS_22_10_26()"; },
               options.gen_jvmstatic);
 
           GenerateGetRootAsAccessors(namer_.Type(struct_def), writer, options);
diff --git a/third_party/flatbuffers/src/idl_gen_python.cpp b/third_party/flatbuffers/src/idl_gen_python.cpp
index 0b8ffa8..38a5bc1 100644
--- a/third_party/flatbuffers/src/idl_gen_python.cpp
+++ b/third_party/flatbuffers/src/idl_gen_python.cpp
@@ -83,11 +83,11 @@
 
   // Most field accessors need to retrieve and test the field offset first,
   // this is the prefix code for that.
-  std::string OffsetPrefix(const FieldDef &field) const {
+  std::string OffsetPrefix(const FieldDef &field, bool new_line = true) const {
     return "\n" + Indent + Indent +
            "o = flatbuffers.number_types.UOffsetTFlags.py_type" +
            "(self._tab.Offset(" + NumToString(field.value.offset) + "))\n" +
-           Indent + Indent + "if o != 0:\n";
+           Indent + Indent + "if o != 0:" + (new_line ? "\n" : "");
   }
 
   // Begin a class declaration.
@@ -164,9 +164,14 @@
 
     GenReceiver(struct_def, code_ptr);
     code += namer_.Method(field) + "Length(self";
-    code += "):" + OffsetPrefix(field);
-    code += Indent + Indent + Indent + "return self._tab.VectorLen(o)\n";
-    code += Indent + Indent + "return 0\n\n";
+    code += "):";
+    if(!IsArray(field.value.type)){
+      code += OffsetPrefix(field,false);
+      code += GenIndents(3) + "return self._tab.VectorLen(o)";
+      code += GenIndents(2) + "return 0\n\n";
+    }else{
+      code += GenIndents(2) + "return "+NumToString(field.value.type.fixed_length)+"\n\n";
+    }
   }
 
   // Determines whether a vector is none or not.
@@ -177,10 +182,15 @@
     GenReceiver(struct_def, code_ptr);
     code += namer_.Method(field) + "IsNone(self";
     code += "):";
-    code += GenIndents(2) +
-            "o = flatbuffers.number_types.UOffsetTFlags.py_type" +
-            "(self._tab.Offset(" + NumToString(field.value.offset) + "))";
-    code += GenIndents(2) + "return o == 0";
+    if(!IsArray(field.value.type)){
+      code += GenIndents(2) +
+              "o = flatbuffers.number_types.UOffsetTFlags.py_type" +
+              "(self._tab.Offset(" + NumToString(field.value.offset) + "))";
+      code += GenIndents(2) + "return o == 0";
+    } else {
+      //assume that we always have an array as memory is preassigned
+      code += GenIndents(2) + "return False";
+    }
     code += "\n\n";
   }
 
@@ -244,21 +254,42 @@
     const auto vec_type = field.value.type.VectorType();
     GenReceiver(struct_def, code_ptr);
     code += namer_.Method(field);
-    if (IsStruct(vec_type)) {
-      code += "(self, obj, i):\n";
-      code += Indent + Indent + "obj.Init(self._tab.Bytes, self._tab.Pos + ";
-      code += NumToString(field.value.offset) + " + i * ";
-      code += NumToString(InlineSize(vec_type));
-      code += ")\n" + Indent + Indent + "return obj\n\n";
-    } else {
-      auto getter = GenGetter(vec_type);
-      code += "(self): return [" + getter;
-      code += "self._tab.Pos + flatbuffers.number_types.UOffsetTFlags.py_type(";
-      code += NumToString(field.value.offset) + " + i * ";
-      code += NumToString(InlineSize(vec_type));
-      code += ")) for i in range(";
-      code += NumToString(field.value.type.fixed_length) + ")]\n";
+    code += "(self, i: int):";
+    if (parser_.opts.include_dependence_headers) {
+      code += GenIndents(2);
+      code += "from " + GenPackageReference(field.value.type) + " import " +
+              TypeName(field);
     }
+    code += GenIndents(2) + "obj = " + TypeName(field) + "()";
+    code += GenIndents(2) + "obj.Init(self._tab.Bytes, self._tab.Pos + ";
+    code += NumToString(field.value.offset) + " + i * ";
+    code += NumToString(InlineSize(vec_type));
+    code += ")" + GenIndents(2) + "return obj\n\n";
+  }
+
+  // Get the value of a vector's non-struct member. Uses a named return
+  // argument to conveniently set the zero value for the result.
+  void GetArrayOfNonStruct(const StructDef &struct_def, const FieldDef &field,
+                           std::string *code_ptr) const {
+    auto &code = *code_ptr;
+    GenReceiver(struct_def, code_ptr);
+    code += namer_.Method(field);
+    code += "(self, j = None):";
+    code += GenIndents(2) + "if j is None:";
+    code += GenIndents(3) + "return [" + GenGetter(field.value.type);
+    code += "self._tab.Pos + flatbuffers.number_types.UOffsetTFlags.py_type(";
+    code += NumToString(field.value.offset) + " + i * ";
+    code += NumToString(InlineSize(field.value.type.VectorType()));
+    code += ")) for i in range(";
+    code += "self."+namer_.Method(field)+"Length()" + ")]";
+    code += GenIndents(2) +"elif j >= 0 and j < self."+namer_.Method(field)+"Length():";
+    code += GenIndents(3) + "return " + GenGetter(field.value.type);
+    code += "self._tab.Pos + flatbuffers.number_types.UOffsetTFlags.py_type(";
+    code += NumToString(field.value.offset) + " + j * ";
+    code += NumToString(InlineSize(field.value.type.VectorType()));
+    code += "))";
+    code += GenIndents(2) + "else:";
+    code += GenIndents(3) + "return None\n\n";
   }
 
   // Get a struct by initializing an existing struct.
@@ -403,18 +434,25 @@
 
     GenReceiver(struct_def, code_ptr);
     code += namer_.Method(field) + "AsNumpy(self):";
-    code += OffsetPrefix(field);
+    if(!IsArray(field.value.type)){
+      code += OffsetPrefix(field, false);
 
-    code += Indent + Indent + Indent;
-    code += "return ";
-    code += "self._tab.GetVectorAsNumpy(flatbuffers.number_types.";
-    code += namer_.Method(GenTypeGet(field.value.type));
-    code += "Flags, o)\n";
+      code += GenIndents(3);
+      code += "return ";
+      code += "self._tab.GetVectorAsNumpy(flatbuffers.number_types.";
+      code += namer_.Method(GenTypeGet(field.value.type));
+      code += "Flags, o)";
 
-    if (IsString(vectortype)) {
-      code += Indent + Indent + "return \"\"\n";
-    } else {
-      code += Indent + Indent + "return 0\n";
+      if (IsString(vectortype)) {
+        code += GenIndents(2) + "return \"\"\n";
+      } else {
+        code += GenIndents(2) + "return 0\n";
+      }
+    }else{
+      code += GenIndents(2) + "return ";
+      code += "self._tab.GetArrayAsNumpy(flatbuffers.number_types.";
+      code += namer_.Method(GenTypeGet(field.value.type.VectorType()));
+      code += "Flags, self._tab.Pos + "+NumToString(field.value.offset)+", "+NumToString("self."+namer_.Method(field)+"Length()")+")\n";
     }
     code += "\n";
   }
@@ -714,8 +752,6 @@
       } else {
         GetScalarFieldOfTable(struct_def, field, code_ptr);
       }
-    } else if (IsArray(field.value.type)) {
-      GetArrayOfStruct(struct_def, field, code_ptr);
     } else {
       switch (field.value.type.base_type) {
         case BASE_TYPE_STRUCT:
@@ -739,6 +775,17 @@
           }
           break;
         }
+        case BASE_TYPE_ARRAY: {
+          auto vectortype = field.value.type.VectorType();
+          if (vectortype.base_type == BASE_TYPE_STRUCT) {
+            GetArrayOfStruct(struct_def, field, code_ptr);
+          } else {
+            GetArrayOfNonStruct(struct_def, field, code_ptr);
+            GetVectorOfNonStructAsNumpy(struct_def, field, code_ptr);
+            GetVectorAsNestedFlatbuffer(struct_def, field, code_ptr);
+          }
+          break;
+        }
         case BASE_TYPE_UNION: GetUnionField(struct_def, field, code_ptr); break;
         default: FLATBUFFERS_ASSERT(0);
       }
@@ -1067,6 +1114,19 @@
     code += "\n";
   }
 
+  void InitializeFromPackedBuf(const StructDef &struct_def,
+                         std::string *code_ptr) const {
+    auto &code = *code_ptr;
+    const auto struct_var = namer_.Variable(struct_def);
+    const auto struct_type = namer_.Type(struct_def);
+
+    code += GenIndents(1) + "@classmethod";
+    code += GenIndents(1) + "def InitFromPackedBuf(cls, buf, pos=0):";
+    code += GenIndents(2) + "n = flatbuffers.encode.Get(flatbuffers.packer.uoffset, buf, pos)";
+    code += GenIndents(2) + "return cls.InitFromBuf(buf, pos+n)";
+    code += "\n";
+  }
+
   void InitializeFromObjForObject(const StructDef &struct_def,
                                   std::string *code_ptr) const {
     auto &code = *code_ptr;
@@ -1100,8 +1160,8 @@
       code += field_type + "()";
     }
     code += ") is not None:";
-    code += GenIndents(3) + "self." + field_field + " = " + field_type +
-            "T.InitFromObj(" + struct_var + "." + field_method + "(";
+    code += GenIndents(3) + "self." + field_field + " = " + namer_.ObjectType(field_type) +
+            + ".InitFromObj(" + struct_var + "." + field_method + "(";
     // A struct's accessor requires a struct buf instance.
     if (struct_def.fixed && field.value.type.base_type == BASE_TYPE_STRUCT) {
       code += field_type + "()";
@@ -1143,18 +1203,47 @@
     auto field_type = TypeName(field);
     auto one_instance = field_type + "_";
     one_instance[0] = CharToLower(one_instance[0]);
-
     if (parser_.opts.include_dependence_headers) {
       auto package_reference = GenPackageReference(field.value.type);
       field_type = package_reference + "." + TypeName(field);
     }
-
     code += GenIndents(4) + "if " + struct_var + "." + field_method +
             "(i) is None:";
     code += GenIndents(5) + "self." + field_field + ".append(None)";
     code += GenIndents(4) + "else:";
-    code += GenIndents(5) + one_instance + " = " + field_type +
-            "T.InitFromObj(" + struct_var + "." + field_method + "(i))";
+    code += GenIndents(5) + one_instance + " = " + namer_.ObjectType(field_type) +
+            ".InitFromObj(" + struct_var + "." + field_method + "(i))";
+    code +=
+        GenIndents(5) + "self." + field_field + ".append(" + one_instance + ")";
+  }
+
+  void GenUnpackForTableVector(const StructDef &struct_def,
+                               const FieldDef &field,
+                               std::string *code_ptr) const {
+    auto &code = *code_ptr;
+    const auto field_field = namer_.Field(field);
+    const auto field_method = namer_.Method(field);
+    const auto struct_var = namer_.Variable(struct_def);
+
+    code += GenIndents(2) + "if not " + struct_var + "." + field_method +
+            "IsNone():";
+    code += GenIndents(3) + "self." + field_field + " = []";
+    code += GenIndents(3) + "for i in range(" + struct_var + "." +
+            field_method + "Length()):";
+
+    auto field_type = TypeName(field);
+    auto one_instance = field_type + "_";
+    one_instance[0] = CharToLower(one_instance[0]);
+    if (parser_.opts.include_dependence_headers) {
+      auto package_reference = GenPackageReference(field.value.type);
+      field_type = package_reference + "." + TypeName(field);
+    }
+    code += GenIndents(4) + "if " + struct_var + "." + field_method +
+            "(i) is None:";
+    code += GenIndents(5) + "self." + field_field + ".append(None)";
+    code += GenIndents(4) + "else:";
+    code += GenIndents(5) + one_instance + " = " + namer_.ObjectType(field_type) +
+            ".InitFromObj(" + struct_var + "." + field_method + "(i))";
     code +=
         GenIndents(5) + "self." + field_field + ".append(" + one_instance + ")";
   }
@@ -1233,6 +1322,7 @@
           GenUnPackForUnion(struct_def, field, &code);
           break;
         }
+        case BASE_TYPE_ARRAY:
         case BASE_TYPE_VECTOR: {
           auto vectortype = field.value.type.VectorType();
           if (vectortype.base_type == BASE_TYPE_STRUCT) {
@@ -1242,10 +1332,6 @@
           }
           break;
         }
-        case BASE_TYPE_ARRAY: {
-          GenUnPackForScalarVector(struct_def, field, &code);
-          break;
-        }
         default: GenUnPackForScalar(struct_def, field, &code);
       }
     }
@@ -1482,6 +1568,7 @@
           GenPackForUnionField(struct_def, field, &code_prefix, &code);
           break;
         }
+        case BASE_TYPE_ARRAY:
         case BASE_TYPE_VECTOR: {
           auto vectortype = field.value.type.VectorType();
           if (vectortype.base_type == BASE_TYPE_STRUCT) {
@@ -1491,10 +1578,6 @@
           }
           break;
         }
-        case BASE_TYPE_ARRAY: {
-          GenPackForScalarVectorField(struct_def, field, &code_prefix, &code);
-          break;
-        }
         case BASE_TYPE_STRING: {
           code_prefix +=
               GenIndents(2) + "if self." + field_field + " is not None:";
@@ -1536,6 +1619,8 @@
 
     InitializeFromBuf(struct_def, &code);
 
+    InitializeFromPackedBuf(struct_def, &code);
+
     InitializeFromObjForObject(struct_def, &code);
 
     GenUnPack(struct_def, &code);
@@ -1666,7 +1751,9 @@
   std::string GenTypePointer(const Type &type) const {
     switch (type.base_type) {
       case BASE_TYPE_STRING: return "string";
-      case BASE_TYPE_VECTOR: return GenTypeGet(type.VectorType());
+      case BASE_TYPE_VECTOR:
+        // fall through
+      case BASE_TYPE_ARRAY: return GenTypeGet(type.VectorType());
       case BASE_TYPE_STRUCT: return type.struct_def->name;
       case BASE_TYPE_UNION:
         // fall through
diff --git a/third_party/flatbuffers/src/idl_gen_rust.cpp b/third_party/flatbuffers/src/idl_gen_rust.cpp
index 64391d0..43237b2 100644
--- a/third_party/flatbuffers/src/idl_gen_rust.cpp
+++ b/third_party/flatbuffers/src/idl_gen_rust.cpp
@@ -16,6 +16,8 @@
 
 // independent from idl_parser, since this code is not needed for most clients
 
+#include <cmath>
+
 #include "flatbuffers/code_generators.h"
 #include "flatbuffers/flatbuffers.h"
 #include "flatbuffers/idl.h"
@@ -738,7 +740,6 @@
       code_ += "pub use self::bitflags_{{ENUM_NAMESPACE}}::{{ENUM_TY}};";
       code_ += "";
 
-      code_.SetValue("FROM_BASE", "unsafe { Self::from_bits_unchecked(b) }");
       code_.SetValue("INTO_BASE", "self.bits()");
     } else {
       // Normal, c-modelled enums.
@@ -811,7 +812,6 @@
       code_ += "  }";
       code_ += "}";
 
-      code_.SetValue("FROM_BASE", "Self(b)");
       code_.SetValue("INTO_BASE", "self.0");
     }
 
@@ -840,35 +840,55 @@
     code_ += "impl<'a> flatbuffers::Follow<'a> for {{ENUM_TY}} {";
     code_ += "  type Inner = Self;";
     code_ += "  #[inline]";
-    code_ += "  fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {";
-    code_ += "    let b = unsafe {";
-    code_ += "      flatbuffers::read_scalar_at::<{{BASE_TYPE}}>(buf, loc)";
-    code_ += "    };";
-    code_ += "    {{FROM_BASE}}";
+    code_ += "  unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {";
+    code_ += "    let b = flatbuffers::read_scalar_at::<{{BASE_TYPE}}>(buf, loc);";
+    if (IsBitFlagsEnum(enum_def)) {
+      // Safety:
+      // This is safe because we know bitflags is implemented with a repr transparent uint of the correct size.
+      // from_bits_unchecked will be replaced by an equivalent but safe from_bits_retain in bitflags 2.0
+      // https://github.com/bitflags/bitflags/issues/262
+      code_ += "    // Safety:";
+      code_ += "    // This is safe because we know bitflags is implemented with a repr transparent uint of the correct size.";
+      code_ += "    // from_bits_unchecked will be replaced by an equivalent but safe from_bits_retain in bitflags 2.0";
+      code_ += "    // https://github.com/bitflags/bitflags/issues/262";
+      code_ += "    Self::from_bits_unchecked(b)";
+    } else {
+      code_ += "    Self(b)";
+    }
     code_ += "  }";
     code_ += "}";
     code_ += "";
     code_ += "impl flatbuffers::Push for {{ENUM_TY}} {";
     code_ += "    type Output = {{ENUM_TY}};";
     code_ += "    #[inline]";
-    code_ += "    fn push(&self, dst: &mut [u8], _rest: &[u8]) {";
-    code_ +=
-        "        unsafe { flatbuffers::emplace_scalar::<{{BASE_TYPE}}>"
-        "(dst, {{INTO_BASE}}); }";
+    code_ += "    unsafe fn push(&self, dst: &mut [u8], _written_len: usize) {";
+    code_ += "        flatbuffers::emplace_scalar::<{{BASE_TYPE}}>(dst, {{INTO_BASE}});";
     code_ += "    }";
     code_ += "}";
     code_ += "";
     code_ += "impl flatbuffers::EndianScalar for {{ENUM_TY}} {";
+    code_ += "  type Scalar = {{BASE_TYPE}};";
     code_ += "  #[inline]";
-    code_ += "  fn to_little_endian(self) -> Self {";
-    code_ += "    let b = {{BASE_TYPE}}::to_le({{INTO_BASE}});";
-    code_ += "    {{FROM_BASE}}";
+    code_ += "  fn to_little_endian(self) -> {{BASE_TYPE}} {";
+    code_ += "    {{INTO_BASE}}.to_le()";
     code_ += "  }";
     code_ += "  #[inline]";
     code_ += "  #[allow(clippy::wrong_self_convention)]";
-    code_ += "  fn from_little_endian(self) -> Self {";
-    code_ += "    let b = {{BASE_TYPE}}::from_le({{INTO_BASE}});";
-    code_ += "    {{FROM_BASE}}";
+    code_ += "  fn from_little_endian(v: {{BASE_TYPE}}) -> Self {";
+    code_ += "    let b = {{BASE_TYPE}}::from_le(v);";
+    if (IsBitFlagsEnum(enum_def)) {
+      // Safety:
+      // This is safe because we know bitflags is implemented with a repr transparent uint of the correct size.
+      // from_bits_unchecked will be replaced by an equivalent but safe from_bits_retain in bitflags 2.0
+      // https://github.com/bitflags/bitflags/issues/262
+      code_ += "    // Safety:";
+      code_ += "    // This is safe because we know bitflags is implemented with a repr transparent uint of the correct size.";
+      code_ += "    // from_bits_unchecked will be replaced by an equivalent but safe from_bits_retain in bitflags 2.0";
+      code_ += "    // https://github.com/bitflags/bitflags/issues/262";
+      code_ += "    unsafe { Self::from_bits_unchecked(b) }";
+    } else {
+      code_ += "    Self(b)";
+    }
     code_ += "  }";
     code_ += "}";
     code_ += "";
@@ -1029,8 +1049,19 @@
       if (field.IsOptional() && !IsUnion(field.value.type)) { return "None"; }
     }
     switch (GetFullType(field.value.type)) {
-      case ftInteger:
+      case ftInteger: {
+        return field.value.constant;
+      }
       case ftFloat: {
+        const std::string float_prefix =
+            (field.value.type.base_type == BASE_TYPE_FLOAT) ? "f32::" : "f64::";
+        if (StringIsFlatbufferNan(field.value.constant)) {
+          return float_prefix + "NAN";
+        } else if (StringIsFlatbufferPositiveInfinity(field.value.constant)) {
+          return float_prefix + "INFINITY";
+        } else if (StringIsFlatbufferNegativeInfinity(field.value.constant)) {
+          return float_prefix + "NEG_INFINITY";
+        }
         return field.value.constant;
       }
       case ftBool: {
@@ -1426,11 +1457,7 @@
       case ftVectorOfBool:
       case ftVectorOfFloat: {
         const auto typname = GetTypeBasic(type.VectorType());
-        const auto vector_type =
-            IsOneByte(type.VectorType().base_type)
-                ? "&" + lifetime + " [" + typname + "]"
-                : "flatbuffers::Vector<" + lifetime + ", " + typname + ">";
-        return WrapOption(vector_type);
+        return WrapOption("flatbuffers::Vector<" + lifetime + ", " + typname + ">");
       }
       case ftVectorOfEnumKey: {
         const auto typname = WrapInNameSpace(*type.enum_def);
@@ -1439,7 +1466,7 @@
       }
       case ftVectorOfStruct: {
         const auto typname = WrapInNameSpace(*type.struct_def);
-        return WrapOption("&" + lifetime + " [" + typname + "]");
+          return WrapOption("flatbuffers::Vector<" + lifetime + ", " + typname + ">");
       }
       case ftVectorOfTable: {
         const auto typname = WrapInNameSpace(*type.struct_def);
@@ -1557,19 +1584,8 @@
             : "None";
     const std::string unwrap = field.IsOptional() ? "" : ".unwrap()";
 
-    const auto t = GetFullType(field.value.type);
-
-    // TODO(caspern): Shouldn't 1byte VectorOfEnumKey be slice too?
-    const std::string safe_slice =
-        (t == ftVectorOfStruct ||
-         ((t == ftVectorOfBool || t == ftVectorOfFloat ||
-           t == ftVectorOfInteger) &&
-          IsOneByte(field.value.type.VectorType().base_type)))
-            ? ".map(|v| v.safe_slice())"
-            : "";
-
-    return "self._tab.get::<" + typname + ">({{STRUCT_TY}}::" + vt_offset +
-           ", " + default_value + ")" + safe_slice + unwrap;
+    return "unsafe { self._tab.get::<" + typname + ">({{STRUCT_TY}}::" + vt_offset +
+           ", " + default_value + ")" + unwrap + "}";
   }
 
   // Generates a fully-qualified name getter for use with --gen-name-strings
@@ -1655,8 +1671,8 @@
     code_ += "impl<'a> flatbuffers::Follow<'a> for {{STRUCT_TY}}<'a> {";
     code_ += "  type Inner = {{STRUCT_TY}}<'a>;";
     code_ += "  #[inline]";
-    code_ += "  fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {";
-    code_ += "    Self { _tab: flatbuffers::Table { buf, loc } }";
+    code_ += "  unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {";
+    code_ += "    Self { _tab: flatbuffers::Table::new(buf, loc) }";
     code_ += "  }";
     code_ += "}";
     code_ += "";
@@ -1677,7 +1693,7 @@
 
     code_ += "  #[inline]";
     code_ +=
-        "  pub fn init_from_table(table: flatbuffers::Table<'a>) -> "
+        "  pub unsafe fn init_from_table(table: flatbuffers::Table<'a>) -> "
         "Self {";
     code_ += "    {{STRUCT_TY}} { _tab: table }";
     code_ += "  }";
@@ -1769,16 +1785,7 @@
             break;
           }
           case ftVectorOfInteger:
-          case ftVectorOfBool: {
-            if (IsOneByte(type.VectorType().base_type)) {
-              // 1 byte stuff is viewed w/ slice instead of flatbuffer::Vector
-              // and thus needs to be cloned out of the slice.
-              code_.SetValue("EXPR", "x.to_vec()");
-              break;
-            }
-            code_.SetValue("EXPR", "x.into_iter().collect()");
-            break;
-          }
+          case ftVectorOfBool:
           case ftVectorOfFloat:
           case ftVectorOfEnumKey: {
             code_.SetValue("EXPR", "x.into_iter().collect()");
@@ -1845,6 +1852,9 @@
       this->GenComment(field.doc_comment);
       code_ += "#[inline]";
       code_ += "pub fn {{FIELD}}(&self) -> {{RETURN_TYPE}} {";
+      code_ += "  // Safety:";
+      code_ += "  // Created from valid Table for this object";
+      code_ += "  // which contains a valid value in this slot";
       code_ += "  " + GenTableAccessorFuncBody(field, "'a");
       code_ += "}";
 
@@ -1869,16 +1879,22 @@
           code_ += "{{NESTED}}<'a> {";
           code_ += "  let data = self.{{FIELD}}();";
           code_ += "  use flatbuffers::Follow;";
+          code_ += "  // Safety:";
+          code_ += "  // Created from a valid Table for this object";
+          code_ += "  // Which contains a valid flatbuffer in this slot";
           code_ +=
-              "  <flatbuffers::ForwardsUOffset<{{NESTED}}<'a>>>"
-              "::follow(data, 0)";
+              "  unsafe { <flatbuffers::ForwardsUOffset<{{NESTED}}<'a>>>"
+              "::follow(data.bytes(), 0) }";
         } else {
           code_ += "Option<{{NESTED}}<'a>> {";
           code_ += "  self.{{FIELD}}().map(|data| {";
           code_ += "    use flatbuffers::Follow;";
+          code_ += "    // Safety:";
+          code_ += "    // Created from a valid Table for this object";
+          code_ += "    // Which contains a valid flatbuffer in this slot";
           code_ +=
-              "    <flatbuffers::ForwardsUOffset<{{NESTED}}<'a>>>"
-              "::follow(data, 0)";
+              "    unsafe { <flatbuffers::ForwardsUOffset<{{NESTED}}<'a>>>"
+              "::follow(data.bytes(), 0) }";
           code_ += "  })";
         }
         code_ += "}";
@@ -1914,11 +1930,17 @@
             // as of April 10, 2020
             if (field.IsRequired()) {
               code_ += "    let u = self.{{FIELD}}();";
-              code_ += "    Some({{U_ELEMENT_TABLE_TYPE}}::init_from_table(u))";
+              code_ += "    // Safety:";
+              code_ += "    // Created from a valid Table for this object";
+              code_ += "    // Which contains a valid union in this slot";
+              code_ += "    Some(unsafe { {{U_ELEMENT_TABLE_TYPE}}::init_from_table(u) })";
             } else {
-              code_ +=
-                  "    self.{{FIELD}}().map("
-                  "{{U_ELEMENT_TABLE_TYPE}}::init_from_table)";
+              code_ +="    self.{{FIELD}}().map(|t| {";
+              code_ += "     // Safety:";
+              code_ += "     // Created from a valid Table for this object";
+              code_ += "     // Which contains a valid union in this slot";
+              code_ += "     unsafe { {{U_ELEMENT_TABLE_TYPE}}::init_from_table(t) }";
+              code_ += "   })";
             }
             code_ += "  } else {";
             code_ += "    None";
@@ -2291,8 +2313,8 @@
 
           MapNativeTableField(
               field,
-              "let w: Vec<_> = x.iter().map(|s| s.as_ref()).collect();"
-              "_fbb.create_vector_of_strings(&w)");
+              "let w: Vec<_> = x.iter().map(|s| _fbb.create_string(s)).collect();"
+              "_fbb.create_vector(&w)");
           return;
         }
         case ftVectorOfTable: {
@@ -2383,32 +2405,6 @@
     code_.SetValue("STRUCT_FN", namer_.Function(struct_def));
     code_.SetValue("STRUCT_CONST", namer_.Constant(struct_def.name));
 
-    // The root datatype accessors:
-    code_ += "#[inline]";
-    code_ +=
-        "#[deprecated(since=\"2.0.0\", "
-        "note=\"Deprecated in favor of `root_as...` methods.\")]";
-    code_ +=
-        "pub fn get_root_as_{{STRUCT_FN}}<'a>(buf: &'a [u8])"
-        " -> {{STRUCT_TY}}<'a> {";
-    code_ +=
-        "  unsafe { flatbuffers::root_unchecked::<{{STRUCT_TY}}"
-        "<'a>>(buf) }";
-    code_ += "}";
-    code_ += "";
-
-    code_ += "#[inline]";
-    code_ +=
-        "#[deprecated(since=\"2.0.0\", "
-        "note=\"Deprecated in favor of `root_as...` methods.\")]";
-    code_ +=
-        "pub fn get_size_prefixed_root_as_{{STRUCT_FN}}"
-        "<'a>(buf: &'a [u8]) -> {{STRUCT_TY}}<'a> {";
-    code_ +=
-        "  unsafe { flatbuffers::size_prefixed_root_unchecked::<{{STRUCT_TY}}"
-        "<'a>>(buf) }";
-    code_ += "}";
-    code_ += "";
     // Default verifier root fns.
     code_ += "#[inline]";
     code_ += "/// Verifies that a buffer of bytes contains a `{{STRUCT_TY}}`";
@@ -2650,43 +2646,25 @@
     // Follow for the value type, Follow for the reference type, Push for the
     // value type, and Push for the reference type.
     code_ += "impl flatbuffers::SimpleToVerifyInSlice for {{STRUCT_TY}} {}";
-    code_ += "impl flatbuffers::SafeSliceAccess for {{STRUCT_TY}} {}";
     code_ += "impl<'a> flatbuffers::Follow<'a> for {{STRUCT_TY}} {";
     code_ += "  type Inner = &'a {{STRUCT_TY}};";
     code_ += "  #[inline]";
-    code_ += "  fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {";
+    code_ += "  unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {";
     code_ += "    <&'a {{STRUCT_TY}}>::follow(buf, loc)";
     code_ += "  }";
     code_ += "}";
     code_ += "impl<'a> flatbuffers::Follow<'a> for &'a {{STRUCT_TY}} {";
     code_ += "  type Inner = &'a {{STRUCT_TY}};";
     code_ += "  #[inline]";
-    code_ += "  fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {";
+    code_ += "  unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {";
     code_ += "    flatbuffers::follow_cast_ref::<{{STRUCT_TY}}>(buf, loc)";
     code_ += "  }";
     code_ += "}";
     code_ += "impl<'b> flatbuffers::Push for {{STRUCT_TY}} {";
     code_ += "    type Output = {{STRUCT_TY}};";
     code_ += "    #[inline]";
-    code_ += "    fn push(&self, dst: &mut [u8], _rest: &[u8]) {";
-    code_ += "        let src = unsafe {";
-    code_ +=
-        "            ::core::slice::from_raw_parts("
-        "self as *const {{STRUCT_TY}} as *const u8, Self::size())";
-    code_ += "        };";
-    code_ += "        dst.copy_from_slice(src);";
-    code_ += "    }";
-    code_ += "}";
-    code_ += "impl<'b> flatbuffers::Push for &'b {{STRUCT_TY}} {";
-    code_ += "    type Output = {{STRUCT_TY}};";
-    code_ += "";
-    code_ += "    #[inline]";
-    code_ += "    fn push(&self, dst: &mut [u8], _rest: &[u8]) {";
-    code_ += "        let src = unsafe {";
-    code_ +=
-        "            ::core::slice::from_raw_parts("
-        "*self as *const {{STRUCT_TY}} as *const u8, Self::size())";
-    code_ += "        };";
+    code_ += "    unsafe fn push(&self, dst: &mut [u8], _written_len: usize) {";
+    code_ += "        let src = ::core::slice::from_raw_parts(self as *const {{STRUCT_TY}} as *const u8, Self::size());";
     code_ += "        dst.copy_from_slice(src);";
     code_ += "    }";
     code_ += "}";
@@ -2759,6 +2737,9 @@
       // Getter.
       if (IsStruct(field.value.type)) {
         code_ += "pub fn {{FIELD}}(&self) -> &{{FIELD_TYPE}} {";
+        code_ += "  // Safety:";
+        code_ += "  // Created from a valid Table for this object";
+        code_ += "  // Which contains a valid struct in this slot";
         code_ +=
             "  unsafe {"
             " &*(self.0[{{FIELD_OFFSET}}..].as_ptr() as *const"
@@ -2770,20 +2751,26 @@
         code_ +=
             "pub fn {{FIELD}}(&'a self) -> "
             "flatbuffers::Array<'a, {{ARRAY_ITEM}}, {{ARRAY_SIZE}}> {";
-        code_ += "  flatbuffers::Array::follow(&self.0, {{FIELD_OFFSET}})";
+        code_ += "  // Safety:";
+        code_ += "  // Created from a valid Table for this object";
+        code_ += "  // Which contains a valid array in this slot";
+        code_ += "  unsafe { flatbuffers::Array::follow(&self.0, {{FIELD_OFFSET}}) }";
       } else {
         code_ += "pub fn {{FIELD}}(&self) -> {{FIELD_TYPE}} {";
         code_ +=
             "  let mut mem = core::mem::MaybeUninit::"
-            "<{{FIELD_TYPE}}>::uninit();";
-        code_ += "  unsafe {";
+            "<<{{FIELD_TYPE}} as EndianScalar>::Scalar>::uninit();";
+        code_ += "  // Safety:";
+        code_ += "  // Created from a valid Table for this object";
+        code_ += "  // Which contains a valid value in this slot";
+        code_ += "  EndianScalar::from_little_endian(unsafe {";
         code_ += "    core::ptr::copy_nonoverlapping(";
         code_ += "      self.0[{{FIELD_OFFSET}}..].as_ptr(),";
         code_ += "      mem.as_mut_ptr() as *mut u8,";
-        code_ += "      core::mem::size_of::<{{FIELD_TYPE}}>(),";
+        code_ += "      core::mem::size_of::<<{{FIELD_TYPE}} as EndianScalar>::Scalar>(),";
         code_ += "    );";
         code_ += "    mem.assume_init()";
-        code_ += "  }.from_little_endian()";
+        code_ += "  })";
       }
       code_ += "}\n";
       // Setter.
@@ -2804,13 +2791,19 @@
           code_ +=
               "pub fn set_{{FIELD}}(&mut self, items: &{{FIELD_TYPE}}) "
               "{";
+          code_ += "  // Safety:";
+          code_ += "  // Created from a valid Table for this object";
+          code_ += "  // Which contains a valid array in this slot";
           code_ +=
-              "  flatbuffers::emplace_scalar_array(&mut self.0, "
-              "{{FIELD_OFFSET}}, items);";
+              "  unsafe { flatbuffers::emplace_scalar_array(&mut self.0, "
+              "{{FIELD_OFFSET}}, items) };";
         } else {
           code_.SetValue("FIELD_SIZE",
                          NumToString(InlineSize(field.value.type)));
           code_ += "pub fn set_{{FIELD}}(&mut self, x: &{{FIELD_TYPE}}) {";
+          code_ += "  // Safety:";
+          code_ += "  // Created from a valid Table for this object";
+          code_ += "  // Which contains a valid array in this slot";
           code_ += "  unsafe {";
           code_ += "    core::ptr::copy(";
           code_ += "      x.as_ptr() as *const u8,";
@@ -2822,11 +2815,14 @@
       } else {
         code_ += "pub fn set_{{FIELD}}(&mut self, x: {{FIELD_TYPE}}) {";
         code_ += "  let x_le = x.to_little_endian();";
+        code_ += "  // Safety:";
+        code_ += "  // Created from a valid Table for this object";
+        code_ += "  // Which contains a valid value in this slot";
         code_ += "  unsafe {";
         code_ += "    core::ptr::copy_nonoverlapping(";
-        code_ += "      &x_le as *const {{FIELD_TYPE}} as *const u8,";
+        code_ += "      &x_le as *const _ as *const u8,";
         code_ += "      self.0[{{FIELD_OFFSET}}..].as_mut_ptr(),";
-        code_ += "      core::mem::size_of::<{{FIELD_TYPE}}>(),";
+        code_ += "      core::mem::size_of::<<{{FIELD_TYPE}} as EndianScalar>::Scalar>(),";
         code_ += "    );";
         code_ += "  }";
       }
diff --git a/third_party/flatbuffers/src/idl_gen_swift.cpp b/third_party/flatbuffers/src/idl_gen_swift.cpp
index b3baa28..c7cf2b5 100644
--- a/third_party/flatbuffers/src/idl_gen_swift.cpp
+++ b/third_party/flatbuffers/src/idl_gen_swift.cpp
@@ -1198,7 +1198,8 @@
 
   void GenEnum(const EnumDef &enum_def) {
     if (enum_def.generated) return;
-    const auto is_private_access = enum_def.attributes.Lookup("private");
+    const bool is_private_access = parser_.opts.swift_implementation_only ||
+       enum_def.attributes.Lookup("private") != nullptr;
     code_.SetValue("ENUM_TYPE",
                    enum_def.is_union ? "UnionEnum" : "Enum, Verifiable");
     code_.SetValue("ACCESS_TYPE", is_private_access ? "internal" : "public");
@@ -1873,7 +1874,7 @@
   }
 
   std::string ValidateFunc() {
-    return "static func validateVersion() { FlatBuffersVersion_2_0_8() }";
+    return "static func validateVersion() { FlatBuffersVersion_22_10_26() }";
   }
 
   std::string GenType(const Type &type,
diff --git a/third_party/flatbuffers/src/idl_gen_text.cpp b/third_party/flatbuffers/src/idl_gen_text.cpp
index 3b69c95..52f854d 100644
--- a/third_party/flatbuffers/src/idl_gen_text.cpp
+++ b/third_party/flatbuffers/src/idl_gen_text.cpp
@@ -16,6 +16,8 @@
 
 // independent from idl_parser, since this code is not needed for most clients
 
+#include <algorithm>
+
 #include "flatbuffers/flatbuffers.h"
 #include "flatbuffers/flexbuffers.h"
 #include "flatbuffers/idl.h"
diff --git a/third_party/flatbuffers/src/idl_gen_ts.cpp b/third_party/flatbuffers/src/idl_gen_ts.cpp
index 32ab863..9fd1203 100644
--- a/third_party/flatbuffers/src/idl_gen_ts.cpp
+++ b/third_party/flatbuffers/src/idl_gen_ts.cpp
@@ -16,6 +16,7 @@
 
 #include <algorithm>
 #include <cassert>
+#include <cmath>
 #include <unordered_map>
 #include <unordered_set>
 
@@ -402,12 +403,26 @@
     const auto &value = field.value;
     if (value.type.enum_def && value.type.base_type != BASE_TYPE_UNION &&
         value.type.base_type != BASE_TYPE_VECTOR) {
-      // If the value is an enum with a 64-bit base type, we have to just
-      // return the bigint value directly since typescript does not support
-      // enums with bigint backing types.
       switch (value.type.base_type) {
+        case BASE_TYPE_ARRAY: {
+          std::string ret = "[";
+          for (auto i = 0; i < value.type.fixed_length; ++i) {
+            std::string enum_name =
+                AddImport(imports, *value.type.enum_def, *value.type.enum_def)
+                    .name;
+            std::string enum_value = namer_.Variant(
+                *value.type.enum_def->FindByValue(value.constant));
+            ret += enum_name + "." + enum_value +
+                   (i < value.type.fixed_length - 1 ? ", " : "");
+          }
+          ret += "]";
+          return ret;
+        }
         case BASE_TYPE_LONG:
         case BASE_TYPE_ULONG: {
+          // If the value is an enum with a 64-bit base type, we have to just
+          // return the bigint value directly since typescript does not support
+          // enums with bigint backing types.
           return "BigInt('" + value.constant + "')";
         }
         default: {
@@ -432,6 +447,7 @@
         return "null";
       }
 
+      case BASE_TYPE_ARRAY:
       case BASE_TYPE_VECTOR: return "[]";
 
       case BASE_TYPE_LONG:
@@ -439,9 +455,16 @@
         return "BigInt('" + value.constant + "')";
       }
 
-      default:
-        if (value.constant == "nan") { return "NaN"; }
+      default: {
+        if (StringIsFlatbufferNan(value.constant)) {
+          return "NaN";
+        } else if (StringIsFlatbufferPositiveInfinity(value.constant)) {
+          return "Infinity";
+        } else if (StringIsFlatbufferNegativeInfinity(value.constant)) {
+          return "-Infinity";
+        }
         return value.constant;
+      }
     }
   }
 
@@ -464,6 +487,22 @@
       case BASE_TYPE_BOOL: return allowNull ? "boolean|null" : "boolean";
       case BASE_TYPE_LONG:
       case BASE_TYPE_ULONG: return allowNull ? "bigint|null" : "bigint";
+      case BASE_TYPE_ARRAY: {
+        std::string name;
+        if (type.element == BASE_TYPE_LONG || type.element == BASE_TYPE_ULONG) {
+          name = "bigint[]";
+        } else if (type.element != BASE_TYPE_STRUCT) {
+          name = "number[]";
+        } else {
+          name = "any[]";
+          if (parser_.opts.generate_object_based_api) {
+            name = "(any|" +
+                   GetTypeName(*type.struct_def, /*object_api =*/true) + ")[]";
+          }
+        }
+
+        return name + (allowNull ? "|null" : "");
+      }
       default:
         if (IsScalar(type.base_type)) {
           if (type.enum_def) {
@@ -536,12 +575,91 @@
         // Generate arguments for a struct inside a struct. To ensure names
         // don't clash, and to make it obvious these arguments are constructing
         // a nested struct, prefix the name with the field name.
-        GenStructBody(*field.value.type.struct_def, body,
-                      nameprefix + field.name + "_");
+        GenStructBody(
+            *field.value.type.struct_def, body,
+            nameprefix.length() ? nameprefix + "_" + field.name : field.name);
       } else {
-        *body += "  builder.write" + GenWriteMethod(field.value.type) + "(";
-        if (field.value.type.base_type == BASE_TYPE_BOOL) { *body += "+"; }
-        *body += nameprefix + field.name + ");\n";
+        auto element_type = field.value.type.element;
+
+        if (field.value.type.base_type == BASE_TYPE_ARRAY) {
+          switch (field.value.type.element) {
+            case BASE_TYPE_STRUCT: {
+              std::string str_last_item_idx =
+                  NumToString(field.value.type.fixed_length - 1);
+              *body += "\n  for (let i = " + str_last_item_idx +
+                       "; i >= 0; --i" + ") {\n";
+
+              std::string fname = nameprefix.length()
+                                      ? nameprefix + "_" + field.name
+                                      : field.name;
+
+              *body += "    const item = " + fname + "?.[i];\n\n";
+
+              if (parser_.opts.generate_object_based_api) {
+                *body += "    if (item instanceof " +
+                         GetTypeName(*field.value.type.struct_def,
+                                     /*object_api =*/true) +
+                         ") {\n";
+                *body += "      item.pack(builder);\n";
+                *body += "      continue;\n";
+                *body += "    }\n\n";
+              }
+
+              std::string class_name =
+                  GetPrefixedName(*field.value.type.struct_def);
+              std::string pack_func_create_call =
+                  class_name + ".create" + class_name + "(builder,\n";
+              pack_func_create_call +=
+                  "    " +
+                  GenStructMemberValueTS(*field.value.type.struct_def, "item",
+                                         ",\n    ", false) +
+                  "\n  ";
+              *body += "    " + pack_func_create_call;
+              *body += "  );\n  }\n\n";
+
+              break;
+            }
+            default: {
+              std::string str_last_item_idx =
+                  NumToString(field.value.type.fixed_length - 1);
+              std::string fname = nameprefix.length()
+                                      ? nameprefix + "_" + field.name
+                                      : field.name;
+
+              *body += "\n  for (let i = " + str_last_item_idx +
+                       "; i >= 0; --i) {\n";
+              *body += "    builder.write";
+              *body += GenWriteMethod(
+                  static_cast<flatbuffers::Type>(field.value.type.element));
+              *body += "(";
+              *body += element_type == BASE_TYPE_BOOL ? "+" : "";
+
+              if (element_type == BASE_TYPE_LONG ||
+                  element_type == BASE_TYPE_ULONG) {
+                *body += "BigInt(" + fname + "?.[i] ?? 0));\n";
+              } else {
+                *body += "(" + fname + "?.[i] ?? 0));\n\n";
+              }
+              *body += "  }\n\n";
+              break;
+            }
+          }
+        } else {
+          std::string fname =
+              nameprefix.length() ? nameprefix + "_" + field.name : field.name;
+
+          *body += "  builder.write" + GenWriteMethod(field.value.type) + "(";
+          if (field.value.type.base_type == BASE_TYPE_BOOL) {
+            *body += "Number(Boolean(" + fname + ")));\n";
+            continue;
+          } else if (field.value.type.base_type == BASE_TYPE_LONG ||
+                     field.value.type.base_type == BASE_TYPE_ULONG) {
+            *body += "BigInt(" + fname + " ?? 0));\n";
+            continue;
+          }
+
+          *body += fname + ");\n";
+        }
       }
     }
   }
@@ -759,10 +877,10 @@
     import.object_name = object_name;
     import.bare_file_path = bare_file_path;
     import.rel_file_path = rel_file_path;
-    import.import_statement =
-        "import { " + symbols_expression + " } from '" + rel_file_path + ".js';";
-    import.export_statement =
-        "export { " + symbols_expression + " } from '." + bare_file_path + ".js';";
+    import.import_statement = "import { " + symbols_expression + " } from '" +
+                              rel_file_path + ".js';";
+    import.export_statement = "export { " + symbols_expression + " } from '." +
+                              bare_file_path + ".js';";
     import.dependency = &dependency;
     import.dependent = &dependent;
 
@@ -903,7 +1021,7 @@
         const auto conversion_function = GenUnionConvFuncName(enum_def);
 
         ret = "(() => {\n";
-        ret += "      let temp = " + conversion_function + "(this." +
+        ret += "      const temp = " + conversion_function + "(this." +
                namer_.Method(field_name, "Type") + "(), " +
                field_binded_method + ");\n";
         ret += "      if(temp === null) { return null; }\n";
@@ -916,17 +1034,20 @@
         const auto conversion_function = GenUnionListConvFuncName(enum_def);
 
         ret = "(() => {\n";
-        ret += "    let ret = [];\n";
+        ret += "    const ret: (" +
+               GenObjApiUnionTypeTS(imports, *union_type.struct_def,
+                                    parser_.opts, *union_type.enum_def) +
+               ")[] = [];\n";
         ret += "    for(let targetEnumIndex = 0; targetEnumIndex < this." +
                namer_.Method(field_name, "TypeLength") + "()" +
                "; "
                "++targetEnumIndex) {\n";
-        ret += "      let targetEnum = this." +
+        ret += "      const targetEnum = this." +
                namer_.Method(field_name, "Type") + "(targetEnumIndex);\n";
         ret += "      if(targetEnum === null || " + enum_type +
                "[targetEnum!] === 'NONE') { "
                "continue; }\n\n";
-        ret += "      let temp = " + conversion_function + "(targetEnum, " +
+        ret += "      const temp = " + conversion_function + "(targetEnum, " +
                field_binded_method + ", targetEnumIndex);\n";
         ret += "      if(temp === null) { continue; }\n";
         ret += union_has_string ? "      if(typeof temp === 'string') { "
@@ -973,6 +1094,11 @@
           std::string nullValue = "0";
           if (field.value.type.base_type == BASE_TYPE_BOOL) {
             nullValue = "false";
+          } else if (field.value.type.base_type == BASE_TYPE_LONG ||
+                     field.value.type.base_type == BASE_TYPE_ULONG) {
+            nullValue = "BigInt(0)";
+          } else if (field.value.type.base_type == BASE_TYPE_ARRAY) {
+            nullValue = "[]";
           }
           ret += "(" + curr_member_accessor + " ?? " + nullValue + ")";
         } else {
@@ -1091,7 +1217,7 @@
             break;
           }
 
-          case BASE_TYPE_VECTOR: {
+          case BASE_TYPE_ARRAY: {
             auto vectortype = field.value.type.VectorType();
             auto vectortypename =
                 GenTypeName(imports, struct_def, vectortype, false);
@@ -1102,13 +1228,15 @@
             switch (vectortype.base_type) {
               case BASE_TYPE_STRUCT: {
                 const auto &sd = *field.value.type.struct_def;
-                field_type += GetTypeName(sd, /*object_api=*/true);
-                ;
+                const auto field_type_name =
+                    GetTypeName(sd, /*object_api=*/true);
+                field_type += field_type_name;
                 field_type += ")[]";
 
-                field_val = GenBBAccess() + ".createObjList(" +
-                            field_binded_method + ", this." +
-                            namer_.Method(field, "Length") + "())";
+                field_val = GenBBAccess() + ".createObjList<" + vectortypename +
+                            ", " + field_type_name + ">(" +
+                            field_binded_method + ", " +
+                            NumToString(field.value.type.fixed_length) + ")";
 
                 if (sd.fixed) {
                   field_offset_decl =
@@ -1128,7 +1256,7 @@
 
               case BASE_TYPE_STRING: {
                 field_type += "string)[]";
-                field_val = GenBBAccess() + ".createScalarList(" +
+                field_val = GenBBAccess() + ".createScalarList<string>(" +
                             field_binded_method + ", this." +
                             namer_.Field(field, "Length") + "())";
                 field_offset_decl =
@@ -1162,10 +1290,99 @@
                   field_type += vectortypename;
                 }
                 field_type += ")[]";
-                field_val = GenBBAccess() + ".createScalarList(" +
+                field_val = GenBBAccess() + ".createScalarList<" +
+                            vectortypename + ">(" + field_binded_method + ", " +
+                            NumToString(field.value.type.fixed_length) + ")";
+
+                field_offset_decl =
+                    AddImport(imports, struct_def, struct_def).name + "." +
+                    namer_.Method("create", field, "Vector") +
+                    "(builder, this." + field_field + ")";
+
+                break;
+              }
+            }
+
+            break;
+          }
+
+          case BASE_TYPE_VECTOR: {
+            auto vectortype = field.value.type.VectorType();
+            auto vectortypename =
+                GenTypeName(imports, struct_def, vectortype, false);
+            is_vector = true;
+
+            field_type = "(";
+
+            switch (vectortype.base_type) {
+              case BASE_TYPE_STRUCT: {
+                const auto &sd = *field.value.type.struct_def;
+                const auto field_type_name =
+                    GetTypeName(sd, /*object_api=*/true);
+                field_type += field_type_name;
+                field_type += ")[]";
+
+                field_val = GenBBAccess() + ".createObjList<" + vectortypename +
+                            ", " + field_type_name + ">(" +
                             field_binded_method + ", this." +
                             namer_.Method(field, "Length") + "())";
 
+                if (sd.fixed) {
+                  field_offset_decl =
+                      "builder.createStructOffsetList(this." + field_field +
+                      ", " + AddImport(imports, struct_def, struct_def).name +
+                      "." + namer_.Method("start", field, "Vector") + ")";
+                } else {
+                  field_offset_decl =
+                      AddImport(imports, struct_def, struct_def).name + "." +
+                      namer_.Method("create", field, "Vector") +
+                      "(builder, builder.createObjectOffsetList(" + "this." +
+                      field_field + "))";
+                }
+
+                break;
+              }
+
+              case BASE_TYPE_STRING: {
+                field_type += "string)[]";
+                field_val = GenBBAccess() + ".createScalarList<string>(" +
+                            field_binded_method + ", this." +
+                            namer_.Field(field, "Length") + "())";
+                field_offset_decl =
+                    AddImport(imports, struct_def, struct_def).name + "." +
+                    namer_.Method("create", field, "Vector") +
+                    "(builder, builder.createObjectOffsetList(" + "this." +
+                    namer_.Field(field) + "))";
+                break;
+              }
+
+              case BASE_TYPE_UNION: {
+                field_type += GenObjApiUnionTypeTS(
+                    imports, struct_def, parser.opts, *(vectortype.enum_def));
+                field_type += ")[]";
+                field_val = GenUnionValTS(imports, struct_def, field_method,
+                                          vectortype, true);
+
+                field_offset_decl =
+                    AddImport(imports, struct_def, struct_def).name + "." +
+                    namer_.Method("create", field, "Vector") +
+                    "(builder, builder.createObjectOffsetList(" + "this." +
+                    namer_.Field(field) + "))";
+
+                break;
+              }
+              default: {
+                if (vectortype.enum_def) {
+                  field_type += GenTypeName(imports, struct_def, vectortype,
+                                            false, HasNullDefault(field));
+                } else {
+                  field_type += vectortypename;
+                }
+                field_type += ")[]";
+                field_val = GenBBAccess() + ".createScalarList<" +
+                            vectortypename + ">(" + field_binded_method +
+                            ", this." + namer_.Method(field, "Length") + "())";
+
                 field_offset_decl =
                     AddImport(imports, struct_def, struct_def).name + "." +
                     namer_.Method("create", field, "Vector") +
@@ -1260,7 +1477,7 @@
     obj_api_class = "\n";
     obj_api_class += "export class ";
     obj_api_class += GetTypeName(struct_def, /*object_api=*/true);
-    obj_api_class += " {\n";
+    obj_api_class += " implements flatbuffers.IGeneratedObject {\n";
     obj_api_class += constructor_func;
     obj_api_class += pack_func_prototype + pack_func_offset_decl +
                      pack_func_create_call + "\n}";
@@ -1298,12 +1515,17 @@
     }
 
     const std::string object_name = GetTypeName(struct_def);
+    const std::string object_api_name = GetTypeName(struct_def, true);
 
     // Emit constructor
     GenDocComment(struct_def.doc_comment, code_ptr);
     code += "export class ";
     code += object_name;
-    code += " {\n";
+    if (parser.opts.generate_object_based_api)
+      code += " implements flatbuffers.IUnpackableObject<" + object_api_name +
+              "> {\n";
+    else
+      code += " {\n";
     code += "  bb: flatbuffers.ByteBuffer|null = null;\n";
     code += "  bb_pos = 0;\n";
 
@@ -1337,9 +1559,16 @@
          it != struct_def.fields.vec.end(); ++it) {
       auto &field = **it;
       if (field.deprecated) continue;
-      auto offset_prefix =
-          "  const offset = " + GenBBAccess() + ".__offset(this.bb_pos, " +
-          NumToString(field.value.offset) + ");\n  return offset ? ";
+      std::string offset_prefix = "";
+
+      if (field.value.type.base_type == BASE_TYPE_ARRAY) {
+        offset_prefix = "    return ";
+      } else {
+        offset_prefix = "  const offset = " + GenBBAccess() +
+                        ".__offset(this.bb_pos, " +
+                        NumToString(field.value.offset) + ");\n";
+        offset_prefix += "  return offset ? ";
+      }
 
       // Emit a scalar field
       const auto is_string = IsString(field.value.type);
@@ -1379,9 +1608,11 @@
         } else {
           std::string index = "this.bb_pos + offset";
           if (is_string) { index += ", optionalEncoding"; }
-          code += offset_prefix +
-                  GenGetter(field.value.type, "(" + index + ")") + " : " +
-                  GenDefaultValue(field, imports);
+          code +=
+              offset_prefix + GenGetter(field.value.type, "(" + index + ")");
+          if (field.value.type.base_type != BASE_TYPE_ARRAY) {
+            code += " : " + GenDefaultValue(field, imports);
+          }
           code += ";\n";
         }
       }
@@ -1414,6 +1645,95 @@
             break;
           }
 
+          case BASE_TYPE_ARRAY: {
+            auto vectortype = field.value.type.VectorType();
+            auto vectortypename =
+                GenTypeName(imports, struct_def, vectortype, false);
+            auto inline_size = InlineSize(vectortype);
+            auto index = "this.bb_pos + " + NumToString(field.value.offset) +
+                         " + index" + MaybeScale(inline_size);
+            std::string ret_type;
+            bool is_union = false;
+            switch (vectortype.base_type) {
+              case BASE_TYPE_STRUCT: ret_type = vectortypename; break;
+              case BASE_TYPE_STRING: ret_type = vectortypename; break;
+              case BASE_TYPE_UNION:
+                ret_type = "?flatbuffers.Table";
+                is_union = true;
+                break;
+              default: ret_type = vectortypename;
+            }
+            GenDocComment(field.doc_comment, code_ptr);
+            std::string prefix = namer_.Method(field);
+            // TODO: make it work without any
+            // if (is_union) { prefix += "<T extends flatbuffers.Table>"; }
+            if (is_union) { prefix += ""; }
+            prefix += "(index: number";
+            if (is_union) {
+              const auto union_type =
+                  GenUnionGenericTypeTS(*(field.value.type.enum_def));
+
+              vectortypename = union_type;
+              code += prefix + ", obj:" + union_type;
+            } else if (vectortype.base_type == BASE_TYPE_STRUCT) {
+              code += prefix + ", obj?:" + vectortypename;
+            } else if (IsString(vectortype)) {
+              code += prefix + "):string\n";
+              code += prefix + ",optionalEncoding:flatbuffers.Encoding" +
+                      "):" + vectortypename + "\n";
+              code += prefix + ",optionalEncoding?:any";
+            } else {
+              code += prefix;
+            }
+            code += "):" + vectortypename + "|null {\n";
+
+            if (vectortype.base_type == BASE_TYPE_STRUCT) {
+              code += offset_prefix + "(obj || " +
+                      GenerateNewExpression(vectortypename);
+              code += ").__init(";
+              code += vectortype.struct_def->fixed
+                          ? index
+                          : GenBBAccess() + ".__indirect(" + index + ")";
+              code += ", " + GenBBAccess() + ")";
+            } else {
+              if (is_union) {
+                index = "obj, " + index;
+              } else if (IsString(vectortype)) {
+                index += ", optionalEncoding";
+              }
+              code += offset_prefix + GenGetter(vectortype, "(" + index + ")");
+            }
+
+            switch (field.value.type.base_type) {
+              case BASE_TYPE_ARRAY: {
+                break;
+              }
+              case BASE_TYPE_BOOL: {
+                code += " : false";
+                break;
+              }
+              case BASE_TYPE_LONG:
+              case BASE_TYPE_ULONG: {
+                code += " : BigInt(0)";
+                break;
+              }
+              default: {
+                if (IsScalar(field.value.type.element)) {
+                  if (field.value.type.enum_def) {
+                    code += field.value.constant;
+                  } else {
+                    code += " : 0";
+                  }
+                } else {
+                  code += ": null";
+                }
+                break;
+              }
+            }
+            code += ";\n";
+            break;
+          }
+
           case BASE_TYPE_VECTOR: {
             auto vectortype = field.value.type.VectorType();
             auto vectortypename =
diff --git a/third_party/flatbuffers/src/idl_parser.cpp b/third_party/flatbuffers/src/idl_parser.cpp
index 524c996..48d0f07 100644
--- a/third_party/flatbuffers/src/idl_parser.cpp
+++ b/third_party/flatbuffers/src/idl_parser.cpp
@@ -507,6 +507,8 @@
       case ')':
       case '[':
       case ']':
+      case '<':
+      case '>':
       case ',':
       case ':':
       case ';':
@@ -1584,7 +1586,6 @@
   return NoError();
 }
 
-
 CheckedError Parser::ParseAlignAttribute(const std::string &align_constant,
                                          size_t min_align, size_t *align) {
   // Use uint8_t to avoid problems with size_t==`unsigned long` on LP64.
@@ -1614,6 +1615,7 @@
   });
   ECHECK(err);
 
+  const size_t alignment = InlineAlignment(type);
   const size_t len = count * InlineSize(type) / InlineAlignment(type);
   const size_t elemsize = InlineAlignment(type);
   const auto force_align = field->attributes.Lookup("force_align");
@@ -1623,7 +1625,8 @@
     if (align > 1) { builder_.ForceVectorAlignment(len, elemsize, align); }
   }
 
-  builder_.StartVector(len, elemsize);
+  // TODO Fix using element alignment as size (`elemsize`)!
+  builder_.StartVector(len, elemsize, alignment);
   for (uoffset_t i = 0; i < count; i++) {
     // start at the back, since we're building the data backwards.
     auto &val = field_stack_.back().first;
@@ -2448,14 +2451,17 @@
         EXPECT(kTokenIntegerConstant);
       }
 
-      ECHECK(evb.AcceptEnumerator());
-
       if (opts.proto_mode && Is('[')) {
         NEXT();
         // ignore attributes on enums.
         while (token_ != ']') NEXT();
         NEXT();
+      } else {
+        // parse attributes in fbs schema
+        ECHECK(ParseMetaData(&ev.attributes));
       }
+
+      ECHECK(evb.AcceptEnumerator());
     }
     if (!Is(opts.proto_mode ? ';' : ',')) break;
     NEXT();
@@ -2550,7 +2556,8 @@
       IDLOptions::kRust | IDLOptions::kSwift | IDLOptions::kLobster |
       IDLOptions::kKotlin | IDLOptions::kCpp | IDLOptions::kJava |
       IDLOptions::kCSharp | IDLOptions::kTs | IDLOptions::kBinary |
-      IDLOptions::kGo | IDLOptions::kPython | IDLOptions::kJson;
+      IDLOptions::kGo | IDLOptions::kPython | IDLOptions::kJson |
+      IDLOptions::kNim;
   unsigned long langs = opts.lang_to_generate;
   return (langs > 0 && langs < IDLOptions::kMAX) && !(langs & ~supported_langs);
 }
@@ -2561,7 +2568,7 @@
 
 bool Parser::SupportsDefaultVectorsAndStrings() const {
   static FLATBUFFERS_CONSTEXPR unsigned long supported_langs =
-      IDLOptions::kRust | IDLOptions::kSwift;
+      IDLOptions::kRust | IDLOptions::kSwift | IDLOptions::kNim;
   return !(opts.lang_to_generate & ~supported_langs);
 }
 
@@ -2569,14 +2576,14 @@
   return (opts.lang_to_generate &
           ~(IDLOptions::kCpp | IDLOptions::kTs | IDLOptions::kPhp |
             IDLOptions::kJava | IDLOptions::kCSharp | IDLOptions::kKotlin |
-            IDLOptions::kBinary | IDLOptions::kSwift)) == 0;
+            IDLOptions::kBinary | IDLOptions::kSwift | IDLOptions::kNim)) == 0;
 }
 
 bool Parser::SupportsAdvancedArrayFeatures() const {
   return (opts.lang_to_generate &
           ~(IDLOptions::kCpp | IDLOptions::kPython | IDLOptions::kJava |
             IDLOptions::kCSharp | IDLOptions::kJsonSchema | IDLOptions::kJson |
-            IDLOptions::kBinary | IDLOptions::kRust)) == 0;
+            IDLOptions::kBinary | IDLOptions::kRust | IDLOptions::kTs)) == 0;
 }
 
 Namespace *Parser::UniqueNamespace(Namespace *ns) {
@@ -2891,6 +2898,8 @@
       NEXT();
       while (!Is(';')) { NEXT(); }  // A variety of formats, just skip.
       NEXT();
+    } else if (IsIdent("map")) {
+      ECHECK(ParseProtoMapField(struct_def));
     } else {
       std::vector<std::string> field_comment = doc_comment_;
       // Parse the qualifier.
@@ -3025,6 +3034,41 @@
   return NoError();
 }
 
+CheckedError Parser::ParseProtoMapField(StructDef *struct_def) {
+  NEXT();
+  EXPECT('<');
+  Type key_type;
+  ECHECK(ParseType(key_type));
+  EXPECT(',');
+  Type value_type;
+  ECHECK(ParseType(value_type));
+  EXPECT('>');
+  auto field_name = attribute_;
+  NEXT();
+  EXPECT('=');
+  EXPECT(kTokenIntegerConstant);
+  EXPECT(';');
+
+  auto entry_table_name = ConvertCase(field_name, Case::kUpperCamel) + "Entry";
+  StructDef *entry_table;
+  ECHECK(StartStruct(entry_table_name, &entry_table));
+  entry_table->has_key = true;
+  FieldDef *key_field;
+  ECHECK(AddField(*entry_table, "key", key_type, &key_field));
+  key_field->key = true;
+  FieldDef *value_field;
+  ECHECK(AddField(*entry_table, "value", value_type, &value_field));
+
+  Type field_type;
+  field_type.base_type = BASE_TYPE_VECTOR;
+  field_type.element = BASE_TYPE_STRUCT;
+  field_type.struct_def = entry_table;
+  FieldDef *field;
+  ECHECK(AddField(*struct_def, field_name, field_type, &field));
+
+  return NoError();
+}
+
 CheckedError Parser::ParseProtoKey() {
   if (token_ == '(') {
     NEXT();
@@ -3259,6 +3303,10 @@
   return done;
 }
 
+std::ptrdiff_t Parser::BytesConsumed() const {
+  return std::distance(source_, cursor_);
+}
+
 CheckedError Parser::StartParseFile(const char *source,
                                     const char *source_filename) {
   file_being_parsed_ = source_filename ? source_filename : "";
@@ -3413,7 +3461,6 @@
   return NoError();
 }
 
-
 CheckedError Parser::DoParse(const char *source, const char **include_paths,
                              const char *source_filename,
                              const char *include_filename) {
@@ -3601,9 +3648,11 @@
                                                : nullptr);
     }
   }
-  // Check that JSON file doesn't contain more objects or IDL directives.
-  // Comments after JSON are allowed.
-  EXPECT(kTokenEof);
+  if (opts.require_json_eof) {
+    // Check that JSON file doesn't contain more objects or IDL directives.
+    // Comments after JSON are allowed.
+    EXPECT(kTokenEof);
+  }
   return NoError();
 }
 
@@ -3635,6 +3684,44 @@
 
 // Schema serialization functionality:
 
+static flatbuffers::Offset<
+    flatbuffers::Vector<flatbuffers::Offset<reflection::KeyValue>>>
+SerializeAttributesCommon(const SymbolTable<Value> &attributes,
+                          FlatBufferBuilder *builder, const Parser &parser) {
+  std::vector<flatbuffers::Offset<reflection::KeyValue>> attrs;
+  for (auto kv = attributes.dict.begin(); kv != attributes.dict.end(); ++kv) {
+    auto it = parser.known_attributes_.find(kv->first);
+    FLATBUFFERS_ASSERT(it != parser.known_attributes_.end());
+    if (parser.opts.binary_schema_builtins || !it->second) {
+      auto key = builder->CreateString(kv->first);
+      auto val = builder->CreateString(kv->second->constant);
+      attrs.push_back(reflection::CreateKeyValue(*builder, key, val));
+    }
+  }
+  if (attrs.size()) {
+    return builder->CreateVectorOfSortedTables(&attrs);
+  } else {
+    return 0;
+  }
+}
+
+static bool DeserializeAttributesCommon(
+    SymbolTable<Value> &attributes, Parser &parser,
+    const Vector<Offset<reflection::KeyValue>> *attrs) {
+  if (attrs == nullptr) return true;
+  for (uoffset_t i = 0; i < attrs->size(); ++i) {
+    auto kv = attrs->Get(i);
+    auto value = new Value();
+    if (kv->value()) { value->constant = kv->value()->str(); }
+    if (attributes.Add(kv->key()->str(), value)) {
+      delete value;
+      return false;
+    }
+    parser.known_attributes_[kv->key()->str()];
+  }
+  return true;
+}
+
 void Parser::Serialize() {
   builder_.Clear();
   AssignIndices(structs_.vec);
@@ -3927,32 +4014,52 @@
   return true;
 }
 
-Offset<reflection::EnumVal> EnumVal::Serialize(FlatBufferBuilder *builder,
-                                               const Parser &parser) const {
-  auto name__ = builder->CreateString(name);
-  auto type__ = union_type.Serialize(builder);
-  auto docs__ = parser.opts.binary_schema_comments
-                    ? builder->CreateVectorOfStrings(doc_comment)
-                    : 0;
-  return reflection::CreateEnumVal(*builder, name__, value, type__, docs__);
+flatbuffers::Offset<
+    flatbuffers::Vector<flatbuffers::Offset<reflection::KeyValue>>>
+EnumVal::SerializeAttributes(FlatBufferBuilder *builder,
+                             const Parser &parser) const {
+  return SerializeAttributesCommon(attributes, builder, parser);
 }
 
-bool EnumVal::Deserialize(const Parser &parser,
-                          const reflection::EnumVal *val) {
+bool EnumVal::DeserializeAttributes(
+    Parser &parser, const Vector<Offset<reflection::KeyValue>> *attrs) {
+  return DeserializeAttributesCommon(attributes, parser, attrs);
+}
+
+Offset<reflection::EnumVal> EnumVal::Serialize(FlatBufferBuilder *builder,
+                                               const Parser &parser) const {
+  const auto name__ = builder->CreateString(name);
+  const auto type__ = union_type.Serialize(builder);
+  const auto attr__ = SerializeAttributes(builder, parser);
+  const auto docs__ = parser.opts.binary_schema_comments
+                          ? builder->CreateVectorOfStrings(doc_comment)
+                          : 0;
+  return reflection::CreateEnumVal(*builder, name__, value, type__, docs__,
+                                   attr__);
+}
+
+bool EnumVal::Deserialize(Parser &parser, const reflection::EnumVal *val) {
   name = val->name()->str();
   value = val->value();
   if (!union_type.Deserialize(parser, val->union_type())) return false;
+  if (!DeserializeAttributes(parser, val->attributes())) return false;
   DeserializeDoc(doc_comment, val->documentation());
   return true;
 }
 
 Offset<reflection::Type> Type::Serialize(FlatBufferBuilder *builder) const {
+  size_t element_size = SizeOf(element);
+  if (base_type == BASE_TYPE_VECTOR && element == BASE_TYPE_STRUCT &&
+      struct_def->bytesize != 0) {
+    // struct_def->bytesize==0 means struct is table
+    element_size = struct_def->bytesize;
+  }
   return reflection::CreateType(
       *builder, static_cast<reflection::BaseType>(base_type),
       static_cast<reflection::BaseType>(element),
       struct_def ? struct_def->index : (enum_def ? enum_def->index : -1),
       fixed_length, static_cast<uint32_t>(SizeOf(base_type)),
-      static_cast<uint32_t>(SizeOf(element)));
+      static_cast<uint32_t>(element_size));
 }
 
 bool Type::Deserialize(const Parser &parser, const reflection::Type *type) {
@@ -3986,37 +4093,12 @@
     flatbuffers::Vector<flatbuffers::Offset<reflection::KeyValue>>>
 Definition::SerializeAttributes(FlatBufferBuilder *builder,
                                 const Parser &parser) const {
-  std::vector<flatbuffers::Offset<reflection::KeyValue>> attrs;
-  for (auto kv = attributes.dict.begin(); kv != attributes.dict.end(); ++kv) {
-    auto it = parser.known_attributes_.find(kv->first);
-    FLATBUFFERS_ASSERT(it != parser.known_attributes_.end());
-    if (parser.opts.binary_schema_builtins || !it->second) {
-      auto key = builder->CreateString(kv->first);
-      auto val = builder->CreateString(kv->second->constant);
-      attrs.push_back(reflection::CreateKeyValue(*builder, key, val));
-    }
-  }
-  if (attrs.size()) {
-    return builder->CreateVectorOfSortedTables(&attrs);
-  } else {
-    return 0;
-  }
+  return SerializeAttributesCommon(attributes, builder, parser);
 }
 
 bool Definition::DeserializeAttributes(
     Parser &parser, const Vector<Offset<reflection::KeyValue>> *attrs) {
-  if (attrs == nullptr) return true;
-  for (uoffset_t i = 0; i < attrs->size(); ++i) {
-    auto kv = attrs->Get(i);
-    auto value = new Value();
-    if (kv->value()) { value->constant = kv->value()->str(); }
-    if (attributes.Add(kv->key()->str(), value)) {
-      delete value;
-      return false;
-    }
-    parser.known_attributes_[kv->key()->str()];
-  }
-  return true;
+  return DeserializeAttributesCommon(attributes, parser, attrs);
 }
 
 /************************************************************************/
@@ -4131,17 +4213,19 @@
         struct_def.defined_namespace->GetFullyQualifiedName(struct_def.name);
     auto struct_def_base = base.LookupStruct(qualified_name);
     if (!struct_def_base) continue;
+    std::set<FieldDef *> renamed_fields;
     for (auto fit = struct_def.fields.vec.begin();
          fit != struct_def.fields.vec.end(); ++fit) {
       auto &field = **fit;
       auto field_base = struct_def_base->fields.Lookup(field.name);
+      const auto qualified_field_name = qualified_name + "." + field.name;
       if (field_base) {
         if (field.value.offset != field_base->value.offset)
-          return "offsets differ for field: " + field.name;
+          return "offsets differ for field: " + qualified_field_name;
         if (field.value.constant != field_base->value.constant)
-          return "defaults differ for field: " + field.name;
+          return "defaults differ for field: " + qualified_field_name;
         if (!EqualByName(field.value.type, field_base->value.type))
-          return "types differ for field: " + field.name;
+          return "types differ for field: " + qualified_field_name;
       } else {
         // Doesn't have to exist, deleting fields is fine.
         // But we should check if there is a field that has the same offset
@@ -4150,14 +4234,28 @@
              fbit != struct_def_base->fields.vec.end(); ++fbit) {
           field_base = *fbit;
           if (field.value.offset == field_base->value.offset) {
+            renamed_fields.insert(field_base);
             if (!EqualByName(field.value.type, field_base->value.type))
-              return "field renamed to different type: " + field.name;
+              return "field renamed to different type: " + qualified_field_name;
             break;
           }
         }
       }
     }
+    // deletion of trailing fields are not allowed
+    for (auto fit = struct_def_base->fields.vec.begin();
+         fit != struct_def_base->fields.vec.end(); ++fit) {
+      auto &field_base = **fit;
+      // not a renamed field
+      if (renamed_fields.find(&field_base) == renamed_fields.end()) {
+        auto field = struct_def.fields.Lookup(field_base.name);
+        if (!field) {
+          return "field deleted: " + qualified_name + "." + field_base.name;
+        }
+      }
+    }
   }
+
   for (auto eit = enums_.vec.begin(); eit != enums_.vec.end(); ++eit) {
     auto &enum_def = **eit;
     auto qualified_name =
diff --git a/third_party/flatbuffers/src/reflection.cpp b/third_party/flatbuffers/src/reflection.cpp
index 7549859..5ddff63 100644
--- a/third_party/flatbuffers/src/reflection.cpp
+++ b/third_party/flatbuffers/src/reflection.cpp
@@ -689,9 +689,10 @@
             FLATBUFFERS_FALLTHROUGH();  // fall thru
           default: {                    // Scalars and structs.
             auto element_size = GetTypeSize(element_base_type);
+            auto element_alignment = element_size; // For primitive elements
             if (elemobjectdef && elemobjectdef->is_struct())
               element_size = elemobjectdef->bytesize();
-            fbb.StartVector(vec->size(), element_size);
+            fbb.StartVector(vec->size(), element_size, element_alignment);
             fbb.PushBytes(vec->Data(), element_size * vec->size());
             offset = fbb.EndVector(vec->size());
             break;
diff --git a/third_party/flatbuffers/src/util.cpp b/third_party/flatbuffers/src/util.cpp
index df324e8..aabc23a 100644
--- a/third_party/flatbuffers/src/util.cpp
+++ b/third_party/flatbuffers/src/util.cpp
@@ -109,7 +109,7 @@
     } else if (!islower(input[i])) {
       // Prevent duplicate underscores for Upper_Snake_Case strings
       // and UPPERCASE strings.
-      if (islower(input[i - 1])) { s += '_'; }
+      if (islower(input[i - 1]) || (isdigit(input[i-1]) && !isdigit(input[i]))) { s += '_'; }
       s += screaming ? CharToUpper(input[i]) : CharToLower(input[i]);
     } else {
       s += screaming ? CharToUpper(input[i]) : input[i];
@@ -135,7 +135,7 @@
     } else if (!islower(input[i])) {
       // Prevent duplicate underscores for Upper_Snake_Case strings
       // and UPPERCASE strings.
-      if (islower(input[i - 1])) { s += '_'; }
+      if (islower(input[i - 1]) || (isdigit(input[i-1]) && !isdigit(input[i]))) { s += '_'; }
       s += CharToLower(input[i]);
     } else {
       s += input[i];