[Python/JS/TS] Codegen SizeOf method for structs (#6136)

* [Python] Codegen SizeOf classmethod for structs

This codegens a `SizeOf()` classmethod for all structs since we can't
determine the size of a FlatBuffer generated struct from Python otherwise.

* [JS/TS] Codegen sizeOf static method for structs

This codegens a `sizeOf()` static method for all structs since we can't
determine the size of a FlatBuffer generated struct from JavaScript or
TypeScript otherwise.
diff --git a/src/idl_gen_js_ts.cpp b/src/idl_gen_js_ts.cpp
index 8be06df..02b85bd 100644
--- a/src/idl_gen_js_ts.cpp
+++ b/src/idl_gen_js_ts.cpp
@@ -1795,6 +1795,18 @@
       code += "}\n\n";
     }
 
+    // Emit the size of the struct.
+    if (struct_def.fixed) {
+      GenDocComment(code_ptr, GenTypeAnnotation(kReturns, "number", "", false));
+      if (lang_.language == IDLOptions::kTs) {
+        code += "static sizeOf():number {\n";
+      } else {
+        code += object_name + ".sizeOf = function() {\n";
+      }
+      code += "  return " + NumToString(struct_def.bytesize) + ";\n";
+      code += "}\n\n";
+    }
+
     // Emit a factory constructor
     if (struct_def.fixed) {
       std::string annotations =
diff --git a/src/idl_gen_python.cpp b/src/idl_gen_python.cpp
index c64357e..95b4490 100644
--- a/src/idl_gen_python.cpp
+++ b/src/idl_gen_python.cpp
@@ -621,6 +621,16 @@
     }
   }
 
+  // Generate struct sizeof.
+  void GenStructSizeOf(const StructDef &struct_def, std::string *code_ptr) {
+    auto &code = *code_ptr;
+    code += Indent + "@classmethod\n";
+    code += Indent + "def SizeOf(cls):\n";
+    code +=
+        Indent + Indent + "return " + NumToString(struct_def.bytesize) + "\n";
+    code += "\n";
+  }
+
   // Generate table constructors, conditioned on its members' types.
   void GenTableBuilders(const StructDef &struct_def, std::string *code_ptr) {
     GetStartOfTable(struct_def, code_ptr);
@@ -678,6 +688,9 @@
         // Generate a special function to test file_identifier
         GenHasFileIdentifier(struct_def, code_ptr);
       }
+    } else {
+      // Generates the SizeOf method for all structs.
+      GenStructSizeOf(struct_def, code_ptr);
     }
     // Generates the Init method that sets the field in a pre-existing
     // accessor object. This is to allow object reuse.
diff --git a/tests/MyGame/Example/Ability.py b/tests/MyGame/Example/Ability.py
index 2cc916b..e57dfd7 100644
--- a/tests/MyGame/Example/Ability.py
+++ b/tests/MyGame/Example/Ability.py
@@ -9,6 +9,10 @@
 class Ability(object):
     __slots__ = ['_tab']
 
+    @classmethod
+    def SizeOf(cls):
+        return 8
+
     # Ability
     def Init(self, buf, pos):
         self._tab = flatbuffers.table.Table(buf, pos)
diff --git a/tests/MyGame/Example/ArrayStruct.py b/tests/MyGame/Example/ArrayStruct.py
index 50f136d..c80bf68 100644
--- a/tests/MyGame/Example/ArrayStruct.py
+++ b/tests/MyGame/Example/ArrayStruct.py
@@ -9,6 +9,10 @@
 class ArrayStruct(object):
     __slots__ = ['_tab']
 
+    @classmethod
+    def SizeOf(cls):
+        return 160
+
     # ArrayStruct
     def Init(self, buf, pos):
         self._tab = flatbuffers.table.Table(buf, pos)
diff --git a/tests/MyGame/Example/NestedStruct.py b/tests/MyGame/Example/NestedStruct.py
index a66cee0..a9db014 100644
--- a/tests/MyGame/Example/NestedStruct.py
+++ b/tests/MyGame/Example/NestedStruct.py
@@ -9,6 +9,10 @@
 class NestedStruct(object):
     __slots__ = ['_tab']
 
+    @classmethod
+    def SizeOf(cls):
+        return 32
+
     # NestedStruct
     def Init(self, buf, pos):
         self._tab = flatbuffers.table.Table(buf, pos)
diff --git a/tests/MyGame/Example/Test.py b/tests/MyGame/Example/Test.py
index 576a656..8357ec2 100644
--- a/tests/MyGame/Example/Test.py
+++ b/tests/MyGame/Example/Test.py
@@ -9,6 +9,10 @@
 class Test(object):
     __slots__ = ['_tab']
 
+    @classmethod
+    def SizeOf(cls):
+        return 4
+
     # Test
     def Init(self, buf, pos):
         self._tab = flatbuffers.table.Table(buf, pos)
diff --git a/tests/MyGame/Example/Vec3.py b/tests/MyGame/Example/Vec3.py
index 5c91a7d..69cd511 100644
--- a/tests/MyGame/Example/Vec3.py
+++ b/tests/MyGame/Example/Vec3.py
@@ -9,6 +9,10 @@
 class Vec3(object):
     __slots__ = ['_tab']
 
+    @classmethod
+    def SizeOf(cls):
+        return 32
+
     # Vec3
     def Init(self, buf, pos):
         self._tab = flatbuffers.table.Table(buf, pos)
diff --git a/tests/monster_test_generated.js b/tests/monster_test_generated.js
index fedc2c0..bab8547 100644
--- a/tests/monster_test_generated.js
+++ b/tests/monster_test_generated.js
@@ -343,6 +343,13 @@
 };
 
 /**
+ * @returns {number}
+ */
+MyGame.Example.Test.sizeOf = function() {
+  return 4;
+}
+
+/**
  * @param {flatbuffers.Builder} builder
  * @param {number} a
  * @param {number} b
@@ -574,6 +581,13 @@
 };
 
 /**
+ * @returns {number}
+ */
+MyGame.Example.Vec3.sizeOf = function() {
+  return 32;
+}
+
+/**
  * @param {flatbuffers.Builder} builder
  * @param {number} x
  * @param {number} y
@@ -660,6 +674,13 @@
 };
 
 /**
+ * @returns {number}
+ */
+MyGame.Example.Ability.sizeOf = function() {
+  return 8;
+}
+
+/**
  * @param {flatbuffers.Builder} builder
  * @param {number} id
  * @param {number} distance
diff --git a/tests/monster_test_generated.ts b/tests/monster_test_generated.ts
index afdaeab..9ba7254 100644
--- a/tests/monster_test_generated.ts
+++ b/tests/monster_test_generated.ts
@@ -377,6 +377,13 @@
 };
 
 /**
+ * @returns number
+ */
+static sizeOf():number {
+  return 4;
+}
+
+/**
  * @param flatbuffers.Builder builder
  * @param number a
  * @param number b
@@ -669,6 +676,13 @@
 };
 
 /**
+ * @returns number
+ */
+static sizeOf():number {
+  return 32;
+}
+
+/**
  * @param flatbuffers.Builder builder
  * @param number x
  * @param number y
@@ -812,6 +826,13 @@
 };
 
 /**
+ * @returns number
+ */
+static sizeOf():number {
+  return 8;
+}
+
+/**
  * @param flatbuffers.Builder builder
  * @param number id
  * @param number distance
diff --git a/tests/namespace_test/NamespaceA/NamespaceB/StructInNestedNS.py b/tests/namespace_test/NamespaceA/NamespaceB/StructInNestedNS.py
index 9df52bd..f49495b 100644
--- a/tests/namespace_test/NamespaceA/NamespaceB/StructInNestedNS.py
+++ b/tests/namespace_test/NamespaceA/NamespaceB/StructInNestedNS.py
@@ -9,6 +9,10 @@
 class StructInNestedNS(object):
     __slots__ = ['_tab']
 
+    @classmethod
+    def SizeOf(cls):
+        return 8
+
     # StructInNestedNS
     def Init(self, buf, pos):
         self._tab = flatbuffers.table.Table(buf, pos)
diff --git a/tests/namespace_test/namespace_test1_generated.js b/tests/namespace_test/namespace_test1_generated.js
index fe1c0a7..7331f64 100644
--- a/tests/namespace_test/namespace_test1_generated.js
+++ b/tests/namespace_test/namespace_test1_generated.js
@@ -206,6 +206,13 @@
 }
 
 /**
+ * @returns {number}
+ */
+NamespaceA.NamespaceB.StructInNestedNS.sizeOf = function() {
+  return 8;
+}
+
+/**
  * @param {flatbuffers.Builder} builder
  * @param {number} a
  * @param {number} b
diff --git a/tests/namespace_test/namespace_test1_generated.ts b/tests/namespace_test/namespace_test1_generated.ts
index 47f8942..933a43d 100644
--- a/tests/namespace_test/namespace_test1_generated.ts
+++ b/tests/namespace_test/namespace_test1_generated.ts
@@ -205,6 +205,13 @@
 }
 
 /**
+ * @returns number
+ */
+static sizeOf():number {
+  return 8;
+}
+
+/**
  * @param flatbuffers.Builder builder
  * @param number a
  * @param number b
diff --git a/tests/union_vector/union_vector_generated.js b/tests/union_vector/union_vector_generated.js
index 01f883c..9e8b76e 100644
--- a/tests/union_vector/union_vector_generated.js
+++ b/tests/union_vector/union_vector_generated.js
@@ -186,6 +186,13 @@
 }
 
 /**
+ * @returns {number}
+ */
+Rapunzel.sizeOf = function() {
+  return 4;
+}
+
+/**
  * @param {flatbuffers.Builder} builder
  * @param {number} hair_length
  * @returns {flatbuffers.Offset}
@@ -246,6 +253,13 @@
 }
 
 /**
+ * @returns {number}
+ */
+BookReader.sizeOf = function() {
+  return 4;
+}
+
+/**
  * @param {flatbuffers.Builder} builder
  * @param {number} books_read
  * @returns {flatbuffers.Offset}
diff --git a/tests/union_vector/union_vector_generated.ts b/tests/union_vector/union_vector_generated.ts
index eb74fcb..806c07f 100644
--- a/tests/union_vector/union_vector_generated.ts
+++ b/tests/union_vector/union_vector_generated.ts
@@ -222,6 +222,13 @@
 }
 
 /**
+ * @returns number
+ */
+static sizeOf():number {
+  return 4;
+}
+
+/**
  * @param flatbuffers.Builder builder
  * @param number hair_length
  * @returns flatbuffers.Offset
@@ -311,6 +318,13 @@
 }
 
 /**
+ * @returns number
+ */
+static sizeOf():number {
+  return 4;
+}
+
+/**
  * @param flatbuffers.Builder builder
  * @param number books_read
  * @returns flatbuffers.Offset