Add support of Optional<T> scalars to C++ code generator (#6092)
authorVladimir Glavnyy <31897320+vglavnyy@users.noreply.github.com>
Fri, 18 Sep 2020 19:51:17 +0000 (02:51 +0700)
committerGitHub <noreply@github.com>
Fri, 18 Sep 2020 19:51:17 +0000 (12:51 -0700)
19 files changed:
CMakeLists.txt
include/flatbuffers/base.h
include/flatbuffers/flatbuffers.h
include/flatbuffers/idl.h
include/flatbuffers/stl_emulation.h
include/flatbuffers/util.h
src/idl_gen_cpp.cpp
src/idl_parser.cpp
tests/BUILD
tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/optional_scalars_generated.swift
tests/cpp17/generated_cpp17/optional_scalars_generated.h [new file with mode: 0644]
tests/cpp17/test_cpp17.cpp
tests/generate_code.bat
tests/generate_code.sh
tests/optional_scalars.fbs
tests/optional_scalars_generated.h [new file with mode: 0644]
tests/optional_scalars_generated.lobster
tests/optional_scalars_generated.rs
tests/test.cpp

index 9201d67..ca06af4 100644 (file)
@@ -158,6 +158,8 @@ set(FlatBuffers_Tests_SRCS
   ${CMAKE_CURRENT_BINARY_DIR}/tests/monster_extra_generated.h
   # file generate by running compiler on tests/monster_test.fbs
   ${CMAKE_CURRENT_BINARY_DIR}/tests/monster_test_bfbs_generated.h
+  # file generate by running compiler on tests/optional_scalars.fbs
+  ${CMAKE_CURRENT_BINARY_DIR}/tests/optional_scalars_generated.h
 )
 
 set(FlatBuffers_Tests_CPP17_SRCS
@@ -168,6 +170,8 @@ set(FlatBuffers_Tests_CPP17_SRCS
   # file generate by running compiler on tests/monster_test.fbs
   ${CMAKE_CURRENT_BINARY_DIR}/tests/cpp17/generated_cpp17/monster_test_generated.h
   ${CMAKE_CURRENT_BINARY_DIR}/tests/monster_test_generated.h
+  ${CMAKE_CURRENT_BINARY_DIR}/tests/cpp17/generated_cpp17/optional_scalars_generated.h
+  ${CMAKE_CURRENT_BINARY_DIR}/tests/optional_scalars_generated.h
 )
 
 set(FlatBuffers_Sample_Binary_SRCS
index d83c775..8e97c08 100644 (file)
 #include <memory>
 
 #if defined(__unix__) && !defined(FLATBUFFERS_LOCALE_INDEPENDENT)
-#include <unistd.h>
-#endif 
+  #include <unistd.h>
+#endif
 
 #ifdef _STLPORT_VERSION
   #define FLATBUFFERS_CPP98_STL
 #endif
-#ifndef FLATBUFFERS_CPP98_STL
-  #include <functional>
-#endif
 
 #ifdef __ANDROID__
   #include <android/api-level.h>
 #endif
 
-#include "flatbuffers/stl_emulation.h"
-
 #if defined(__ICCARM__)
 #include <intrinsics.h>
 #endif
@@ -162,10 +157,12 @@ namespace flatbuffers {
     defined(__clang__)
   #define FLATBUFFERS_FINAL_CLASS final
   #define FLATBUFFERS_OVERRIDE override
+  #define FLATBUFFERS_EXPLICIT_CPP11 explicit
   #define FLATBUFFERS_VTABLE_UNDERLYING_TYPE : flatbuffers::voffset_t
 #else
   #define FLATBUFFERS_FINAL_CLASS
   #define FLATBUFFERS_OVERRIDE
+  #define FLATBUFFERS_EXPLICIT_CPP11
   #define FLATBUFFERS_VTABLE_UNDERLYING_TYPE
 #endif
 
@@ -173,10 +170,14 @@ namespace flatbuffers {
     (!defined(__GNUC__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 406)) || \
     (defined(__cpp_constexpr) && __cpp_constexpr >= 200704)
   #define FLATBUFFERS_CONSTEXPR constexpr
+  #define FLATBUFFERS_CONSTEXPR_CPP11 constexpr
+  #define FLATBUFFERS_CONSTEXPR_DEFINED
 #else
   #define FLATBUFFERS_CONSTEXPR const
+  #define FLATBUFFERS_CONSTEXPR_CPP11
 #endif
 
+// This macro is never used in code!
 #if (defined(__cplusplus) && __cplusplus >= 201402L) || \
     (defined(__cpp_constexpr) && __cpp_constexpr >= 201304)
   #define FLATBUFFERS_CONSTEXPR_CPP14 FLATBUFFERS_CONSTEXPR
@@ -202,6 +203,16 @@ namespace flatbuffers {
   #define FLATBUFFERS_DELETE_FUNC(func) private: func;
 #endif
 
+// Check if we can use template aliases
+// Not possible if Microsoft Compiler before 2012
+// Possible is the language feature __cpp_alias_templates is defined well
+// Or possible if the C++ std is C+11 or newer
+#if (defined(_MSC_VER) && _MSC_VER > 1700 /* MSVC2012 */) \
+    || (defined(__cpp_alias_templates) && __cpp_alias_templates >= 200704) \
+    || (defined(__cplusplus) && __cplusplus >= 201103L)
+  #define FLATBUFFERS_TEMPLATES_ALIASES
+#endif
+
 #ifndef FLATBUFFERS_HAS_STRING_VIEW
   // Only provide flatbuffers::string_view if __has_include can be used
   // to detect a header that provides an implementation
index 12ab68a..2844124 100644 (file)
 #define FLATBUFFERS_H_
 
 #include "flatbuffers/base.h"
+#include "flatbuffers/stl_emulation.h"
+
+#ifndef FLATBUFFERS_CPP98_STL
+  #include <functional>
+#endif
 
 #if defined(FLATBUFFERS_NAN_DEFAULTS)
 #  include <cmath>
@@ -1303,6 +1308,11 @@ class FlatBufferBuilder {
     TrackField(field, off);
   }
 
+  template<typename T> void AddElement(voffset_t field, T e) {
+    auto off = PushElement(e);
+    TrackField(field, off);
+  }
+
   template<typename T> void AddOffset(voffset_t field, Offset<T> off) {
     if (off.IsNull()) return;  // Don't store.
     AddElement(field, ReferTo(off.o), static_cast<uoffset_t>(0));
@@ -2460,12 +2470,26 @@ class Table {
     return field_offset ? reinterpret_cast<P>(p) : nullptr;
   }
 
+  template<typename Raw, typename Face>
+  flatbuffers::Optional<Face> GetOptional(voffset_t field) const {
+    auto field_offset = GetOptionalFieldOffset(field);
+    auto p = data_ + field_offset;
+    return field_offset ? Optional<Face>(static_cast<Face>(ReadScalar<Raw>(p)))
+                        : Optional<Face>();
+  }
+
   template<typename T> bool SetField(voffset_t field, T val, T def) {
     auto field_offset = GetOptionalFieldOffset(field);
     if (!field_offset) return IsTheSameAs(val, def);
     WriteScalar(data_ + field_offset, val);
     return true;
   }
+  template<typename T> bool SetField(voffset_t field, T val) {
+    auto field_offset = GetOptionalFieldOffset(field);
+    if (!field_offset) return false;
+    WriteScalar(data_ + field_offset, val);
+    return true;
+  }
 
   bool SetPointer(voffset_t field, const uint8_t *val) {
     auto field_offset = GetOptionalFieldOffset(field);
@@ -2533,6 +2557,17 @@ class Table {
   uint8_t data_[1];
 };
 
+// This specialization allows avoiding warnings like:
+// MSVC C4800: type: forcing value to bool 'true' or 'false'.
+template<>
+inline flatbuffers::Optional<bool> Table::GetOptional<uint8_t, bool>(
+    voffset_t field) const {
+  auto field_offset = GetOptionalFieldOffset(field);
+  auto p = data_ + field_offset;
+  return field_offset ? Optional<bool>(ReadScalar<uint8_t>(p) != 0)
+                      : Optional<bool>();
+}
+
 template<typename T>
 void FlatBufferBuilder::Required(Offset<T> table, voffset_t field) {
   auto table_ptr = reinterpret_cast<const Table *>(buf_.data_at(table.o));
index a361c65..a3c3188 100644 (file)
@@ -847,6 +847,11 @@ class Parser : public ParserState {
 
   FLATBUFFERS_CHECKED_ERROR Error(const std::string &msg);
 
+  // @brief Verify that any of 'opts.lang_to_generate' supports Optional scalars
+  // in a schema.
+  // @param opts Options used to parce a schema and generate code.
+  static bool SupportsOptionalScalars(const flatbuffers::IDLOptions &opts);
+
  private:
   void Message(const std::string &msg);
   void Warning(const std::string &msg);
index d7d655e..c9a1a8b 100644 (file)
@@ -18,6 +18,7 @@
 #define FLATBUFFERS_STL_EMULATION_H_
 
 // clang-format off
+#include "flatbuffers/base.h"
 
 #include <string>
 #include <type_traits>
 #include <memory>
 #include <limits>
 
+// Detect C++17 compatible compiler.
+// __cplusplus >= 201703L - a compiler has support of 'static inline' variables.
+#if defined(FLATBUFFERS_USE_STD_OPTIONAL) \
+    || (defined(__cplusplus) && __cplusplus >= 201703L) \
+    || (defined(_MSVC_LANG) &&  (_MSVC_LANG >= 201703L))
+  #include <optional>
+  #ifndef FLATBUFFERS_USE_STD_OPTIONAL
+    #define FLATBUFFERS_USE_STD_OPTIONAL
+  #endif
+#endif
+
 #if defined(_STLPORT_VERSION) && !defined(FLATBUFFERS_CPP98_STL)
   #define FLATBUFFERS_CPP98_STL
 #endif  // defined(_STLPORT_VERSION) && !defined(FLATBUFFERS_CPP98_STL)
   #include <cctype>
 #endif  // defined(FLATBUFFERS_CPP98_STL)
 
-// Check if we can use template aliases
-// Not possible if Microsoft Compiler before 2012
-// Possible is the language feature __cpp_alias_templates is defined well
-// Or possible if the C++ std is C+11 or newer
-#if (defined(_MSC_VER) && _MSC_VER > 1700 /* MSVC2012 */) \
-    || (defined(__cpp_alias_templates) && __cpp_alias_templates >= 200704) \
-    || (defined(__cplusplus) && __cplusplus >= 201103L)
-  #define FLATBUFFERS_TEMPLATES_ALIASES
-#endif
-
 // This header provides backwards compatibility for C++98 STLs like stlport.
 namespace flatbuffers {
 
@@ -302,6 +304,146 @@ inline void vector_emplace_back(std::vector<T> *vector, V &&data) {
 
 #endif  // !FLATBUFFERS_CPP98_STL
 
+#ifdef FLATBUFFERS_USE_STD_OPTIONAL
+template<class T>
+using Optional = std::optional<T>;
+using nullopt_t = std::nullopt_t;
+inline constexpr nullopt_t nullopt = std::nullopt;
+
+#else
+// Limited implementation of Optional<T> type for a scalar T.
+// This implementation limited by trivial types compatible with
+// std::is_arithmetic<T> or std::is_enum<T> type traits.
+
+// A tag to indicate an empty flatbuffers::optional<T>.
+struct nullopt_t {
+  explicit FLATBUFFERS_CONSTEXPR_CPP11 nullopt_t(int) {}
+};
+
+#if defined(FLATBUFFERS_CONSTEXPR_DEFINED)
+  namespace internal {
+    template <class> struct nullopt_holder {
+      static constexpr nullopt_t instance_ = nullopt_t(0);
+    };
+    template<class Dummy>
+    constexpr nullopt_t nullopt_holder<Dummy>::instance_;
+  }
+  static constexpr const nullopt_t &nullopt = internal::nullopt_holder<void>::instance_;
+
+#else
+  namespace internal {
+    template <class> struct nullopt_holder {
+      static const nullopt_t instance_;
+    };
+    template<class Dummy>
+    const nullopt_t nullopt_holder<Dummy>::instance_  = nullopt_t(0);
+  }
+  static const nullopt_t &nullopt = internal::nullopt_holder<void>::instance_;
+
+#endif
+
+template<class T>
+class Optional FLATBUFFERS_FINAL_CLASS {
+  // Non-scalar 'T' would extremely complicated Optional<T>.
+  // Use is_scalar<T> checking because flatbuffers flatbuffers::is_arithmetic<T>
+  // isn't implemented.
+  static_assert(flatbuffers::is_scalar<T>::value, "unexpected type T");
+
+ public:
+  ~Optional() {}
+
+  FLATBUFFERS_CONSTEXPR_CPP11 Optional() FLATBUFFERS_NOEXCEPT
+    : value_(), has_value_(false) {}
+
+  FLATBUFFERS_CONSTEXPR_CPP11 Optional(nullopt_t) FLATBUFFERS_NOEXCEPT
+    : value_(), has_value_(false) {}
+
+  FLATBUFFERS_CONSTEXPR_CPP11 Optional(T val) FLATBUFFERS_NOEXCEPT
+    : value_(val), has_value_(true) {}
+
+  FLATBUFFERS_CONSTEXPR_CPP11 Optional(const Optional &other) FLATBUFFERS_NOEXCEPT
+    : value_(other.value_), has_value_(other.has_value_) {}
+
+  FLATBUFFERS_CONSTEXPR_CPP14 Optional &operator=(const Optional &other) FLATBUFFERS_NOEXCEPT {
+    value_ = other.value_;
+    has_value_ = other.has_value_;
+    return *this;
+  }
+
+  FLATBUFFERS_CONSTEXPR_CPP14 Optional &operator=(nullopt_t) FLATBUFFERS_NOEXCEPT {
+    value_ = T();
+    has_value_ = false;
+    return *this;
+  }
+
+  FLATBUFFERS_CONSTEXPR_CPP14 Optional &operator=(T val) FLATBUFFERS_NOEXCEPT {
+    value_ = val;
+    has_value_ = true;
+    return *this;
+  }
+
+  void reset() FLATBUFFERS_NOEXCEPT {
+    *this = nullopt;
+  }
+
+  void swap(Optional &other) FLATBUFFERS_NOEXCEPT {
+    std::swap(value_, other.value_);
+    std::swap(has_value_, other.has_value_);
+  }
+
+  FLATBUFFERS_CONSTEXPR_CPP11 FLATBUFFERS_EXPLICIT_CPP11 operator bool() const FLATBUFFERS_NOEXCEPT {
+    return has_value_;
+  }
+
+  FLATBUFFERS_CONSTEXPR_CPP11 bool has_value() const FLATBUFFERS_NOEXCEPT {
+    return has_value_;
+  }
+
+  FLATBUFFERS_CONSTEXPR_CPP11 const T& operator*() const FLATBUFFERS_NOEXCEPT {
+    return value_;
+  }
+
+  const T& value() const {
+    FLATBUFFERS_ASSERT(has_value());
+    return value_;
+  }
+
+  T value_or(T default_value) const FLATBUFFERS_NOEXCEPT {
+    return has_value() ? value_ : default_value;
+  }
+
+ private:
+  T value_;
+  bool has_value_;
+};
+
+template<class T>
+FLATBUFFERS_CONSTEXPR_CPP11 bool operator==(const Optional<T>& opt, nullopt_t) FLATBUFFERS_NOEXCEPT {
+  return !opt;
+}
+template<class T>
+FLATBUFFERS_CONSTEXPR_CPP11 bool operator==(nullopt_t, const Optional<T>& opt) FLATBUFFERS_NOEXCEPT {
+  return !opt;
+}
+
+template<class T, class U>
+FLATBUFFERS_CONSTEXPR_CPP11 bool operator==(const Optional<T>& lhs, const U& rhs) FLATBUFFERS_NOEXCEPT {
+  return static_cast<bool>(lhs) && (*lhs == rhs);
+}
+
+template<class T, class U>
+FLATBUFFERS_CONSTEXPR_CPP11 bool operator==(const T& lhs, const Optional<U>& rhs) FLATBUFFERS_NOEXCEPT {
+  return static_cast<bool>(rhs) && (lhs == *rhs);
+}
+
+template<class T, class U>
+FLATBUFFERS_CONSTEXPR_CPP11 bool operator==(const Optional<T>& lhs, const Optional<U>& rhs) FLATBUFFERS_NOEXCEPT {
+  return static_cast<bool>(lhs) != static_cast<bool>(rhs)
+              ? false
+              : !static_cast<bool>(lhs) ? false : (*lhs == *rhs);
+}
+#endif // FLATBUFFERS_USE_STD_OPTIONAL
+
 }  // namespace flatbuffers
 
 #endif  // FLATBUFFERS_STL_EMULATION_H_
index b6340a2..37ea1b9 100644 (file)
@@ -20,6 +20,7 @@
 #include <errno.h>
 
 #include "flatbuffers/base.h"
+#include "flatbuffers/stl_emulation.h"
 
 #ifndef FLATBUFFERS_PREFER_PRINTF
 #  include <sstream>
index f7b14b5..890845b 100644 (file)
@@ -751,6 +751,12 @@ class CppGenerator : public BaseGenerator {
     return ptr_type == "naked" ? "" : ".get()";
   }
 
+  std::string GenOptionalNull() { return "flatbuffers::nullopt"; }
+
+  std::string GenOptionalDecl(const Type &type) {
+    return "flatbuffers::Optional<" + GenTypeBasic(type, true) + ">";
+  }
+
   std::string GenTypeNative(const Type &type, bool invector,
                             const FieldDef &field) {
     switch (type.base_type) {
@@ -788,7 +794,8 @@ class CppGenerator : public BaseGenerator {
         return type_name + "Union";
       }
       default: {
-        return GenTypeBasic(type, true);
+        return field.IsScalarOptional() ? GenOptionalDecl(type)
+                                        : GenTypeBasic(type, true);
       }
     }
   }
@@ -1581,17 +1588,17 @@ class CppGenerator : public BaseGenerator {
   }
 
   std::string GetDefaultScalarValue(const FieldDef &field, bool is_ctor) {
-    if (field.value.type.enum_def && IsScalar(field.value.type.base_type)) {
-      auto ev = field.value.type.enum_def->FindByValue(field.value.constant);
+    const auto &type = field.value.type;
+    if (type.enum_def && IsScalar(type.base_type)) {
+      auto ev = type.enum_def->FindByValue(field.value.constant);
       if (ev) {
-        return WrapInNameSpace(field.value.type.enum_def->defined_namespace,
-                               GetEnumValUse(*field.value.type.enum_def, *ev));
+        return WrapInNameSpace(type.enum_def->defined_namespace,
+                               GetEnumValUse(*type.enum_def, *ev));
       } else {
         return GenUnderlyingCast(
-            field, true,
-            NumToStringCpp(field.value.constant, field.value.type.base_type));
+            field, true, NumToStringCpp(field.value.constant, type.base_type));
       }
-    } else if (field.value.type.base_type == BASE_TYPE_BOOL) {
+    } else if (type.base_type == BASE_TYPE_BOOL) {
       return field.value.constant == "0" ? "false" : "true";
     } else if (field.attributes.Lookup("cpp_type")) {
       if (is_ctor) {
@@ -1604,7 +1611,8 @@ class CppGenerator : public BaseGenerator {
         return "0";
       }
     } else {
-      return GenDefaultConstant(field);
+      return field.IsScalarOptional() ? GenOptionalNull()
+                                      : GenDefaultConstant(field);
     }
   }
 
@@ -1629,8 +1637,14 @@ class CppGenerator : public BaseGenerator {
       }
       code_.SetValue("PARAM_VALUE", "nullptr");
     } else {
-      code_.SetValue("PARAM_TYPE", GenTypeWire(field.value.type, " ", true));
-      code_.SetValue("PARAM_VALUE", GetDefaultScalarValue(field, false));
+      const auto &type = field.value.type;
+      if (field.IsScalarOptional()) {
+        code_.SetValue("PARAM_TYPE", GenOptionalDecl(type));
+        code_.SetValue("PARAM_VALUE", GenOptionalNull());
+      } else {
+        code_.SetValue("PARAM_TYPE", GenTypeWire(type, " ", true));
+        code_.SetValue("PARAM_VALUE", GetDefaultScalarValue(field, false));
+      }
     }
     code_ += "{{PRE}}{{PARAM_TYPE}}{{PARAM_NAME}} = {{PARAM_VALUE}}\\";
   }
@@ -1692,7 +1706,9 @@ class CppGenerator : public BaseGenerator {
         auto native_default = field.attributes.Lookup("native_default");
         // Scalar types get parsed defaults, raw pointers get nullptrs.
         if (IsScalar(field.value.type.base_type)) {
-          if (!initializer_list.empty()) { initializer_list += ",\n        "; }
+          if (!initializer_list.empty()) {
+            initializer_list += ",\n        ";
+          }
           initializer_list += Name(field);
           initializer_list +=
               "(" +
@@ -1906,16 +1922,6 @@ class CppGenerator : public BaseGenerator {
     }
   }
 
-  std::string GetFieldAccessor(const FieldDef &field) const {
-    const auto &type = field.value.type;
-    if (IsScalar(type.base_type))
-      return "GetField<";
-    else if (IsStruct(type))
-      return "GetStruct<";
-    else
-      return "GetPointer<";
-  }
-
   void GenTableUnionAsGetters(const FieldDef &field) {
     const auto &type = field.value.type;
     auto u = type.enum_def;
@@ -1950,33 +1956,47 @@ class CppGenerator : public BaseGenerator {
   }
 
   void GenTableFieldGetter(const FieldDef &field) {
-    const auto& type = field.value.type;
-    const bool is_scalar = IsScalar(type.base_type);
-
-    // Call a different accessor for pointers, that indirects.
-    auto accessor = GetFieldAccessor(field);
-    auto offset_str = GenFieldOffsetName(field);
-    auto offset_type = GenTypeGet(type, "", "const ", " *", false);
-
-    auto call = accessor + offset_type + ">(" + offset_str;
-    // Default value as second arg for non-pointer types.
-    if (is_scalar) { call += ", " + GenDefaultConstant(field); }
-    call += ")";
+    const auto &type = field.value.type;
+    const auto offset_str = GenFieldOffsetName(field);
 
-    std::string afterptr = " *" + NullableExtension();
     GenComment(field.doc_comment, "  ");
-    code_.SetValue("FIELD_TYPE", GenTypeGet(type, " ", "const ",
-                                            afterptr.c_str(), true));
-    code_.SetValue("FIELD_VALUE", GenUnderlyingCast(field, true, call));
-    code_.SetValue("NULLABLE_EXT", NullableExtension());
-
-    code_ += "  {{FIELD_TYPE}}{{FIELD_NAME}}() const {";
-    code_ += "    return {{FIELD_VALUE}};";
-    code_ += "  }";
-
-    if (type.base_type == BASE_TYPE_UNION) {
-      GenTableUnionAsGetters(field);
+    // Call a different accessor for pointers, that indirects.
+    if (false == field.IsScalarOptional()) {
+      const bool is_scalar = IsScalar(type.base_type);
+      std::string accessor;
+      if (is_scalar)
+        accessor = "GetField<";
+      else if (IsStruct(type))
+        accessor = "GetStruct<";
+      else
+        accessor = "GetPointer<";
+      auto offset_type = GenTypeGet(type, "", "const ", " *", false);
+      auto call = accessor + offset_type + ">(" + offset_str;
+      // Default value as second arg for non-pointer types.
+      if (is_scalar) { call += ", " + GenDefaultConstant(field); }
+      call += ")";
+
+      std::string afterptr = " *" + NullableExtension();
+      code_.SetValue("FIELD_TYPE",
+                     GenTypeGet(type, " ", "const ", afterptr.c_str(), true));
+      code_.SetValue("FIELD_VALUE", GenUnderlyingCast(field, true, call));
+      code_.SetValue("NULLABLE_EXT", NullableExtension());
+      code_ += "  {{FIELD_TYPE}}{{FIELD_NAME}}() const {";
+      code_ += "    return {{FIELD_VALUE}};";
+      code_ += "  }";
     }
+    else {
+      auto wire_type = GenTypeBasic(type, false);
+      auto face_type = GenTypeBasic(type, true);
+      auto opt_value = "GetOptional<" + wire_type + ", " + face_type + ">(" +
+                       offset_str + ")";
+      code_.SetValue("FIELD_TYPE", GenOptionalDecl(type));
+      code_ += "  {{FIELD_TYPE}} {{FIELD_NAME}}() const {";
+      code_ += "    return " + opt_value + ";";
+      code_ += "  }";
+    }
+
+    if (type.base_type == BASE_TYPE_UNION) { GenTableUnionAsGetters(field); }
   }
 
   void GenTableFieldSetter(const FieldDef &field) {
@@ -1984,7 +2004,7 @@ class CppGenerator : public BaseGenerator {
     const bool is_scalar = IsScalar(type.base_type);
     if (is_scalar && IsUnion(type))
       return; // changing of a union's type is forbidden
-    auto accessor = GetFieldAccessor(field);
+
     auto offset_str = GenFieldOffsetName(field);
     if (is_scalar) {
       const auto wire_type = GenTypeWire(type, "", false);
@@ -1993,18 +2013,23 @@ class CppGenerator : public BaseGenerator {
       code_.SetValue("FIELD_TYPE", GenTypeBasic(type, true));
       code_.SetValue("FIELD_VALUE",
                      GenUnderlyingCast(field, false, "_" + Name(field)));
-      code_.SetValue("DEFAULT_VALUE", GenDefaultConstant(field));
 
       code_ +=
           "  bool mutate_{{FIELD_NAME}}({{FIELD_TYPE}} "
           "_{{FIELD_NAME}}) {";
-      code_ +=
-          "    return {{SET_FN}}({{OFFSET_NAME}}, {{FIELD_VALUE}}, "
-          "{{DEFAULT_VALUE}});";
+      if (false == field.IsScalarOptional()) {
+        code_.SetValue("DEFAULT_VALUE", GenDefaultConstant(field));
+        code_ +=
+            "    return {{SET_FN}}({{OFFSET_NAME}}, {{FIELD_VALUE}}, "
+            "{{DEFAULT_VALUE}});";
+      } else {
+        code_ += "    return {{SET_FN}}({{OFFSET_NAME}}, {{FIELD_VALUE}});";
+      }
       code_ += "  }";
     } else {
       auto postptr = " *" + NullableExtension();
       auto wire_type = GenTypeGet(type, " ", "", postptr.c_str(), true);
+      std::string accessor = IsStruct(type) ? "GetStruct<" : "GetPointer<";
       auto underlying = accessor + wire_type + ">(" + offset_str + ")";
       code_.SetValue("FIELD_TYPE", wire_type);
       code_.SetValue("FIELD_VALUE", GenUnderlyingCast(field, true, underlying));
@@ -2073,7 +2098,7 @@ class CppGenerator : public BaseGenerator {
         // Deprecated fields won't be accessible.
         continue;
       }
-      
+
       code_.SetValue("FIELD_NAME", Name(field));
       GenTableFieldGetter(field);
       if (opts_.mutable_buffer) {
@@ -2219,43 +2244,44 @@ class CppGenerator : public BaseGenerator {
     for (auto it = struct_def.fields.vec.begin();
          it != struct_def.fields.vec.end(); ++it) {
       const auto &field = **it;
-      if (!field.deprecated) {
-        const bool is_scalar = IsScalar(field.value.type.base_type);
-        const bool is_string = field.value.type.base_type == BASE_TYPE_STRING;
-        const bool is_vector = field.value.type.base_type == BASE_TYPE_VECTOR;
-        if (is_string || is_vector) { has_string_or_vector_fields = true; }
-
-        std::string offset = GenFieldOffsetName(field);
-        std::string name = GenUnderlyingCast(field, false, Name(field));
-        std::string value = is_scalar ? GenDefaultConstant(field) : "";
-
-        // Generate accessor functions of the form:
-        // void add_name(type name) {
-        //   fbb_.AddElement<type>(offset, name, default);
-        // }
-        code_.SetValue("FIELD_NAME", Name(field));
-        code_.SetValue("FIELD_TYPE", GenTypeWire(field.value.type, " ", true));
-        code_.SetValue("ADD_OFFSET", Name(struct_def) + "::" + offset);
-        code_.SetValue("ADD_NAME", name);
-        code_.SetValue("ADD_VALUE", value);
-        if (is_scalar) {
-          const auto type = GenTypeWire(field.value.type, "", false);
-          code_.SetValue("ADD_FN", "AddElement<" + type + ">");
-        } else if (IsStruct(field.value.type)) {
-          code_.SetValue("ADD_FN", "AddStruct");
-        } else {
-          code_.SetValue("ADD_FN", "AddOffset");
-        }
+      if (field.deprecated)
+        continue;
+      const bool is_scalar = IsScalar(field.value.type.base_type);
+      const bool is_default_scalar = is_scalar && !field.IsScalarOptional();
+      const bool is_string = field.value.type.base_type == BASE_TYPE_STRING;
+      const bool is_vector = field.value.type.base_type == BASE_TYPE_VECTOR;
+      if (is_string || is_vector) { has_string_or_vector_fields = true; }
+
+      std::string offset = GenFieldOffsetName(field);
+      std::string name = GenUnderlyingCast(field, false, Name(field));
+      std::string value = is_default_scalar ? GenDefaultConstant(field) : "";
+
+      // Generate accessor functions of the form:
+      // void add_name(type name) {
+      //   fbb_.AddElement<type>(offset, name, default);
+      // }
+      code_.SetValue("FIELD_NAME", Name(field));
+      code_.SetValue("FIELD_TYPE", GenTypeWire(field.value.type, " ", true));
+      code_.SetValue("ADD_OFFSET", Name(struct_def) + "::" + offset);
+      code_.SetValue("ADD_NAME", name);
+      code_.SetValue("ADD_VALUE", value);
+      if (is_scalar) {
+        const auto type = GenTypeWire(field.value.type, "", false);
+        code_.SetValue("ADD_FN", "AddElement<" + type + ">");
+      } else if (IsStruct(field.value.type)) {
+        code_.SetValue("ADD_FN", "AddStruct");
+      } else {
+        code_.SetValue("ADD_FN", "AddOffset");
+      }
 
-        code_ += "  void add_{{FIELD_NAME}}({{FIELD_TYPE}}{{FIELD_NAME}}) {";
-        code_ += "    fbb_.{{ADD_FN}}(\\";
-        if (is_scalar) {
-          code_ += "{{ADD_OFFSET}}, {{ADD_NAME}}, {{ADD_VALUE}});";
-        } else {
-          code_ += "{{ADD_OFFSET}}, {{ADD_NAME}});";
-        }
-        code_ += "  }";
+      code_ += "  void add_{{FIELD_NAME}}({{FIELD_TYPE}}{{FIELD_NAME}}) {";
+      code_ += "    fbb_.{{ADD_FN}}(\\";
+      if (is_default_scalar) {
+        code_ += "{{ADD_OFFSET}}, {{ADD_NAME}}, {{ADD_VALUE}});";
+      } else {
+        code_ += "{{ADD_OFFSET}}, {{ADD_NAME}});";
       }
+      code_ += "  }";
     }
 
     // Builder constructor
@@ -2307,7 +2333,13 @@ class CppGenerator : public BaseGenerator {
         if (!field.deprecated && (!struct_def.sortbysize ||
                                   size == SizeOf(field.value.type.base_type))) {
           code_.SetValue("FIELD_NAME", Name(field));
-          code_ += "  builder_.add_{{FIELD_NAME}}({{FIELD_NAME}});";
+          if (field.IsScalarOptional()) {
+            code_ +=
+                "  if({{FIELD_NAME}}) { "
+                "builder_.add_{{FIELD_NAME}}(*{{FIELD_NAME}}); }";
+          } else {
+            code_ += "  builder_.add_{{FIELD_NAME}}({{FIELD_NAME}});";
+          }
         }
       }
     }
index 05b1b19..088246f 100644 (file)
@@ -743,6 +743,34 @@ CheckedError Parser::ParseField(StructDef &struct_def) {
       return Error(
           "default values currently only supported for scalars in tables");
   }
+
+  // Mark the optional scalars. Note that a side effect of ParseSingleValue is
+  // fixing field->value.constant to null.
+  if (IsScalar(type.base_type)) {
+    field->optional = (field->value.constant == "null");
+    if (field->optional) {
+      if (type.enum_def && type.enum_def->Lookup("null")) {
+        FLATBUFFERS_ASSERT(IsInteger(type.base_type));
+        return Error(
+            "the default 'null' is reserved for declaring optional scalar "
+            "fields, it conflicts with declaration of enum '" +
+            type.enum_def->name + "'.");
+      }
+      if (field->attributes.Lookup("key")) {
+        return Error("only a non-optional scalar field can be used as a 'key' field");
+      }
+      if (!SupportsOptionalScalars()) {
+        return Error(
+            "Optional scalars are not yet supported in at least one the of "
+            "the specified programming languages.");
+      }
+    }
+  } else {
+    // For nonscalars, only required fields are non-optional.
+    // At least until https://github.com/google/flatbuffers/issues/6053
+    field->optional = !field->required;
+  }
+
   // Append .0 if the value has not it (skip hex and scientific floats).
   // This suffix needed for generated C++ code.
   if (IsFloat(type.base_type)) {
@@ -772,6 +800,7 @@ CheckedError Parser::ParseField(StructDef &struct_def) {
     } else {
       // All unions should have the NONE ("0") enum value.
       auto in_enum = type.enum_def->attributes.Lookup("bit_flags") ||
+                     field->IsScalarOptional() ||
                      type.enum_def->FindByValue(field->value.constant);
       if (false == in_enum)
         return Error("default value of " + field->value.constant +
@@ -833,17 +862,7 @@ CheckedError Parser::ParseField(StructDef &struct_def) {
   if (field->required && (struct_def.fixed || IsScalar(type.base_type)))
     return Error("only non-scalar fields in tables may be 'required'");
 
-  // Mark the optional scalars. Note that a side effect of ParseSingleValue is
-  // fixing field->value.constant to null.
-  if (IsScalar(type.base_type)) {
-    field->optional = (field->value.constant == "null");
-    if (field->optional && !SupportsOptionalScalars()) {
-      return Error(
-        "Optional scalars are not yet supported in at least one the of "
-        "the specified programming languages."
-      );
-    }
-  } else {
+  if(!IsScalar(type.base_type)) {
     // For nonscalars, only required fields are non-optional.
     // At least until https://github.com/google/flatbuffers/issues/6053
     field->optional = !field->required;
@@ -2260,11 +2279,17 @@ CheckedError Parser::CheckClash(std::vector<FieldDef *> &fields,
   return NoError();
 }
 
+bool Parser::SupportsOptionalScalars(const flatbuffers::IDLOptions &opts){
+  static FLATBUFFERS_CONSTEXPR unsigned long supported_langs =
+      IDLOptions::kRust | IDLOptions::kSwift | IDLOptions::kLobster |
+      IDLOptions::kKotlin | IDLOptions::kCpp;
+  unsigned long langs = opts.lang_to_generate;
+  return (langs > 0 && langs < IDLOptions::kMAX) && !(langs & ~supported_langs);
+}
 
 bool Parser::SupportsOptionalScalars() const {
-  return !(opts.lang_to_generate &
-           ~(IDLOptions::kRust | IDLOptions::kSwift | IDLOptions::kLobster |
-             IDLOptions::kKotlin));
+  // Check in general if a language isn't specified.
+  return opts.lang_to_generate == 0 || SupportsOptionalScalars(opts);
 }
 
 bool Parser::SupportsAdvancedUnionFeatures() const {
index f66d414..203a08c 100644 (file)
@@ -20,6 +20,7 @@ cc_test(
         "test_builder.cpp",
         "test_builder.h",
         "union_vector/union_vector_generated.h",
+        "optional_scalars_generated.h",
     ],
     copts = [
         "-DFLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE",
@@ -53,6 +54,7 @@ cc_test(
         ":unicode_test.json",
         ":union_vector/union_vector.fbs",
         ":union_vector/union_vector.json",
+        ":optional_scalars.fbs",
     ],
     includes = [
         "",
index 1d7dc97..7669a3f 100644 (file)
@@ -3,12 +3,25 @@
 
 import FlatBuffers
 
+public enum optional_scalars_OptionalByte: Int8, Enum { 
+    public typealias T = Int8
+    public static var byteSize: Int { return MemoryLayout<Int8>.size }
+    public var value: Int8 { return self.rawValue }
+    case none_ = 0
+    case one = 1
+    
+
+    public static var max: optional_scalars_OptionalByte { return .one }
+    public static var min: optional_scalars_OptionalByte { return .none_ }
+}
+
 public struct optional_scalars_ScalarStuff: FlatBufferObject {
 
     static func validateVersion() { FlatBuffersVersion_1_12_0() }
     public var __buffer: ByteBuffer! { return _accessor.bb }
     private var _accessor: Table
 
+    public static func finish(_ fbb: inout FlatBufferBuilder, end: Offset<UOffset>, prefix: Bool = false) { fbb.finish(offset: end, fileId: "NULL", addPrefix: prefix) }
     public static func getRootAsScalarStuff(bb: ByteBuffer) -> optional_scalars_ScalarStuff { return optional_scalars_ScalarStuff(Table(bb: bb, position: Int32(bb.read(def: UOffset.self, position: bb.reader)) + Int32(bb.reader))) }
 
     private init(_ t: Table) { _accessor = t }
@@ -48,6 +61,8 @@ public struct optional_scalars_ScalarStuff: FlatBufferObject {
         case justBool = 64
         case maybeBool = 66
         case defaultBool = 68
+        case justEnum = 70
+        case defaultEnum = 72
         var v: Int32 { Int32(self.rawValue) }
         var p: VOffset { self.rawValue }
     }
@@ -85,7 +100,9 @@ public struct optional_scalars_ScalarStuff: FlatBufferObject {
     public var justBool: Bool { let o = _accessor.offset(VTOFFSET.justBool.v); return o == 0 ? false : 0 != _accessor.readBuffer(of: Byte.self, at: o) }
     public var maybeBool: Bool? { let o = _accessor.offset(VTOFFSET.maybeBool.v); return o == 0 ? true : 0 != _accessor.readBuffer(of: Byte.self, at: o) }
     public var defaultBool: Bool { let o = _accessor.offset(VTOFFSET.defaultBool.v); return o == 0 ? true : 0 != _accessor.readBuffer(of: Byte.self, at: o) }
-    public static func startScalarStuff(_ fbb: inout FlatBufferBuilder) -> UOffset { fbb.startTable(with: 33) }
+    public var justEnum: optional_scalars_OptionalByte { let o = _accessor.offset(VTOFFSET.justEnum.v); return o == 0 ? .none_ : optional_scalars_OptionalByte(rawValue: _accessor.readBuffer(of: Int8.self, at: o)) ?? .none_ }
+    public var defaultEnum: optional_scalars_OptionalByte { let o = _accessor.offset(VTOFFSET.defaultEnum.v); return o == 0 ? .one : optional_scalars_OptionalByte(rawValue: _accessor.readBuffer(of: Int8.self, at: o)) ?? .one }
+    public static func startScalarStuff(_ fbb: inout FlatBufferBuilder) -> UOffset { fbb.startTable(with: 35) }
     public static func add(justI8: Int8, _ fbb: inout FlatBufferBuilder) { fbb.add(element: justI8, def: 0, at: VTOFFSET.justI8.p) }
     public static func add(maybeI8: Int8?, _ fbb: inout FlatBufferBuilder) { fbb.add(element: maybeI8, at: VTOFFSET.maybeI8.p) }
     public static func add(defaultI8: Int8, _ fbb: inout FlatBufferBuilder) { fbb.add(element: defaultI8, def: 42, at: VTOFFSET.defaultI8.p) }
@@ -121,6 +138,8 @@ public struct optional_scalars_ScalarStuff: FlatBufferObject {
     public static func add(maybeBool: Bool?, _ fbb: inout FlatBufferBuilder) { fbb.add(element: maybeBool, at: VTOFFSET.maybeBool.p) }
     public static func add(defaultBool: Bool, _ fbb: inout FlatBufferBuilder) { fbb.add(element: defaultBool, def: true,
      at: VTOFFSET.defaultBool.p) }
+    public static func add(justEnum: optional_scalars_OptionalByte, _ fbb: inout FlatBufferBuilder) { fbb.add(element: justEnum.rawValue, def: 0, at: VTOFFSET.justEnum.p) }
+    public static func add(defaultEnum: optional_scalars_OptionalByte, _ fbb: inout FlatBufferBuilder) { fbb.add(element: defaultEnum.rawValue, def: 1, at: VTOFFSET.defaultEnum.p) }
     public static func endScalarStuff(_ fbb: inout FlatBufferBuilder, start: UOffset) -> Offset<UOffset> { let end = Offset<UOffset>(offset: fbb.endTable(at: start)); return end }
     public static func createScalarStuff(
         _ fbb: inout FlatBufferBuilder,
@@ -156,7 +175,9 @@ public struct optional_scalars_ScalarStuff: FlatBufferObject {
         defaultF64: Double = 42.0,
         justBool: Bool = false,
         maybeBool: Bool? = nil,
-        defaultBool: Bool = true
+        defaultBool: Bool = true,
+        justEnum: optional_scalars_OptionalByte = .none_,
+        defaultEnum: optional_scalars_OptionalByte = .one
     ) -> Offset<UOffset> {
         let __start = optional_scalars_ScalarStuff.startScalarStuff(&fbb)
         optional_scalars_ScalarStuff.add(justI8: justI8, &fbb)
@@ -192,6 +213,8 @@ public struct optional_scalars_ScalarStuff: FlatBufferObject {
         optional_scalars_ScalarStuff.add(justBool: justBool, &fbb)
         optional_scalars_ScalarStuff.add(maybeBool: maybeBool, &fbb)
         optional_scalars_ScalarStuff.add(defaultBool: defaultBool, &fbb)
+        optional_scalars_ScalarStuff.add(justEnum: justEnum, &fbb)
+        optional_scalars_ScalarStuff.add(defaultEnum: defaultEnum, &fbb)
         return optional_scalars_ScalarStuff.endScalarStuff(&fbb, start: __start)
     }
 }
diff --git a/tests/cpp17/generated_cpp17/optional_scalars_generated.h b/tests/cpp17/generated_cpp17/optional_scalars_generated.h
new file mode 100644 (file)
index 0000000..cc87913
--- /dev/null
@@ -0,0 +1,878 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+
+#ifndef FLATBUFFERS_GENERATED_OPTIONALSCALARS_OPTIONAL_SCALARS_H_
+#define FLATBUFFERS_GENERATED_OPTIONALSCALARS_OPTIONAL_SCALARS_H_
+
+#include "flatbuffers/flatbuffers.h"
+
+namespace optional_scalars {
+
+struct ScalarStuff;
+struct ScalarStuffBuilder;
+struct ScalarStuffT;
+
+inline const flatbuffers::TypeTable *ScalarStuffTypeTable();
+
+enum class OptionalByte : int8_t {
+  None = 0,
+  One = 1,
+  MIN = None,
+  MAX = One
+};
+
+inline const OptionalByte (&EnumValuesOptionalByte())[2] {
+  static const OptionalByte values[] = {
+    OptionalByte::None,
+    OptionalByte::One
+  };
+  return values;
+}
+
+inline const char * const *EnumNamesOptionalByte() {
+  static const char * const names[3] = {
+    "None",
+    "One",
+    nullptr
+  };
+  return names;
+}
+
+inline const char *EnumNameOptionalByte(OptionalByte e) {
+  if (flatbuffers::IsOutRange(e, OptionalByte::None, OptionalByte::One)) return "";
+  const size_t index = static_cast<size_t>(e);
+  return EnumNamesOptionalByte()[index];
+}
+
+struct ScalarStuffT : public flatbuffers::NativeTable {
+  typedef ScalarStuff TableType;
+  int8_t just_i8 = 0;
+  flatbuffers::Optional<int8_t> maybe_i8 = flatbuffers::nullopt;
+  int8_t default_i8 = 42;
+  uint8_t just_u8 = 0;
+  flatbuffers::Optional<uint8_t> maybe_u8 = flatbuffers::nullopt;
+  uint8_t default_u8 = 42;
+  int16_t just_i16 = 0;
+  flatbuffers::Optional<int16_t> maybe_i16 = flatbuffers::nullopt;
+  int16_t default_i16 = 42;
+  uint16_t just_u16 = 0;
+  flatbuffers::Optional<uint16_t> maybe_u16 = flatbuffers::nullopt;
+  uint16_t default_u16 = 42;
+  int32_t just_i32 = 0;
+  flatbuffers::Optional<int32_t> maybe_i32 = flatbuffers::nullopt;
+  int32_t default_i32 = 42;
+  uint32_t just_u32 = 0;
+  flatbuffers::Optional<uint32_t> maybe_u32 = flatbuffers::nullopt;
+  uint32_t default_u32 = 42;
+  int64_t just_i64 = 0;
+  flatbuffers::Optional<int64_t> maybe_i64 = flatbuffers::nullopt;
+  int64_t default_i64 = 42LL;
+  uint64_t just_u64 = 0;
+  flatbuffers::Optional<uint64_t> maybe_u64 = flatbuffers::nullopt;
+  uint64_t default_u64 = 42ULL;
+  float just_f32 = 0.0f;
+  flatbuffers::Optional<float> maybe_f32 = flatbuffers::nullopt;
+  float default_f32 = 42.0f;
+  double just_f64 = 0.0;
+  flatbuffers::Optional<double> maybe_f64 = flatbuffers::nullopt;
+  double default_f64 = 42.0;
+  bool just_bool = false;
+  flatbuffers::Optional<bool> maybe_bool = true;
+  bool default_bool = true;
+  optional_scalars::OptionalByte just_enum = optional_scalars::OptionalByte::None;
+  optional_scalars::OptionalByte default_enum = optional_scalars::OptionalByte::One;
+};
+
+struct ScalarStuff FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+  typedef ScalarStuffT NativeTableType;
+  typedef ScalarStuffBuilder Builder;
+  struct Traits;
+  static const flatbuffers::TypeTable *MiniReflectTypeTable() {
+    return ScalarStuffTypeTable();
+  }
+  enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
+    VT_JUST_I8 = 4,
+    VT_MAYBE_I8 = 6,
+    VT_DEFAULT_I8 = 8,
+    VT_JUST_U8 = 10,
+    VT_MAYBE_U8 = 12,
+    VT_DEFAULT_U8 = 14,
+    VT_JUST_I16 = 16,
+    VT_MAYBE_I16 = 18,
+    VT_DEFAULT_I16 = 20,
+    VT_JUST_U16 = 22,
+    VT_MAYBE_U16 = 24,
+    VT_DEFAULT_U16 = 26,
+    VT_JUST_I32 = 28,
+    VT_MAYBE_I32 = 30,
+    VT_DEFAULT_I32 = 32,
+    VT_JUST_U32 = 34,
+    VT_MAYBE_U32 = 36,
+    VT_DEFAULT_U32 = 38,
+    VT_JUST_I64 = 40,
+    VT_MAYBE_I64 = 42,
+    VT_DEFAULT_I64 = 44,
+    VT_JUST_U64 = 46,
+    VT_MAYBE_U64 = 48,
+    VT_DEFAULT_U64 = 50,
+    VT_JUST_F32 = 52,
+    VT_MAYBE_F32 = 54,
+    VT_DEFAULT_F32 = 56,
+    VT_JUST_F64 = 58,
+    VT_MAYBE_F64 = 60,
+    VT_DEFAULT_F64 = 62,
+    VT_JUST_BOOL = 64,
+    VT_MAYBE_BOOL = 66,
+    VT_DEFAULT_BOOL = 68,
+    VT_JUST_ENUM = 70,
+    VT_DEFAULT_ENUM = 72
+  };
+  int8_t just_i8() const {
+    return GetField<int8_t>(VT_JUST_I8, 0);
+  }
+  bool mutate_just_i8(int8_t _just_i8) {
+    return SetField<int8_t>(VT_JUST_I8, _just_i8, 0);
+  }
+  flatbuffers::Optional<int8_t> maybe_i8() const {
+    return GetOptional<int8_t, int8_t>(VT_MAYBE_I8);
+  }
+  bool mutate_maybe_i8(int8_t _maybe_i8) {
+    return SetField<int8_t>(VT_MAYBE_I8, _maybe_i8);
+  }
+  int8_t default_i8() const {
+    return GetField<int8_t>(VT_DEFAULT_I8, 42);
+  }
+  bool mutate_default_i8(int8_t _default_i8) {
+    return SetField<int8_t>(VT_DEFAULT_I8, _default_i8, 42);
+  }
+  uint8_t just_u8() const {
+    return GetField<uint8_t>(VT_JUST_U8, 0);
+  }
+  bool mutate_just_u8(uint8_t _just_u8) {
+    return SetField<uint8_t>(VT_JUST_U8, _just_u8, 0);
+  }
+  flatbuffers::Optional<uint8_t> maybe_u8() const {
+    return GetOptional<uint8_t, uint8_t>(VT_MAYBE_U8);
+  }
+  bool mutate_maybe_u8(uint8_t _maybe_u8) {
+    return SetField<uint8_t>(VT_MAYBE_U8, _maybe_u8);
+  }
+  uint8_t default_u8() const {
+    return GetField<uint8_t>(VT_DEFAULT_U8, 42);
+  }
+  bool mutate_default_u8(uint8_t _default_u8) {
+    return SetField<uint8_t>(VT_DEFAULT_U8, _default_u8, 42);
+  }
+  int16_t just_i16() const {
+    return GetField<int16_t>(VT_JUST_I16, 0);
+  }
+  bool mutate_just_i16(int16_t _just_i16) {
+    return SetField<int16_t>(VT_JUST_I16, _just_i16, 0);
+  }
+  flatbuffers::Optional<int16_t> maybe_i16() const {
+    return GetOptional<int16_t, int16_t>(VT_MAYBE_I16);
+  }
+  bool mutate_maybe_i16(int16_t _maybe_i16) {
+    return SetField<int16_t>(VT_MAYBE_I16, _maybe_i16);
+  }
+  int16_t default_i16() const {
+    return GetField<int16_t>(VT_DEFAULT_I16, 42);
+  }
+  bool mutate_default_i16(int16_t _default_i16) {
+    return SetField<int16_t>(VT_DEFAULT_I16, _default_i16, 42);
+  }
+  uint16_t just_u16() const {
+    return GetField<uint16_t>(VT_JUST_U16, 0);
+  }
+  bool mutate_just_u16(uint16_t _just_u16) {
+    return SetField<uint16_t>(VT_JUST_U16, _just_u16, 0);
+  }
+  flatbuffers::Optional<uint16_t> maybe_u16() const {
+    return GetOptional<uint16_t, uint16_t>(VT_MAYBE_U16);
+  }
+  bool mutate_maybe_u16(uint16_t _maybe_u16) {
+    return SetField<uint16_t>(VT_MAYBE_U16, _maybe_u16);
+  }
+  uint16_t default_u16() const {
+    return GetField<uint16_t>(VT_DEFAULT_U16, 42);
+  }
+  bool mutate_default_u16(uint16_t _default_u16) {
+    return SetField<uint16_t>(VT_DEFAULT_U16, _default_u16, 42);
+  }
+  int32_t just_i32() const {
+    return GetField<int32_t>(VT_JUST_I32, 0);
+  }
+  bool mutate_just_i32(int32_t _just_i32) {
+    return SetField<int32_t>(VT_JUST_I32, _just_i32, 0);
+  }
+  flatbuffers::Optional<int32_t> maybe_i32() const {
+    return GetOptional<int32_t, int32_t>(VT_MAYBE_I32);
+  }
+  bool mutate_maybe_i32(int32_t _maybe_i32) {
+    return SetField<int32_t>(VT_MAYBE_I32, _maybe_i32);
+  }
+  int32_t default_i32() const {
+    return GetField<int32_t>(VT_DEFAULT_I32, 42);
+  }
+  bool mutate_default_i32(int32_t _default_i32) {
+    return SetField<int32_t>(VT_DEFAULT_I32, _default_i32, 42);
+  }
+  uint32_t just_u32() const {
+    return GetField<uint32_t>(VT_JUST_U32, 0);
+  }
+  bool mutate_just_u32(uint32_t _just_u32) {
+    return SetField<uint32_t>(VT_JUST_U32, _just_u32, 0);
+  }
+  flatbuffers::Optional<uint32_t> maybe_u32() const {
+    return GetOptional<uint32_t, uint32_t>(VT_MAYBE_U32);
+  }
+  bool mutate_maybe_u32(uint32_t _maybe_u32) {
+    return SetField<uint32_t>(VT_MAYBE_U32, _maybe_u32);
+  }
+  uint32_t default_u32() const {
+    return GetField<uint32_t>(VT_DEFAULT_U32, 42);
+  }
+  bool mutate_default_u32(uint32_t _default_u32) {
+    return SetField<uint32_t>(VT_DEFAULT_U32, _default_u32, 42);
+  }
+  int64_t just_i64() const {
+    return GetField<int64_t>(VT_JUST_I64, 0);
+  }
+  bool mutate_just_i64(int64_t _just_i64) {
+    return SetField<int64_t>(VT_JUST_I64, _just_i64, 0);
+  }
+  flatbuffers::Optional<int64_t> maybe_i64() const {
+    return GetOptional<int64_t, int64_t>(VT_MAYBE_I64);
+  }
+  bool mutate_maybe_i64(int64_t _maybe_i64) {
+    return SetField<int64_t>(VT_MAYBE_I64, _maybe_i64);
+  }
+  int64_t default_i64() const {
+    return GetField<int64_t>(VT_DEFAULT_I64, 42LL);
+  }
+  bool mutate_default_i64(int64_t _default_i64) {
+    return SetField<int64_t>(VT_DEFAULT_I64, _default_i64, 42LL);
+  }
+  uint64_t just_u64() const {
+    return GetField<uint64_t>(VT_JUST_U64, 0);
+  }
+  bool mutate_just_u64(uint64_t _just_u64) {
+    return SetField<uint64_t>(VT_JUST_U64, _just_u64, 0);
+  }
+  flatbuffers::Optional<uint64_t> maybe_u64() const {
+    return GetOptional<uint64_t, uint64_t>(VT_MAYBE_U64);
+  }
+  bool mutate_maybe_u64(uint64_t _maybe_u64) {
+    return SetField<uint64_t>(VT_MAYBE_U64, _maybe_u64);
+  }
+  uint64_t default_u64() const {
+    return GetField<uint64_t>(VT_DEFAULT_U64, 42ULL);
+  }
+  bool mutate_default_u64(uint64_t _default_u64) {
+    return SetField<uint64_t>(VT_DEFAULT_U64, _default_u64, 42ULL);
+  }
+  float just_f32() const {
+    return GetField<float>(VT_JUST_F32, 0.0f);
+  }
+  bool mutate_just_f32(float _just_f32) {
+    return SetField<float>(VT_JUST_F32, _just_f32, 0.0f);
+  }
+  flatbuffers::Optional<float> maybe_f32() const {
+    return GetOptional<float, float>(VT_MAYBE_F32);
+  }
+  bool mutate_maybe_f32(float _maybe_f32) {
+    return SetField<float>(VT_MAYBE_F32, _maybe_f32);
+  }
+  float default_f32() const {
+    return GetField<float>(VT_DEFAULT_F32, 42.0f);
+  }
+  bool mutate_default_f32(float _default_f32) {
+    return SetField<float>(VT_DEFAULT_F32, _default_f32, 42.0f);
+  }
+  double just_f64() const {
+    return GetField<double>(VT_JUST_F64, 0.0);
+  }
+  bool mutate_just_f64(double _just_f64) {
+    return SetField<double>(VT_JUST_F64, _just_f64, 0.0);
+  }
+  flatbuffers::Optional<double> maybe_f64() const {
+    return GetOptional<double, double>(VT_MAYBE_F64);
+  }
+  bool mutate_maybe_f64(double _maybe_f64) {
+    return SetField<double>(VT_MAYBE_F64, _maybe_f64);
+  }
+  double default_f64() const {
+    return GetField<double>(VT_DEFAULT_F64, 42.0);
+  }
+  bool mutate_default_f64(double _default_f64) {
+    return SetField<double>(VT_DEFAULT_F64, _default_f64, 42.0);
+  }
+  bool just_bool() const {
+    return GetField<uint8_t>(VT_JUST_BOOL, 0) != 0;
+  }
+  bool mutate_just_bool(bool _just_bool) {
+    return SetField<uint8_t>(VT_JUST_BOOL, static_cast<uint8_t>(_just_bool), 0);
+  }
+  flatbuffers::Optional<bool> maybe_bool() const {
+    return GetOptional<uint8_t, bool>(VT_MAYBE_BOOL);
+  }
+  bool mutate_maybe_bool(bool _maybe_bool) {
+    return SetField<uint8_t>(VT_MAYBE_BOOL, static_cast<uint8_t>(_maybe_bool));
+  }
+  bool default_bool() const {
+    return GetField<uint8_t>(VT_DEFAULT_BOOL, 1) != 0;
+  }
+  bool mutate_default_bool(bool _default_bool) {
+    return SetField<uint8_t>(VT_DEFAULT_BOOL, static_cast<uint8_t>(_default_bool), 1);
+  }
+  optional_scalars::OptionalByte just_enum() const {
+    return static_cast<optional_scalars::OptionalByte>(GetField<int8_t>(VT_JUST_ENUM, 0));
+  }
+  bool mutate_just_enum(optional_scalars::OptionalByte _just_enum) {
+    return SetField<int8_t>(VT_JUST_ENUM, static_cast<int8_t>(_just_enum), 0);
+  }
+  optional_scalars::OptionalByte default_enum() const {
+    return static_cast<optional_scalars::OptionalByte>(GetField<int8_t>(VT_DEFAULT_ENUM, 1));
+  }
+  bool mutate_default_enum(optional_scalars::OptionalByte _default_enum) {
+    return SetField<int8_t>(VT_DEFAULT_ENUM, static_cast<int8_t>(_default_enum), 1);
+  }
+  bool Verify(flatbuffers::Verifier &verifier) const {
+    return VerifyTableStart(verifier) &&
+           VerifyField<int8_t>(verifier, VT_JUST_I8) &&
+           VerifyField<int8_t>(verifier, VT_MAYBE_I8) &&
+           VerifyField<int8_t>(verifier, VT_DEFAULT_I8) &&
+           VerifyField<uint8_t>(verifier, VT_JUST_U8) &&
+           VerifyField<uint8_t>(verifier, VT_MAYBE_U8) &&
+           VerifyField<uint8_t>(verifier, VT_DEFAULT_U8) &&
+           VerifyField<int16_t>(verifier, VT_JUST_I16) &&
+           VerifyField<int16_t>(verifier, VT_MAYBE_I16) &&
+           VerifyField<int16_t>(verifier, VT_DEFAULT_I16) &&
+           VerifyField<uint16_t>(verifier, VT_JUST_U16) &&
+           VerifyField<uint16_t>(verifier, VT_MAYBE_U16) &&
+           VerifyField<uint16_t>(verifier, VT_DEFAULT_U16) &&
+           VerifyField<int32_t>(verifier, VT_JUST_I32) &&
+           VerifyField<int32_t>(verifier, VT_MAYBE_I32) &&
+           VerifyField<int32_t>(verifier, VT_DEFAULT_I32) &&
+           VerifyField<uint32_t>(verifier, VT_JUST_U32) &&
+           VerifyField<uint32_t>(verifier, VT_MAYBE_U32) &&
+           VerifyField<uint32_t>(verifier, VT_DEFAULT_U32) &&
+           VerifyField<int64_t>(verifier, VT_JUST_I64) &&
+           VerifyField<int64_t>(verifier, VT_MAYBE_I64) &&
+           VerifyField<int64_t>(verifier, VT_DEFAULT_I64) &&
+           VerifyField<uint64_t>(verifier, VT_JUST_U64) &&
+           VerifyField<uint64_t>(verifier, VT_MAYBE_U64) &&
+           VerifyField<uint64_t>(verifier, VT_DEFAULT_U64) &&
+           VerifyField<float>(verifier, VT_JUST_F32) &&
+           VerifyField<float>(verifier, VT_MAYBE_F32) &&
+           VerifyField<float>(verifier, VT_DEFAULT_F32) &&
+           VerifyField<double>(verifier, VT_JUST_F64) &&
+           VerifyField<double>(verifier, VT_MAYBE_F64) &&
+           VerifyField<double>(verifier, VT_DEFAULT_F64) &&
+           VerifyField<uint8_t>(verifier, VT_JUST_BOOL) &&
+           VerifyField<uint8_t>(verifier, VT_MAYBE_BOOL) &&
+           VerifyField<uint8_t>(verifier, VT_DEFAULT_BOOL) &&
+           VerifyField<int8_t>(verifier, VT_JUST_ENUM) &&
+           VerifyField<int8_t>(verifier, VT_DEFAULT_ENUM) &&
+           verifier.EndTable();
+  }
+  ScalarStuffT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const;
+  void UnPackTo(ScalarStuffT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const;
+  static flatbuffers::Offset<ScalarStuff> Pack(flatbuffers::FlatBufferBuilder &_fbb, const ScalarStuffT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
+};
+
+struct ScalarStuffBuilder {
+  typedef ScalarStuff Table;
+  flatbuffers::FlatBufferBuilder &fbb_;
+  flatbuffers::uoffset_t start_;
+  void add_just_i8(int8_t just_i8) {
+    fbb_.AddElement<int8_t>(ScalarStuff::VT_JUST_I8, just_i8, 0);
+  }
+  void add_maybe_i8(int8_t maybe_i8) {
+    fbb_.AddElement<int8_t>(ScalarStuff::VT_MAYBE_I8, maybe_i8);
+  }
+  void add_default_i8(int8_t default_i8) {
+    fbb_.AddElement<int8_t>(ScalarStuff::VT_DEFAULT_I8, default_i8, 42);
+  }
+  void add_just_u8(uint8_t just_u8) {
+    fbb_.AddElement<uint8_t>(ScalarStuff::VT_JUST_U8, just_u8, 0);
+  }
+  void add_maybe_u8(uint8_t maybe_u8) {
+    fbb_.AddElement<uint8_t>(ScalarStuff::VT_MAYBE_U8, maybe_u8);
+  }
+  void add_default_u8(uint8_t default_u8) {
+    fbb_.AddElement<uint8_t>(ScalarStuff::VT_DEFAULT_U8, default_u8, 42);
+  }
+  void add_just_i16(int16_t just_i16) {
+    fbb_.AddElement<int16_t>(ScalarStuff::VT_JUST_I16, just_i16, 0);
+  }
+  void add_maybe_i16(int16_t maybe_i16) {
+    fbb_.AddElement<int16_t>(ScalarStuff::VT_MAYBE_I16, maybe_i16);
+  }
+  void add_default_i16(int16_t default_i16) {
+    fbb_.AddElement<int16_t>(ScalarStuff::VT_DEFAULT_I16, default_i16, 42);
+  }
+  void add_just_u16(uint16_t just_u16) {
+    fbb_.AddElement<uint16_t>(ScalarStuff::VT_JUST_U16, just_u16, 0);
+  }
+  void add_maybe_u16(uint16_t maybe_u16) {
+    fbb_.AddElement<uint16_t>(ScalarStuff::VT_MAYBE_U16, maybe_u16);
+  }
+  void add_default_u16(uint16_t default_u16) {
+    fbb_.AddElement<uint16_t>(ScalarStuff::VT_DEFAULT_U16, default_u16, 42);
+  }
+  void add_just_i32(int32_t just_i32) {
+    fbb_.AddElement<int32_t>(ScalarStuff::VT_JUST_I32, just_i32, 0);
+  }
+  void add_maybe_i32(int32_t maybe_i32) {
+    fbb_.AddElement<int32_t>(ScalarStuff::VT_MAYBE_I32, maybe_i32);
+  }
+  void add_default_i32(int32_t default_i32) {
+    fbb_.AddElement<int32_t>(ScalarStuff::VT_DEFAULT_I32, default_i32, 42);
+  }
+  void add_just_u32(uint32_t just_u32) {
+    fbb_.AddElement<uint32_t>(ScalarStuff::VT_JUST_U32, just_u32, 0);
+  }
+  void add_maybe_u32(uint32_t maybe_u32) {
+    fbb_.AddElement<uint32_t>(ScalarStuff::VT_MAYBE_U32, maybe_u32);
+  }
+  void add_default_u32(uint32_t default_u32) {
+    fbb_.AddElement<uint32_t>(ScalarStuff::VT_DEFAULT_U32, default_u32, 42);
+  }
+  void add_just_i64(int64_t just_i64) {
+    fbb_.AddElement<int64_t>(ScalarStuff::VT_JUST_I64, just_i64, 0);
+  }
+  void add_maybe_i64(int64_t maybe_i64) {
+    fbb_.AddElement<int64_t>(ScalarStuff::VT_MAYBE_I64, maybe_i64);
+  }
+  void add_default_i64(int64_t default_i64) {
+    fbb_.AddElement<int64_t>(ScalarStuff::VT_DEFAULT_I64, default_i64, 42LL);
+  }
+  void add_just_u64(uint64_t just_u64) {
+    fbb_.AddElement<uint64_t>(ScalarStuff::VT_JUST_U64, just_u64, 0);
+  }
+  void add_maybe_u64(uint64_t maybe_u64) {
+    fbb_.AddElement<uint64_t>(ScalarStuff::VT_MAYBE_U64, maybe_u64);
+  }
+  void add_default_u64(uint64_t default_u64) {
+    fbb_.AddElement<uint64_t>(ScalarStuff::VT_DEFAULT_U64, default_u64, 42ULL);
+  }
+  void add_just_f32(float just_f32) {
+    fbb_.AddElement<float>(ScalarStuff::VT_JUST_F32, just_f32, 0.0f);
+  }
+  void add_maybe_f32(float maybe_f32) {
+    fbb_.AddElement<float>(ScalarStuff::VT_MAYBE_F32, maybe_f32);
+  }
+  void add_default_f32(float default_f32) {
+    fbb_.AddElement<float>(ScalarStuff::VT_DEFAULT_F32, default_f32, 42.0f);
+  }
+  void add_just_f64(double just_f64) {
+    fbb_.AddElement<double>(ScalarStuff::VT_JUST_F64, just_f64, 0.0);
+  }
+  void add_maybe_f64(double maybe_f64) {
+    fbb_.AddElement<double>(ScalarStuff::VT_MAYBE_F64, maybe_f64);
+  }
+  void add_default_f64(double default_f64) {
+    fbb_.AddElement<double>(ScalarStuff::VT_DEFAULT_F64, default_f64, 42.0);
+  }
+  void add_just_bool(bool just_bool) {
+    fbb_.AddElement<uint8_t>(ScalarStuff::VT_JUST_BOOL, static_cast<uint8_t>(just_bool), 0);
+  }
+  void add_maybe_bool(bool maybe_bool) {
+    fbb_.AddElement<uint8_t>(ScalarStuff::VT_MAYBE_BOOL, static_cast<uint8_t>(maybe_bool));
+  }
+  void add_default_bool(bool default_bool) {
+    fbb_.AddElement<uint8_t>(ScalarStuff::VT_DEFAULT_BOOL, static_cast<uint8_t>(default_bool), 1);
+  }
+  void add_just_enum(optional_scalars::OptionalByte just_enum) {
+    fbb_.AddElement<int8_t>(ScalarStuff::VT_JUST_ENUM, static_cast<int8_t>(just_enum), 0);
+  }
+  void add_default_enum(optional_scalars::OptionalByte default_enum) {
+    fbb_.AddElement<int8_t>(ScalarStuff::VT_DEFAULT_ENUM, static_cast<int8_t>(default_enum), 1);
+  }
+  explicit ScalarStuffBuilder(flatbuffers::FlatBufferBuilder &_fbb)
+        : fbb_(_fbb) {
+    start_ = fbb_.StartTable();
+  }
+  flatbuffers::Offset<ScalarStuff> Finish() {
+    const auto end = fbb_.EndTable(start_);
+    auto o = flatbuffers::Offset<ScalarStuff>(end);
+    return o;
+  }
+};
+
+inline flatbuffers::Offset<ScalarStuff> CreateScalarStuff(
+    flatbuffers::FlatBufferBuilder &_fbb,
+    int8_t just_i8 = 0,
+    flatbuffers::Optional<int8_t>maybe_i8 = flatbuffers::nullopt,
+    int8_t default_i8 = 42,
+    uint8_t just_u8 = 0,
+    flatbuffers::Optional<uint8_t>maybe_u8 = flatbuffers::nullopt,
+    uint8_t default_u8 = 42,
+    int16_t just_i16 = 0,
+    flatbuffers::Optional<int16_t>maybe_i16 = flatbuffers::nullopt,
+    int16_t default_i16 = 42,
+    uint16_t just_u16 = 0,
+    flatbuffers::Optional<uint16_t>maybe_u16 = flatbuffers::nullopt,
+    uint16_t default_u16 = 42,
+    int32_t just_i32 = 0,
+    flatbuffers::Optional<int32_t>maybe_i32 = flatbuffers::nullopt,
+    int32_t default_i32 = 42,
+    uint32_t just_u32 = 0,
+    flatbuffers::Optional<uint32_t>maybe_u32 = flatbuffers::nullopt,
+    uint32_t default_u32 = 42,
+    int64_t just_i64 = 0,
+    flatbuffers::Optional<int64_t>maybe_i64 = flatbuffers::nullopt,
+    int64_t default_i64 = 42LL,
+    uint64_t just_u64 = 0,
+    flatbuffers::Optional<uint64_t>maybe_u64 = flatbuffers::nullopt,
+    uint64_t default_u64 = 42ULL,
+    float just_f32 = 0.0f,
+    flatbuffers::Optional<float>maybe_f32 = flatbuffers::nullopt,
+    float default_f32 = 42.0f,
+    double just_f64 = 0.0,
+    flatbuffers::Optional<double>maybe_f64 = flatbuffers::nullopt,
+    double default_f64 = 42.0,
+    bool just_bool = false,
+    flatbuffers::Optional<bool>maybe_bool = flatbuffers::nullopt,
+    bool default_bool = true,
+    optional_scalars::OptionalByte just_enum = optional_scalars::OptionalByte::None,
+    optional_scalars::OptionalByte default_enum = optional_scalars::OptionalByte::One) {
+  ScalarStuffBuilder builder_(_fbb);
+  builder_.add_default_f64(default_f64);
+  if(maybe_f64) { builder_.add_maybe_f64(*maybe_f64); }
+  builder_.add_just_f64(just_f64);
+  builder_.add_default_u64(default_u64);
+  if(maybe_u64) { builder_.add_maybe_u64(*maybe_u64); }
+  builder_.add_just_u64(just_u64);
+  builder_.add_default_i64(default_i64);
+  if(maybe_i64) { builder_.add_maybe_i64(*maybe_i64); }
+  builder_.add_just_i64(just_i64);
+  builder_.add_default_f32(default_f32);
+  if(maybe_f32) { builder_.add_maybe_f32(*maybe_f32); }
+  builder_.add_just_f32(just_f32);
+  builder_.add_default_u32(default_u32);
+  if(maybe_u32) { builder_.add_maybe_u32(*maybe_u32); }
+  builder_.add_just_u32(just_u32);
+  builder_.add_default_i32(default_i32);
+  if(maybe_i32) { builder_.add_maybe_i32(*maybe_i32); }
+  builder_.add_just_i32(just_i32);
+  builder_.add_default_u16(default_u16);
+  if(maybe_u16) { builder_.add_maybe_u16(*maybe_u16); }
+  builder_.add_just_u16(just_u16);
+  builder_.add_default_i16(default_i16);
+  if(maybe_i16) { builder_.add_maybe_i16(*maybe_i16); }
+  builder_.add_just_i16(just_i16);
+  builder_.add_default_enum(default_enum);
+  builder_.add_just_enum(just_enum);
+  builder_.add_default_bool(default_bool);
+  if(maybe_bool) { builder_.add_maybe_bool(*maybe_bool); }
+  builder_.add_just_bool(just_bool);
+  builder_.add_default_u8(default_u8);
+  if(maybe_u8) { builder_.add_maybe_u8(*maybe_u8); }
+  builder_.add_just_u8(just_u8);
+  builder_.add_default_i8(default_i8);
+  if(maybe_i8) { builder_.add_maybe_i8(*maybe_i8); }
+  builder_.add_just_i8(just_i8);
+  return builder_.Finish();
+}
+
+struct ScalarStuff::Traits {
+  using type = ScalarStuff;
+  static auto constexpr Create = CreateScalarStuff;
+};
+
+flatbuffers::Offset<ScalarStuff> CreateScalarStuff(flatbuffers::FlatBufferBuilder &_fbb, const ScalarStuffT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
+
+inline ScalarStuffT *ScalarStuff::UnPack(const flatbuffers::resolver_function_t *_resolver) const {
+  auto _o = std::make_unique<ScalarStuffT>();
+  UnPackTo(_o.get(), _resolver);
+  return _o.release();
+}
+
+inline void ScalarStuff::UnPackTo(ScalarStuffT *_o, const flatbuffers::resolver_function_t *_resolver) const {
+  (void)_o;
+  (void)_resolver;
+  { auto _e = just_i8(); _o->just_i8 = _e; }
+  { auto _e = maybe_i8(); _o->maybe_i8 = _e; }
+  { auto _e = default_i8(); _o->default_i8 = _e; }
+  { auto _e = just_u8(); _o->just_u8 = _e; }
+  { auto _e = maybe_u8(); _o->maybe_u8 = _e; }
+  { auto _e = default_u8(); _o->default_u8 = _e; }
+  { auto _e = just_i16(); _o->just_i16 = _e; }
+  { auto _e = maybe_i16(); _o->maybe_i16 = _e; }
+  { auto _e = default_i16(); _o->default_i16 = _e; }
+  { auto _e = just_u16(); _o->just_u16 = _e; }
+  { auto _e = maybe_u16(); _o->maybe_u16 = _e; }
+  { auto _e = default_u16(); _o->default_u16 = _e; }
+  { auto _e = just_i32(); _o->just_i32 = _e; }
+  { auto _e = maybe_i32(); _o->maybe_i32 = _e; }
+  { auto _e = default_i32(); _o->default_i32 = _e; }
+  { auto _e = just_u32(); _o->just_u32 = _e; }
+  { auto _e = maybe_u32(); _o->maybe_u32 = _e; }
+  { auto _e = default_u32(); _o->default_u32 = _e; }
+  { auto _e = just_i64(); _o->just_i64 = _e; }
+  { auto _e = maybe_i64(); _o->maybe_i64 = _e; }
+  { auto _e = default_i64(); _o->default_i64 = _e; }
+  { auto _e = just_u64(); _o->just_u64 = _e; }
+  { auto _e = maybe_u64(); _o->maybe_u64 = _e; }
+  { auto _e = default_u64(); _o->default_u64 = _e; }
+  { auto _e = just_f32(); _o->just_f32 = _e; }
+  { auto _e = maybe_f32(); _o->maybe_f32 = _e; }
+  { auto _e = default_f32(); _o->default_f32 = _e; }
+  { auto _e = just_f64(); _o->just_f64 = _e; }
+  { auto _e = maybe_f64(); _o->maybe_f64 = _e; }
+  { auto _e = default_f64(); _o->default_f64 = _e; }
+  { auto _e = just_bool(); _o->just_bool = _e; }
+  { auto _e = maybe_bool(); _o->maybe_bool = _e; }
+  { auto _e = default_bool(); _o->default_bool = _e; }
+  { auto _e = just_enum(); _o->just_enum = _e; }
+  { auto _e = default_enum(); _o->default_enum = _e; }
+}
+
+inline flatbuffers::Offset<ScalarStuff> ScalarStuff::Pack(flatbuffers::FlatBufferBuilder &_fbb, const ScalarStuffT* _o, const flatbuffers::rehasher_function_t *_rehasher) {
+  return CreateScalarStuff(_fbb, _o, _rehasher);
+}
+
+inline flatbuffers::Offset<ScalarStuff> CreateScalarStuff(flatbuffers::FlatBufferBuilder &_fbb, const ScalarStuffT *_o, const flatbuffers::rehasher_function_t *_rehasher) {
+  (void)_rehasher;
+  (void)_o;
+  struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const ScalarStuffT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va;
+  auto _just_i8 = _o->just_i8;
+  auto _maybe_i8 = _o->maybe_i8;
+  auto _default_i8 = _o->default_i8;
+  auto _just_u8 = _o->just_u8;
+  auto _maybe_u8 = _o->maybe_u8;
+  auto _default_u8 = _o->default_u8;
+  auto _just_i16 = _o->just_i16;
+  auto _maybe_i16 = _o->maybe_i16;
+  auto _default_i16 = _o->default_i16;
+  auto _just_u16 = _o->just_u16;
+  auto _maybe_u16 = _o->maybe_u16;
+  auto _default_u16 = _o->default_u16;
+  auto _just_i32 = _o->just_i32;
+  auto _maybe_i32 = _o->maybe_i32;
+  auto _default_i32 = _o->default_i32;
+  auto _just_u32 = _o->just_u32;
+  auto _maybe_u32 = _o->maybe_u32;
+  auto _default_u32 = _o->default_u32;
+  auto _just_i64 = _o->just_i64;
+  auto _maybe_i64 = _o->maybe_i64;
+  auto _default_i64 = _o->default_i64;
+  auto _just_u64 = _o->just_u64;
+  auto _maybe_u64 = _o->maybe_u64;
+  auto _default_u64 = _o->default_u64;
+  auto _just_f32 = _o->just_f32;
+  auto _maybe_f32 = _o->maybe_f32;
+  auto _default_f32 = _o->default_f32;
+  auto _just_f64 = _o->just_f64;
+  auto _maybe_f64 = _o->maybe_f64;
+  auto _default_f64 = _o->default_f64;
+  auto _just_bool = _o->just_bool;
+  auto _maybe_bool = _o->maybe_bool;
+  auto _default_bool = _o->default_bool;
+  auto _just_enum = _o->just_enum;
+  auto _default_enum = _o->default_enum;
+  return optional_scalars::CreateScalarStuff(
+      _fbb,
+      _just_i8,
+      _maybe_i8,
+      _default_i8,
+      _just_u8,
+      _maybe_u8,
+      _default_u8,
+      _just_i16,
+      _maybe_i16,
+      _default_i16,
+      _just_u16,
+      _maybe_u16,
+      _default_u16,
+      _just_i32,
+      _maybe_i32,
+      _default_i32,
+      _just_u32,
+      _maybe_u32,
+      _default_u32,
+      _just_i64,
+      _maybe_i64,
+      _default_i64,
+      _just_u64,
+      _maybe_u64,
+      _default_u64,
+      _just_f32,
+      _maybe_f32,
+      _default_f32,
+      _just_f64,
+      _maybe_f64,
+      _default_f64,
+      _just_bool,
+      _maybe_bool,
+      _default_bool,
+      _just_enum,
+      _default_enum);
+}
+
+inline const flatbuffers::TypeTable *OptionalByteTypeTable() {
+  static const flatbuffers::TypeCode type_codes[] = {
+    { flatbuffers::ET_CHAR, 0, 0 },
+    { flatbuffers::ET_CHAR, 0, 0 }
+  };
+  static const flatbuffers::TypeFunction type_refs[] = {
+    optional_scalars::OptionalByteTypeTable
+  };
+  static const char * const names[] = {
+    "None",
+    "One"
+  };
+  static const flatbuffers::TypeTable tt = {
+    flatbuffers::ST_ENUM, 2, type_codes, type_refs, nullptr, names
+  };
+  return &tt;
+}
+
+inline const flatbuffers::TypeTable *ScalarStuffTypeTable() {
+  static const flatbuffers::TypeCode type_codes[] = {
+    { flatbuffers::ET_CHAR, 0, -1 },
+    { flatbuffers::ET_CHAR, 0, -1 },
+    { flatbuffers::ET_CHAR, 0, -1 },
+    { flatbuffers::ET_UCHAR, 0, -1 },
+    { flatbuffers::ET_UCHAR, 0, -1 },
+    { flatbuffers::ET_UCHAR, 0, -1 },
+    { flatbuffers::ET_SHORT, 0, -1 },
+    { flatbuffers::ET_SHORT, 0, -1 },
+    { flatbuffers::ET_SHORT, 0, -1 },
+    { flatbuffers::ET_USHORT, 0, -1 },
+    { flatbuffers::ET_USHORT, 0, -1 },
+    { flatbuffers::ET_USHORT, 0, -1 },
+    { flatbuffers::ET_INT, 0, -1 },
+    { flatbuffers::ET_INT, 0, -1 },
+    { flatbuffers::ET_INT, 0, -1 },
+    { flatbuffers::ET_UINT, 0, -1 },
+    { flatbuffers::ET_UINT, 0, -1 },
+    { flatbuffers::ET_UINT, 0, -1 },
+    { flatbuffers::ET_LONG, 0, -1 },
+    { flatbuffers::ET_LONG, 0, -1 },
+    { flatbuffers::ET_LONG, 0, -1 },
+    { flatbuffers::ET_ULONG, 0, -1 },
+    { flatbuffers::ET_ULONG, 0, -1 },
+    { flatbuffers::ET_ULONG, 0, -1 },
+    { flatbuffers::ET_FLOAT, 0, -1 },
+    { flatbuffers::ET_FLOAT, 0, -1 },
+    { flatbuffers::ET_FLOAT, 0, -1 },
+    { flatbuffers::ET_DOUBLE, 0, -1 },
+    { flatbuffers::ET_DOUBLE, 0, -1 },
+    { flatbuffers::ET_DOUBLE, 0, -1 },
+    { flatbuffers::ET_BOOL, 0, -1 },
+    { flatbuffers::ET_BOOL, 0, -1 },
+    { flatbuffers::ET_BOOL, 0, -1 },
+    { flatbuffers::ET_CHAR, 0, 0 },
+    { flatbuffers::ET_CHAR, 0, 0 }
+  };
+  static const flatbuffers::TypeFunction type_refs[] = {
+    optional_scalars::OptionalByteTypeTable
+  };
+  static const char * const names[] = {
+    "just_i8",
+    "maybe_i8",
+    "default_i8",
+    "just_u8",
+    "maybe_u8",
+    "default_u8",
+    "just_i16",
+    "maybe_i16",
+    "default_i16",
+    "just_u16",
+    "maybe_u16",
+    "default_u16",
+    "just_i32",
+    "maybe_i32",
+    "default_i32",
+    "just_u32",
+    "maybe_u32",
+    "default_u32",
+    "just_i64",
+    "maybe_i64",
+    "default_i64",
+    "just_u64",
+    "maybe_u64",
+    "default_u64",
+    "just_f32",
+    "maybe_f32",
+    "default_f32",
+    "just_f64",
+    "maybe_f64",
+    "default_f64",
+    "just_bool",
+    "maybe_bool",
+    "default_bool",
+    "just_enum",
+    "default_enum"
+  };
+  static const flatbuffers::TypeTable tt = {
+    flatbuffers::ST_TABLE, 35, type_codes, type_refs, nullptr, names
+  };
+  return &tt;
+}
+
+inline const optional_scalars::ScalarStuff *GetScalarStuff(const void *buf) {
+  return flatbuffers::GetRoot<optional_scalars::ScalarStuff>(buf);
+}
+
+inline const optional_scalars::ScalarStuff *GetSizePrefixedScalarStuff(const void *buf) {
+  return flatbuffers::GetSizePrefixedRoot<optional_scalars::ScalarStuff>(buf);
+}
+
+inline ScalarStuff *GetMutableScalarStuff(void *buf) {
+  return flatbuffers::GetMutableRoot<ScalarStuff>(buf);
+}
+
+inline const char *ScalarStuffIdentifier() {
+  return "NULL";
+}
+
+inline bool ScalarStuffBufferHasIdentifier(const void *buf) {
+  return flatbuffers::BufferHasIdentifier(
+      buf, ScalarStuffIdentifier());
+}
+
+inline bool VerifyScalarStuffBuffer(
+    flatbuffers::Verifier &verifier) {
+  return verifier.VerifyBuffer<optional_scalars::ScalarStuff>(ScalarStuffIdentifier());
+}
+
+inline bool VerifySizePrefixedScalarStuffBuffer(
+    flatbuffers::Verifier &verifier) {
+  return verifier.VerifySizePrefixedBuffer<optional_scalars::ScalarStuff>(ScalarStuffIdentifier());
+}
+
+inline const char *ScalarStuffExtension() {
+  return "mon";
+}
+
+inline void FinishScalarStuffBuffer(
+    flatbuffers::FlatBufferBuilder &fbb,
+    flatbuffers::Offset<optional_scalars::ScalarStuff> root) {
+  fbb.Finish(root, ScalarStuffIdentifier());
+}
+
+inline void FinishSizePrefixedScalarStuffBuffer(
+    flatbuffers::FlatBufferBuilder &fbb,
+    flatbuffers::Offset<optional_scalars::ScalarStuff> root) {
+  fbb.FinishSizePrefixed(root, ScalarStuffIdentifier());
+}
+
+inline std::unique_ptr<optional_scalars::ScalarStuffT> UnPackScalarStuff(
+    const void *buf,
+    const flatbuffers::resolver_function_t *res = nullptr) {
+  return std::unique_ptr<optional_scalars::ScalarStuffT>(GetScalarStuff(buf)->UnPack(res));
+}
+
+inline std::unique_ptr<optional_scalars::ScalarStuffT> UnPackSizePrefixedScalarStuff(
+    const void *buf,
+    const flatbuffers::resolver_function_t *res = nullptr) {
+  return std::unique_ptr<optional_scalars::ScalarStuffT>(GetSizePrefixedScalarStuff(buf)->UnPack(res));
+}
+
+}  // namespace optional_scalars
+
+#endif  // FLATBUFFERS_GENERATED_OPTIONALSCALARS_OPTIONAL_SCALARS_H_
index 91390bd..9b47c10 100644 (file)
 // Embed generated code into an isolated namespace.
 namespace cpp17 {
 #include "generated_cpp17/monster_test_generated.h"
+#include "generated_cpp17/optional_scalars_generated.h"
 }  // namespace cpp17
 
 namespace cpp11 {
 #include "../monster_test_generated.h"
+#include "../optional_scalars_generated.h"
 }  // namespace cpp11
 
 void CreateTableByTypeTest() {
@@ -59,8 +61,50 @@ void CreateTableByTypeTest() {
   TEST_EQ(stat->count(), 7);
 }
 
+void OptionalScalarsTest() {
+  static_assert(std::is_same<flatbuffers::Optional<float>, std::optional<float>>::value);
+  static_assert(std::is_same<flatbuffers::nullopt_t, std::nullopt_t>::value);
+
+  // test C++ nullable
+  flatbuffers::FlatBufferBuilder fbb;
+  FinishScalarStuffBuffer(fbb, cpp17::optional_scalars::CreateScalarStuff(
+                                   fbb, 1, static_cast<int8_t>(2)));
+  auto opts =
+      cpp17::optional_scalars::GetMutableScalarStuff(fbb.GetBufferPointer());
+  TEST_ASSERT(!opts->maybe_bool());
+  TEST_ASSERT(!opts->maybe_f32().has_value());
+  TEST_ASSERT(opts->maybe_i8().has_value());
+  TEST_EQ(opts->maybe_i8().value(), 2);
+  TEST_ASSERT(opts->mutate_maybe_i8(3));
+  TEST_ASSERT(opts->maybe_i8().has_value());
+  TEST_EQ(opts->maybe_i8().value(), 3);
+  TEST_ASSERT(!opts->mutate_maybe_i16(-10));
+
+  cpp17::optional_scalars::ScalarStuffT obj;
+  opts->UnPackTo(&obj);
+  TEST_ASSERT(!obj.maybe_bool);
+  TEST_ASSERT(!obj.maybe_f32.has_value());
+  TEST_ASSERT(obj.maybe_i8.has_value() && obj.maybe_i8.value() == 3);
+  TEST_ASSERT(obj.maybe_i8 && *obj.maybe_i8 == 3);
+  obj.maybe_i32 = -1;
+
+  fbb.Clear();
+  FinishScalarStuffBuffer(
+      fbb, cpp17::optional_scalars::ScalarStuff::Pack(fbb, &obj));
+  opts = cpp17::optional_scalars::GetMutableScalarStuff(fbb.GetBufferPointer());
+  TEST_ASSERT(opts->maybe_i8().has_value());
+  TEST_EQ(opts->maybe_i8().value(), 3);
+  TEST_ASSERT(opts->maybe_i32().has_value());
+  TEST_EQ(opts->maybe_i32().value(), -1);
+
+  TEST_EQ(std::optional<int32_t>(opts->maybe_i32()).value(), -1);
+  TEST_EQ(std::optional<int64_t>(opts->maybe_i32()).value(), -1);
+  TEST_ASSERT(opts->maybe_i32() == std::optional<int64_t>(-1));
+}
+
 int FlatBufferCpp17Tests() {
   CreateTableByTypeTest();
+  OptionalScalarsTest();
   return 0;
 }
 
index e9518c3..33e7168 100644 (file)
@@ -56,6 +56,7 @@ set TEST_NOINCL_FLAGS=%TEST_BASE_FLAGS% --no-includes --no-fb-import
 
 @rem Generate the optional scalar code for tests.
 ..\%buildtype%\flatc.exe --rust --lobster optional_scalars.fbs || goto FAIL
+..\%buildtype%\flatc.exe %TEST_NOINCL_FLAGS% %TEST_CPP_FLAGS% --cpp optional_scalars.fbs || goto FAIL
 
 @rem Generate the schema evolution tests
 ..\%buildtype%\flatc.exe --cpp --scoped-enums %TEST_CPP_FLAGS% -o evolution_test ./evolution_test/evolution_v1.fbs ./evolution_test/evolution_v2.fbs || goto FAIL
@@ -72,6 +73,7 @@ set TEST_CPP17_FLAGS=--cpp --cpp-std c++17 -o ./cpp17/generated_cpp17 %TEST_NOIN
 if NOT "%MONSTER_EXTRA%"=="skip" (
   @rem Flag c++17 requires Clang6, GCC7, MSVC2017 (_MSC_VER >= 1914)  or higher.
   ..\%buildtype%\flatc.exe %TEST_CPP17_FLAGS% -I include_test monster_test.fbs  || goto FAIL
+  ..\%buildtype%\flatc.exe %TEST_CPP17_FLAGS% optional_scalars.fbs || goto FAIL
   @rem..\%buildtype%\flatc.exe %TEST_CPP17_FLAGS% arrays_test.fbs                   || goto FAIL
   @rem..\%buildtype%\flatc.exe %TEST_CPP17_FLAGS% native_type_test.fbs              || goto FAIL
   @rem..\%buildtype%\flatc.exe %TEST_CPP17_FLAGS% monster_extra.fbs                 || goto FAIL
index c0a0833..4dbf7aa 100755 (executable)
@@ -54,6 +54,7 @@ $TEST_NOINCL_FLAGS $TEST_CPP_FLAGS $TEST_CS_FLAGS $TEST_JS_TS_FLAGS -o namespace
 
 # Generate optional scalar code for tests.
 ../flatc --kotlin --rust --lobster optional_scalars.fbs
+../flatc $TEST_NOINCL_FLAGS $TEST_CPP_FLAGS --cpp optional_scalars.fbs
 
 # Generate the schema evolution tests
 ../flatc --cpp --scoped-enums $TEST_CPP_FLAGS -o evolution_test ./evolution_test/evolution_v*.fbs
@@ -84,6 +85,7 @@ fi
 # Flag c++17 requires Clang6, GCC7, MSVC2017 (_MSC_VER >= 1914)  or higher.
 TEST_CPP17_FLAGS="--cpp --cpp-std c++17 -o ./cpp17/generated_cpp17 $TEST_NOINCL_FLAGS"
 ../flatc $TEST_CPP17_FLAGS -I include_test monster_test.fbs
+../flatc $TEST_CPP17_FLAGS optional_scalars.fbs
 
 cd ../samples
 ../flatc --cpp --lobster $TEST_BASE_FLAGS $TEST_CPP_FLAGS monster.fbs
index 051bae3..abea320 100644 (file)
@@ -1,5 +1,10 @@
 namespace optional_scalars;
 
+enum OptionalByte: byte {
+  None = 0,
+  One = 1,
+}
+
 // This table tests optional scalars in tables. It should be integrated with
 // the main monster test once most languages support optional scalars.
 table ScalarStuff {
@@ -41,4 +46,14 @@ table ScalarStuff {
   just_bool: bool;
   maybe_bool: bool = null;
   default_bool: bool = true;
+
+  just_enum: OptionalByte;
+  // Rust code generator failed with optional<enum>
+  //maybe_enum: OptionalByte = null;
+  default_enum: OptionalByte = One;
 }
+
+root_type ScalarStuff;
+
+file_identifier "NULL";
+file_extension "mon";
diff --git a/tests/optional_scalars_generated.h b/tests/optional_scalars_generated.h
new file mode 100644 (file)
index 0000000..95e51d3
--- /dev/null
@@ -0,0 +1,956 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+
+#ifndef FLATBUFFERS_GENERATED_OPTIONALSCALARS_OPTIONAL_SCALARS_H_
+#define FLATBUFFERS_GENERATED_OPTIONALSCALARS_OPTIONAL_SCALARS_H_
+
+#include "flatbuffers/flatbuffers.h"
+
+namespace optional_scalars {
+
+struct ScalarStuff;
+struct ScalarStuffBuilder;
+struct ScalarStuffT;
+
+bool operator==(const ScalarStuffT &lhs, const ScalarStuffT &rhs);
+bool operator!=(const ScalarStuffT &lhs, const ScalarStuffT &rhs);
+
+inline const flatbuffers::TypeTable *ScalarStuffTypeTable();
+
+enum OptionalByte {
+  OptionalByte_None = 0,
+  OptionalByte_One = 1,
+  OptionalByte_MIN = OptionalByte_None,
+  OptionalByte_MAX = OptionalByte_One
+};
+
+inline const OptionalByte (&EnumValuesOptionalByte())[2] {
+  static const OptionalByte values[] = {
+    OptionalByte_None,
+    OptionalByte_One
+  };
+  return values;
+}
+
+inline const char * const *EnumNamesOptionalByte() {
+  static const char * const names[3] = {
+    "None",
+    "One",
+    nullptr
+  };
+  return names;
+}
+
+inline const char *EnumNameOptionalByte(OptionalByte e) {
+  if (flatbuffers::IsOutRange(e, OptionalByte_None, OptionalByte_One)) return "";
+  const size_t index = static_cast<size_t>(e);
+  return EnumNamesOptionalByte()[index];
+}
+
+struct ScalarStuffT : public flatbuffers::NativeTable {
+  typedef ScalarStuff TableType;
+  int8_t just_i8;
+  flatbuffers::Optional<int8_t> maybe_i8;
+  int8_t default_i8;
+  uint8_t just_u8;
+  flatbuffers::Optional<uint8_t> maybe_u8;
+  uint8_t default_u8;
+  int16_t just_i16;
+  flatbuffers::Optional<int16_t> maybe_i16;
+  int16_t default_i16;
+  uint16_t just_u16;
+  flatbuffers::Optional<uint16_t> maybe_u16;
+  uint16_t default_u16;
+  int32_t just_i32;
+  flatbuffers::Optional<int32_t> maybe_i32;
+  int32_t default_i32;
+  uint32_t just_u32;
+  flatbuffers::Optional<uint32_t> maybe_u32;
+  uint32_t default_u32;
+  int64_t just_i64;
+  flatbuffers::Optional<int64_t> maybe_i64;
+  int64_t default_i64;
+  uint64_t just_u64;
+  flatbuffers::Optional<uint64_t> maybe_u64;
+  uint64_t default_u64;
+  float just_f32;
+  flatbuffers::Optional<float> maybe_f32;
+  float default_f32;
+  double just_f64;
+  flatbuffers::Optional<double> maybe_f64;
+  double default_f64;
+  bool just_bool;
+  flatbuffers::Optional<bool> maybe_bool;
+  bool default_bool;
+  optional_scalars::OptionalByte just_enum;
+  optional_scalars::OptionalByte default_enum;
+  ScalarStuffT()
+      : just_i8(0),
+        maybe_i8(flatbuffers::nullopt),
+        default_i8(42),
+        just_u8(0),
+        maybe_u8(flatbuffers::nullopt),
+        default_u8(42),
+        just_i16(0),
+        maybe_i16(flatbuffers::nullopt),
+        default_i16(42),
+        just_u16(0),
+        maybe_u16(flatbuffers::nullopt),
+        default_u16(42),
+        just_i32(0),
+        maybe_i32(flatbuffers::nullopt),
+        default_i32(42),
+        just_u32(0),
+        maybe_u32(flatbuffers::nullopt),
+        default_u32(42),
+        just_i64(0),
+        maybe_i64(flatbuffers::nullopt),
+        default_i64(42LL),
+        just_u64(0),
+        maybe_u64(flatbuffers::nullopt),
+        default_u64(42ULL),
+        just_f32(0.0f),
+        maybe_f32(flatbuffers::nullopt),
+        default_f32(42.0f),
+        just_f64(0.0),
+        maybe_f64(flatbuffers::nullopt),
+        default_f64(42.0),
+        just_bool(false),
+        maybe_bool(true),
+        default_bool(true),
+        just_enum(optional_scalars::OptionalByte_None),
+        default_enum(optional_scalars::OptionalByte_One) {
+  }
+};
+
+inline bool operator==(const ScalarStuffT &lhs, const ScalarStuffT &rhs) {
+  return
+      (lhs.just_i8 == rhs.just_i8) &&
+      (lhs.maybe_i8 == rhs.maybe_i8) &&
+      (lhs.default_i8 == rhs.default_i8) &&
+      (lhs.just_u8 == rhs.just_u8) &&
+      (lhs.maybe_u8 == rhs.maybe_u8) &&
+      (lhs.default_u8 == rhs.default_u8) &&
+      (lhs.just_i16 == rhs.just_i16) &&
+      (lhs.maybe_i16 == rhs.maybe_i16) &&
+      (lhs.default_i16 == rhs.default_i16) &&
+      (lhs.just_u16 == rhs.just_u16) &&
+      (lhs.maybe_u16 == rhs.maybe_u16) &&
+      (lhs.default_u16 == rhs.default_u16) &&
+      (lhs.just_i32 == rhs.just_i32) &&
+      (lhs.maybe_i32 == rhs.maybe_i32) &&
+      (lhs.default_i32 == rhs.default_i32) &&
+      (lhs.just_u32 == rhs.just_u32) &&
+      (lhs.maybe_u32 == rhs.maybe_u32) &&
+      (lhs.default_u32 == rhs.default_u32) &&
+      (lhs.just_i64 == rhs.just_i64) &&
+      (lhs.maybe_i64 == rhs.maybe_i64) &&
+      (lhs.default_i64 == rhs.default_i64) &&
+      (lhs.just_u64 == rhs.just_u64) &&
+      (lhs.maybe_u64 == rhs.maybe_u64) &&
+      (lhs.default_u64 == rhs.default_u64) &&
+      (lhs.just_f32 == rhs.just_f32) &&
+      (lhs.maybe_f32 == rhs.maybe_f32) &&
+      (lhs.default_f32 == rhs.default_f32) &&
+      (lhs.just_f64 == rhs.just_f64) &&
+      (lhs.maybe_f64 == rhs.maybe_f64) &&
+      (lhs.default_f64 == rhs.default_f64) &&
+      (lhs.just_bool == rhs.just_bool) &&
+      (lhs.maybe_bool == rhs.maybe_bool) &&
+      (lhs.default_bool == rhs.default_bool) &&
+      (lhs.just_enum == rhs.just_enum) &&
+      (lhs.default_enum == rhs.default_enum);
+}
+
+inline bool operator!=(const ScalarStuffT &lhs, const ScalarStuffT &rhs) {
+    return !(lhs == rhs);
+}
+
+
+struct ScalarStuff FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+  typedef ScalarStuffT NativeTableType;
+  typedef ScalarStuffBuilder Builder;
+  static const flatbuffers::TypeTable *MiniReflectTypeTable() {
+    return ScalarStuffTypeTable();
+  }
+  enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
+    VT_JUST_I8 = 4,
+    VT_MAYBE_I8 = 6,
+    VT_DEFAULT_I8 = 8,
+    VT_JUST_U8 = 10,
+    VT_MAYBE_U8 = 12,
+    VT_DEFAULT_U8 = 14,
+    VT_JUST_I16 = 16,
+    VT_MAYBE_I16 = 18,
+    VT_DEFAULT_I16 = 20,
+    VT_JUST_U16 = 22,
+    VT_MAYBE_U16 = 24,
+    VT_DEFAULT_U16 = 26,
+    VT_JUST_I32 = 28,
+    VT_MAYBE_I32 = 30,
+    VT_DEFAULT_I32 = 32,
+    VT_JUST_U32 = 34,
+    VT_MAYBE_U32 = 36,
+    VT_DEFAULT_U32 = 38,
+    VT_JUST_I64 = 40,
+    VT_MAYBE_I64 = 42,
+    VT_DEFAULT_I64 = 44,
+    VT_JUST_U64 = 46,
+    VT_MAYBE_U64 = 48,
+    VT_DEFAULT_U64 = 50,
+    VT_JUST_F32 = 52,
+    VT_MAYBE_F32 = 54,
+    VT_DEFAULT_F32 = 56,
+    VT_JUST_F64 = 58,
+    VT_MAYBE_F64 = 60,
+    VT_DEFAULT_F64 = 62,
+    VT_JUST_BOOL = 64,
+    VT_MAYBE_BOOL = 66,
+    VT_DEFAULT_BOOL = 68,
+    VT_JUST_ENUM = 70,
+    VT_DEFAULT_ENUM = 72
+  };
+  int8_t just_i8() const {
+    return GetField<int8_t>(VT_JUST_I8, 0);
+  }
+  bool mutate_just_i8(int8_t _just_i8) {
+    return SetField<int8_t>(VT_JUST_I8, _just_i8, 0);
+  }
+  flatbuffers::Optional<int8_t> maybe_i8() const {
+    return GetOptional<int8_t, int8_t>(VT_MAYBE_I8);
+  }
+  bool mutate_maybe_i8(int8_t _maybe_i8) {
+    return SetField<int8_t>(VT_MAYBE_I8, _maybe_i8);
+  }
+  int8_t default_i8() const {
+    return GetField<int8_t>(VT_DEFAULT_I8, 42);
+  }
+  bool mutate_default_i8(int8_t _default_i8) {
+    return SetField<int8_t>(VT_DEFAULT_I8, _default_i8, 42);
+  }
+  uint8_t just_u8() const {
+    return GetField<uint8_t>(VT_JUST_U8, 0);
+  }
+  bool mutate_just_u8(uint8_t _just_u8) {
+    return SetField<uint8_t>(VT_JUST_U8, _just_u8, 0);
+  }
+  flatbuffers::Optional<uint8_t> maybe_u8() const {
+    return GetOptional<uint8_t, uint8_t>(VT_MAYBE_U8);
+  }
+  bool mutate_maybe_u8(uint8_t _maybe_u8) {
+    return SetField<uint8_t>(VT_MAYBE_U8, _maybe_u8);
+  }
+  uint8_t default_u8() const {
+    return GetField<uint8_t>(VT_DEFAULT_U8, 42);
+  }
+  bool mutate_default_u8(uint8_t _default_u8) {
+    return SetField<uint8_t>(VT_DEFAULT_U8, _default_u8, 42);
+  }
+  int16_t just_i16() const {
+    return GetField<int16_t>(VT_JUST_I16, 0);
+  }
+  bool mutate_just_i16(int16_t _just_i16) {
+    return SetField<int16_t>(VT_JUST_I16, _just_i16, 0);
+  }
+  flatbuffers::Optional<int16_t> maybe_i16() const {
+    return GetOptional<int16_t, int16_t>(VT_MAYBE_I16);
+  }
+  bool mutate_maybe_i16(int16_t _maybe_i16) {
+    return SetField<int16_t>(VT_MAYBE_I16, _maybe_i16);
+  }
+  int16_t default_i16() const {
+    return GetField<int16_t>(VT_DEFAULT_I16, 42);
+  }
+  bool mutate_default_i16(int16_t _default_i16) {
+    return SetField<int16_t>(VT_DEFAULT_I16, _default_i16, 42);
+  }
+  uint16_t just_u16() const {
+    return GetField<uint16_t>(VT_JUST_U16, 0);
+  }
+  bool mutate_just_u16(uint16_t _just_u16) {
+    return SetField<uint16_t>(VT_JUST_U16, _just_u16, 0);
+  }
+  flatbuffers::Optional<uint16_t> maybe_u16() const {
+    return GetOptional<uint16_t, uint16_t>(VT_MAYBE_U16);
+  }
+  bool mutate_maybe_u16(uint16_t _maybe_u16) {
+    return SetField<uint16_t>(VT_MAYBE_U16, _maybe_u16);
+  }
+  uint16_t default_u16() const {
+    return GetField<uint16_t>(VT_DEFAULT_U16, 42);
+  }
+  bool mutate_default_u16(uint16_t _default_u16) {
+    return SetField<uint16_t>(VT_DEFAULT_U16, _default_u16, 42);
+  }
+  int32_t just_i32() const {
+    return GetField<int32_t>(VT_JUST_I32, 0);
+  }
+  bool mutate_just_i32(int32_t _just_i32) {
+    return SetField<int32_t>(VT_JUST_I32, _just_i32, 0);
+  }
+  flatbuffers::Optional<int32_t> maybe_i32() const {
+    return GetOptional<int32_t, int32_t>(VT_MAYBE_I32);
+  }
+  bool mutate_maybe_i32(int32_t _maybe_i32) {
+    return SetField<int32_t>(VT_MAYBE_I32, _maybe_i32);
+  }
+  int32_t default_i32() const {
+    return GetField<int32_t>(VT_DEFAULT_I32, 42);
+  }
+  bool mutate_default_i32(int32_t _default_i32) {
+    return SetField<int32_t>(VT_DEFAULT_I32, _default_i32, 42);
+  }
+  uint32_t just_u32() const {
+    return GetField<uint32_t>(VT_JUST_U32, 0);
+  }
+  bool mutate_just_u32(uint32_t _just_u32) {
+    return SetField<uint32_t>(VT_JUST_U32, _just_u32, 0);
+  }
+  flatbuffers::Optional<uint32_t> maybe_u32() const {
+    return GetOptional<uint32_t, uint32_t>(VT_MAYBE_U32);
+  }
+  bool mutate_maybe_u32(uint32_t _maybe_u32) {
+    return SetField<uint32_t>(VT_MAYBE_U32, _maybe_u32);
+  }
+  uint32_t default_u32() const {
+    return GetField<uint32_t>(VT_DEFAULT_U32, 42);
+  }
+  bool mutate_default_u32(uint32_t _default_u32) {
+    return SetField<uint32_t>(VT_DEFAULT_U32, _default_u32, 42);
+  }
+  int64_t just_i64() const {
+    return GetField<int64_t>(VT_JUST_I64, 0);
+  }
+  bool mutate_just_i64(int64_t _just_i64) {
+    return SetField<int64_t>(VT_JUST_I64, _just_i64, 0);
+  }
+  flatbuffers::Optional<int64_t> maybe_i64() const {
+    return GetOptional<int64_t, int64_t>(VT_MAYBE_I64);
+  }
+  bool mutate_maybe_i64(int64_t _maybe_i64) {
+    return SetField<int64_t>(VT_MAYBE_I64, _maybe_i64);
+  }
+  int64_t default_i64() const {
+    return GetField<int64_t>(VT_DEFAULT_I64, 42LL);
+  }
+  bool mutate_default_i64(int64_t _default_i64) {
+    return SetField<int64_t>(VT_DEFAULT_I64, _default_i64, 42LL);
+  }
+  uint64_t just_u64() const {
+    return GetField<uint64_t>(VT_JUST_U64, 0);
+  }
+  bool mutate_just_u64(uint64_t _just_u64) {
+    return SetField<uint64_t>(VT_JUST_U64, _just_u64, 0);
+  }
+  flatbuffers::Optional<uint64_t> maybe_u64() const {
+    return GetOptional<uint64_t, uint64_t>(VT_MAYBE_U64);
+  }
+  bool mutate_maybe_u64(uint64_t _maybe_u64) {
+    return SetField<uint64_t>(VT_MAYBE_U64, _maybe_u64);
+  }
+  uint64_t default_u64() const {
+    return GetField<uint64_t>(VT_DEFAULT_U64, 42ULL);
+  }
+  bool mutate_default_u64(uint64_t _default_u64) {
+    return SetField<uint64_t>(VT_DEFAULT_U64, _default_u64, 42ULL);
+  }
+  float just_f32() const {
+    return GetField<float>(VT_JUST_F32, 0.0f);
+  }
+  bool mutate_just_f32(float _just_f32) {
+    return SetField<float>(VT_JUST_F32, _just_f32, 0.0f);
+  }
+  flatbuffers::Optional<float> maybe_f32() const {
+    return GetOptional<float, float>(VT_MAYBE_F32);
+  }
+  bool mutate_maybe_f32(float _maybe_f32) {
+    return SetField<float>(VT_MAYBE_F32, _maybe_f32);
+  }
+  float default_f32() const {
+    return GetField<float>(VT_DEFAULT_F32, 42.0f);
+  }
+  bool mutate_default_f32(float _default_f32) {
+    return SetField<float>(VT_DEFAULT_F32, _default_f32, 42.0f);
+  }
+  double just_f64() const {
+    return GetField<double>(VT_JUST_F64, 0.0);
+  }
+  bool mutate_just_f64(double _just_f64) {
+    return SetField<double>(VT_JUST_F64, _just_f64, 0.0);
+  }
+  flatbuffers::Optional<double> maybe_f64() const {
+    return GetOptional<double, double>(VT_MAYBE_F64);
+  }
+  bool mutate_maybe_f64(double _maybe_f64) {
+    return SetField<double>(VT_MAYBE_F64, _maybe_f64);
+  }
+  double default_f64() const {
+    return GetField<double>(VT_DEFAULT_F64, 42.0);
+  }
+  bool mutate_default_f64(double _default_f64) {
+    return SetField<double>(VT_DEFAULT_F64, _default_f64, 42.0);
+  }
+  bool just_bool() const {
+    return GetField<uint8_t>(VT_JUST_BOOL, 0) != 0;
+  }
+  bool mutate_just_bool(bool _just_bool) {
+    return SetField<uint8_t>(VT_JUST_BOOL, static_cast<uint8_t>(_just_bool), 0);
+  }
+  flatbuffers::Optional<bool> maybe_bool() const {
+    return GetOptional<uint8_t, bool>(VT_MAYBE_BOOL);
+  }
+  bool mutate_maybe_bool(bool _maybe_bool) {
+    return SetField<uint8_t>(VT_MAYBE_BOOL, static_cast<uint8_t>(_maybe_bool));
+  }
+  bool default_bool() const {
+    return GetField<uint8_t>(VT_DEFAULT_BOOL, 1) != 0;
+  }
+  bool mutate_default_bool(bool _default_bool) {
+    return SetField<uint8_t>(VT_DEFAULT_BOOL, static_cast<uint8_t>(_default_bool), 1);
+  }
+  optional_scalars::OptionalByte just_enum() const {
+    return static_cast<optional_scalars::OptionalByte>(GetField<int8_t>(VT_JUST_ENUM, 0));
+  }
+  bool mutate_just_enum(optional_scalars::OptionalByte _just_enum) {
+    return SetField<int8_t>(VT_JUST_ENUM, static_cast<int8_t>(_just_enum), 0);
+  }
+  optional_scalars::OptionalByte default_enum() const {
+    return static_cast<optional_scalars::OptionalByte>(GetField<int8_t>(VT_DEFAULT_ENUM, 1));
+  }
+  bool mutate_default_enum(optional_scalars::OptionalByte _default_enum) {
+    return SetField<int8_t>(VT_DEFAULT_ENUM, static_cast<int8_t>(_default_enum), 1);
+  }
+  bool Verify(flatbuffers::Verifier &verifier) const {
+    return VerifyTableStart(verifier) &&
+           VerifyField<int8_t>(verifier, VT_JUST_I8) &&
+           VerifyField<int8_t>(verifier, VT_MAYBE_I8) &&
+           VerifyField<int8_t>(verifier, VT_DEFAULT_I8) &&
+           VerifyField<uint8_t>(verifier, VT_JUST_U8) &&
+           VerifyField<uint8_t>(verifier, VT_MAYBE_U8) &&
+           VerifyField<uint8_t>(verifier, VT_DEFAULT_U8) &&
+           VerifyField<int16_t>(verifier, VT_JUST_I16) &&
+           VerifyField<int16_t>(verifier, VT_MAYBE_I16) &&
+           VerifyField<int16_t>(verifier, VT_DEFAULT_I16) &&
+           VerifyField<uint16_t>(verifier, VT_JUST_U16) &&
+           VerifyField<uint16_t>(verifier, VT_MAYBE_U16) &&
+           VerifyField<uint16_t>(verifier, VT_DEFAULT_U16) &&
+           VerifyField<int32_t>(verifier, VT_JUST_I32) &&
+           VerifyField<int32_t>(verifier, VT_MAYBE_I32) &&
+           VerifyField<int32_t>(verifier, VT_DEFAULT_I32) &&
+           VerifyField<uint32_t>(verifier, VT_JUST_U32) &&
+           VerifyField<uint32_t>(verifier, VT_MAYBE_U32) &&
+           VerifyField<uint32_t>(verifier, VT_DEFAULT_U32) &&
+           VerifyField<int64_t>(verifier, VT_JUST_I64) &&
+           VerifyField<int64_t>(verifier, VT_MAYBE_I64) &&
+           VerifyField<int64_t>(verifier, VT_DEFAULT_I64) &&
+           VerifyField<uint64_t>(verifier, VT_JUST_U64) &&
+           VerifyField<uint64_t>(verifier, VT_MAYBE_U64) &&
+           VerifyField<uint64_t>(verifier, VT_DEFAULT_U64) &&
+           VerifyField<float>(verifier, VT_JUST_F32) &&
+           VerifyField<float>(verifier, VT_MAYBE_F32) &&
+           VerifyField<float>(verifier, VT_DEFAULT_F32) &&
+           VerifyField<double>(verifier, VT_JUST_F64) &&
+           VerifyField<double>(verifier, VT_MAYBE_F64) &&
+           VerifyField<double>(verifier, VT_DEFAULT_F64) &&
+           VerifyField<uint8_t>(verifier, VT_JUST_BOOL) &&
+           VerifyField<uint8_t>(verifier, VT_MAYBE_BOOL) &&
+           VerifyField<uint8_t>(verifier, VT_DEFAULT_BOOL) &&
+           VerifyField<int8_t>(verifier, VT_JUST_ENUM) &&
+           VerifyField<int8_t>(verifier, VT_DEFAULT_ENUM) &&
+           verifier.EndTable();
+  }
+  ScalarStuffT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const;
+  void UnPackTo(ScalarStuffT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const;
+  static flatbuffers::Offset<ScalarStuff> Pack(flatbuffers::FlatBufferBuilder &_fbb, const ScalarStuffT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
+};
+
+struct ScalarStuffBuilder {
+  typedef ScalarStuff Table;
+  flatbuffers::FlatBufferBuilder &fbb_;
+  flatbuffers::uoffset_t start_;
+  void add_just_i8(int8_t just_i8) {
+    fbb_.AddElement<int8_t>(ScalarStuff::VT_JUST_I8, just_i8, 0);
+  }
+  void add_maybe_i8(int8_t maybe_i8) {
+    fbb_.AddElement<int8_t>(ScalarStuff::VT_MAYBE_I8, maybe_i8);
+  }
+  void add_default_i8(int8_t default_i8) {
+    fbb_.AddElement<int8_t>(ScalarStuff::VT_DEFAULT_I8, default_i8, 42);
+  }
+  void add_just_u8(uint8_t just_u8) {
+    fbb_.AddElement<uint8_t>(ScalarStuff::VT_JUST_U8, just_u8, 0);
+  }
+  void add_maybe_u8(uint8_t maybe_u8) {
+    fbb_.AddElement<uint8_t>(ScalarStuff::VT_MAYBE_U8, maybe_u8);
+  }
+  void add_default_u8(uint8_t default_u8) {
+    fbb_.AddElement<uint8_t>(ScalarStuff::VT_DEFAULT_U8, default_u8, 42);
+  }
+  void add_just_i16(int16_t just_i16) {
+    fbb_.AddElement<int16_t>(ScalarStuff::VT_JUST_I16, just_i16, 0);
+  }
+  void add_maybe_i16(int16_t maybe_i16) {
+    fbb_.AddElement<int16_t>(ScalarStuff::VT_MAYBE_I16, maybe_i16);
+  }
+  void add_default_i16(int16_t default_i16) {
+    fbb_.AddElement<int16_t>(ScalarStuff::VT_DEFAULT_I16, default_i16, 42);
+  }
+  void add_just_u16(uint16_t just_u16) {
+    fbb_.AddElement<uint16_t>(ScalarStuff::VT_JUST_U16, just_u16, 0);
+  }
+  void add_maybe_u16(uint16_t maybe_u16) {
+    fbb_.AddElement<uint16_t>(ScalarStuff::VT_MAYBE_U16, maybe_u16);
+  }
+  void add_default_u16(uint16_t default_u16) {
+    fbb_.AddElement<uint16_t>(ScalarStuff::VT_DEFAULT_U16, default_u16, 42);
+  }
+  void add_just_i32(int32_t just_i32) {
+    fbb_.AddElement<int32_t>(ScalarStuff::VT_JUST_I32, just_i32, 0);
+  }
+  void add_maybe_i32(int32_t maybe_i32) {
+    fbb_.AddElement<int32_t>(ScalarStuff::VT_MAYBE_I32, maybe_i32);
+  }
+  void add_default_i32(int32_t default_i32) {
+    fbb_.AddElement<int32_t>(ScalarStuff::VT_DEFAULT_I32, default_i32, 42);
+  }
+  void add_just_u32(uint32_t just_u32) {
+    fbb_.AddElement<uint32_t>(ScalarStuff::VT_JUST_U32, just_u32, 0);
+  }
+  void add_maybe_u32(uint32_t maybe_u32) {
+    fbb_.AddElement<uint32_t>(ScalarStuff::VT_MAYBE_U32, maybe_u32);
+  }
+  void add_default_u32(uint32_t default_u32) {
+    fbb_.AddElement<uint32_t>(ScalarStuff::VT_DEFAULT_U32, default_u32, 42);
+  }
+  void add_just_i64(int64_t just_i64) {
+    fbb_.AddElement<int64_t>(ScalarStuff::VT_JUST_I64, just_i64, 0);
+  }
+  void add_maybe_i64(int64_t maybe_i64) {
+    fbb_.AddElement<int64_t>(ScalarStuff::VT_MAYBE_I64, maybe_i64);
+  }
+  void add_default_i64(int64_t default_i64) {
+    fbb_.AddElement<int64_t>(ScalarStuff::VT_DEFAULT_I64, default_i64, 42LL);
+  }
+  void add_just_u64(uint64_t just_u64) {
+    fbb_.AddElement<uint64_t>(ScalarStuff::VT_JUST_U64, just_u64, 0);
+  }
+  void add_maybe_u64(uint64_t maybe_u64) {
+    fbb_.AddElement<uint64_t>(ScalarStuff::VT_MAYBE_U64, maybe_u64);
+  }
+  void add_default_u64(uint64_t default_u64) {
+    fbb_.AddElement<uint64_t>(ScalarStuff::VT_DEFAULT_U64, default_u64, 42ULL);
+  }
+  void add_just_f32(float just_f32) {
+    fbb_.AddElement<float>(ScalarStuff::VT_JUST_F32, just_f32, 0.0f);
+  }
+  void add_maybe_f32(float maybe_f32) {
+    fbb_.AddElement<float>(ScalarStuff::VT_MAYBE_F32, maybe_f32);
+  }
+  void add_default_f32(float default_f32) {
+    fbb_.AddElement<float>(ScalarStuff::VT_DEFAULT_F32, default_f32, 42.0f);
+  }
+  void add_just_f64(double just_f64) {
+    fbb_.AddElement<double>(ScalarStuff::VT_JUST_F64, just_f64, 0.0);
+  }
+  void add_maybe_f64(double maybe_f64) {
+    fbb_.AddElement<double>(ScalarStuff::VT_MAYBE_F64, maybe_f64);
+  }
+  void add_default_f64(double default_f64) {
+    fbb_.AddElement<double>(ScalarStuff::VT_DEFAULT_F64, default_f64, 42.0);
+  }
+  void add_just_bool(bool just_bool) {
+    fbb_.AddElement<uint8_t>(ScalarStuff::VT_JUST_BOOL, static_cast<uint8_t>(just_bool), 0);
+  }
+  void add_maybe_bool(bool maybe_bool) {
+    fbb_.AddElement<uint8_t>(ScalarStuff::VT_MAYBE_BOOL, static_cast<uint8_t>(maybe_bool));
+  }
+  void add_default_bool(bool default_bool) {
+    fbb_.AddElement<uint8_t>(ScalarStuff::VT_DEFAULT_BOOL, static_cast<uint8_t>(default_bool), 1);
+  }
+  void add_just_enum(optional_scalars::OptionalByte just_enum) {
+    fbb_.AddElement<int8_t>(ScalarStuff::VT_JUST_ENUM, static_cast<int8_t>(just_enum), 0);
+  }
+  void add_default_enum(optional_scalars::OptionalByte default_enum) {
+    fbb_.AddElement<int8_t>(ScalarStuff::VT_DEFAULT_ENUM, static_cast<int8_t>(default_enum), 1);
+  }
+  explicit ScalarStuffBuilder(flatbuffers::FlatBufferBuilder &_fbb)
+        : fbb_(_fbb) {
+    start_ = fbb_.StartTable();
+  }
+  flatbuffers::Offset<ScalarStuff> Finish() {
+    const auto end = fbb_.EndTable(start_);
+    auto o = flatbuffers::Offset<ScalarStuff>(end);
+    return o;
+  }
+};
+
+inline flatbuffers::Offset<ScalarStuff> CreateScalarStuff(
+    flatbuffers::FlatBufferBuilder &_fbb,
+    int8_t just_i8 = 0,
+    flatbuffers::Optional<int8_t>maybe_i8 = flatbuffers::nullopt,
+    int8_t default_i8 = 42,
+    uint8_t just_u8 = 0,
+    flatbuffers::Optional<uint8_t>maybe_u8 = flatbuffers::nullopt,
+    uint8_t default_u8 = 42,
+    int16_t just_i16 = 0,
+    flatbuffers::Optional<int16_t>maybe_i16 = flatbuffers::nullopt,
+    int16_t default_i16 = 42,
+    uint16_t just_u16 = 0,
+    flatbuffers::Optional<uint16_t>maybe_u16 = flatbuffers::nullopt,
+    uint16_t default_u16 = 42,
+    int32_t just_i32 = 0,
+    flatbuffers::Optional<int32_t>maybe_i32 = flatbuffers::nullopt,
+    int32_t default_i32 = 42,
+    uint32_t just_u32 = 0,
+    flatbuffers::Optional<uint32_t>maybe_u32 = flatbuffers::nullopt,
+    uint32_t default_u32 = 42,
+    int64_t just_i64 = 0,
+    flatbuffers::Optional<int64_t>maybe_i64 = flatbuffers::nullopt,
+    int64_t default_i64 = 42LL,
+    uint64_t just_u64 = 0,
+    flatbuffers::Optional<uint64_t>maybe_u64 = flatbuffers::nullopt,
+    uint64_t default_u64 = 42ULL,
+    float just_f32 = 0.0f,
+    flatbuffers::Optional<float>maybe_f32 = flatbuffers::nullopt,
+    float default_f32 = 42.0f,
+    double just_f64 = 0.0,
+    flatbuffers::Optional<double>maybe_f64 = flatbuffers::nullopt,
+    double default_f64 = 42.0,
+    bool just_bool = false,
+    flatbuffers::Optional<bool>maybe_bool = flatbuffers::nullopt,
+    bool default_bool = true,
+    optional_scalars::OptionalByte just_enum = optional_scalars::OptionalByte_None,
+    optional_scalars::OptionalByte default_enum = optional_scalars::OptionalByte_One) {
+  ScalarStuffBuilder builder_(_fbb);
+  builder_.add_default_f64(default_f64);
+  if(maybe_f64) { builder_.add_maybe_f64(*maybe_f64); }
+  builder_.add_just_f64(just_f64);
+  builder_.add_default_u64(default_u64);
+  if(maybe_u64) { builder_.add_maybe_u64(*maybe_u64); }
+  builder_.add_just_u64(just_u64);
+  builder_.add_default_i64(default_i64);
+  if(maybe_i64) { builder_.add_maybe_i64(*maybe_i64); }
+  builder_.add_just_i64(just_i64);
+  builder_.add_default_f32(default_f32);
+  if(maybe_f32) { builder_.add_maybe_f32(*maybe_f32); }
+  builder_.add_just_f32(just_f32);
+  builder_.add_default_u32(default_u32);
+  if(maybe_u32) { builder_.add_maybe_u32(*maybe_u32); }
+  builder_.add_just_u32(just_u32);
+  builder_.add_default_i32(default_i32);
+  if(maybe_i32) { builder_.add_maybe_i32(*maybe_i32); }
+  builder_.add_just_i32(just_i32);
+  builder_.add_default_u16(default_u16);
+  if(maybe_u16) { builder_.add_maybe_u16(*maybe_u16); }
+  builder_.add_just_u16(just_u16);
+  builder_.add_default_i16(default_i16);
+  if(maybe_i16) { builder_.add_maybe_i16(*maybe_i16); }
+  builder_.add_just_i16(just_i16);
+  builder_.add_default_enum(default_enum);
+  builder_.add_just_enum(just_enum);
+  builder_.add_default_bool(default_bool);
+  if(maybe_bool) { builder_.add_maybe_bool(*maybe_bool); }
+  builder_.add_just_bool(just_bool);
+  builder_.add_default_u8(default_u8);
+  if(maybe_u8) { builder_.add_maybe_u8(*maybe_u8); }
+  builder_.add_just_u8(just_u8);
+  builder_.add_default_i8(default_i8);
+  if(maybe_i8) { builder_.add_maybe_i8(*maybe_i8); }
+  builder_.add_just_i8(just_i8);
+  return builder_.Finish();
+}
+
+flatbuffers::Offset<ScalarStuff> CreateScalarStuff(flatbuffers::FlatBufferBuilder &_fbb, const ScalarStuffT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
+
+inline ScalarStuffT *ScalarStuff::UnPack(const flatbuffers::resolver_function_t *_resolver) const {
+  flatbuffers::unique_ptr<optional_scalars::ScalarStuffT> _o = flatbuffers::unique_ptr<optional_scalars::ScalarStuffT>(new ScalarStuffT());
+  UnPackTo(_o.get(), _resolver);
+  return _o.release();
+}
+
+inline void ScalarStuff::UnPackTo(ScalarStuffT *_o, const flatbuffers::resolver_function_t *_resolver) const {
+  (void)_o;
+  (void)_resolver;
+  { auto _e = just_i8(); _o->just_i8 = _e; }
+  { auto _e = maybe_i8(); _o->maybe_i8 = _e; }
+  { auto _e = default_i8(); _o->default_i8 = _e; }
+  { auto _e = just_u8(); _o->just_u8 = _e; }
+  { auto _e = maybe_u8(); _o->maybe_u8 = _e; }
+  { auto _e = default_u8(); _o->default_u8 = _e; }
+  { auto _e = just_i16(); _o->just_i16 = _e; }
+  { auto _e = maybe_i16(); _o->maybe_i16 = _e; }
+  { auto _e = default_i16(); _o->default_i16 = _e; }
+  { auto _e = just_u16(); _o->just_u16 = _e; }
+  { auto _e = maybe_u16(); _o->maybe_u16 = _e; }
+  { auto _e = default_u16(); _o->default_u16 = _e; }
+  { auto _e = just_i32(); _o->just_i32 = _e; }
+  { auto _e = maybe_i32(); _o->maybe_i32 = _e; }
+  { auto _e = default_i32(); _o->default_i32 = _e; }
+  { auto _e = just_u32(); _o->just_u32 = _e; }
+  { auto _e = maybe_u32(); _o->maybe_u32 = _e; }
+  { auto _e = default_u32(); _o->default_u32 = _e; }
+  { auto _e = just_i64(); _o->just_i64 = _e; }
+  { auto _e = maybe_i64(); _o->maybe_i64 = _e; }
+  { auto _e = default_i64(); _o->default_i64 = _e; }
+  { auto _e = just_u64(); _o->just_u64 = _e; }
+  { auto _e = maybe_u64(); _o->maybe_u64 = _e; }
+  { auto _e = default_u64(); _o->default_u64 = _e; }
+  { auto _e = just_f32(); _o->just_f32 = _e; }
+  { auto _e = maybe_f32(); _o->maybe_f32 = _e; }
+  { auto _e = default_f32(); _o->default_f32 = _e; }
+  { auto _e = just_f64(); _o->just_f64 = _e; }
+  { auto _e = maybe_f64(); _o->maybe_f64 = _e; }
+  { auto _e = default_f64(); _o->default_f64 = _e; }
+  { auto _e = just_bool(); _o->just_bool = _e; }
+  { auto _e = maybe_bool(); _o->maybe_bool = _e; }
+  { auto _e = default_bool(); _o->default_bool = _e; }
+  { auto _e = just_enum(); _o->just_enum = _e; }
+  { auto _e = default_enum(); _o->default_enum = _e; }
+}
+
+inline flatbuffers::Offset<ScalarStuff> ScalarStuff::Pack(flatbuffers::FlatBufferBuilder &_fbb, const ScalarStuffT* _o, const flatbuffers::rehasher_function_t *_rehasher) {
+  return CreateScalarStuff(_fbb, _o, _rehasher);
+}
+
+inline flatbuffers::Offset<ScalarStuff> CreateScalarStuff(flatbuffers::FlatBufferBuilder &_fbb, const ScalarStuffT *_o, const flatbuffers::rehasher_function_t *_rehasher) {
+  (void)_rehasher;
+  (void)_o;
+  struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const ScalarStuffT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va;
+  auto _just_i8 = _o->just_i8;
+  auto _maybe_i8 = _o->maybe_i8;
+  auto _default_i8 = _o->default_i8;
+  auto _just_u8 = _o->just_u8;
+  auto _maybe_u8 = _o->maybe_u8;
+  auto _default_u8 = _o->default_u8;
+  auto _just_i16 = _o->just_i16;
+  auto _maybe_i16 = _o->maybe_i16;
+  auto _default_i16 = _o->default_i16;
+  auto _just_u16 = _o->just_u16;
+  auto _maybe_u16 = _o->maybe_u16;
+  auto _default_u16 = _o->default_u16;
+  auto _just_i32 = _o->just_i32;
+  auto _maybe_i32 = _o->maybe_i32;
+  auto _default_i32 = _o->default_i32;
+  auto _just_u32 = _o->just_u32;
+  auto _maybe_u32 = _o->maybe_u32;
+  auto _default_u32 = _o->default_u32;
+  auto _just_i64 = _o->just_i64;
+  auto _maybe_i64 = _o->maybe_i64;
+  auto _default_i64 = _o->default_i64;
+  auto _just_u64 = _o->just_u64;
+  auto _maybe_u64 = _o->maybe_u64;
+  auto _default_u64 = _o->default_u64;
+  auto _just_f32 = _o->just_f32;
+  auto _maybe_f32 = _o->maybe_f32;
+  auto _default_f32 = _o->default_f32;
+  auto _just_f64 = _o->just_f64;
+  auto _maybe_f64 = _o->maybe_f64;
+  auto _default_f64 = _o->default_f64;
+  auto _just_bool = _o->just_bool;
+  auto _maybe_bool = _o->maybe_bool;
+  auto _default_bool = _o->default_bool;
+  auto _just_enum = _o->just_enum;
+  auto _default_enum = _o->default_enum;
+  return optional_scalars::CreateScalarStuff(
+      _fbb,
+      _just_i8,
+      _maybe_i8,
+      _default_i8,
+      _just_u8,
+      _maybe_u8,
+      _default_u8,
+      _just_i16,
+      _maybe_i16,
+      _default_i16,
+      _just_u16,
+      _maybe_u16,
+      _default_u16,
+      _just_i32,
+      _maybe_i32,
+      _default_i32,
+      _just_u32,
+      _maybe_u32,
+      _default_u32,
+      _just_i64,
+      _maybe_i64,
+      _default_i64,
+      _just_u64,
+      _maybe_u64,
+      _default_u64,
+      _just_f32,
+      _maybe_f32,
+      _default_f32,
+      _just_f64,
+      _maybe_f64,
+      _default_f64,
+      _just_bool,
+      _maybe_bool,
+      _default_bool,
+      _just_enum,
+      _default_enum);
+}
+
+inline const flatbuffers::TypeTable *OptionalByteTypeTable() {
+  static const flatbuffers::TypeCode type_codes[] = {
+    { flatbuffers::ET_CHAR, 0, 0 },
+    { flatbuffers::ET_CHAR, 0, 0 }
+  };
+  static const flatbuffers::TypeFunction type_refs[] = {
+    optional_scalars::OptionalByteTypeTable
+  };
+  static const char * const names[] = {
+    "None",
+    "One"
+  };
+  static const flatbuffers::TypeTable tt = {
+    flatbuffers::ST_ENUM, 2, type_codes, type_refs, nullptr, names
+  };
+  return &tt;
+}
+
+inline const flatbuffers::TypeTable *ScalarStuffTypeTable() {
+  static const flatbuffers::TypeCode type_codes[] = {
+    { flatbuffers::ET_CHAR, 0, -1 },
+    { flatbuffers::ET_CHAR, 0, -1 },
+    { flatbuffers::ET_CHAR, 0, -1 },
+    { flatbuffers::ET_UCHAR, 0, -1 },
+    { flatbuffers::ET_UCHAR, 0, -1 },
+    { flatbuffers::ET_UCHAR, 0, -1 },
+    { flatbuffers::ET_SHORT, 0, -1 },
+    { flatbuffers::ET_SHORT, 0, -1 },
+    { flatbuffers::ET_SHORT, 0, -1 },
+    { flatbuffers::ET_USHORT, 0, -1 },
+    { flatbuffers::ET_USHORT, 0, -1 },
+    { flatbuffers::ET_USHORT, 0, -1 },
+    { flatbuffers::ET_INT, 0, -1 },
+    { flatbuffers::ET_INT, 0, -1 },
+    { flatbuffers::ET_INT, 0, -1 },
+    { flatbuffers::ET_UINT, 0, -1 },
+    { flatbuffers::ET_UINT, 0, -1 },
+    { flatbuffers::ET_UINT, 0, -1 },
+    { flatbuffers::ET_LONG, 0, -1 },
+    { flatbuffers::ET_LONG, 0, -1 },
+    { flatbuffers::ET_LONG, 0, -1 },
+    { flatbuffers::ET_ULONG, 0, -1 },
+    { flatbuffers::ET_ULONG, 0, -1 },
+    { flatbuffers::ET_ULONG, 0, -1 },
+    { flatbuffers::ET_FLOAT, 0, -1 },
+    { flatbuffers::ET_FLOAT, 0, -1 },
+    { flatbuffers::ET_FLOAT, 0, -1 },
+    { flatbuffers::ET_DOUBLE, 0, -1 },
+    { flatbuffers::ET_DOUBLE, 0, -1 },
+    { flatbuffers::ET_DOUBLE, 0, -1 },
+    { flatbuffers::ET_BOOL, 0, -1 },
+    { flatbuffers::ET_BOOL, 0, -1 },
+    { flatbuffers::ET_BOOL, 0, -1 },
+    { flatbuffers::ET_CHAR, 0, 0 },
+    { flatbuffers::ET_CHAR, 0, 0 }
+  };
+  static const flatbuffers::TypeFunction type_refs[] = {
+    optional_scalars::OptionalByteTypeTable
+  };
+  static const char * const names[] = {
+    "just_i8",
+    "maybe_i8",
+    "default_i8",
+    "just_u8",
+    "maybe_u8",
+    "default_u8",
+    "just_i16",
+    "maybe_i16",
+    "default_i16",
+    "just_u16",
+    "maybe_u16",
+    "default_u16",
+    "just_i32",
+    "maybe_i32",
+    "default_i32",
+    "just_u32",
+    "maybe_u32",
+    "default_u32",
+    "just_i64",
+    "maybe_i64",
+    "default_i64",
+    "just_u64",
+    "maybe_u64",
+    "default_u64",
+    "just_f32",
+    "maybe_f32",
+    "default_f32",
+    "just_f64",
+    "maybe_f64",
+    "default_f64",
+    "just_bool",
+    "maybe_bool",
+    "default_bool",
+    "just_enum",
+    "default_enum"
+  };
+  static const flatbuffers::TypeTable tt = {
+    flatbuffers::ST_TABLE, 35, type_codes, type_refs, nullptr, names
+  };
+  return &tt;
+}
+
+inline const optional_scalars::ScalarStuff *GetScalarStuff(const void *buf) {
+  return flatbuffers::GetRoot<optional_scalars::ScalarStuff>(buf);
+}
+
+inline const optional_scalars::ScalarStuff *GetSizePrefixedScalarStuff(const void *buf) {
+  return flatbuffers::GetSizePrefixedRoot<optional_scalars::ScalarStuff>(buf);
+}
+
+inline ScalarStuff *GetMutableScalarStuff(void *buf) {
+  return flatbuffers::GetMutableRoot<ScalarStuff>(buf);
+}
+
+inline const char *ScalarStuffIdentifier() {
+  return "NULL";
+}
+
+inline bool ScalarStuffBufferHasIdentifier(const void *buf) {
+  return flatbuffers::BufferHasIdentifier(
+      buf, ScalarStuffIdentifier());
+}
+
+inline bool VerifyScalarStuffBuffer(
+    flatbuffers::Verifier &verifier) {
+  return verifier.VerifyBuffer<optional_scalars::ScalarStuff>(ScalarStuffIdentifier());
+}
+
+inline bool VerifySizePrefixedScalarStuffBuffer(
+    flatbuffers::Verifier &verifier) {
+  return verifier.VerifySizePrefixedBuffer<optional_scalars::ScalarStuff>(ScalarStuffIdentifier());
+}
+
+inline const char *ScalarStuffExtension() {
+  return "mon";
+}
+
+inline void FinishScalarStuffBuffer(
+    flatbuffers::FlatBufferBuilder &fbb,
+    flatbuffers::Offset<optional_scalars::ScalarStuff> root) {
+  fbb.Finish(root, ScalarStuffIdentifier());
+}
+
+inline void FinishSizePrefixedScalarStuffBuffer(
+    flatbuffers::FlatBufferBuilder &fbb,
+    flatbuffers::Offset<optional_scalars::ScalarStuff> root) {
+  fbb.FinishSizePrefixed(root, ScalarStuffIdentifier());
+}
+
+inline flatbuffers::unique_ptr<optional_scalars::ScalarStuffT> UnPackScalarStuff(
+    const void *buf,
+    const flatbuffers::resolver_function_t *res = nullptr) {
+  return flatbuffers::unique_ptr<optional_scalars::ScalarStuffT>(GetScalarStuff(buf)->UnPack(res));
+}
+
+inline flatbuffers::unique_ptr<optional_scalars::ScalarStuffT> UnPackSizePrefixedScalarStuff(
+    const void *buf,
+    const flatbuffers::resolver_function_t *res = nullptr) {
+  return flatbuffers::unique_ptr<optional_scalars::ScalarStuffT>(GetSizePrefixedScalarStuff(buf)->UnPack(res));
+}
+
+}  // namespace optional_scalars
+
+#endif  // FLATBUFFERS_GENERATED_OPTIONALSCALARS_OPTIONAL_SCALARS_H_
index 0c4b928..3a9f0c5 100644 (file)
@@ -3,6 +3,10 @@ import flatbuffers
 
 namespace optional_scalars
 
+enum OptionalByte:
+    OptionalByte_None = 0
+    OptionalByte_One = 1
+
 class ScalarStuff
 
 class ScalarStuff : flatbuffers_handle
@@ -72,13 +76,17 @@ class ScalarStuff : flatbuffers_handle
         return buf_.flatbuffers_field_int8(pos_, 66, 0), buf_.flatbuffers_field_present(pos_, 66)
     def default_bool():
         return buf_.flatbuffers_field_int8(pos_, 68, 1)
+    def just_enum():
+        return OptionalByte(buf_.flatbuffers_field_int8(pos_, 70, 0))
+    def default_enum():
+        return OptionalByte(buf_.flatbuffers_field_int8(pos_, 72, 1))
 
 def GetRootAsScalarStuff(buf:string): return ScalarStuff { buf, buf.flatbuffers_indirect(0) }
 
 struct ScalarStuffBuilder:
     b_:flatbuffers_builder
     def start():
-        b_.StartObject(33)
+        b_.StartObject(35)
         return this
     def add_just_i8(just_i8:int):
         b_.PrependInt8Slot(0, just_i8, 0)
@@ -179,6 +187,12 @@ struct ScalarStuffBuilder:
     def add_default_bool(default_bool:int):
         b_.PrependBoolSlot(32, default_bool, 1)
         return this
+    def add_just_enum(just_enum:OptionalByte):
+        b_.PrependInt8Slot(33, just_enum, 0)
+        return this
+    def add_default_enum(default_enum:OptionalByte):
+        b_.PrependInt8Slot(34, default_enum, 1)
+        return this
     def end():
         return b_.EndObject()
 
index 2cc413c..39625a4 100644 (file)
@@ -17,6 +17,66 @@ pub mod optional_scalars {
   extern crate flatbuffers;
   use self::flatbuffers::EndianScalar;
 
+#[allow(non_camel_case_types)]
+#[repr(i8)]
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
+pub enum OptionalByte {
+  None = 0,
+  One = 1,
+
+}
+
+pub const ENUM_MIN_OPTIONAL_BYTE: i8 = 0;
+pub const ENUM_MAX_OPTIONAL_BYTE: i8 = 1;
+
+impl<'a> flatbuffers::Follow<'a> for OptionalByte {
+  type Inner = Self;
+  #[inline]
+  fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+    flatbuffers::read_scalar_at::<Self>(buf, loc)
+  }
+}
+
+impl flatbuffers::EndianScalar for OptionalByte {
+  #[inline]
+  fn to_little_endian(self) -> Self {
+    let n = i8::to_le(self as i8);
+    let p = &n as *const i8 as *const OptionalByte;
+    unsafe { *p }
+  }
+  #[inline]
+  fn from_little_endian(self) -> Self {
+    let n = i8::from_le(self as i8);
+    let p = &n as *const i8 as *const OptionalByte;
+    unsafe { *p }
+  }
+}
+
+impl flatbuffers::Push for OptionalByte {
+    type Output = OptionalByte;
+    #[inline]
+    fn push(&self, dst: &mut [u8], _rest: &[u8]) {
+        flatbuffers::emplace_scalar::<OptionalByte>(dst, *self);
+    }
+}
+
+#[allow(non_camel_case_types)]
+pub const ENUM_VALUES_OPTIONAL_BYTE: [OptionalByte; 2] = [
+  OptionalByte::None,
+  OptionalByte::One
+];
+
+#[allow(non_camel_case_types)]
+pub const ENUM_NAMES_OPTIONAL_BYTE: [&str; 2] = [
+    "None",
+    "One"
+];
+
+pub fn enum_name_optional_byte(e: OptionalByte) -> &'static str {
+  let index = e as i8;
+  ENUM_NAMES_OPTIONAL_BYTE[index as usize]
+}
+
 pub enum ScalarStuffOffset {}
 #[derive(Copy, Clone, Debug, PartialEq)]
 
@@ -68,6 +128,8 @@ impl<'a> ScalarStuff<'a> {
       builder.add_default_i16(args.default_i16);
       if let Some(x) = args.maybe_i16 { builder.add_maybe_i16(x); }
       builder.add_just_i16(args.just_i16);
+      builder.add_default_enum(args.default_enum);
+      builder.add_just_enum(args.just_enum);
       builder.add_default_bool(args.default_bool);
       if let Some(x) = args.maybe_bool { builder.add_maybe_bool(x); }
       builder.add_just_bool(args.just_bool);
@@ -113,6 +175,8 @@ impl<'a> ScalarStuff<'a> {
     pub const VT_JUST_BOOL: flatbuffers::VOffsetT = 64;
     pub const VT_MAYBE_BOOL: flatbuffers::VOffsetT = 66;
     pub const VT_DEFAULT_BOOL: flatbuffers::VOffsetT = 68;
+    pub const VT_JUST_ENUM: flatbuffers::VOffsetT = 70;
+    pub const VT_DEFAULT_ENUM: flatbuffers::VOffsetT = 72;
 
   #[inline]
   pub fn just_i8(&self) -> i8 {
@@ -246,6 +310,14 @@ impl<'a> ScalarStuff<'a> {
   pub fn default_bool(&self) -> bool {
     self._tab.get::<bool>(ScalarStuff::VT_DEFAULT_BOOL, Some(true)).unwrap()
   }
+  #[inline]
+  pub fn just_enum(&self) -> OptionalByte {
+    self._tab.get::<OptionalByte>(ScalarStuff::VT_JUST_ENUM, Some(OptionalByte::None)).unwrap()
+  }
+  #[inline]
+  pub fn default_enum(&self) -> OptionalByte {
+    self._tab.get::<OptionalByte>(ScalarStuff::VT_DEFAULT_ENUM, Some(OptionalByte::One)).unwrap()
+  }
 }
 
 pub struct ScalarStuffArgs {
@@ -282,6 +354,8 @@ pub struct ScalarStuffArgs {
     pub just_bool: bool,
     pub maybe_bool: Option<bool>,
     pub default_bool: bool,
+    pub just_enum: OptionalByte,
+    pub default_enum: OptionalByte,
 }
 impl<'a> Default for ScalarStuffArgs {
     #[inline]
@@ -320,6 +394,8 @@ impl<'a> Default for ScalarStuffArgs {
             just_bool: false,
             maybe_bool: None,
             default_bool: true,
+            just_enum: OptionalByte::None,
+            default_enum: OptionalByte::One,
         }
     }
 }
@@ -461,6 +537,14 @@ impl<'a: 'b, 'b> ScalarStuffBuilder<'a, 'b> {
     self.fbb_.push_slot::<bool>(ScalarStuff::VT_DEFAULT_BOOL, default_bool, true);
   }
   #[inline]
+  pub fn add_just_enum(&mut self, just_enum: OptionalByte) {
+    self.fbb_.push_slot::<OptionalByte>(ScalarStuff::VT_JUST_ENUM, just_enum, OptionalByte::None);
+  }
+  #[inline]
+  pub fn add_default_enum(&mut self, default_enum: OptionalByte) {
+    self.fbb_.push_slot::<OptionalByte>(ScalarStuff::VT_DEFAULT_ENUM, default_enum, OptionalByte::One);
+  }
+  #[inline]
   pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> ScalarStuffBuilder<'a, 'b> {
     let start = _fbb.start_table();
     ScalarStuffBuilder {
@@ -475,5 +559,40 @@ impl<'a: 'b, 'b> ScalarStuffBuilder<'a, 'b> {
   }
 }
 
+#[inline]
+pub fn get_root_as_scalar_stuff<'a>(buf: &'a [u8]) -> ScalarStuff<'a> {
+  flatbuffers::get_root::<ScalarStuff<'a>>(buf)
+}
+
+#[inline]
+pub fn get_size_prefixed_root_as_scalar_stuff<'a>(buf: &'a [u8]) -> ScalarStuff<'a> {
+  flatbuffers::get_size_prefixed_root::<ScalarStuff<'a>>(buf)
+}
+
+pub const SCALAR_STUFF_IDENTIFIER: &str = "NULL";
+
+#[inline]
+pub fn scalar_stuff_buffer_has_identifier(buf: &[u8]) -> bool {
+  flatbuffers::buffer_has_identifier(buf, SCALAR_STUFF_IDENTIFIER, false)
+}
+
+#[inline]
+pub fn scalar_stuff_size_prefixed_buffer_has_identifier(buf: &[u8]) -> bool {
+  flatbuffers::buffer_has_identifier(buf, SCALAR_STUFF_IDENTIFIER, true)
+}
+
+pub const SCALAR_STUFF_EXTENSION: &str = "mon";
+
+#[inline]
+pub fn finish_scalar_stuff_buffer<'a, 'b>(
+    fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>,
+    root: flatbuffers::WIPOffset<ScalarStuff<'a>>) {
+  fbb.finish(root, Some(SCALAR_STUFF_IDENTIFIER));
+}
+
+#[inline]
+pub fn finish_size_prefixed_scalar_stuff_buffer<'a, 'b>(fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>, root: flatbuffers::WIPOffset<ScalarStuff<'a>>) {
+  fbb.finish_size_prefixed(root, Some(SCALAR_STUFF_IDENTIFIER));
+}
 }  // pub mod optional_scalars
 
index 7f3c7d3..3f20560 100644 (file)
@@ -23,7 +23,6 @@
 
 // clang-format off
 #ifdef FLATBUFFERS_CPP98_STL
-  #include "flatbuffers/stl_emulation.h"
   namespace std {
     using flatbuffers::unique_ptr;
   }
@@ -35,6 +34,7 @@
 #include "namespace_test/namespace_test2_generated.h"
 #include "union_vector/union_vector_generated.h"
 #include "monster_extra_generated.h"
+#include "optional_scalars_generated.h"
 #if !defined(_MSC_VER) || _MSC_VER >= 1700
 #  include "arrays_test_generated.h"
 #  include "evolution_test/evolution_v1_generated.h"
@@ -3462,23 +3462,51 @@ void OptionalScalarsTest() {
     TEST_EQ(mana->optional, has_null);
   }
 
-  // Test if optional scalars are allowed for each language.
-  const int kNumLanguages = 17;
-  const auto supported = (flatbuffers::IDLOptions::kRust |
-                          flatbuffers::IDLOptions::kSwift |
-                          flatbuffers::IDLOptions::kKotlin |
-                          flatbuffers::IDLOptions::kLobster);
-  for (int lang=0; lang<kNumLanguages; lang++) {
+  // Test if nullable scalars are allowed for each language.
+  for (unsigned lang = 1; lang < flatbuffers::IDLOptions::kMAX; lang <<= 1) {
     flatbuffers::IDLOptions opts;
-    opts.lang_to_generate |= 1 << lang;
-    if (opts.lang_to_generate & supported) continue;
+    opts.lang_to_generate = lang;
+    if (false == flatbuffers::Parser::SupportsOptionalScalars(opts)) {
+      continue;
+    }
     for (auto schema = schemas.begin(); schema < schemas.end(); schema++) {
-      const bool has_null = schema->find("null") != std::string::npos;
       flatbuffers::Parser parser(opts);
-      // Its not supported in any language yet so has_null means error.
-      TEST_EQ(parser.Parse(schema->c_str()), !has_null);
+      auto done = parser.Parse(schema->c_str());
+      TEST_EQ_STR(parser.error_.c_str(), "");
+      TEST_ASSERT(done);
     }
   }
+
+  // test C++ nullable
+  flatbuffers::FlatBufferBuilder fbb;
+  FinishScalarStuffBuffer(
+      fbb, optional_scalars::CreateScalarStuff(fbb, 1, static_cast<int8_t>(2)));
+  auto opts = optional_scalars::GetMutableScalarStuff(fbb.GetBufferPointer());
+  TEST_ASSERT(!opts->maybe_bool());
+  TEST_ASSERT(!opts->maybe_f32().has_value());
+  TEST_ASSERT(opts->maybe_i8().has_value());
+  TEST_EQ(opts->maybe_i8().value(), 2);
+  TEST_ASSERT(opts->mutate_maybe_i8(3));
+  TEST_ASSERT(opts->maybe_i8().has_value());
+  TEST_EQ(opts->maybe_i8().value(), 3);
+  TEST_ASSERT(!opts->mutate_maybe_i16(-10));
+
+  optional_scalars::ScalarStuffT obj;
+  opts->UnPackTo(&obj);
+  TEST_ASSERT(!obj.maybe_bool);
+  TEST_ASSERT(!obj.maybe_f32.has_value());
+  TEST_ASSERT(obj.maybe_i8.has_value() && obj.maybe_i8.value() == 3);
+  TEST_ASSERT(obj.maybe_i8 && *obj.maybe_i8 == 3);
+  obj.maybe_i32 = -1;
+
+  fbb.Clear();
+  FinishScalarStuffBuffer(fbb, optional_scalars::ScalarStuff::Pack(fbb, &obj));
+  opts = optional_scalars::GetMutableScalarStuff(fbb.GetBufferPointer());
+  TEST_ASSERT(opts->maybe_i8().has_value());
+  TEST_EQ(opts->maybe_i8().value(), 3);
+  TEST_ASSERT(opts->maybe_i32().has_value());
+  TEST_EQ(opts->maybe_i32().value(), -1);
+  TEST_ASSERT(opts->maybe_i32() == flatbuffers::Optional<int64_t>(-1));
 }
 
 void ParseFlexbuffersFromJsonWithNullTest() {